diff -ur --new-file old/linux/CREDITS new/linux/CREDITS --- old/linux/CREDITS Thu Jan 28 20:25:04 1999 +++ new/linux/CREDITS Tue May 11 18:57:14 1999 @@ -256,6 +256,10 @@ D: Configuration help text support D: Linux CD and Support Giveaway List +N: Zoltan Boszormenyi +E: zboszor@mol.hu +D: MTRR emulation with Cyrix style ARR registers + N: John Boyd E: boyd@cis.ohio-state.edu D: Co-author of wd7000 SCSI driver @@ -779,6 +783,15 @@ S: Mountain View, California 94043 S: USA +N: Benjamin Herrenschmidt +E: bh40@calva.net +E: benh@mipsys.com +D: PowerMac booter (BootX) +D: Additional PowerBook support +S: 22, rue des Marguettes +S: 75012 Paris +S: France + N: Sebastian Hetze E: she@lunetix.de D: German Linux Documentation, @@ -801,12 +814,13 @@ D: Transmeta BOFH in my copius free time N: Dirk Hohndel -E: hohndel@aib.com +E: hohndel@suse.de D: The XFree86[tm] Project -S: AIB Software Corporation -S: 46030 Manekin Plaza, Suite 160 -S: Dulles, Virginia 20166 -S: USA +D: USB mouse maintainer +S: SuSE Rhein/Main AG +S: Mergenthalerallee 45-47 +S: 65760 Eschborn +S: Germany N: Kenji Tsutomu Hollis E: khollis@bitgate.com @@ -1061,6 +1075,14 @@ S: L3R 8B2 S: Canada +N: Russell Kroll +E: rkroll@exploits.org +W: http://www.exploits.org/ +D: V4L Aztech radio card driver, mods to Aimslab driver +S: Post Office Box 49458 +S: Colorado Springs, Colorado 80949-9458 +S: USA + N: Gero Kuhlmann E: gero@gkminix.han.de D: mounting root via NFS @@ -1403,6 +1425,13 @@ S: FIN-00330 Helsingfors S: Finland +N: Trond Myklebust +E: trond.myklebust@fys.uio.no +D: current NFS client hacker. +S: Dagaliveien 31e +S: N-0391 Oslo +S: Norway + N: Matija Nalis E: mnalis@jagor.srce.hr E: mnalis@voyager.hr @@ -1745,7 +1774,7 @@ N: Jaspreet Singh E: jaspreet@sangoma.com W: www.sangoma.com -D: WANPIPE driver for Sangoma S508/FT1 cards +D: WANPIPE drivers & API Support for Sangoma S508/FT1 cards S: Sangoma Technologies Inc., S: 1001 Denison Street S: Suite 101 @@ -1850,7 +1879,7 @@ N: Linus Torvalds E: torvalds@transmeta.com -W: http://www.cs.helsinki.fi/~torvalds/ +W: http://www.cs.helsinki.fi/Linus.Torvalds P: 1024/A86B35C5 96 54 50 29 EC 11 44 7A BE 67 3C 24 03 13 62 C8 D: Original kernel hacker S: 1050 Woodduck Avenue @@ -1997,6 +2026,14 @@ S: 10200 Prague 10, Hostivar S: Czech Republic +N: James R. Van Zandt +E: jrv@vanzandt.mv.com +P: 1024/E298966D F0 37 4F FD E5 7E C5 E6 F1 A0 1E 22 6F 46 DA 0C +D: Author and maintainer of the Double Talk speech synthesizer driver +S: 27 Spencer Drive +S: Nashua, New Hampshire 03062 +S: USA + N: Andrew Veliath E: andrewtv@usa.net D: Turtle Beach MultiSound sound driver @@ -2184,6 +2221,12 @@ S: 1507 145th Place SE #B5 S: Bellevue, Washington 98007 S: USA + +N: Richard Zidlicky +E: rdzidlic@geocities.com,rdzidlic@cip.informatik.uni-erlangen.de +W: http://www.geocities.com/SiliconValley/Bay/2602/ +D: Q40 port - see arch/m68k/q40/README +S: Germany N: Werner Zimmermann E: Werner.Zimmermann@fht-esslingen.de diff -ur --new-file old/linux/Documentation/00-INDEX new/linux/Documentation/00-INDEX --- old/linux/Documentation/00-INDEX Fri Dec 18 23:01:48 1998 +++ new/linux/Documentation/00-INDEX Thu Apr 29 20:53:41 1999 @@ -38,7 +38,7 @@ digiepca.txt - info on Digi Intl. {PC,PCI,EISA}Xx and Xem series cards. exception.txt - - how linux v2.1 handles exceptions without verify_area etc. + - how Linux v2.2 handles exceptions without verify_area etc. filesystems/ - directory with info on the various filesystems that Linux supports. ftape.txt @@ -52,11 +52,13 @@ ioctl-number.txt - how to implement and register device/driver ioctl calls. isdn/ - - directory with info on the linux ISDN support, and supported cards. + - directory with info on the Linux ISDN support, and supported cards. java.txt - info on the in-kernel binary support for Java(tm) joystick.txt - - info on using joystick devices (and driver) with linux. + - info on using joystick devices (and driver) with Linux. +kbuild/ + - directory with info about the kernel build process kmod.txt - - info on the kernel module loader/unloader (kerneld replacement) locks.txt @@ -70,7 +72,7 @@ magic-number.txt - list of magic numbers used to mark/protect kernel data structures. mandatory.txt - - info on the linux implementation of Sys V mandatory file locking. + - info on the Linux implementation of Sys V mandatory file locking. mca.txt - info on supporting Micro Channel Architecture (e.g. PS/2) systems. md.txt @@ -98,7 +100,7 @@ pcwd-watchdog.txt - info and sample code for using with the PC Watchdog reset card. powerpc/ - - directory with info on using linux with the PowerPC. + - directory with info on using Linux with the PowerPC. ramdisk.txt - short guide on how to set up and use the RAM disk. riscom8.txt @@ -108,7 +110,7 @@ scsi.txt - short blurb on using SCSI support as a module. serial-console.txt - - how to set up linux with a serial line console as the default. + - how to set up Linux with a serial line console as the default. smart-config.txt - description of the Smart Config makefile feature. smp.tex diff -ur --new-file old/linux/Documentation/ARM-README new/linux/Documentation/ARM-README --- old/linux/Documentation/ARM-README Thu May 21 03:54:33 1998 +++ new/linux/Documentation/ARM-README Thu Apr 29 20:53:41 1999 @@ -70,8 +70,8 @@ a 'make zImage' instead of 'make all'. -Bug reports etc ---------------- +Bug reports etc. +---------------- Please send patches, bug reports and code for the ARM Linux project to linux@arm.uk.linux.org. Patches will not be included into future @@ -116,7 +116,7 @@ at the top of the screen. The colours have the following significance when run in a 16 colour mode with the default palette: - Stripes of White,Red,Yellow,Green: + Stripes of white, red, yellow, and green: Kernel does not support the processor architecture detected. @@ -142,11 +142,11 @@ HDC base to the source. As of 31/3/96 it works with two drives (you should get the ADFS - *configure harddrive set to 2). I've got an internal 20MB and a great - big external 5.25" FH 64MB drive (who could ever want more :-) ). + *configure hard drive set to 2). I've got an internal 20 MB and a great + big external 5.25" FH 64 MB drive (who could ever want more :-) ). - I've just got 240K/s off it (a dd with bs=128k); thats about half of what - RiscOS gets; but it's a heck of a lot better than the 50K/s I was getting + I've just got 240 K/s off it (a dd with bs=128k); that's about half of what + RiscOS gets, but it's a heck of a lot better than the 50 K/s I was getting last week :-) Known bug: Drive data errors can cause a hang; including cases where diff -ur --new-file old/linux/Documentation/Changes new/linux/Documentation/Changes --- old/linux/Documentation/Changes Tue Jan 19 18:48:01 1999 +++ new/linux/Documentation/Changes Fri May 7 18:31:25 1999 @@ -19,10 +19,6 @@ texinfo so a diff is useless anyway (though I can incorporate one by hand if you insist upon sending it that way ;-). - Check out -http://www.mindspring.com/~nunez/info/linux/LinuxBleed.html for an -HTML-ized shopping list. - For those of you in Europe, http://www.datanet.hu/generations/linux/Changes2.html is an English-language HTML version. @@ -30,10 +26,14 @@ The most current version should always be available from http://cyberbuzz.gatech.edu/kaboom/linux/ as well. + Voir +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. -Last updated: January 18, 1999 +Last updated: March 16, 1999 Current Author: Chris Ricker (kaboom@gatech.edu or chris.ricker@m.cc.utah.edu). Current Minimal Requirements @@ -43,17 +43,17 @@ encountered a bug! If you're unsure what version you're currently running, the suggested command should tell you. -- Kernel modules 2.1.121 ; insmod -V +- Kernel modutils 2.1.121 ; insmod -V - Gnu C 2.7.2.3 ; gcc --version - Binutils 2.8.1.0.23 ; ld -v -- Linux libc5 C Library 5.4.46 ; ls -l /lib/libc.so.* -- Linux libc6 C Library 2.0.7pre6 ; ls -l /lib/libc.so.* +- Linux libc5 C Library 5.4.46 ; ls -l /lib/libc* +- Linux libc6 C Library 2.0.7pre6 ; ls -l /lib/libc* - Dynamic Linker (ld.so) 1.9.9 ; ldd --version or ldd -v - Linux C++ Library 2.7.2.8 ; ls -l /usr/lib/libg++.so.* - Procps 1.2.9 ; ps --version -- Procinfo 15 ; procinfo -v +- Procinfo 16 ; procinfo -v - Psmisc 17 ; pstree -V -- Net-tools 1.49 ; hostname -V +- Net-tools 1.50 ; hostname -V - Loadlin 1.6a - Sh-utils 1.16 ; basename --v - Autofs 3.1.1 ; automount --version @@ -61,8 +61,8 @@ - Bash 1.14.7 ; bash -version - Ncpfs 2.2.0 ; ncpmount -v - Pcmcia-cs 3.0.7 ; cardmgr -V -- PPP 2.3.5 ; pppd -v -- Util-linux 2.9g ; chsh -v +- PPP 2.3.5 ; pppd --version +- Util-linux 2.9i ; chsh -v Upgrade notes ************* @@ -105,7 +105,7 @@ none /dev/pts devpts gid=5,mode=620 0 0 - (Note: gid=5 is applicable for RedHat systems for which group "tty" has + (Note: gid=5 is applicable for Red Hat systems for which group "tty" has gid 5. Adjust according to your distribution. Use mode=600 if you want "mesg n" to be default.) - Mount /dev/pts @@ -142,7 +142,9 @@ unless you're running glibc2 / libc6. If you upgrade to libc-5.4.x, you may also need to upgrade ypbind if -you're using NIS. +you're using NIS. For ypbind and glibc, you'll probably need the +ypbind-3.3-glibc5.diff patch available in the same place as the ypbind +source. If you upgrade to libc-5.4.46, please read and pay attention to its accompanying release notes. The section about it breaking make is not a @@ -189,6 +191,12 @@ users should especially try to use the 2.9.1.0.x releases, as they resolve known issues with glibc2 and binutils-2.8.x releases. + libbfd, libiberty, and /usr/include/bfd.h, which are part of recent +binutils packages, are also required to compile ksymoops. Depending +upon your distribution, this may require you to install both binutils +and binutils-development packages (Debian puts bfd.h in binutils-dev, +for example). + Gnu C ===== @@ -247,9 +255,14 @@ DHCP clients for 2.0 do not work with the new networking code in the 2.2 kernel. You will need to upgrade your dhcpcd / dhcpclient. - The ISDN code in the stock 2.0 kernel may not work for you. If it + The ISDN code in the stock 2.2 kernel may not work for you. If it doesn't, look in ftp://ftp.suse.com/pub/isdn4linux for updated versions. + In 2.0.x the kernel could be configured to drop source routed IP +packets via a compile time configuration option. In 2.2.x, this has +been replaced by a sysctl. See Documentation/networking/ip-sysctl.txt +for more information. + Memory ====== @@ -274,11 +287,25 @@ 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. + + RPM === If you run Red Hat Linux or any other distribution that uses RPM, -you need to upgrade RPM to version 2.2.7 or later. +you need to upgrade RPM to a 2.5.x or later version. DOSEMU ====== @@ -324,7 +351,7 @@ 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 ==== @@ -406,7 +433,7 @@ Xosview ======= - /proc interface changes require a recent xosview. + Changes to the /proc interface require a recent xosview. RealPlayer ========== @@ -417,8 +444,8 @@ software available shortly. In the mean time, you can always try 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 + 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.... @@ -444,6 +471,30 @@ Most distributed ping clients are buggy. Get an updated one from the iputils package. +Patch +===== + + Really old versions of patch cannot delete files. This can be a +problem if you try to upgrade via patches. If, for example, you are +unable to compile Linux 2.2, you may have an outdated version of patch. +Upgrade, re-patch the kernel, and try again. + +Process accounting +================== + + If you use process accounting, you need to recompile the package +against 2.2 kernel includes for it to work properly. Furthermore, when +you do so, watch out for a quirky configure script. Your generated +config.h file needs to + + #define HAVE_LINUX_ACCT_H + + but instead it often has + + /* #undef HAVE_LINUX_ACCT_H */ + + so be sure to check that when you recompile. + Where to get the files ********************** @@ -481,7 +532,7 @@ ftp://metalab.unc.edu/pub/Linux/GCC/release.egcs-1.0.3 Gnu C 2.7.2.3 source: -ftp://prep.ai.mit.edu/pub/gnu/gcc-2.7.2.3.tar.gz +ftp://ftp.gnu.org/gnu/gcc/gcc-2.7.2.3.tar.gz ftp://metalab.unc.edu/pub/gnu/gcc-2.7.2.3.tar.gz Linux C Library @@ -501,12 +552,8 @@ Linux C++ Library ================= -The 2.7.2.8 release: -ftp://tsx-11.mit.edu/pub/linux/packages/GCC/libg++-2.7.2.8.bin.tar.gz -ftp://metalab.unc.edu/pub/Linux/GCC/libg++-2.7.2.8.bin.tar.gz -Installation notes: -ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.libg++-2.7.2.8 -ftp://metalab.unc.edu/pub/Linux/GCC/release.libg++-2.7.2.8 +The 2.7.2 release: +ftp://ftp.gnu.org/gnu/libg++/libg++-2.7.2.tar.gz Dynamic Linker ============== @@ -531,8 +578,8 @@ Procinfo utilities ================== -The 15 release: -ftp://ftp.cistron.nl/pub/people/svm/procinfo-15.tar.gz +The 16 release: +ftp://ftp.cistron.nl/pub/people/svm/procinfo-16.tar.gz Psmisc utilities ================ @@ -544,15 +591,9 @@ RPM utilities ============= -The 2.2.7 release for Intel: -ftp://ftp.redhat.com/pub/redhat/old-releases/redhat-4.0/updates/i386/rpm-2.2.7-1.i386.rpm -ftp://ftp.redhat.com/pub/redhat/old-releases/redhat-4.0/updates/i386/rpm-devel-2.2.7-1.i386.rpm -The 2.2.7 release for Alpha: -ftp://ftp.redhat.com/pub/redhat/old-releases/redhat-4.0/updates/axp/rpm-2.2.7-1.axp.rpm -ftp://ftp.redhat.com/pub/redhat/old-releases/redhat-4.0/updates/axp/rpm-devel-2.2.7-1.axp.rpm -The 2.2.7 release for SPARC: -ftp://ftp.redhat.com/pub/redhat/old-releases/redhat-4.0/updates/sparc/rpm-2.2.7-1.sparc.rpm -ftp://ftp.redhat.com/pub/redhat/old-releases/redhat-4.0/updates/sparc/rpm-devel-2.2.7-1.sparc.rpm +The 2.5.1 source release: +ftp://ftp.rpm.org/pub/rpm/dist/rpm-2.5.x/rpm-2.5.1-1.src.rpm +ftp://ftp.rpm.org/pub/rpm/dist/rpm-2.5.x/rpm-2.5.1.tar.gz DOSEMU ====== @@ -573,26 +614,26 @@ The 1.16 release: ftp://metalab.unc.edu/pub/gnu/sh-utils-1.16.tar.gz -ftp://prep.ai.mit.edu/pub/gnu/sh-utils-1.16.tar.gz +ftp://ftp.gnu.org/gnu/sh-utils/sh-utils-1.16.tar.gz Util-linux ========== The 2.9 release: -ftp://ftp.win.tue.nl/pub/linux/util/util-linux-2.9g.tar.gz +ftp://ftp.win.tue.nl/pub/linux/utils/util-linux/util-linux-2.9i.tar.gz Autofs ====== -The 3.1.1 release: -ftp://ftp.kernel.org/pub/linux/daemons/autofs/autofs-3.1.1.tar.gz +The 3.1.3 release: +ftp://ftp.kernel.org/pub/linux/daemons/autofs/autofs-3.1.3.tar.gz NFS === The user-land 2.2beta40 release: -ftp://ftp.mathematik.th-darmstadt.de/pub/linux/okir/nfs-server-2.2beta40.tar.gz -ftp://linux.nrao.edu/mirrors/fb0429.mathematik.th-darmstadt.de/pub/linux/okir/nfs-server-2.2beta40.tar.gz +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 @@ -601,30 +642,30 @@ Net-tools ========= -The 1.49 release: -ftp://ftp.cs-ipv6.lancs.ac.uk/pub/Code/Linux/Net_Tools/net-tools-1.49.tar.gz -http://www.tazenda.demon.co.uk/phil/net-tools/net-tools-1.49.tar.gz +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 Ypbind ====== The 3.3 release: -ftp://ftp.uni-paderborn.de/pub/linux/local/yp/ypbind-3.3.tar.gz +ftp://ftp.kernel.org/pub/linux/utils/net/NIS/ypbind-3.3.tar.gz Sysklogd ======== -The 1.3-30 release: -ftp://metalab.unc.edu/pub/Linux/system/daemons/sysklogd-1.3-30.tar.gz +The 1.3-31 release: +ftp://metalab.unc.edu/pub/Linux/system/daemons/sysklogd-1.3-31.tar.gz Bash ==== The 1.14.7 release: -ftp://prep.ai.mit.edu/pub/gnu/bash-1.14.7.tar.gz +ftp://ftp.gnu.org/gnu/bash/bash-1.14.7.tar.gz The 2.02.1 release: -ftp://prep.ai.mit.edu/pub/gnu/bash-2.02.1.tar.gz +ftp://ftp.gnu.org/gnu/bash/bash-2.02.1.tar.gz Ncpfs ===== @@ -726,8 +767,14 @@ IP utils ======== -The 11/01/98 release: -ftp://ftp.inr.ac.ru/pub/ip-routing/iputils-ss981101.tar.gz +The 03/01/99 release: +ftp://ftp.inr.ac.ru/ip-routing/iproute2-2.1.99-now-ss990301.tar.gz + +Patch +===== + +The 2.5 release: +ftp://ftp.gnu.org/gnu/patch/patch-2.5.tar.gz Other Info ========== @@ -744,7 +791,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://rawhide.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. diff -ur --new-file old/linux/Documentation/Configure.help new/linux/Documentation/Configure.help --- old/linux/Documentation/Configure.help Thu Jun 3 02:11:11 1999 +++ new/linux/Documentation/Configure.help Thu Jun 3 02:12:04 1999 @@ -17,6 +17,8 @@ # ftp://ftp-pavia1.linux.it/pub/linux/Configure.help # - Polish, by Cezar Cichocki (cezar@cs.net.pl), at # http://www.cs.net.pl/~cezar/Kernel +# - German, by Jörg Strebel (jstrebel@suse.de) and Karl Eichwalder +# (ke@suse.de), at http://www.suse.de/~ke/kernel/Configure.de.help.gz # # Information about what a kernel is, what it does, how to patch and # compile it and much more is contained in the Kernel-HOWTO, available @@ -51,7 +53,7 @@ # All this was shamelessly stolen from several different sources. Many # thanks to all the contributors. Feel free to use these help texts in # your own kernel configuration tools. The texts are copyrighted (c) -# 1995-1998 by Axel Boldt and many others and are governed by the GNU +# 1995-1999 by Axel Boldt and many others and are governed by the GNU # General Public License. Prompt for development and/or incomplete code/drivers @@ -69,7 +71,7 @@ in some special cases. Detailed bug reports from people familiar with the kernel internals are usually welcomed by the developers (before submitting bug reports, please read the documents README, - MAINTAINERS, Documentation/BUG-HUNTING, and + MAINTAINERS, REPORTING_BUGS, Documentation/BUG-HUNTING, and Documentation/oops-tracing.txt in the kernel source). Unless you intend to help test and develop a feature or driver that @@ -81,30 +83,33 @@ Symmetric Multi Processing CONFIG_SMP - This enables support for systems with more than one CPU. If you have a - system with only one CPU, like most personal computers, say N. If you - have a system with more than one CPU, say Y. - - A non-SMP kernel will run on any machine, but will use only one CPU of - a multi-CPU machine. An SMP kernel will run on many, but not all, - single-CPU machines. On a single-CPU machine, a non-SMP kernel - will run faster than an SMP kernel. - - i486 based SMP boards don't boot CONFIG_M586/M686 kernels. CONFIG_M686 - SMP kernels might not work on all Pentium based boards. - - People using multiprocessor machines should also say Y to "Enhanced - Real Time Clock Support", below. The "Advanced Power Management" - code will be disabled in an SMP kernel. + This enables support for systems with more than one CPU. If you have + 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 + you say Y here, the kernel will run on many, but not all, + singleprocessor machines. On a singleprocessor machine, the kernel + will run faster if you say N here. + + Note that if you say Y here and choose architecture "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. + + People using multiprocessor machines who say Y here should also say + Y to "Enhanced Real Time Clock Support", below. The "Advanced Power + Management" code will be disabled if you say Y here. - If you don't know what to do here, say N. - See also: Documentation/SMP.txt, Documentation/smp.tex, Documentation/smp.txt, and Documentation/IO-APIC.txt. Also see the SMP-FAQ on the WWW at http://www.irisa.fr/prive/mentre/smp-faq/ (to browse the WWW, you need to have access to a machine on the Internet that has a program like lynx or netscape). + If you don't know what to do here, say N. + Kernel math emulation CONFIG_MATH_EMULATION Linux can emulate a math coprocessor (used for floating point @@ -124,19 +129,44 @@ available via FTP (user: anonymous) in ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.) This means that it is a good idea to say Y here if you intend to use this kernel on - different machines. More information about the internals of Linux - math coprocessor emulation can be found in - arch/i386/math-emu/README. + different machines. + + More information about the internals of the Linux math coprocessor + emulation can be found in arch/i386/math-emu/README. 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 + to provide useful information about your current system status. + + If you are compiling a kernel for a NetWinder or EBSA-285, you + will be able to select which LEDs are active using the options + below. If you are compiling a kernel for the EBSA-110 however, + the red LED will simply flash regularly to indicate that the + system is still functional. It is still safe to say yes here if + you have a CATS system, but the driver will do nothing. + +Timer LED +CONFIG_LEDS_TIMER + If you say yes here, one of the system LEDs (the green one on the + NetWinder or the amber one on the EBSA285) will flash regularly to + indicate that the system is still operational. This is mainly + useful to kernel hackers who are debugging unstable kernels. + +CPU usage LED +CONFIG_LEDS_CPU + If you say yes here, the red LED will be used to give a good real + time indication of CPU usage, by lighting whenever the idle task + is not currently executing. Kernel FP software completion CONFIG_MATHEMU This option is required for IEEE compliant floating point arithmetic - on the Alpha. The only time you would ever not say Y is to say M - in order to debug the code. Do not say anything but Y unless you - know what you are doing. + on the Alpha. The only time you would ever not say Y is to say M in + order to debug the code. Say Y unless you know what you are doing. Normal PC floppy disk support CONFIG_BLK_DEV_FD @@ -216,8 +246,8 @@ To use the loop device, you need the losetup utility and a recent version of the mount program, both contained in the util-linux - package (available via FTP (user: anonymous) from - ftp://ftp.win.tue.nl/pub/linux/util/). + package. The location and current version number of util-linux is + contained in the file Documentation/Changes. Note that this loop device has nothing to do with the loopback device used for network connections from the machine to itself. @@ -274,12 +304,19 @@ To fine-tune IDE drive/interface parameters for improved performance, look for the hdparm package at - ftp://metalab.unc.edu:/pub/Linux/kernel/patches/diskdrives/ + ftp://metalab.unc.edu/pub/Linux/kernel/patches/diskdrives/ - If you have one or more IDE drives, say Y here. If your system has - no IDE drives, or if memory requirements are really tight, you could - say N here, and select the "Old hard disk driver" instead to save - about 13 KB of memory in the kernel. + If you want to compile this 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 and + Documentation/ide.txt. The module will be called ide.o. Do not + compile this driver as a module if your root filesystem (the one + containing the directory /) is located on an IDE device. + + If you have one or more IDE drives, say Y or M here. If your system + has no IDE drives, or if memory requirements are really tight, you + could say N here, and select the "Old hard disk driver" below + instead to save about 13 KB of memory in the kernel. Old hard disk (MFM/RLL/IDE) driver CONFIG_BLK_DEV_HD_ONLY @@ -382,10 +419,12 @@ CONFIG_BLK_DEV_IDEFLOPPY If you have an IDE floppy drive which uses the ATAPI protocol, answer Y. ATAPI is a newer protocol used by IDE CDROM/tape/floppy - drives, similar to the SCSI protocol. IDE floppy drives include the - LS-120 and the ATAPI ZIP (ATAPI PD-CD/CDR drives are not supported - by this driver; support for PD-CD/CDR drives is available if you - answer Y to "SCSI emulation support", below). + drives, similar to the SCSI protocol. + + The LS-120 and the IDE/ATAPI Iomega ZIP drive are also supported by + this driver. (ATAPI PD-CD/CDR drives are not supported by this + driver; support for PD-CD/CDR drives is available if you answer Y to + "SCSI emulation support", below). If you say Y here, the FLOPPY drive will be identified along with other IDE devices, as "hdb" or "hdc", or something similar (check @@ -464,7 +503,7 @@ Generic PCI IDE chipset support CONFIG_BLK_DEV_IDEPCI - Enable this for PCI systems which use IDE drive(s). + Say Y here for PCI systems which use IDE drive(s). This option helps the IDE driver to automatically detect and configure all PCI-based IDE interfaces in your system. @@ -519,7 +558,8 @@ If you suspect your hardware is at all flakey, say N here. Do NOT email the IDE kernel people regarding this issue! - It is nearly always safe to say Y to this question. + It is normally safe to answer Y to this question unless your + motherboard uses a VIA VP2 chipset, in which case you should say N. Other IDE chipset support CONFIG_IDE_CHIPSETS @@ -548,15 +588,16 @@ This driver is enabled at runtime using the "ide0=dtc2278" kernel boot parameter. It enables support for the secondary IDE interface of the DTC-2278 card, and permits faster I/O speeds to be set as - well. See the Documentation/ide.txt and dtc2278.c files for more - info. + well. See the Documentation/ide.txt and drivers/block/dtc2278.c + files for more info. Holtek HT6560B support CONFIG_BLK_DEV_HT6560B This driver is enabled at runtime using the "ide0=ht6560b" kernel boot parameter. It enables support for the secondary IDE interface of the Holtek card, and permits faster I/O speeds to be set as well. - See the Documentation/ide.txt and ht6560b.c files for more info. + See the Documentation/ide.txt and drivers/block/ht6560b.c files for + more info. PROMISE DC4030 support (EXPERIMENTAL) CONFIG_BLK_DEV_PDC4030 @@ -572,6 +613,11 @@ CONFIG_BLK_DEV_PS2 Say Y here if you have a PS/2 machine with a MCA bus and an ESDI hard disk. + + 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 ps2esdi.o. Tekram TRM290 chipset support (EXPERIMENTAL) CONFIG_BLK_DEV_TRM290 @@ -601,36 +647,26 @@ If you say Y here, you also need to say Y to "Use DMA by default when available", above. - Please read the comments at the top of drivers/block/via82C586.c - If unsure, say N. CMD646 chipset support (EXPERIMENTAL) CONFIG_BLK_DEV_CMD646 Say Y here if you have an IDE controller like this. -HPT343 chipset support (EXPERIMENTAL) -CONFIG_BLK_DEV_HPT343 - This driver adds up to 4 more EIDE devices sharing a single - interrupt. The HPT343 chipset in its current form is a non-bootable - PCI UDMA controller. This driver requires dynamic tuning of the - chipset during the ide-probe at boot. It is reported to support DVD - II drives, by the manufacturer. - - Please read the comments at the top of drivers/block/hpt343.c - QDI QD6580 support CONFIG_BLK_DEV_QD6580 This driver is enabled at runtime using the "ide0=qd6580" kernel boot parameter. It permits faster I/O speeds to be set. See the - files Documentation/ide.txt and qd6580.c for more info. + files Documentation/ide.txt and drivers/block/qd6580.c for more + info. UMC 8672 support CONFIG_BLK_DEV_UMC8672 This driver is enabled at runtime using the "ide0=umc8672" kernel boot parameter. It enables support for the secondary IDE interface of the UMC-8672, and permits faster I/O speeds to be set as well. - See the files Documentation/ide.txt and umc8672.c for more info. + See the files Documentation/ide.txt and drivers/block/umc8672.c for + more info. ALI M14xx support CONFIG_BLK_DEV_ALI14XX @@ -638,7 +674,7 @@ boot parameter. It enables support for the secondary IDE interface of the ALI M1439/1443/1445/1487/1489 chipsets, and permits faster I/O speeds to be set as well. See the files Documentation/ide.txt - and ali14xx.c for more info. + and drivers/block/ali14xx.c for more info. XT hard disk support CONFIG_BLK_DEV_XD @@ -1017,6 +1053,24 @@ board uses the R4300 and a R5230 CPUs. For more information about this board see http://www.algor.co.uk. +IDE card support +CONFIG_BLK_DEV_IDE_CARDS + On Acorn systems, enable this if you wish to use an IDE interface + expansion card. If you do not or are unsure, say N to this. + +ICS IDE interface +CONFIG_BLK_DEV_IDE_ICS + On Acorn systems, enable this if you wish to use the ICS IDE + interface card. This is not required for ICS partition support. + If you are unsure, say N to this. + +ADFS partition support +CONFIG_BLK_DEV_PART + This allows Linux on Acorn systems to determine its partitions in + the 'non-ADFS' partition area of the hard disk - usually located + after the ADFS partition. You are probably using this system, so + you should enable it. + Support for Mips Magnum 4000 CONFIG_MIPS_MAGNUM_4000 This is a machine with a R4000 100 MHz CPU. To compile a Linux @@ -1068,24 +1122,9 @@ contained in the package net-tools, the location and version number of which are given in Documentation/Changes. -Network aliasing -CONFIG_NET_ALIAS - If you say Y here, you will be able to set multiple network - addresses on the same low-level network device driver. This is - typically used for services that act differently based on the - address they listen on (e.g. "multihosting" or "virtual domains" or - "virtual hosting services" on the web server apache and the ftp - server wuftpd -- read the Virtual-Services-HOWTO, available via FTP - (user: anonymous) from ftp://metalab.unc.edu/pub/Linux/docs/HOWTO) - or for connecting to different logical networks through the same - physical interface (most commonly an Ethernet networking card). See - Documentation/networking/alias.txt for more info. - - This is the generic part, later when configuring network protocol - options you will be asked for protocol-specific aliasing support, - and you will have to say Y to at least one of them, most likely to - "IP: aliasing support". If you need this feature (for any protocol, - like IP) say Y; if unsure, say N. + For a general introduction to Linux networking, it is highly + recommended to read the NET-3-HOWTO, available via FTP (user: + anonymous) from ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. Socket filtering CONFIG_FILTER @@ -1178,12 +1217,12 @@ Alpha system type CONFIG_ALPHA_GENERIC This is the system type of your hardware. A "generic" kernel will - run on any supported Alpha system. Configuring a kernel for one - specific system can save about 200K and operate more efficiently. + run on any supported Alpha system. However, if you configure a + kernel for your specific system, it will be faster and smaller. To find out what type of Alpha system you have, you may want to check out the Linux/Alpha FAQ, accessible on the WWW from - http://www.azstarnet.com/~axplinux/ (To browse the WWW, you need to + http://www.alphalinux.org (To browse the WWW, you need to have access to a machine on the Internet that has a program like lynx or netscape). In summary: @@ -1197,7 +1236,8 @@ EB64+ EB64+ 21064 evaluation board EB66 EB66 21066 evaluation board EB66+ EB66+ 21066 evaluation board - Jensen DECpc 150, DEC 2000 model 300, DEC 2000 model 500 + Jensen DECpc 150, DEC 2000 model 300, + DEC 2000 model 500 LX164 AlphaPC164-LX Miata Personal Workstation 433a, 433au, 500a, 500au, 600a, or 600au @@ -1227,7 +1267,7 @@ which is command line driven, and ARC, which uses menus and arrow keys. Details about the Linux/Alpha booting process are contained in the Linux/Alpha FAQ, accessible on the WWW from - http://www.azstarnet.com/~axplinux/ (To browse the WWW, you need to + http://www.alphalinux.org (To browse the WWW, you need to have access to a machine on the Internet that has a program like lynx or netscape). @@ -1333,34 +1373,26 @@ Find out whether you have a PCI motherboard. PCI is the name of a bus system, i.e. the way the CPU talks to the other stuff inside your box. Other bus systems are ISA, EISA, Microchannel (MCA) or - VESA. If you have PCI, say Y, otherwise N. The PCI-HOWTO, available - via FTP (user: anonymous) in + VESA. If you have PCI, say Y, otherwise N. + + The PCI-HOWTO, available via FTP (user: anonymous) in ftp://metalab.unc.edu/pub/Linux/docs/HOWTO, contains valuable information about which PCI hardware does work under Linux and which doesn't. - If some of your PCI devices don't work and you get a warning during - boot time ("man dmesg"), please follow the instructions at the top - of include/linux/pci.h. - PCI access mode CONFIG_PCI_GOBIOS - If you have enabled PCI bus support above, you probably want to - allow Linux to use your PCI BIOS to detect the PCI devices and - determine their configuration. Note: some old PCI motherboards have - BIOS bugs and may crash if you say Y here -- for such motherboards, - you should say N here and say Y to "PCI direct access support" - instead. - - Except for some special cases (embedded systems with no BIOS), you - probably should say Y here. - - If you don't want to use the PCI BIOS (e.g., because you run some - embedded system with no BIOS at all) or Linux says it cannot use - your PCI BIOS, you can enable direct PCI hardware here. It might - fail if your machine is based on some unusual chipset, but it - usually works. If both PCI BIOS and direct PCI access are enabled, - the use of BIOS is preferred. If unsure, say Y. + On PCI systems, the BIOS can be used to detect the PCI devices and + determine their configuration. However, some old PCI motherboards + have BIOS bugs and may crash if this is done. Also, some embedded + PCI-based systems don't have any BIOS at all. Linux can also try to + detect the PCI hardware directly without using the BIOS. + + With this option, you can specify how Linux should detect the PCI + devices. If you choose "BIOS", the BIOS will be used, if you choose + "Direct", the BIOS won't be used, and if you choose "Any", the + kernel will try the direct access method and falls back to the BIOS + if that doesn't work. If unsure, go with the default. PCI quirks CONFIG_PCI_QUIRKS @@ -1385,11 +1417,8 @@ PCI (/proc/bus/pci) has been implemented and the old one is supported for compatibility reasons only; you'll get the old one (in addition to the new one) if you say Y here and to "/proc filesystem - support", below. If unsure, say Y. - -If you say Y here and to the "/proc filesystem support" below, you - will get a directory /proc/pci with information about your PCI - hardware. If unsure, say Y. + support", below. If unsure, say Y. If you say N, you'll only get the + new /proc/bus/pci interface. MCA support CONFIG_MCA @@ -1398,7 +1427,7 @@ Documentation/mca.txt (and especially the web page given there) before attempting to build an MCA bus kernel. -SGI Visal Workstation support +SGI Visual Workstation support CONFIG_VISWS The SGI Visual Workstation series is an IA32-based workstation based on SGI systems chips with some legacy PC hardware attached. @@ -1407,6 +1436,10 @@ PC boards and vice versa. See Documentation/sgi-visws.txt for more. +SGI Visual Workstation framebuffer support +CONFIG_FB_SGIVW + SGI Visual Workstation support for framebuffer graphics. + System V IPC CONFIG_SYSVIPC Inter Process Communication is a suite of library functions and @@ -1593,19 +1626,21 @@ all x86 CPU types (albeit not optimally fast), you can specify "386" here. - If you specify one of "486" or "Pentium" or "PPro", then the kernel - will not necessarily run on earlier architectures (ie a Pentium - optimized kernel will run on a PPro, but not necessarily on a i486). + If you specify one of "486" or "586" or "Pentium" or "PPro", then + the kernel will not necessarily run on earlier architectures (e.g. a + Pentium optimized kernel will run on a PPro, but not necessarily on + a i486). Here are the settings recommended for greatest speed: - - "386" for the AMD/Cyrix/Intel 386DX/DXL/SL/SLC/SX and - Cyrix/TI 486DLC/DLC2. Only "386" kernels will run on a 386 class - machine. + - "386" for the AMD/Cyrix/Intel 386DX/DXL/SL/SLC/SX, Cyrix/TI + 486DLC/DLC2 and UMC 486SX-S. Only "386" kernels will run on a 386 + class machine. - "486" for the AMD/Cyrix/IBM/Intel DX4 or 486DX/DX2/SL/SX/SX2, AMD/Cyrix 5x86, NexGen Nx586 and UMC U5D or U5S. - - "586" for generic Pentium CPU's, possibly lacking the TSC register. - - "Pentium" for the Intel Pentium/Pentium MMX, AMD K5, K6 and K6-3D. - This option will assume that you have a time stamp counter. + - "586" for generic Pentium CPUs, possibly lacking the TSC + (time stamp counter) register. + - "Pentium" for the Intel Pentium/Pentium MMX, AMD K5, K6 and + K6-3D. - "PPro" for the Cyrix/IBM/National Semiconductor 6x86MX, MII and Intel Pentium II/Pentium Pro. @@ -1667,9 +1702,9 @@ If you are compiling for the x86 architecture, you can say Y if you want to play with it, but it is not essential. Please note that - running graphical applications that directly touch the hardware (e.g. - and accelerated X server) and that are not frame buffer device-aware - may cause unexpected results. If unsure, say N. + running graphical applications that directly touch the hardware + (e.g. an accelerated X server) and that are not frame buffer + device-aware may cause unexpected results. If unsure, say N. Acorn VIDC support CONFIG_FB_ACORN @@ -1807,65 +1842,72 @@ This is the frame buffer device driver for generic VESA 2.0 compliant graphic cards. The older VESA 1.2 cards are not supported. You will get a boot time penguin logo at no additional cost. Please - read Documentation/fb/vesafb.txt and the . If unsure, say Y. + read Documentation/fb/vesafb.txt. If unsure, say Y. Backward compatibility mode for Xpmac CONFIG_FB_COMPAT_XPMAC - If you use the Xpmac X server (common with mklinux), you'll need - to enable this to use X. You should consider changing to XFree86 - which includes a server that supports the frame buffer device - directly (XF68_FBDev). + If you use the Xpmac X server (common with mklinux), you'll need to + say Y here to use X. You should consider changing to XFree86 which + includes a server that supports the frame buffer device directly + (XF68_FBDev). Matrox unified accelerated driver CONFIG_FB_MATROX - Say Y here if you have Matrox Millennium, Matrox Millennium II, + Say Y here if you have Matrox Millennium, Matrox Millennium II, Matrox Mystique, Matrox Mystique 220, Matrox Productiva G100, Matrox - Mystique G200, Matrox Millennium G200 or Matrox Marvel G200 in your - box. At this time, G100, Mystique G200 and Marvel G200 support is - untested. If you want, you can select M, in this case module - matroxfb.o will be created. You can pass parameters into driver if - it is compiled into kernel by specifying "video=matrox:XXX", where - meaning of XXX you can found at the end of main source file - (drivers/video/matroxfb.c) at boot time. Same parameters can be - passed into insmod if driver is used as module. + Mystique G200, Matrox Millennium G200 or Matrox Marvel G200 video + card in your box. At this time, support for the G100, Mystique G200 + and Marvel G200 is untested. + + This driver is also available as a module ( = code which can be + inserted and removed from the running kernel whenever you want). + The module will be called matroxfb.o. If you want to compile it as + a module, say M here and read Documentation/modules.txt. + + You can pass several parameters to the driver at boot time or at + module load time. The parameters look like "video=matrox:XXX", where + the meaning of XXX can be found at the end of the main source file + (drivers/video/matroxfb.c). Please see the file + Documentation/fb/matroxfb.txt. Matrox Millennium support CONFIG_FB_MATROX_MILLENIUM - Say Y here if you have Matrox Millennium or Matrox Millennium II in - the box. If you select "Advanced lowlevel driver options", you should - check 4 bpp packed pixel, 8 bpp packed pixel, 16 bpp packed pixel, 24 - bpp packed pixel and 32 bpp packed pixel. You can also use font - widths different from 8. + Say Y here if you have a Matrox Millennium or Matrox Millennium II + video card. If you select "Advanced lowlevel driver options" below, + you should check 4 bpp packed pixel, 8 bpp packed pixel, 16 bpp + packed pixel, 24 bpp packed pixel and 32 bpp packed pixel. You can + also use font widths different from 8. Matrox Mystique support CONFIG_FB_MATROX_MYSTIQUE - Say Y here if you have Matrox Mystique or Matrox Mystique 220 in the - box. If you select "Advanced lowlevel driver options", you should - check 8 bpp packed pixel, 16 bpp packed pixel, 24 bpp packed pixel - and 32 bpp packed pixel. You can also use font widths different - from 8. + Say Y here if you have a Matrox Mystique or Matrox Mystique 220 + video card. If you select "Advanced lowlevel driver options" below, + you should check 8 bpp packed pixel, 16 bpp packed pixel, 24 bpp + packed pixel and 32 bpp packed pixel. You can also use font widths + different from 8. Matrox G100/G200 support CONFIG_FB_MATROX_G100 - Say Y here if you have Matrox Productiva G100, Matrox Mystique G200, - Matrox Marvel G200 or Matrox Millennium G200 in the box. If you - select "Advanced lowlevel driver options", you should check 8 bpp - packed pixel, 16 bpp packed pixel, 24 bpp packed pixel and 32 bpp - packed pixel. You can also use font widths different from 8. + Say Y here if you have a Matrox Productiva G100, Matrox Mystique + G200, Matrox Marvel G200 or Matrox Millennium G200 video card. If + you select "Advanced lowlevel driver options", you should check 8 + bpp packed pixel, 16 bpp packed pixel, 24 bpp packed pixel and 32 + bpp packed pixel. You can also use font widths different from 8. Matrox unified driver multihead support CONFIG_FB_MATROX_MULTIHEAD - Say Y here if you have more than one (supported) Matrox device in - computer and you want to use all of them. If you have only one - device, you should say N because of driver compiled with Y is larger - and a bit slower, especially on ia32 (ix86). - If you compiled driver as module, you are VERY interested in speed - and you can use 40KB of memory per each Matrox device, you can - compile driver without multihead support and instead of it insmod - more module instances. In this case, you MUST specify parameter dev=N - to insmod, where N is sequential number of Matrox device (0 = first, - 1 = second and so on). - + Say Y here if you have more than one (supported) Matrox device in + your computer and you want to use all of them. If you have only one + device, you should say N because the driver compiled with Y is + larger and a bit slower, especially on ia32 (ix86). + + If you said M to "Matrox unified accelerated driver" and N here, you + will still be able to use several Matrox devices simultaneously. + This is slightly faster but uses 40 KB of kernel memory per Matrox + card. You do this by inserting several instances of the module + matroxfb.o into the kernel with insmod, supplying the parameter + "dev=N" where N is 0, 1, etc. for the different Matrox devices. + MDA text console (dual-headed) CONFIG_MDA_CONSOLE Say Y here if you have an old MDA or monochrome Hercules graphics @@ -2025,7 +2067,7 @@ Parallel-port support CONFIG_PARPORT If you want to use devices connected to your machine's parallel port - (the connector at the computer with 25 holes), e.g. printer, Zip + (the connector at the computer with 25 holes), e.g. printer, ZIP drive, PLIP link (Parallel Line Internet Protocol is mainly used to create a mini network by connecting the parallel ports of two local machines) etc., then you need to say Y here; please read @@ -2052,10 +2094,13 @@ CONFIG_PARPORT_PC You should say Y here if you have a PC-style parallel port. All IBM PC compatible computers and some Alphas have PC-style parallel - ports. This code is also available as a module. If you want to it as - a module ( = code which can be inserted in and removed from the + ports. + + This code is also available as a module. If you want to compile it + 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 parport_pc.o. + If unsure, say Y. Support foreign hardware @@ -2079,7 +2124,7 @@ CONFIG_PNP_PARPORT Some IEEE-1284 conforming parallel-port devices can identify themselves when requested. Say Y to enable this feature, or M to - compile it as a module (parport_ieee1284.o). If in doubt, say N. + compile it as a module (parport_probe.o). If in doubt, say N. Enable loadable module support CONFIG_MODULES @@ -2145,15 +2190,20 @@ TCP/IP networking CONFIG_INET These are the protocols used on the Internet and on most local - Ethernets. The safest is to say Y here (which will enlarge your - kernel by about 35 kB), since some programs (e.g. the X window + Ethernets. It is highly recommended to say Y here (this will enlarge + your kernel by about 35 KB), since some programs (e.g. the X window system) use TCP/IP even if your machine is not connected to any other computer. You will get the so-called loopback device which - allows you to ping yourself (great fun, that!). This option is - also necessary if you want to use the full power of term (term - is a program which gives you almost full Internet connectivity - if you have a regular dial up shell account on some Internet - connected Unix computer; for more information, read + allows you to ping yourself (great fun, that!). + + For an excellent introduction to Linux networking, please read the + NET-3-HOWTO, available via FTP (user: anonymous) from + ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. + + This option is also necessary if you want to use the full power of + term (term is a program which gives you almost full Internet + connectivity if you have a regular dial up shell account on some + Internet connected Unix computer; for more information, read http://www.bart.nl/~patrickr/term-howto/Term-HOWTO.html). If you say Y here and also to "/proc filesystem support" and "Sysctl @@ -2221,8 +2271,18 @@ the Linux router will also be able to take the packet's source address into account. Furthermore, if you also say Y to "IP: use TOS value as routing key" below, the TOS (Type-Of-Service) field of the - packet can be used for routing decisions as well. - + packet can be used for routing decisions as well. In addition, if + you say Y here and to "IP: fast network address translation" below, + the router will also be able to modify source and destination + addresses of forwarded packets. + + If you are interested in this, please see the preliminary + documentation at http://www.compendium.com.ar/policy-routing.txt and + ftp://post.tepkom.ru/pub/vol2/Linux/docs/advanced-routing.tex. You + will need supporting software from ftp://ftp.inr.ac.ru/ip-routing/ + + If unsure, say N. + IP: equal cost multipath CONFIG_IP_ROUTE_MULTIPATH Normally, the routing tables specify a single action to be taken in @@ -2241,6 +2301,12 @@ you say Y here, you will be able to specify different routes for packets with different TOS values. +IP: use FWMARK value as routing key +CONFIG_IP_ROUTE_FWMARK + If you say Y here, you will be able to specify different routes for + packets with different FWMARK ("firewalling mark") values + (see ipchains(8), "-m" argument). + IP: verbose route monitoring CONFIG_IP_ROUTE_VERBOSE If you say Y here, which is recommended, then the kernel will print @@ -2259,7 +2325,9 @@ CONFIG_IP_ROUTE_NAT If you say Y here, your router will be able to modify source and destination addresses of packets that pass through it, in a manner - you specify. + you specify. General information about Network Address Translation + can be gotten from the document + http://www.csn.tu-chemnitz.de/~mha/linux-ip-nat/diplom/nat.html IP: optimize as router not host CONFIG_IP_ROUTER @@ -2293,7 +2361,7 @@ http://www.rustcorp.com/linux/ipchains/) to allow selective blocking of Internet traffic based on type, origin and destination. Note that the Linux firewall code has changed and the old program - called ipfwadm won't work anymore. + called ipfwadm won't work anymore. Please read the IPCHAINS-HOWTO. The type of firewall provided by ipchains and this kernel support is called a "packet filter". The other type of firewall, a @@ -2330,19 +2398,16 @@ IP: firewall packet netlink device CONFIG_IP_FIREWALL_NETLINK - If you say Y here, then the first 128 bytes of each packet that hit - your Linux firewall and was blocked are passed on to optional user - space monitoring software that can then look for attacks and take - actions such as paging the administrator of the site. + If you say Y here, you can use the ipchains tool to copy all or part + of any packet you specify that hits your Linux firewall to optional + user space monitoring software that can then look for attacks and + take actions such as paging the administrator of the site. To use this, you need to create a character special file under /dev with major number 36 and minor number 3 using mknod ("man mknod"), and you need (to write) a program that reads from that device and takes appropriate action. - With the ipchains tool you can specify which packets you want to go - to this device, as well as how many bytes from each packet. - IP: kernel level autoconfiguration CONFIG_IP_PNP This enables automatic configuration of IP addresses of devices and @@ -2433,7 +2498,7 @@ host replies, the Linux firewall will silently forward the traffic to the corresponding local computer. This way, the computers on your local net are completely invisible to the outside world, even though - they can reach the outside and can be reached. This makes it + they can reach the outside and can receive replies. This makes it possible to have the computers on the local network participate on the Internet even if they don't have officially registered IP addresses. (This last problem can also be solved by connecting the @@ -2480,8 +2545,8 @@ IP: masquerading special modules support CONFIG_IP_MASQUERADE_MOD This provides support for special modules that can modify the - rewriting rules used when masquerading. Please note that this feature - adds a little overhead in the input packet processing chain. + rewriting rules used when masquerading. Please note that this + feature adds a little overhead in the input packet processing chain. Examples of such modules are ipautofw (allowing the masquerading of protocols which don't have their own protocol helpers) and port @@ -2521,15 +2586,15 @@ forwarding of packets from outside to inside a firewall on given ports. This could be useful if, for example, you want to run a web server behind the firewall or masquerading host and that web server - should be visible to the outside world. An external client connects - to port 80 of the firewall, the firewall forwards requests to this - port to the web server, the web server handles the request and the - results are sent through the firewall to the original client. The - client thinks that the firewall machine itself is running the web - server. This can also be used for load balancing if you have a farm - of identical web servers behind the firewall. + should be accessible from the outside world. An external client + sends a request to port 80 of the firewall, the firewall forwards + this request to the web server, the web server handles the request + and the results are sent through the firewall to the original + client. The client thinks that the firewall machine itself is + running the web server. This can also be used for load balancing if + you have a farm of identical web servers behind the firewall. - Information about it is available from + Information about this feature is available from http://www.monmouth.demon.co.uk/ipsubs/portforwarding.html (to browse the WWW, you need to have access to a machine on the Internet that has a program like lynx or netscape). For general info, please @@ -2548,12 +2613,14 @@ IP: ipmarkfw masquerade support CONFIG_IP_MASQUERADE_MFW - This provides functionality similar to port forwarding, the - difference is that Firewall Mark Forwarding uses "firewalling mark" - to select which packets must forward (see ipchains(8), "-m" argument). + Firewall Mark Forwarding provides functionality similar to port + forwarding (see "IP: ipportfw masquerade support", above), the + difference being that Firewall Mark Forwarding uses "firewalling + mark" to select which packets must be forwarded (see ipchains(8), + "-m" argument). - The ip_masq_mfw code is still under development and so is currently - marked EXPERIMENTAL. If you want to try it, say Y. + This code is still under development and so is currently marked + EXPERIMENTAL. If you want to try it, say Y. This code is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -2584,12 +2651,12 @@ Sometimes it is useful to give several IP addresses to a single physical network interface (serial port or Ethernet card). The most common case is that you want to serve different WWW or ftp documents - to the outside according to which of your host names was used to + to the outside depending on which of your host names was used to connect to you. This is called "multihosting" or "virtual domains" or "virtual hosting services" and is explained in detail on the WWW at http://www.thesphere.com/~dlp/TwoServers/ (to browse the WWW, you need to have access to a machine on the Internet that has a program - like lynx or netscape) and also in the Virtual-Hosting-HOWTO, + like lynx or netscape) and also in the Virtual-Services-HOWTO, available via FTP (user: anonymous) from ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. @@ -2709,20 +2776,6 @@ enabled. Those programs that would benefit from disabling this facility can do it on a per connection basis themselves. -IP: Drop source routed frames -CONFIG_IP_NOSR - Usually, the originator of an IP frame (packet) specifies only the - destination, and the hosts along the way do the routing, i.e. they - decide how to forward the frame. However, there is a feature of the - IP protocol that allows to specify the full route for a given frame - already at its origin. A frame with such a fully specified route is - called "source routed". The question now is whether we should honour - these route requests when such frames arrive, or if we should drop - all those frames instead. Honouring them can introduce security - problems (and is rarely a useful feature), and hence it is - recommended that you say Y here unless you really know what you're - doing. - IP: Allow large windows (not recommended if <16 MB of memory) CONFIG_SKB_LARGE On high speed, long distance networks the performance limit on @@ -2739,22 +2792,25 @@ Unix domain sockets CONFIG_UNIX - This includes Unix domain sockets, the standard Unix mechanism for - establishing and accessing network connections. Many commonly used - programs such as the X Window system and syslog use these sockets - even if your machine is not connected to any network. Unless you are - working on an embedded system or something similar, you therefore - definitely want to say Y here. + If you say Y here, you will include support for Unix domain sockets; + sockets are the standard Unix mechanism for establishing and + accessing network connections. Many commonly used programs such as + the X Window system and syslog use these sockets even if your + machine is not connected to any network. Unless you are working on + an embedded system or something similar, you therefore definitely + want to say Y here. - The socket support is also available as a module ( = code which can - be inserted in and removed from the running kernel whenever you - want). The module will be called unix.o. If you want to compile it - as a module, say M here and read Documentation/modules.txt. If you - try building this as a module and you have said Y to "Kernel module - loader support" above, be sure to add 'alias net-pf-1 unix' to your - /etc/conf.modules file. + However, the socket support is also available as a module ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read Documentation/modules.txt. The module will be called + unix.o. If you try building this as a module and you have said Y to + "Kernel module loader support" above, be sure to add 'alias net-pf-1 + unix' to your /etc/conf.modules file. Note that several important + services won't work correctly if you say M here and then neglect to + load the module. - If unsure, say Y. + Say Y unless you know what you are doing. The IPv6 protocol CONFIG_IPV6 @@ -2894,14 +2950,14 @@ for details (to browse the WWW, you need to have access to a machine on the Internet that has a program like lynx or netscape). EtherTalk is the name used for AppleTalk over Ethernet and the cheaper and - slower LocalTalk is AppleTalk over a proprietary apple network using + slower LocalTalk is AppleTalk over a proprietary Apple network using serial links. EtherTalk and LocalTalk are fully supported by Linux. - The NET-2-HOWTO, available via FTP (user: anonymous) in - ftp://metalab.unc.edu/pub/Linux/docs/HOWTO contains valuable - information as well. General information about how to connect Linux, Windows machines and Macs is on the WWW at http://www.eats.com/linux_mac_win.html + The NET-3-HOWTO, available via FTP (user: anonymous) in + ftp://metalab.unc.edu/pub/Linux/docs/HOWTO contains valuable + information as well. This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -2914,36 +2970,45 @@ CONFIG_IPDDP This allows IP networking for users who only have AppleTalk networking available. This feature is experimental. With this - driver, you can either encapsulate IP inside AppleTalk (e.g. if your - Linux box is stuck on an AppleTalk only network) or decapsulate - (e.g. if you want your Linux box to act as an Internet gateway for a - zoo of AppleTalk connected Macs). You decide which one of the two - you want in the following two questions; you can say Y to only one - of them. Please see Documentation/networking/ipddp.txt for more - information. + driver, you can encapsulate IP inside AppleTalk (e.g. if your Linux + box is stuck on an AppleTalk only network) or decapsulate (e.g. if + you want your Linux box to act as an Internet gateway for a zoo of + AppleTalk connected Macs). Please see the file + Documentation/networking/ipddp.txt for more information. + + If you say Y here, the AppleTalk-IP support will be compiled into + the kernel. In this case, you can either use encapsulation or + decapsulation, but not both. With the following two questions, you + decide which one you want. - 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 is called ipddp.o. If you want to compile it as a module, - say M here and read Documentation/modules.txt. + If you say M here, the AppleTalk-IP support will be compiled as a + module ( = code which can be inserted in and removed from the + running kernel whenever you want, read Documentation/modules.txt). + The module is called ipddp.o. In this case, you will be able to use + both encapsulation and decapsulation simultaneously, by loading two + copies of the module and specifying different values for the module + option ipddp_mode. IP to AppleTalk-IP Encapsulation support CONFIG_IPDDP_ENCAP - If you say Y here, the kernel will be able to encapsulate IP packets - inside AppleTalk frames; this is useful if your Linux box is stuck - on an AppleTalk network (which hopefully contains a decapsulator - somewhere). Please see Documentation/networking/ipddp.txt for more - information. If you say Y here, you cannot say Y to "AppleTalk-IP to - IP Decapsulation support", below. + If you say Y here, the AppleTalk-IP code will be able to encapsulate + IP packets inside AppleTalk frames; this is useful if your Linux box + is stuck on an AppleTalk network (which hopefully contains a + decapsulator somewhere). Please see + Documentation/networking/ipddp.txt for more information. If you said + Y to "AppleTalk-IP driver support" above and you say Y here, then + you cannot say Y to "AppleTalk-IP to IP Decapsulation support", + below. AppleTalk-IP to IP Decapsulation support CONFIG_IPDDP_DECAP - If you say Y here, the kernel will be able to decapsulate + If you say Y here, the AppleTalk-IP code will be able to decapsulate AppleTalk-IP frames to IP packets; this is useful if you want your - Linux box to act as an Internet gateway for an AppleTalk - network. Please see Documentation/networking/ipddp.txt for more - information. If you say Y here, you cannot say Y to "IP to - AppleTalk-IP Encapsulation support", above. + Linux box to act as an Internet gateway for an AppleTalk network. + Please see Documentation/networking/ipddp.txt for more information. + If you said Y to "AppleTalk-IP driver support" above and you say Y + here, then you cannot say Y to "IP to AppleTalk-IP Encapsulation + support", above. Apple/Farallon LocalTalk PC card support CONFIG_LTPC @@ -3686,7 +3751,7 @@ ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. The SCSI-Programming-HOWTO contains information about how to add or remove an SCSI device from a running Linux machine without - rebooting. + rebooting. This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -3731,7 +3796,7 @@ CONFIG_BLK_DEV_SR If you want to use a SCSI CDROM under Linux, say Y and read the SCSI-HOWTO and the CDROM-HOWTO from - ftp://metalab.unc.edu:/pub/Linux/docs/HOWTO. Also make sure to say Y + ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. Also make sure to say Y or M to "ISO 9660 CDROM filesystem support" later. This driver is also available as a module ( = code which can be @@ -3759,7 +3824,8 @@ other devices, it's possible that you'll have to write the driver software yourself, so have a look at the SCSI-HOWTO and at the SCSI-Programming-HOWTO, both available via FTP (user: anonymous) in - ftp://metalab.unc.edu:/pub/Linux/docs/HOWTO. + ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. Please read the file + Documentation/scsi-generic.txt for more information. If you want to compile this as a module ( = code which can be inserted in and removed from the running kernel whenever you want), @@ -3819,11 +3885,13 @@ Adaptec AHA152X/2825 support CONFIG_SCSI_AHA152X - This is support for the AVA-1505 (irq etc must be manually specified), - AHA-1510, AHA-1520, AHA-1522, and AHA-2825 SCSI host adapters. It is - explained in section 3.3 of the SCSI-HOWTO, available via FTP - (user: anonymous) at ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. You - might also want to read the comments at the top of + This is a driver for the AHA-1510, AHA-1520, AHA-1522, and AHA-2825 + SCSI host adapters. It also works for the AVA-1505, but the IRQ etc. + must be manually specified in this case. + + It is explained in section 3.3 of the SCSI-HOWTO, available via FTP + (user: anonymous) at ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. You + might also want to read the comments at the top of drivers/scsi/aha152x.c. This driver is also available as a module ( = code which can be @@ -3861,25 +3929,31 @@ Adaptec AIC7xxx chipset SCSI controller support CONFIG_SCSI_AIC7XXX This is support for the various aic7xxx based Adaptec SCSI - controllers. These include the 274x EISA cards; 284x VLB cards; 2902, - 2910, 293x, 294x, 394x, 3985 and several other PCI and motherboard based - SCSI controllers from Adaptec. It does not support the AAA-13x RAID - controllers from Adaptec, nor will it likely ever support them. It - does not support the 2920 cards from Adaptec that use the Future Domain - SCSI controller chip. For those cards, you need the "Future Domain - 16xx SCSI support" driver. + controllers. These include the 274x EISA cards; 284x VLB cards; + 2902, 2910, 293x, 294x, 394x, 3985 and several other PCI and + motherboard based SCSI controllers from Adaptec. It does not support + the AAA-13x RAID controllers from Adaptec, nor will it likely ever + support them. It does not support the 2920 cards from Adaptec that + use the Future Domain SCSI controller chip. For those cards, you + need the "Future Domain 16xx SCSI support" driver. In general, if the controller is based on an Adaptec SCSI controller - chip from the aic777x series or the aic78xx series, it should work. The - only exception is the 7810 which is specifically not supported (that's the - RAID controller chip on the AAA-13x cards). + chip from the aic777x series or the aic78xx series, this driver + should work. The only exception is the 7810 which is specifically + not supported (that's the RAID controller chip on the AAA-13x + cards). + + Note that the AHA2920 SCSI host adapter is *not* supported by this + driver; choose "Future Domain 16xx SCSI support" instead if you have + one of those. Information on the configuration options for this controller can be found by checking the help file for each of the available configuration options. You should read drivers/scsi/README.aic7xxx at a minimum before contacting the maintainer with any questions. The SCSI-HOWTO, available via FTP (user: anonymous) at - ftp://metalab.unc.edu/pub/Linux/docs/HOWTO can also be of great help. + ftp://metalab.unc.edu/pub/Linux/docs/HOWTO can also be of great + help. If you want to compile this driver as a module ( = code which can be inserted in and removed from the running kernel whenever you want), @@ -3980,16 +4054,15 @@ EATA-DMA [Obsolete] (DPT, NEC, AT&T, SNI, AST, Olivetti, Alphatronix) support CONFIG_SCSI_EATA_DMA - This driver is obsolete. You should normally be using the generic EATA - driver for this hardware. - This is support for the EATA-DMA protocol compliant SCSI Host Adapters like the SmartCache III/IV, SmartRAID controller families - and the DPT PM2011B and PM2012B controllers. Note that there is - also another driver for the same hardware: "EATA ISA/EISA/PCI - support". You should only say Y to one of them. Please read the - SCSI-HOWTO, available via FTP (user: anonymous) at - ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. + and the DPT PM2011B and PM2012B controllers. + + Note that this driver is obsolete; if you have one of the above SCSI + Host Adapters, you should normally say N here and Y to "EATA + ISA/EISA/PCI support", below. Please read the SCSI-HOWTO, available + via FTP (user: anonymous) at + 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). @@ -4032,19 +4105,19 @@ CONFIG_SCSI_U14_34F_LINKED_COMMANDS This option enables elevator sorting for all probed SCSI disks and CDROMs. It definitely reduces the average seek distance when doing - random seeks, but this does not necessarily results in a noticeable + random seeks, but this does not necessarily result in a noticeable performance improvement: your mileage may vary... + The safe answer is N. maximum number of queued commands CONFIG_SCSI_U14_34F_MAX_TAGS - This specifies how many SCSI commands can be maximally queued for each - probed SCSI device. You should reduce the default value of 8 only if - you have disks with buggy or limited tagged command support. + This specifies how many SCSI commands can be maximally queued for + each probed SCSI device. You should reduce the default value of 8 + only if you have disks with buggy or limited tagged command support. Minimum is 2 and maximum is 14. This value is also the window size - used by the elevator sorting option above. - The effective value used by the driver for each probed SCSI device is - reported at boot time. + used by the elevator sorting option above. The effective value used + by the driver for each probed SCSI device is reported at boot time. Future Domain 16xx SCSI/AHA-2920A support CONFIG_SCSI_FUTURE_DOMAIN @@ -4055,10 +4128,10 @@ It is explained in section 3.7 of the SCSI-HOWTO, available via FTP (user: anonymous) at ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. - NOTE: Newer Adaptec AHA-2920C boards use the Adaptec AIC-7850 chip and - should use the aic7xxx driver (CONFIG_SCSI_AIC7XXX). The Future Domain - driver works with the older Adaptec AHA-2920A boards with a Future Domain - chip on them. + NOTE: Newer Adaptec AHA-2920C boards use the Adaptec AIC-7850 chip + and should use the aic7xxx driver ("Adaptec AIC7xxx chipset SCSI + controller support"). This Future Domain driver works with the older + Adaptec AHA-2920A boards with a Future Domain chip on them. This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -4068,9 +4141,10 @@ Future Domain MCS-600/700 SCSI support CONFIG_SCSI_FD_MCS This is support for Future Domain MCS 600/700 MCA SCSI adapters. Some - PS/2s are also equipped with IBM Fast SCSI Adapter/A which is an OEM - of the MCS 700. This driver also supports Reply SB16/SCSI card (the - SCSI part). It supports multiple adapters in the same system. + PS/2 computers are equipped with IBM Fast SCSI Adapter/A which is + identical to the MCS 700 and hence also supported by this driver. + This driver also supports the Reply SB16/SCSI card (the SCSI part). + It supports multiple adapters in the same system. Generic NCR5380/53c400 SCSI support CONFIG_SCSI_GENERIC_NCR5380 @@ -4103,16 +4177,17 @@ NCR53c7,8xx SCSI support CONFIG_SCSI_NCR53C7xx - This is the 53c7 and 8xx NCR family of SCSI controllers, not to be - confused with the NCR 5380 controllers. It is explained in section - 3.8 of the SCSI-HOWTO, available via FTP (user: anonymous) at - ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. If it doesn't work out - of the box, you may have to change some settings in - drivers/scsi/53c7,8xx.h. + This is a driver for the 53c7 and 8xx NCR family of SCSI + controllers, not to be confused with the NCR 5380 controllers. It is + explained in section 3.8 of the SCSI-HOWTO, available via FTP (user: + anonymous) at ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. If it + doesn't work out of the box, you may have to change some settings in + drivers/scsi/53c7,8xx.h. Please read drivers/scsi/README.ncr53c7xx + for the available boot time command line options. Note: there is another driver for the 53c8xx family of controllers - ("NCR53C8XX SCSI support" below). You cannot say Y to both of them; - you can say M to both and build them as modules, but only one may be + ("NCR53C8XX SCSI support" below). If you want to use them both, you + need to say M to both and build them as modules, but only one may be active at a time. If you have a 53c8xx board, it's better to use the other driver. @@ -4152,17 +4227,41 @@ tagged command queuing and fast synchronous data transfers up to 80 MB/s with wide FAST-40 LVD devices and controllers. - The NCR53C860 and NCR53C875 support FAST-20 transfers. The NCR53C895 - supports FAST-40 transfers with Ultra2 LVD devices. + Recent versions of the 53C8XX chips are better supported by the + option "SYM53C8XX SCSI support", below. - Note: there is another driver for the 53c8xx family of controllers - ("NCR53c7,8xx SCSI support" above). You cannot say Y to both of - them; you can say M to both and build them as modules, but only one - may be active at a time. If you have a 53c8xx board, it's best to - use this driver. + Note: there is yet another driver for the 53c8xx family of controllers + ("NCR53c7,8xx SCSI support" above). If you want to use them both, + you need to say M to both and build them as modules, but only one + may be active at a time. If you have a 53c8xx board, you probably do + not want to use the "NCR53c7,8xx SCSI support". Please read drivers/scsi/README.ncr53c8xx for more information. +SYM53C8XX SCSI support +CONFIG_SCSI_SYM53C8XX + This driver supports all the features of recent 53C8XX chips (used + in PCI SCSI controllers), notably the hardware phase mismatch + feature of the SYM53C896. + + Older versions of the 53C8XX chips are not supported by this + driver. If your system uses either a 810 rev. < 16, a 815, or a 825 + rev. < 16 PCI SCSI processor, you must use the generic NCR53C8XX + driver ("NCR53C8XX SCSI support" above) or configure both the + NCR53C8XX and this SYM53C8XX drivers either as module or linked to + the kernel image. + + When both drivers are linked to the kernel, the SYM53C8XX driver is + called first at initialization and you can use the 'excl=ioaddr' + driver boot option to exclude attachment of adapters by the SYM53C8XX + driver. For instance, entering 'sym53c8xx=excl:0xb400,excl=0xc000' at + lilo prompt prevents adapters at io address 0xb400 and 0xc000 from + being attached by the SYM53C8XX driver, thus allowing the NCR53C8XX + driver to attach them. The 'excl' option is also supported by the + NCR53C8XX driver. + + Please read drivers/scsi/README.ncr53c8xx for more information. + synchronous data transfers frequency CONFIG_SCSI_NCR53C8XX_SYNC The SCSI Parallel Interface-2 Standard defines 4 classes of transfer @@ -4275,6 +4374,16 @@ The normal answer therefore is N. +include support for the NCR PQS/PDS SCSI card +CONFIG_SCSI_NCR53C8XX_PQS_PDS + Say Y here if you have a special SCSI adapter produced by NCR + corporation called a PCI Quad SCSI or PCI Dual SCSI. You do not need + this if you do not have one of these adapters. However, since this + device is detected as a specific PCI device, this option is quite + safe. + + The common answer here is N, but answering Y is safe. + IBMMCA SCSI support CONFIG_SCSI_IBMMCA This is support for the IBM SCSI adapter found in many of the PS/2 @@ -4348,10 +4457,10 @@ controller based on the NCR 53C94. This driver will allow use of the controller on the 3550, and very possibly others. - If you want to compile this as a module (= code which can be inserted - and removed from the running kernel whenever you want), - say M here and read Documentation/modules.txt. The module will be - called mca_53c9x.o. + If you want to compile this as a module (= code which can be + inserted and removed from the running kernel whenever you want), say + M here and read Documentation/modules.txt. The module will be called + mca_53c9x.o. Always IN2000 SCSI support CONFIG_SCSI_IN2000 @@ -4369,18 +4478,7 @@ CONFIG_SCSI_INITIO This is support for the Initio 91XXU(W) SCSI host adapter. Please read the SCSI-HOWTO, available via FTP (user: anonymous) at - ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO. - - 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. The module will be - called initio.o - -Initio 91XXU(W) SCSI support -CONFIG_SCSI_INITIO - This is support for the Initio 91XXU(W) SCSI host adapter. - Please read the SCSI-HOWTO, available via FTP (user: anonymous) at - ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO. + ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. If you want to compile this as a module ( = code which can be inserted in and removed from the running kernel whenever you want), @@ -4400,6 +4498,17 @@ The module will be called pas16.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. +Initio INI-A100U2W SCSI support +CONFIG_SCSI_INIA100 + This is support for the Initio INI-A100U2W SCSI host adapter. + Please read the SCSI-HOWTO, available via FTP (user: anonymous) at + ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. + + 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. The module will be + called a100u2w.o + PCI2000 support CONFIG_SCSI_PCI2000 This is support for the PCI2000I EIDE interface card which acts as a @@ -4435,14 +4544,18 @@ Qlogic FAS SCSI support CONFIG_SCSI_QLOGIC_FAS - This driver works only with the ISA, VLB, and PCMCIA versions of the - Qlogic FastSCSI! cards as well as any other card based on the FASXX - chip (including the Control Concepts SCSI/IDE/SIO/PIO/FDC cards); it - does NOT support the PCI version. The PCI versions are supported by - the Qlogic ISP driver though. Information about this driver is - contained in drivers/scsi/README.qlogicfas. You should also read - the SCSI-HOWTO, available via FTP (user: anonymous) at - ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. + This is a driver for the ISA, VLB, and PCMCIA versions of the Qlogic + FastSCSI! cards as well as any other card based on the FASXX chip + (including the Control Concepts SCSI/IDE/SIO/PIO/FDC cards). + + This driver does NOT support the PCI versions of these cards. The + PCI versions are supported by the Qlogic ISP driver ("Qlogic ISP + SCSI support"), below. + + Information about this driver is contained in + drivers/scsi/README.qlogicfas. You should also read the SCSI-HOWTO, + available via FTP (user: anonymous) at + 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). @@ -4455,7 +4568,8 @@ IQ-PCI-10, IQ_PCI-D) except for the PCI-basic card. (This latter card is supported by the "AM53/79C974 PCI SCSI" driver). - If you say Y here, make sure to say Y to "PCI BIOS support" as well. + If you say Y here, make sure to choose "BIOS" at the question "PCI + access mode". Please read the file drivers/scsi/README.qlogicisp. You should also read the SCSI-HOWTO, available via FTP (user: anonymous) at @@ -4466,6 +4580,15 @@ The module will be called qlogicisp.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. +Qlogic ISP FC SCSI support +CONFIG_SCSI_QLOGIC_FC + This is a driver for the QLogic ISP2100 SCSI-FCP host adapter. + + 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 be called qlogicfc.o. If you want to compile it as + a module, say M here and read Documentation/modules.txt. + Seagate ST-02 and Future Domain TMC-8xx SCSI support CONFIG_SCSI_SEAGATE These are 8-bit SCSI controllers; the ST-01 is also supported by @@ -4521,14 +4644,25 @@ want). The module will be called wd7000.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. +ACARD SCSI support +CONFIG_SCSI_ACARD + This driver supports the ACARD 870U/W SCSI host adapter. + + 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 be called atp870u.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + EATA ISA/EISA/PCI (DPT and generic EATA/DMA-compliant boards) support CONFIG_SCSI_EATA - This driver supports all the EATA/DMA-compliant SCSI host adapters. - DPT ISA and all EISA i/o addresses are probed looking for the "EATA" - signature. If you said Y to "PCI support", the addresses of all the - PCI SCSI controllers reported by the PCI subsystem are probed as well. - You want to read the start of drivers/scsi/eata.c and the SCSI-HOWTO, - available via FTP (user: anonymous) at + This driver supports all EATA/DMA-compliant SCSI host adapters. DPT + ISA and all EISA i/o addresses are probed looking for the "EATA" + signature. If you chose "BIOS" at the question "PCI access mode", + the addresses of all the PCI SCSI controllers reported by the PCI + subsystem are probed as well. + + You want to read the start of drivers/scsi/eata.c and the + SCSI-HOWTO, available via FTP (user: anonymous) at ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. Note that there is also another driver for the same hardware @@ -4544,26 +4678,25 @@ This is a feature of SCSI-2 which improves performance: the host adapter can send several SCSI commands to a device's queue even if previous commands haven't finished yet. Most EATA adapters negotiate - this feature automatically with the device, even if your answer is N. - The safe answer is N. + this feature automatically with the device, even if your answer is + N. The safe answer is N. enable elevator sorting CONFIG_SCSI_EATA_LINKED_COMMANDS This option enables elevator sorting for all probed SCSI disks and - CDROMs. It definetly reduces the average seek distance when doing + CDROMs. It definitely reduces the average seek distance when doing random seeks, but this does not necessarily result in a noticeable performance improvement: your mileage may vary... The safe answer is N. maximum number of queued commands CONFIG_SCSI_EATA_MAX_TAGS - This specifies how many SCSI commands can be maximally queued for each - probed SCSI device. You should reduce the default value of 16 only if - you have disks with buggy or limited tagged command support. + This specifies how many SCSI commands can be maximally queued for + each probed SCSI device. You should reduce the default value of 16 + only if you have disks with buggy or limited tagged command support. Minimum is 2 and maximum is 62. This value is also the window size - used by the elevator sorting option above. - The effective value used by the driver for each probed SCSI device is - reported at boot time. + used by the elevator sorting option above. The effective value used + by the driver for each probed SCSI device is reported at boot time. NCR53c406a SCSI support CONFIG_SCSI_NCR53C406A @@ -4577,6 +4710,25 @@ say M here and read Documentation/modules.txt. The module will be called NCR53c406.o. +Symbios Logic sym53c416 support +CONFIG_SCSI_SYM53C416 + This is support for the sym53c416 SCSI host adapter, the SCSI + adapter that comes with some HP scanners. This driver requires that + the sym53c416 is configured first using some sort of pnp + configuration program (e.g. isapnp) or by a PnP aware BIOS. If you + are using isapnp then you need to compile this driver as a module + and then load it using insmod after isapnp has run. The parameters + of the configured card(s) should be passed to the driver. The format + is: + + insmod sym53c416 sym53c416=, [sym53c416_1=,] + + There is support for up to four adapters. If you want to compile + this 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 + sym53c416.o. + Tekram DC390(T) and Am53/79C974 (PCscsi) SCSI support CONFIG_SCSI_DC390T This driver supports PCI SCSI host adapters based on the Am53C974A @@ -4587,7 +4739,8 @@ Note that this driver does NOT support Tekram DC390W/U/F, which are based on NCR/Symbios chips. Use "NCR53C8XX SCSI support" for those. - Also note that there is another generic Am53C974 driver. + Also note that there is another generic Am53C974 driver, + "AM53/79C974 PCI SCSI support" below. You can pick either one. If you want to compile this driver as a module ( = code which can be inserted in and removed from the running kernel whenever you want), @@ -4617,13 +4770,30 @@ ftp://metalab.unc.edu/pub/Linux/docs/HOWTO, is for you. Note that there is another driver for AM53C974 based adapters: - "Tekram DC390(T) and Am53/79C974 (PCscsi) SCSI support", above. + "Tekram DC390(T) and Am53/79C974 (PCscsi) SCSI support", above. You + can pick either one. If you want to compile this 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 AM53C974.o. +AMI MegaRAID support +CONFIG_SCSI_MEGARAID + This driver supports the AMI MegaRAID 428 and 438 (and maybe 466) + SCSI host adapters. + + If you want to compile this 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 megaraid.o. + +### +### What is this? +### +#Concurrent IO commands on MegaRAID +#CONFIG_MEGARAID_MULTI_IO + GDT SCSI Disk Array Controller support CONFIG_SCSI_GDTH This is a driver for all SCSI Disk Array Controllers (EISA/ISA/PCI) @@ -4635,36 +4805,59 @@ If you want to compile it as a module, say M here and read Documentation/modules.txt. -IOMEGA Parallel Port ZIP drive SCSI support +IOMEGA parallel port (ppa - older drives) CONFIG_SCSI_PPA - This driver supports the parallel port version of IOMEGA's ZIP drive - (a 100 MB removable media device). For more information about this - driver and how to use it you should read the file - drivers/scsi/README.ppa. You should also read the SCSI-HOWTO, which - is available via FTP (user: anonymous) from + This driver supports older versions of IOMEGA's parallel port ZIP + drive (a 100 MB removable media device). + + Note that you can say N here if you have the SCSI version of the ZIP + drive: it will be supported automatically if you said Y to the + generic "SCSI disk support", above. + + If you have the ZIP Plus drive or a more recent parallel port ZIP + drive (if the supplied cable with the drive is labeled "AutoDetect") + then you should say N here and Y to "IOMEGA parallel port (imm - + newer drives)", below. + + For more information about this driver and how to use it you should + read the file drivers/scsi/README.ppa. You should also read the + SCSI-HOWTO, which is available via FTP (user: anonymous) from ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. If you use this driver, you will still be able to use the parallel port for other tasks, such as a printer; it is safe to compile both drivers into the kernel. + This driver is also available as a module which can be inserted in + and removed from the running kernel whenever you want. To compile + this driver as a module, say M here and read + Documentation/modules.txt. The module will be called ppa.o. + +IOMEGA parallel port (imm - newer drives) +CONFIG_SCSI_IMM + This driver supports newer versions of IOMEGA's parallel port ZIP + drive (a 100 MB removable media device). + Note that you can say N here if you have the SCSI version of the ZIP drive: it will be supported automatically if you said Y to the generic "SCSI disk support", above. - The ZIP Plus drive is supported by the imm driver, also more recent - parallel port ZIP drives use an imm compatible interface. If the - supplied cable with the drive is labeled "AutoDetect" then you will - need the imm driver. + If you have the ZIP Plus drive or a more recent parallel port ZIP + drive (if the supplied cable with the drive is labeled "AutoDetect") + then you should say Y here; if you have an older ZIP drive, say N + here and Y to "IOMEGA Parallel Port (ppa - older drives)", above. + + For more information about this driver and how to use it you should + read the file drivers/scsi/README.ppa. You should also read the + SCSI-HOWTO, which is available via FTP (user: anonymous) from + ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. If you use this driver, + you will still be able to use the parallel port for other tasks, + such as a printer; it is safe to compile both drivers into the + kernel. This driver is also available as a module which can be inserted in and removed from the running kernel whenever you want. To compile this driver as a module, say M here and read - Documentation/modules.txt. The module will be called ppa.o. - -IOMEGA Parallel Port ZIP drive SCSI support -CONFIG_SCSI_IMM - All "new and improved" parallel port to SCSI interface from Iomega. - Please read the comments for the ppa driver for further information + Documentation/modules.txt. The module will be called imm.o. Force the Iomega ZIP drivers to use EPP-16 CONFIG_SCSI_IZIP_EPP16 @@ -4674,19 +4867,20 @@ Some parallel port chipsets are slower than their motherboard, and so we have to control the state of the chipset's FIFO queue every - now and then to avoid data loss. This will be done if you say Y here. + now and then to avoid data loss. This will be done if you say Y + here. Generally, saying Y is the safe option and slows things down a bit. Assume slow parallel port control register CONFIG_SCSI_IZIP_SLOW_CTR - Some parallel ports are known to have excessive delays between changing - the parallel port control register and good data being available on - the parallel port data/status register. This option forces a small delay - (1.0 usec to be exact) after changing the control register to let things - settle out. Enabling this option may result in a big drop in performance - but some very old parallel ports (found in 386 vintage machines) will - not work properly. + Some parallel ports are known to have excessive delays between + changing the parallel port control register and good data being + available on the parallel port data/status register. This option + forces a small delay (1.0 usec to be exact) after changing the + control register to let things settle out. Enabling this option may + result in a big drop in performance but some very old parallel ports + (found in 386 vintage machines) will not work properly. Generally, saying N is fine. @@ -4775,11 +4969,11 @@ Network device support? CONFIG_NETDEVICES - You can say N here if you don't intend to connect to any other - computer at all or if all your connections will be over a telephone - line with a modem either via UUCP (UUCP is a protocol to forward - mail and news between unix hosts over telephone lines; read the - UUCP-HOWTO, available via FTP (user: anonymous) in + You can say N here if you don't intend to connect your Linux box to + any other computer at all or if all your connections will be over a + telephone line with a modem either via UUCP (UUCP is a protocol to + forward mail and news between unix hosts over telephone lines; read + the UUCP-HOWTO, available via FTP (user: anonymous) in ftp://metalab.unc.edu/pub/Linux/docs/HOWTO) or dialing up a shell account or a BBS, even using term (term is a program which gives you almost full Internet connectivity if you have a regular dial up @@ -4792,18 +4986,18 @@ you want to use under Linux (make sure you know its name because you will be asked for it and read the Ethernet-HOWTO (especially if you plan to use more than one network card under Linux), available from - ftp://metalab.unc.edu:/pub/Linux/docs/HOWTO/mini) or if you want to + ftp://metalab.unc.edu/pub/Linux/docs/HOWTO/mini) or if you want to use SLIP (Serial Line Internet Protocol is the protocol used to send Internet traffic over telephone lines or null modem cables) or CSLIP (compressed SLIP) or PPP (Point to Point Protocol, a better and newer replacement for SLIP) or PLIP (Parallel Line Internet Protocol is mainly used to create a mini network by connecting the parallel ports of two local machines) or AX.25/KISS (protocol for sending - Internet traffic over radio links). + Internet traffic over amateur radio links). - Make sure to read the NET-2-HOWTO. Eventually, you will have to read + Make sure to read the NET-3-HOWTO. Eventually, you will have to read Olaf Kirch's excellent and free book "Network Administrator's - Guide", to be found in ftp://metalab.unc.edu:/pub/Linux/docs/LDP. If + Guide", to be found in ftp://metalab.unc.edu/pub/Linux/docs/LDP. If unsure, say Y. Dummy net driver support @@ -4842,7 +5036,7 @@ ftp://metalab.unc.edu/pub/Linux/system/network/serial/ ) which allows you to use SLIP over a regular dial up shell connection. If you plan to use SLiRP, make sure to say Y to CSLIP, below. The - NET-2-HOWTO, available via FTP (user: anonymous) in + NET-3-HOWTO, available via FTP (user: anonymous) in ftp://metalab.unc.edu/pub/Linux/docs/HOWTO, explains how to configure SLIP. Note that you don't need this option if you just want to run term (term is a program which gives you almost full @@ -4869,7 +5063,7 @@ anonymous) from ftp://metalab.unc.edu/pub/Linux/system/network/serial/) which allows you to use SLIP over a regular dial up shell connection, you - definitely want to say Y here. The NET-2-HOWTO, available via FTP + definitely want to say Y here. The NET-3-HOWTO, available via FTP (user: anonymous) in ftp://metalab.unc.edu/pub/Linux/docs/HOWTO, explains how to configure CSLIP. This won't enlarge your kernel. @@ -4909,7 +5103,7 @@ To use PPP, you need an additional program called pppd as described in Documentation/networking/ppp.txt and in the PPP-HOWTO, available - from ftp://metalab.unc.edu:/pub/Linux/docs/HOWTO. If you upgrade + from ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. If you upgrade from an older kernel, you might need to upgrade pppd as well. The PPP option enlarges your kernel by about 16 KB. @@ -4971,8 +5165,9 @@ radio frequencies 900 MHz and 2.4 GHz. This driver support the ISA version of the WaveLAN card. A separate - driver for the pcmcia hardware is available in David Hinds' - pcmcia-cs package (see the file Documentation/Changes for location). + driver for the PCMCIA (PC-card) hardware is available in David + Hinds' pcmcia-cs package (see the file Documentation/Changes for + location). If you want to use an ISA WaveLAN card under Linux, say Y and read the Ethernet-HOWTO, available via FTP (user: anonymous) in @@ -5062,7 +5257,7 @@ If you want to use PLIP, say Y and read the PLIP mini-HOWTO, available via FTP (user: anonymous) in ftp://metalab.unc.edu/pub/Linux/docs/HOWTO/mini as well as the - NET-2-HOWTO in ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. Note that + NET-3-HOWTO in ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. Note that the PLIP protocol was changed and this PLIP driver won't work together with the PLIP support in Linux versions 1.0.x. This option enlarges your kernel by about 8 KB. @@ -5078,11 +5273,15 @@ If you have two serial connections to some other computer (this usually requires two modems and two telephone lines) and you use SLIP (the protocol for sending Internet traffic over telephone - lines) or PPP (a better SLIP) on them, you can make them behave - like one double speed connection using this driver. Naturally, this - has to be supported at the other end as well, either with a similar - EQL Linux driver or with a Livingston Portmaster 2e. Say Y if you - want this and read Documentation/networking/eql.txt. + lines) or PPP (a better SLIP) on them, you can make them behave like + one double speed connection using this driver. Naturally, this has + to be supported at the other end as well, either with a similar EQL + Linux driver or with a Livingston Portmaster 2e. + + Say Y if you want this and read Documentation/networking/eql.txt. + You may also want to read section 6.2 of the NET-3-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). @@ -5199,16 +5398,18 @@ With relatively inexpensive WAN interface cards available on the market, a perfectly usable router can be built for less than half the price of an external router. If you have one of those cards and - wish to use your Linux box as a WAN router, say Y here and to the - WAN driver for your card, below. You will also need a wan-tools - package available via FTP (user: anonymous) from + wish to use your Linux box as a WAN router, say Y here and also to + the WAN driver for your card, below. You will then need the + wan-tools package which is available via FTP (user: anonymous) from ftp://ftp.sangoma.com. Read Documentation/networking/wan-router.txt for more information. - WAN routing support is always built as a module ( = code which can - be inserted in and removed from the running kernel whenever you - want). The module is called wanrouter.o. For general information - about modules read Documentation/modules.txt. + The WAN routing support is also available as a module called + wanrouter.o ( = code which can be inserted in and removed from the + running kernel whenever you want). If you want to compile it as a + module, say M here and read Documentation/modules.txt. + + If unsure, say N. Fast switching (read help!) CONFIG_NET_FASTROUTE @@ -5217,11 +5418,13 @@ *** This option is NOT COMPATIBLE with several important *** *** networking options: especially CONFIG*FIREWALL. *** + *** Say N here if you intend to use Linux as a firewall. *** However, it will work with all options in CONFIG_IP_ADVANCED_ROUTER - section (except for CONFIG_IP_ROUTE_TOS). At the moment, few devices - support fast switching (tulip is one of them, modified 8390 can be - found at ftp://ftp.inr.ac.ru/ip-routing/fastroute-8390.tar.gz). + section (except for CONFIG_IP_ROUTE_TOS and CONFIG_IP_ROUTE_FWMARK). + At the moment, few devices support fast switching (tulip is one of + them, modified 8390 can be found at + ftp://ftp.inr.ac.ru/ip-routing/fastroute-8390.tar.gz). If unsure, say N. @@ -5414,30 +5617,42 @@ Comtrol Hostess SV-11 support CONFIG_HOSTESS_SV11 This is a network card for low speed synchronous serial links, at - up to 256Kbits. It supports both PPP and Cisco HDLC + up to 256Kbps. It supports both PPP and Cisco HDLC. + At this point, the driver can only be compiled as a module. COSA/SRP sync serial boards support CONFIG_COSA - This is a driver for COSA and SRP synchronous serial boards. - These boards enable to connect synchronous serial devices (for - example base-band modems, or any other device with the X.21, V.24, - V.35 or V.36 interface) to your Linux box. The cards can work - as the character device, synchronous PPP network device, or the Cisco - HDLC network device. + This is a driver for COSA and SRP synchronous serial boards. These + boards allow to connect synchronous serial devices (for example + base-band modems, or any other device with the X.21, V.24, V.35 or + V.36 interface) to your Linux box. The cards can work as the + character device, synchronous PPP network device, or the Cisco HDLC + network device. To actually use the COSA or SRP board, you will need user-space - utilities for downloading the firmware to the cards and to set - them up. Look at the http://www.fi.muni.cz/~kas/cosa/ for more + utilities for downloading the firmware to the cards and to set them + up. Look at the http://www.fi.muni.cz/~kas/cosa/ for more information about the cards (including the pointer to the user-space utilities). You can also read the comment at the top of the - drivers/net/cosa.c for details about the cards and the driver itself. + drivers/net/cosa.c for details about the cards and the driver + itself. The driver will be compiled as a module ( = code which can be inserted in and removed from the running kernel whenever you want). The module will be called cosa.o. For general information about modules read Documentation/modules.txt. +Red Creek Hardware VPN (EXPERIMENTAL) +CONFIG_RCPCI + This is a driver for hardware which provides a Virtual Private + Network (VPN). Say Y if you have it. + + This code is also available as a module called rcpci.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read Documentation/modules.txt. + WAN Drivers CONFIG_WAN_DRIVERS Say Y to this option if your Linux box contains a WAN card and you @@ -5728,7 +5943,6 @@ say M here and read Documentation/modules.txt. This is recommended. The module will be called acenic.o. - AMD LANCE and PCnet (AT1500 and NE2100) support CONFIG_LANCE If you have a network (Ethernet) card of this type, say Y and read @@ -5736,6 +5950,11 @@ ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. Some LinkSys cards are of this type. + If you want to compile this 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. This is recommended. + The module will be called lance.o. + 3COM cards CONFIG_NET_VENDOR_3COM If you have a network (Ethernet) card belonging to this class, say Y @@ -5811,6 +6030,18 @@ module, say M here and read Documentation/modules.txt as well as Documentation/networking/net-modules.txt. +3c527 support +CONFIG_ELMC_II + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available via FTP (user: anonymous) in + 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 be called 3c527.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt as well as + Documentation/networking/net-modules.txt. + 3c509/3c579 support CONFIG_EL3 If you have a network (Ethernet) card belonging to the 3Com @@ -6362,11 +6593,11 @@ one of those, say Y and read the Ethernet-HOWTO, available via FTP (user: anonymous) from ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. - If you want to plug a network card into the PCMCIA slot of your - laptop instead (PCMCIA is the standard for credit card size - extension cards used by all modern laptops), look on the FTP site - (user: anonymous) ftp://cb-iris.stanford.edu/pub/pcmcia and say N - here. + If you want to plug a network (or some other) card into the PCMCIA + (or PC-card) slot of your laptop instead (PCMCIA is the standard for + credit card size extension cards used by all modern laptops), you + need the pcmcia-cs package (location contained in the file + Documentation/Changes) and you can say N here. Laptop users should read the Linux Laptop home page at http://www.cs.utexas.edu/users/kharker/linux-laptop/ (to browse the @@ -6497,6 +6728,16 @@ under Linux, say Y here (you must also remember to enable the driver for your HIPPI card below). Most people will say N here. +CERN HIPPI PCI adapter support +CONFIG_CERN_HIPPI + Say Y here if this is your PCI HIPPI network card. + + 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 be called cern_hippi.o. If you want to compile it as + a module, say M here and read Documentation/modules.txt. If unsure, + say N. + Essential RoadRunner HIPPI PCI adapter support CONFIG_ROADRUNNER Say Y here if this is your PCI HIPPI network card. @@ -6609,6 +6850,20 @@ The module will be called mcd.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. +IRQ channel for Mitsumi CD-ROM +CONFIG_MCD_IRQ + This allows you to specify the default value of the IRQ used by the + driver. This setting can be overridden by passing the "mcd=" + parameter to the kernel at boot time (or at module load time if you + said M to "Standard Mitsumi CDROM support"). + +I/O base address for Mitsumi CD-ROM +CONFIG_MCD_BASE + This allows you to specify the default value of the I/O base address + used by the driver. This setting can be overridden by passing the + "mcd=" parameter to the kernel at boot time (or at module load time + if you said M to "Standard Mitsumi CDROM support"). + Mitsumi [XA/MultiSession] support CONFIG_MCDX Use this driver if you want to be able to read XA or MultiSession @@ -6799,6 +7054,13 @@ ftp://metalab.unc.edu/pub/Linux/docs/HOWTO/mini. Probably the quota support is only useful for multi user systems. If unsure, say N. +Acorn's ADFS filesystem support (read only) (EXPERIMENTAL) +CONFIG_ADFS_FS + The Advanced Disk File System is the filesystem used on floppy and + hard disks by Acorn Systems. Currently in development, as a read- + only driver for hard disks. These should be the first partition + (eg. /dev/[sh]d?1) on each of your drives. If unsure, say N. + Minix fs support CONFIG_MINIX_FS Minix is a simple operating system used in many classes about OS's. @@ -6959,7 +7221,7 @@ vfat fs support CONFIG_VFAT_FS This option provides support for normal Windows filesystems with - long filenames. That includes noncompressed FAT-based filesystems + long filenames. That includes non-compressed FAT-based filesystems used by Windows 95, Windows 98, Windows NT 4.0, and mtools. You cannot use the VFAT filesystem for your Linux root partition @@ -7006,21 +7268,24 @@ of the system. "Virtual" means that it doesn't take up any space on your hard disk: the files are created on the fly by the kernel when you try to access them. Also, you cannot read the files with older - version of the program less: you need to use more or cat. The - filesystem is explained in the Kernel Hacker's Guide at - http://www.redhat.com:8080/HyperNews/get/khg.html on the WWW (to - browse the WWW, you need to have access to a machine on the Internet - that has a program like lynx or netscape), and also on the proc(8) - manpage ("man 8 proc"). + version of the program less: you need to use more or cat. It's totally cool; for example, "cat /proc/interrupts" gives information about what the different IRQs are used for at the moment (there is a small number of Interrupt ReQuest lines in your computer that are used by the attached devices to gain the CPU's attention -- often a source of trouble if two devices are mistakenly configured - to use the same IRQ). This option will enlarge your kernel by about - 18 kB. Several programs depend on this, so everyone should say Y - here. + to use the same IRQ). + + The /proc filesystem is explained in the file + Documentation/proc.txt, in the Kernel Hacker's Guide at + http://www.redhat.com:8080/HyperNews/get/khg.html on the WWW (to + browse the WWW, you need to have access to a machine on the Internet + that has a program like lynx or netscape), and also on the proc(8) + manpage ("man 8 proc"). + + This option will enlarge your kernel by about 18 KB. Several + programs depend on this, so everyone should say Y here. NFS filesystem support CONFIG_NFS_FS @@ -7048,11 +7313,11 @@ say M here and read Documentation/modules.txt. If you are configuring a diskless machine which will mount its root - filesystem over NFS at boot time, say Y here and to "Root file - system on NFS" and to "IP: kernel level autoconfiguration". You - cannot compile this driver as a module in this case. There are two - packages designed for booting diskless machines over the net: - netboot and etherboot, both available via FTP (user: anonymous) from + filesystem over NFS at boot time, say Y here and to "IP: kernel + level autoconfiguration" above and to "Root file system on NFS" + below. You cannot compile this driver as a module in this case. + There are two packages designed for booting diskless machines over + the net: netboot and etherboot, both available via FTP from ftp://metalab.unc.edu/pub/Linux/system/boot/ethernet/ . If you don't know what all this is about, say N. @@ -7078,10 +7343,13 @@ should say N here, or you can say Y and use this new experimental kernel based NFS server. The advantage of the kernel based solution is that it is faster; it might not be completely stable yet, though. - You will need the support software from the linux-nfs package - available at ftp://ftp.mathematik.th-darmstadt.de/pub/linux/okir/. + + In either case, you will need support software; the respective + locations are given in the file Documentation/Changes in the NFS + section. + Please read the NFS-HOWTO, available via FTP (user: anonymous) from - ftp://metalab.unc.edu:/pub/Linux/docs/HOWTO. + ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. The NFS server is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -7156,7 +7424,7 @@ tar" or preferably "info tar"). Note also that this option has nothing whatsoever to do with the option "System V IPC". Read about the System V filesystem in Documentation/filesystems/sysv-fs.txt. - Saying Y here will enlarge your kernel by about 34 kB. + Saying Y here will enlarge your kernel by about 34 KB. If you want to compile this as a module ( = code which can be inserted in and removed from the running kernel whenever you want), @@ -7218,7 +7486,9 @@ QNX filesystem support (EXPERIMENTAL) CONFIG_QNX4FS_FS This is the filesystem used by the operating system QNX 4. Say Y if - you intend to mount QNX hard disks or floppies. + you intend to mount QNX hard disks or floppies. Unless you say Y to + "QNXFS read-write support" below, you will only be able to read + these filesystems. This filesystem support is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you @@ -7227,6 +7497,10 @@ If unsure, say N. +QNXFS read-write support (FOR TESTING ONLY) +CONFIG_QNX4FS_RW + Say Y if you want to test write support for QNX filesystems. + Kernel automounter support CONFIG_AUTOFS_FS The automounter is a tool to automatically mount remote filesystems @@ -7252,7 +7526,9 @@ OpenBSD and NeXTstep) use a filesystem called UFS. Some System V Unixes can create and mount hard disk partitions and diskettes using this filesystem as well. Saying Y here will allow you to read from - these partitions and diskettes. + these partitions; if you also want to write to them, say Y to the + experimental "UFS filesystem write support", below. Please read the + file Documentation/filesystems/ufs.txt for more information. If you only intend to mount files from some other Unix over the network using NFS, you don't need the UFS filesystem support (but @@ -7274,44 +7550,42 @@ If you haven't heard about all of this before, it's safe to say N. -UFS filesystem write support +UFS filesystem write support (experimental) CONFIG_UFS_FS_WRITE - You will be able to write to 4.4BSD (e.g. FreeBSD, NetBSD and - OpenBSD) and SunOS partitions and diskettes if you say Y to this - option in addition to "UFS filesystem support", above. + Say Y here if you want to try writing to UFS partitions. This is + experimental, so you should back up your UFS partitions beforehand. BSD disklabel (FreeBSD partition tables) support CONFIG_BSD_DISKLABEL FreeBSD uses its own hard disk partition scheme on your PC. It requires only one entry in the primary partition table of your disk and manages it similarly to DOS extended partitions, putting in its - first sector a new partition table in disklabel format. Saying Y + first sector a new partition table in BSD disklabel format. Saying Y here allows you to read these disklabels and further mount FreeBSD - partitions read-only from within Linux if you have also said Y to - "UFS filesystem support", above. If you don't know what all this - is about, say N. + partitions from within Linux if you have also said Y to "UFS + filesystem support", above. If you don't know what all this is + about, say N. SMD disklabel (Sun partition tables) support CONFIG_SMD_DISKLABEL Like most systems, SunOS uses its own hard disk partition table format, incompatible with all others. Saying Y here allows you to - read these partition tables and further mount SunOS disks read-only - from within Linux if you have also said Y to "UFS filesystem - support", above. This is mainly used to carry data from a SPARC - under SunOS to your Linux box via a removable medium like - magneto-optical or ZIP drives; note however that a good portable way - to transport files and directories between unixes (and even other - operating systems) is given by the tar program ("man tar" or - preferably "info tar"). If you don't know what all this is about, - say N. + read these partition tables and further mount SunOS disks from + within Linux if you have also said Y to "UFS filesystem support", + above. This is mainly used to carry data from a SPARC under SunOS to + your Linux box via a removable medium like magneto-optical or ZIP + drives; note however that a good portable way to transport files and + directories between unixes (and even other operating systems) is + given by the tar program ("man tar" or preferably "info tar"). If + you don't know what all this is about, say N. Solaris (x86) partition table support CONFIG_SOLARIS_X86_PARTITION Like most systems, Solaris x86 uses its own hard disk partition table format, incompatible with all others. Saying Y here allows you to read these partition tables and further mount Solaris x86 disks - read-only from within Linux if you have also said Y to "UFS - filesystem support", above. + from within Linux if you have also said Y to "UFS filesystem + support", above. ADFS filesystem support (read only) (EXPERIMENTAL) CONFIG_ADFS_FS @@ -7341,27 +7615,29 @@ to acquire a pseudo terminal, a process opens /dev/ptmx; the number of the pseudo terminal is then made available to the process and the pseudo terminal slave can be accessed as /dev/pts/. What was - traditionally /dev/ttyp2 will then be /dev/pts/2, for example. The - GNU C library glibc 2.1 contains the requisite support for this mode - of operation; you also need clients that use the Unix98 API. + traditionally /dev/ttyp2 will then be /dev/pts/2, for example. + + The GNU C library glibc 2.1 contains the requisite support for this + mode of operation; you also need client programs that use the Unix98 + API. -Unixware slices support (EXPERIMENTAL) +UnixWare slices support (EXPERIMENTAL) CONFIG_UNIXWARE_DISKLABEL - Like some systems, Unixware uses, except DOS-like partition table, - its own slice table inside a partition (VTOC - Virtual Table of - Contents). Its format is incompatible with all other OSes. Saying Y - here allows you to read VTOC and further mount Unixware partitions - read-only from within Linux if you have also said Y to "UFS - filesystem support" or "System V and Coherent filesystem support", - above. + Like some systems, UnixWare uses its own slice table inside a + partition (VTOC - Virtual Table of Contents). Its format is + incompatible with all other OSes. Saying Y here allows you to read + VTOC and further mount UnixWare partitions read-only from within + Linux if you have also said Y to "UFS filesystem support" or "System + V and Coherent filesystem support", above. - This is mainly used to carry data from a Unixware box to your + This is mainly used to carry data from a UnixWare box to your Linux box via a removable medium like magneto-optical, ZIP or removable IDE drives. Note, however, that a good portable way to transport files and directories between unixes (and even other operating systems) is given by the tar program ("man tar" or - preferably "info tar"). If you don't know what all this is about, - say N. + preferably "info tar"). + + If you don't know what all this is about, say N. Macintosh partition map support CONFIG_MAC_PARTITION @@ -7372,7 +7648,7 @@ SMB filesystem support (to mount Windows shares etc...) CONFIG_SMB_FS SMB (Server Message Block) is the protocol Windows for Workgroups - (WfW), Windows 95, Windows NT and OS/2 Lan Manager use to share + (WfW), Windows 95/98, Windows NT and OS/2 Lan Manager use to share files and printers over local networks. Saying Y here allows you to mount their filesystems (often called "shares" in this context) and access them just like any other Unix directory. Currently, this @@ -7436,7 +7712,7 @@ mount NetWare file server volumes and to access them just like any other Unix directory. For details, please read the file Documentation/filesystems/ncpfs.txt in the kernel source and the - IPX-HOWTO on ftp://metalab.unc.edu:/pub/Linux/docs/howto. + IPX-HOWTO on ftp://metalab.unc.edu/pub/Linux/docs/howto. You do not have to say Y here if you want your Linux box to act as a file *server* for Novell NetWare clients. @@ -7482,6 +7758,25 @@ case insensitive, and case in names is preserved. Say Y. You can disable it at mount time with the -N os2 parameter of ncpmount. +Lowercase DOS filenames on LONG namespace volume +CONFIG_NCPFS_SMALLDOS + If you say Y here, every filename on a NetWare server volume using + the OS2/LONG namespace will be converted to lowercase characters. + (For regular NetWare file server volumes with DOS namespace, this is + done automatically, even if you say N here.) Saying N here will give + you these filenames in uppercase. + + This is only a cosmetic option since the OS2/LONG namespace is case + insensitive. The only major reason for this option is backward + compatibility when moving from DOS to OS2/LONG namespace support. + Long filenames (created by Win95) will not be affected. + + This option does not solve the problem that filenames appear + differently under Linux and under Windows, since Windows does an + additional conversions on the client side. You can achieve similar + effects by saying Y to "Allow using of Native Language Support" + below. + Allow mounting of volume subdirectories CONFIG_NCPFS_MOUNT_SUBDIR Allows you to mount not only whole servers or whole volumes, but @@ -7500,28 +7795,23 @@ servers. Do not say Y if security is primary for you because root can read your session key (from /proc/kcore). -nls: Native language codepages and Unicode support -CONFIG_NLS - This is required by the FAT and NTFS filesystems and by the ISO 9660 - filesystem when it is compiled with Joliet support. Joliet is a - Microsoft extension for CDROMs that supports Unicode. This allows - translation between different character sets. - - When dealing with the FAT based filesystems, there are two character - sets that are important. The first is the codepage. Codepages are - character sets that are used by DOS to allow filenames to have - native language characters when character sets were limited to 256 - characters. The codepage is the character set that is used to store - native language characters on disk. The two most common codepages - are 437 in the United States and 850 in much of Europe. - - The second important character set is the input/output character - set. This is the character set that is displayed on the screen. In - the United States, this will almost always be the ISO 8859-1 - character set. This is the default. +Allow using of Native Language Support +CONFIG_NCPFS_NLS + Allows you to use codepages and I/O charsets for file name + translation between the server file system and input/output. This + may be useful, if you want to access the server with other operating + systems, e.g. Windows 95. See also NLS for more Information. + + To select codepages and I/O charsets use ncpfs-2.2.0.13 or newer. + +Symbolic links and mode permission bits +CONFIG_NCPFS_EXTRAS + This enables the use of symbolic links and an execute permission + bit on NCPFS. The file server need not have long name space or NFS + name space loaded for these to work. - Linux will only translate the FAT filenames, not the contents of the - files. + To use the new attributes, it is recommended to use the flags + '-f 600 -d 755' on the ncpmount command line. nls codepage 437 CONFIG_NLS_CODEPAGE_437 @@ -7710,8 +8000,7 @@ set, which covers most West European languages such as Albanian, Catalan, Danish, Dutch, English, Faeroese, Finnish, French, German, Galician, Irish, Icelandic, Italian, Norwegian, Portuguese, Spanish, - Swedish, and Valencian. It is also the default for the US. If - unsure, say Y. + and Swedish. It is also the default for the US. If unsure, say Y. nls iso8859-2 CONFIG_NLS_ISO8859_2 @@ -7803,7 +8092,7 @@ set, which covers most West European languages such as Albanian, Catalan, Danish, Dutch, English, Estonian, Faeroese, Finnish, French, German, Galician, Irish, Icelandic, Italian, Norwegian, - Portuguese, Spanish, Swedish, and Valencian. Latin 9 is an update to + Portuguese, Spanish, and Swedish. Latin 9 is an update to Latin 1 (ISO 8859-1) that removes a handful of rarely used characters and instead adds support for Estonian, corrects the support for French and Finnish, and adds the new Euro character. If @@ -8054,6 +8343,29 @@ read Documentation/modules.txt. The module will be called istallion.o. +Microgate SyncLink adapter support +CONFIG_SYNCLINK + Provides support for the SyncLink ISA and PCI + multiprotocol serial adapters. These adapters + support asynchronous and HDLC bit synchronous + communication up to 10Mbps (PCI adapter). + + This driver can only be built as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called synclink.o. If you want to do that, say M + here. + +Synchronous HDLC line discipline support +CONFIG_N_HDLC + Allows synchronous HDLC communications with + tty device drivers that support synchronous + HDLC such as the Microgate SyncLink adapter. + + This driver can only be built as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called n_hdlc.o. If you want to do that, say M + here. + Hayes ESP serial port support CONFIG_ESPSERIAL This is a driver which supports Hayes ESP serial ports. Both single @@ -8065,14 +8377,22 @@ and read Documentation/modules.txt. The module will be called esp.o. If unsure, say N. +Multi-Tech multiport card support +CONFIG_ISI + This is a driver for the Multi-Tech cards which provide several + serial ports. The driver is experimental and can currently only be + built as a module ( = code which can be inserted in and removed from + the running kernel whenever you want). Please read + Documentation/modules.txt. The module will be called isicom.o + Unix98 PTY support CONFIG_UNIX98_PTYS A pseudo terminal (PTY) is a software device consisting of two halves: a master and a slave. The slave device behaves identical to a physical terminal; the master device is used by a process to read data from and write data to the slave, thereby emulating a - terminal. Typical programs for the master side are xterm and telnet - servers. + terminal. Typical programs for the master side are telnet servers + and xterms. Linux has traditionally used the BSD-like names /dev/ptyxx for masters and /dev/ttyxx for slaves of pseudo terminals. This scheme @@ -8087,9 +8407,10 @@ filesystem; therefore, if you say Y here you should say Y to "/dev/pts filesystem for Unix98 PTYs" as well. - You should say Y here only if your C library is glibc 2.1 or later - (equal to libc-6.1, check with "ls -l /lib/libc.so.*"). Read the - instructions in Documentation/Changes. + If you want to say Y here, you need to have the C library glibc 2.1 + or later (equal to libc-6.1, check with "ls -l /lib/libc.so.*"). + Read the instructions in Documentation/Changes pertaining to pseudo + terminals. It's safe to say N. Maximum number of Unix98 PTYs in use (0-2048) CONFIG_UNIX98_PTY_COUNT @@ -8117,15 +8438,14 @@ removed from the running kernel whenever you want), say M here and read Documentation/modules.txt. The module will be called lp.o. - If you have several parallel ports, you should specify the base - address for the port to be used by the printer with the "lp" kernel - command line option. (Try "man bootparam" or see the documentation - of your boot loader (lilo or loadlin) about how to pass options to - the kernel at boot time. The lilo procedure is also explained in the - SCSI-HOWTO, available via FTP (user: anonymous) in - ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.) The standard base - addresses as well as the syntax of the "lp" command line option can - be found in drivers/char/lp.c. + If you have several parallel ports, you can specify which ports to + use with the "lp" kernel command line option. (Try "man bootparam" + or see the documentation of your boot loader (lilo or loadlin) + about how to pass options to the kernel at boot time. The lilo + procedure is also explained in the SCSI-HOWTO, available via FTP + (user: anonymous) in ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.) + The syntax of the "lp" command line option can be found in + drivers/char/lp.c. If you have more than 3 printers, you need to increase the LP_NO variable in lp.c. @@ -8186,7 +8506,7 @@ When using a PS/2 mouse, you can get problems if you want to use the mouse both on the Linux console and under X. Using the "-R" option of the Linux mouse managing program gpm (available from - ftp://metalab.unc.edu:/pub/Linux/system/Daemons) solves this + ftp://metalab.unc.edu/pub/Linux/system/Daemons) solves this problem, or you can get the "mconv" utility also from metalab. C&T 82C710 mouse port support (as on TI Travelmate) @@ -8397,7 +8717,7 @@ Ftape can print lots of debugging messages to the system console resp. kernel log files. Reducing the amount of possible debugging - output reduces the size of the kernel module by some kb, so it might + output reduces the size of the kernel module by some KB, so it might be a good idea to use "None" for emergency boot floppies. If you want to save memory then the following strategy is @@ -8557,17 +8877,24 @@ MTRR control and configuration CONFIG_MTRR - On Intel Pentium Pro and Pentium II systems the Memory Type Range - Registers (MTRRs) may be used to control processor access to memory - ranges. This is most useful when you have a video (VGA) card on a - PCI or AGP bus. Enabling write-combining allows bus write transfers - to be combined into a larger transfer before bursting over the - PCI/AGP bus. This can increase performance of image write operations - 2.5 times or more. This option creates a /proc/mtrr file which may - be used to manipulate your MTRRs. Typically the X server should use - this. This should have a reasonably generic interface so that - similar control registers on other processors can be easily - supported. + On Intel P6 family processors (Pentium Pro, Pentium II and later) + the Memory Type Range Registers (MTRRs) may be used to control + processor access to memory ranges. This is most useful when you have + a video (VGA) card on a PCI or AGP bus. Enabling write-combining + allows bus write transfers to be combined into a larger transfer + before bursting over the PCI/AGP bus. This can increase performance + of image write operations 2.5 times or more. This option creates a + /proc/mtrr file which may be used to manipulate your + MTRRs. Typically the X server should use this. This should have a + reasonably generic interface so that similar control registers on + other processors can be easily supported. + + The Cyrix 6x86, 6x86MX and M II processors have Address Range + Registers (ARRs) which provide a similar functionality to MTRRs. For + these, the ARRs are used to emulate the MTRRs. + + The AMD K6-2 (stepping 8 and above) and K6-3 processors have two + MTRRs. These are supported. Saying Y here also fixes a problem with buggy SMP BIOSes which only set the MTRRs for the boot CPU and not the secondary CPUs. This can @@ -8589,6 +8916,15 @@ This driver does not exist at this point, so you might as well say N. +Double Talk PC internal speech card support +CONFIG_DTLK + This driver is for the DoubleTalk PC, a speech synthesizer + manufactured by RC Systems (http://www.rcsys.com/). It is also + called the `internal DoubleTalk'. 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. The module will be called dtlk.o. + Advanced Power Management CONFIG_APM APM is a BIOS specification for saving power using several different @@ -8712,36 +9048,28 @@ CONFIG_APM_IGNORE_SUSPEND_BOUNCE This option is necessary on the Dell Inspiron 3200 and others, but should be safe for all other laptops. When enabled, a system suspend - event that occurs within three seconds of a resume is ignored. Without - this the Inspiron will shut itself off a few seconds after you open - the lid, requiring you to press the power button to resume it a - second time. - Say Y. + event that occurs within three seconds of a resume is ignored. + Without this the Inspiron will shut itself off a few seconds after + you open the lid, requiring you to press the power button to resume + it a second time. Say Y. RTC stores time in GMT CONFIG_APM_RTC_IS_GMT - This option can be used when your RTC (Real Time Clock aka. Hardware - Clock) stores the time in GMT (Greenwich Mean Time) rather than - localtime. When suspending/resuming, the kernel needs to know what - is stored in the RTC so it can update the system clock (which is - always GMT). Without this option the kernel attempts to measure - the offset between the RTC and the system clock. This means you - can loose one second on each suspend/resume cycle. - Also, on the Dell Inspiron 3200, the hardware slows down the system - even before the kernel can measure the RTC/system clock offset. It - can then take 15 seconds to do this measurement and it can be - incorrect by several seconds. - Say Y if GMT is stored in your RTC. - GMT is usually the best anyway, because you don't have to worry about - daylight savings time changes. The only reason to not use GMT in - your RTC is if you also run a broken OS that doesn't understand GMT. + Say Y here if your RTC (Real Time Clock a.k.a. hardware clock) + stores the time in GMT (Greenwich Mean Time). Say N if your RTC + stores localtime. + + It is in fact recommended to store GMT in your RTC, because then you + don't have to worry about daylight savings time changes. The only + reason not to use GMT in your RTC is if you also run a broken OS + that doesn't understand GMT. Allow interrupts during APM BIOS calls CONFIG_APM_ALLOW_INTS Normally we disable external interrupts while we are making calls to the APM BIOS as a measure to lessen the effects of a badly behaving - BIOS implementation. The BIOS should reeanble interrupts if it - needs to. Unfortunately, some BIOS's do not - especially those in + BIOS implementation. The BIOS should reenable interrupts if it + needs to. Unfortunately, some BIOSes do not - especially those in many of the newer IBM Thinkpads. If you experience hangs when you suspend, try setting this to Y. Otherwise, say N. @@ -8854,8 +9182,9 @@ 24 hour alarm. It reports status information via the file /proc/rtc and its behaviour is set by various ioctls on /dev/rtc. - If you enabled CONFIG_SMP, you should say Y here to read and set the - RTC clock in an SMP compatible fashion. + If you run Linux on a multiprocessor machine and said Y to + "Symmetric Multi Processing" above, you should say Y here to read + and set the RTC clock in an SMP compatible fashion. If you think you have a use for such a device (such as periodic data sampling), then say Y here, and read Documentation/rtc.txt for @@ -8875,14 +9204,16 @@ with major number 10 and minor number 144 using mknod ("man mknod"), you get read and write access to the 50 bytes of non-volatile memory in the real time clock (RTC), which is contained in every PC and - most Ataris. This memory is conventionally called "CMOS RAM" on PCs - and "NVRAM" on Ataris. /dev/nvram may be used to view settings - there, or to change them (with some utility). It could also be used - to frequently save a few bits of very important data that may not be - lost over power-off and for which writing to disk is too insecure. Note - however that most NVRAM space in a PC belongs to the BIOS and you should - NEVER idly tamper with it. See Ralf Browns interrupt list for a guide to - the use of CMOS bytes by your BIOS. + most Ataris. + + This memory is conventionally called "CMOS RAM" on PCs and "NVRAM" + on Ataris. /dev/nvram may be used to view settings there, or to + change them (with some utility). It could also be used to frequently + save a few bits of very important data that may not be lost over + power-off and for which writing to disk is too insecure. Note + however that most NVRAM space in a PC belongs to the BIOS and you + should NEVER idly tamper with it. See Ralf Brown's interrupt list + for a guide to the use of CMOS bytes by your BIOS. On Atari machines, /dev/nvram is always configured and does not need to be selected. @@ -8892,6 +9223,17 @@ The module will be called nvram.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. +Atomwide Serial Support +CONFIG_ATOMWIDE_SERIAL + If you have an Atomwide Serial card for an Acorn system, say Y to + this option. The driver can handle 1, 2, or 3 port cards. + If unsure, say N + +The Serial Port Dual Serial Port +CONFIG_DUALSP_SERIAL + If you have the Serial Port's dual serial card for an Acorn system, + say Y to this option. If unsure, say N + Joystick support CONFIG_JOYSTICK If you have a joystick, you can say Y here to enable generic @@ -8975,7 +9317,7 @@ Say Y here if you have the TurboGraFX interface by Steffen Schwenke, and want to use it with Multiststem -- Atari, Amiga, Commodore, Amstrad CPC joystick. For more information on how to use the driver - please read Documentation/joystick-parport.txt and + please read Documentation/joystick.txt and Documentation/joystick-parport.txt Amiga joysticks @@ -8995,17 +9337,48 @@ If you have the Serial Port's dual serial card for an Acorn system, say Y to this option. If unsure, say N +NetWinder Button +CONFIG_NWBUTTON + If you enable this driver and create a character device node + /dev/nwbutton with major and minor numbers 10 and 158 ("man mknod"), + then every time the orange button is pressed a number of times, the + number of times the button was pressed will be written to that device. + This is most useful for applications, as yet unwritten, which perform + actions based on how many times the button is pressed in a row. + Do not hold the button down for too long, as the driver does not alter + the behaviour of the hardware reset circuitry attached to the button; + it will still execute a hard reset if the button is held down for + longer than approximately five seconds. + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + Documentation/modules.txt. The module will be called nwbutton.o. + Most people will answer Y to this question and "Reboot Using Button" + below to be able to initiate a system shutdown from the button. + +Reboot Using Button +CONFIG_NWBUTTON_REBOOT + If you enable this option, then you will be able to initiate a system + shutdown and reboot by pressing the orange button a number of times. + The number of presses to initiate the shutdown is two by default, but + this can be altered by modifying the value of NUM_PRESSES_REBOOT in + nwbutton.h and recompiling the driver or, if you compile the driver as + a module, you can specify the number of presses at load time with + "insmod button reboot_count=". + Sound card support CONFIG_SOUND If you have a sound card in your computer, i.e. if it can say more than an occasional beep, say Y. Be sure to have all the information about your sound card and its configuration down (I/O port, - interrupt and DMA channel), because you will be asked for it. You - want to read the Sound-HOWTO, available via FTP (user: anonymous) - from ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. There is also some - information in various README files in drivers/sound, esp. in - Readme.cards which you should read first to find out whether your - card is supported by Linux, and, if yes, which driver to use. + interrupt and DMA channel), because you will be asked for it. + + You want to read the Sound-HOWTO, available via FTP (user: + anonymous) from ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. General + information about the modular sound system is contained in the files + Documentation/sound/Introduction. The file + Documentation/sound/README.OSS contains some slightly outdated but + still useful information as well. If you have a PnP sound card and you want to configure it at boot time using the ISA PnP tools (read @@ -9016,7 +9389,8 @@ from the running kernel whenever you want) and load that module after the PnP configuration is finished. To do this, say M here and read Documentation/modules.txt as well as - drivers/sound/Readme.modules; the module will be called sound.o. + Documentation/sound/README.modules; the module will be called + sound.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. @@ -9030,7 +9404,22 @@ here (the module will be called sound.o) if you haven't found a driver for your sound card above, then pick your driver from the list below. - + +Persistent DMA buffers +CONFIG_SOUND_DMAP + Linux can often have problems allocating DMA buffers for ISA sound + cards on machines with more than 16MB of RAM. This is because ISA + DMA buffers must exist below the 16MB boundary and it is quite + possible that a large enough free block in this region cannot be + found after the machine has been running for a while. If you say Y + here the DMA buffers (64Kb) will be allocated at boot time and kept + until the shutdown. This option is only useful if you said Y to + "OSS sound modules", above. If you said M to "OSS sound modules" + then you can get the persistent DMA buffer functionality by passing + the command-line argument "dmabuf=1" to the sound.o module. + + Say Y unless you have 16MB or less RAM or a PCI sound card. + Support for Aztech Sound Galaxy (non-PnP) cards CONFIG_SOUND_SGALAXY This module initializes the older non Plug and Play sound galaxy @@ -9039,7 +9428,7 @@ Support for AD1816(A) based cards (EXPERIMENTAL) CONFIG_SOUND_AD1816 - Say M here if you have a soundcard based on the Analog Devices + Say M here if you have a sound card based on the Analog Devices AD1816(A) chip. NOTE: This driver is still EXPERIMENTAL. @@ -9060,25 +9449,23 @@ 100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support CONFIG_SOUND_SB - Answer Y if you have an original Sound Blaster card made by - Creative Labs or a 100% hardware compatible clone (like the - Thunderboard or SM Games). If your card was in the list of supported - cards look at the card specific instructions in the - drivers/sound/Readme.cards file before answering this question. For - an unknown card you may answer Y if the card claims to be - Sound Blaster-compatible. + Answer Y if you have an original Sound Blaster card made by Creative + Labs or a 100% hardware compatible clone (like the Thunderboard or + SM Games). For an unknown card you may answer Y if the card claims + to be Sound Blaster-compatible. - You can say M here to compile this driver as a module; the module is - called sb.o. + Please read the file Documentation/sound/Soundblaster. You should also say Y here for cards based on the Avance Logic - ALS-007 chip (read Documentation/sound/ALS007) and for ESS1688 and - ESS1868 cards (read Documentation/sound/ESS1868). If you have an SB - AWE 32 or SB AWE 64, say Y here and also to "Additional lowlevel - drivers" and to "SB32/AWE support" below. If you have an IBM Mwave - card, say Y here and read Documentation/sound/mwave. + ALS-007 chip (read Documentation/sound/ALS007) and for cards based + on ESS chips (read Documentation/sound/ESS1868 and + Documentation/sound/ESS). If you have an SB AWE 32 or SB AWE 64, say + Y here and also to "Additional lowlevel drivers" and to "SB32/AWE + support" below and read Documentation/sound/INSTALL.awe. If you have + an IBM Mwave card, say Y here and read Documentation/sound/mwave. - Please read Documentation/sound/Soundblaster. + You can say M here to compile this driver as a module; the module is + called sb.o. Generic OPL2/OPL3 FM synthesizer support CONFIG_SOUND_ADLIB @@ -9379,19 +9766,20 @@ ACI mixer (miroPCM12/PCM20) CONFIG_ACI_MIXER - Audio Command Interface (ACI) driver. ACI is a protocol used to - communicate with the microcontroller on some sound cards produced by - miro, e.g. the miroSOUND PCM12 and PCM20. The main function of the - ACI is to control the mixer and to get a product identification. + ACI (Audio Command Interface) is a protocol used to communicate with + the microcontroller on some sound cards produced by miro, e.g. the + miroSOUND PCM12 and PCM20. The main function of the ACI is to + control the mixer and to get a product identification. + This Voxware ACI driver currently only supports the ACI functions on the miroSOUND PCM12 and PCM20 cards. On the PCM20, ACI also controls - the radio tuner. This is supported in the video4linux radio-miropcm20 - driver. + the radio tuner. This is supported in the video4linux + radio-miropcm20 driver. SB32/AWE support CONFIG_AWE32_SYNTH Say Y here if you have a Sound Blaster SB32, AWE32-PnP, SB AWE64 or - similar sound card. See drivers/sound/lowlevel/README.awe, + similar sound card. See Documentation/sound/README.awe, Documentation/sound/AWE32 and the Soundblaster-AWE mini-HOWTO, available via FTP (user: anonymous) from ftp://metalab.unc.edu/pub/Linux/docs/HOWTO/mini for more info. @@ -9454,9 +9842,9 @@ Audio Excel DSP 16 DMA CONFIG_AEDSP16_MSS_DMA - This is the IRQ of the Audio Excel DSP 16 card. It must be 0, 1 or 3. - If you compiled aedsp16.o as a module you can specify this parameter - as 'dma=NN'. + This is the IRQ of the Audio Excel DSP 16 card. It must be 0, 1 + or 3. If you compiled aedsp16.o as a module you can specify this + parameter as 'dma=NN'. SC-6600 based audio cards (new Audio Excel DSP 16) CONFIG_SC6600 @@ -9466,28 +9854,30 @@ SC-6600 Joystick Interface CONFIG_SC6600_JOY - This option activate the Joystick interface of Audio Excel DSP 16 card. + Say Y here in order to use the joystick interface of the Audio Excel + DSP 16 card. SC-6600 CDROM Interface CONFIG_SC6600_CDROM - This option activate the CDROM interface of Audio Excel DSP 16 card. - Required parameter can be: 0 for Sony, 1 for Panasonic, 2 for IDE, 4 for - no CDROM present. + This is used to activate the the CDROM interface of the Audio Excel + DSP 16 card. Enter: 0 for Sony, 1 for Panasonic, 2 for IDE, 4 for no + CDROM present. Audio Excel DSP 16 (MPU401 emulation) CONFIG_AEDSP16_MPU401 Answer Y if you want your audio card to emulate the MPU-401 midi - interface. You should then say Y to "MPU-401 support". - You have to note that the I/O base for MPU-401 support of aedsp16 is - the same you have selected for "MPU-401 support". If you are using - this driver as a module you have to specify the MPU I/O base address - with the parameter 'mpu_base=0xNNN'. + interface. You should then also say Y to "MPU-401 support". + + Note that the I/O base for MPU-401 support of aedsp16 is the same + you have selected for "MPU-401 support". If you are using this + driver as a module you have to specify the MPU I/O base address with + the parameter 'mpu_base=0xNNN'. MPU401 IRQ for Audio Excel DSP 16 CONFIG_AEDSP16_MPU_IRQ - This is the IRQ of the MPU-401 emulation of Audio Excel DSP 16 card. - It must be 5, 7, 9, 10 or 0 (to disable MPU-401 interface). If you - compiled aedsp16.o as a module you can specify this parameter as + This is the IRQ of the MPU-401 emulation of your Audio Excel DSP 16 + card. It must be 5, 7, 9, 10 or 0 (to disable MPU-401 interface). If + you compiled aedsp16.o as a module you can specify this parameter as 'mpu_irq=NN'. Ensoniq ES1370 based PCI sound cards @@ -9515,14 +9905,18 @@ models are either ES1370 or ES1371 based. This driver differs slightly from OSS/Free, so PLEASE READ Documentation/sound/es1371. +Joystick support at boot time +CONFIG_SOUND_ES1371_JOYPORT_BOOT + Say Y here to use the joystick port of your sound card. + Gameport I/O-range selection CONFIG_SOUND_ES1371_GAMEPORT - Select the I/O-range of the gameport on a ES1371 based soundcard. + Select the I/O-range of the gameport on a ES1371 based sound card. The card uses 8 ioports and the gameport is available at all eight ioports. Legal hexadecimal values are 200, 208, 210 and 218. The joystick driver will by default use 0x201. Leave the default 200 unless you have a joystick not attached - to your soundcard. + to your sound card. S3 SonicVibes based PCI sound cards CONFIG_SOUND_SONICVIBES @@ -9533,6 +9927,11 @@ differs slightly from OSS/Free, so PLEASE READ Documentation/sound/sonicvibes. +Rockwell WaveArtist +CONFIG_SOUND_WAVEARTIST + Say Y here to include support for the Rockwell WaveArtist sound + system. This driver is mainly for the NetWinder. + Are you using a crosscompiler CONFIG_CROSSCOMPILE Say Y here if you are compiling the kernel on a different @@ -9958,12 +10357,10 @@ HP9000/300 support CONFIG_HP300 - This option enables support for the HP9000/300 series of workstations. - Support for these machines is still very experimental. If you plan to - try to use the kernel on such a machine say Y here. Everybody else - says N. - -# CONFIG_APOLLO, etc. coming soon (?) + This option enables support for the HP9000/300 series of + workstations. Support for these machines is still very experimental. + If you plan to try to use the kernel on such a machine say Y here. + Everybody else says N. 68020 support CONFIG_M68020 @@ -9984,27 +10381,11 @@ MC68EC040 will not work, as it does not include an MMU (Memory Management Unit). -Use -m68040 flag for 68040 specific optimizations -CONFIG_OPTIMIZE_040 - If you will only be running this kernel on a 68040-series processor, - this will make the kernel run somewhat faster. However, it will no - longer run on a 68020 or 68030, no matter whether you included 68020 - and 68030 support or not. Say N unless the only processor you are - compiling support for is the 68040 (or 68LC040). - 68060 support CONFIG_M68060 If you anticipate running this kernel on a computer with a MC68060 processor, say Y. Otherwise, say N. -Use -m68060 flag for 68060 specific optimizations -CONFIG_OPTIMIZE_060 - If you will only be running this kernel on a 68060-series processor, - this will make the kernel run somewhat faster. However, it will no - longer run on a 68020, 68030 or 68040, no matter whether you - included support for those processors or not. Say N unless the only - processor you are compiling support for is the 68060. - Advanced processor options CONFIG_ADVANCED_CPU This gives you access to some advanced options for the CPU. The @@ -10037,25 +10418,9 @@ Note that even if you say N here, you can still use your expansion cards. If in doubt, say Y. -Amiga OCS chipset support -CONFIG_AMIFB_OCS - This enables support for the original Agnus and Denise video chips, - found in the Amiga 1000 and most A500's and A2000's. If you intend - to run Linux on any of these systems, say Y; otherwise say N. - -Amiga ECS chipset support -CONFIG_AMIFB_ECS - This enables support for the Enhanced Chip Set, found in later - A500's, later A2000's, the A600, the A3000, the A3000T and CDTV. If - you intend to run Linux on any of these systems, say Y; otherwise - say N. - -Amiga AGA chipset support -CONFIG_AMIFB_AGA - This enables support for the Advanced Graphics Architecture (also - known as the AGA or AA) Chip Set, found in the A1200, A4000, A4000T - and CD32. If you intend to run Linux on any of these systems, say Y; - otherwise say N. +CONFIG_AMIGA_PCMCIA + Include support in the kernel for pcmcia on Amiga 1200 and Amiga 600. + If you intend to use pcmcia cards say Y; otherwise say N. Amiga GSP (TMS340x0) support CONFIG_AMIGA_GSP @@ -10261,6 +10626,16 @@ want). The module is called hydra.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. +Pcmcia NE2000 compatible support +CONFIG_APNE + If you have a pcmcia ne2000 compatible adapter, say Y. Otherwise, + say N. + + 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 is called apne.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + Atari Lance support CONFIG_ATARILANCE Say Y to include support for several Atari Ethernet adapters based @@ -10413,13 +10788,14 @@ HP on-board LANCE support CONFIG_HPLANCE - If you want to use the builtin "LANCE" Ethernet controller on an HP300 - machine, say Y here. + If you want to use the builtin "LANCE" Ethernet controller on an + HP300 machine, say Y here. DIO bus support CONFIG_DIO - Say Y here to enable support for the "DIO" expansion bus used in HP300 - machines. If you are using such a system you almost certainly want this. + Say Y here to enable support for the "DIO" expansion bus used in + HP300 machines. If you are using such a system you almost certainly + want this. MSDOS partition support CONFIG_MSDOS_PARTITION @@ -10491,11 +10867,21 @@ motherboard will usually use a MACE (Medium Access Control for Ethernet) interface. Say Y to include support for the MACE chip. + This driver is also available as a module called mace.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read Documentation/modules.txt. + BMAC (G3 ethernet) support CONFIG_BMAC Say Y for support of BMAC Ethernet interfaces. These are used on G3 computers. + This driver is also available as a module called bmac.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read Documentation/modules.txt. + Video For Linux CONFIG_VIDEO_DEV Support for audio/video capture and overlay devices and FM radio @@ -10605,6 +10991,44 @@ CONFIG_RADIO_SF16FMI_PORT Enter the I/O port of your SF16FMI radio card. +Typhoon Radio +CONFIG_RADIO_TYPHOON + Choose Y here if you have one of these FM radio cards, and then fill + in the port address and the frequency used for muting below. + + 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 + http://roadrunner.swansea.uk.linux.org/v4l.shtml; to browse the WWW, + you need to have access to a machine on the Internet that has a + program like lynx or netscape. + + If you want to compile this 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 radio-typhoon.o + +Support for /proc/radio-typhoon +CONFIG_RADIO_TYPHOON_PROC_FS + Say Y here if you want the typhoon radio card driver to write + status information (frequency, volume, muted, mute frequency, + base address) to /proc/radio-typhoon. The file can be viewed with + your favorite pager (i.e. use "more /proc/radio-typhoon" or "less + /proc/radio-typhoon" or simply "cat /proc/radio-typhoon"). + +Typhoon I/O port (0x316 or 0x336) +CONFIG_RADIO_TYPHOON_PORT + Enter the I/O port of your Typhoon or EcoRadio radio card. + +Typhoon frequency set when muting the device (kHz) +CONFIG_RADIO_TYPHOON_MUTEFREQ + Enter the frequency used for muting the radio. The device is never + completely silent. If the volume is just turned down, you can still + hear silent voices and music. For that reason, the frequency of the + radio device is set to the frequency you can enter here whenever + the device is muted. There should be no local radio station at that + frequency. + Zoltrix Radio CONFIG_RADIO_ZOLTRIX Choose Y here if you have one of these FM radio cards, and then fill @@ -10626,11 +11050,27 @@ CONFIG_RADIO_ZOLTRIX_PORT Enter the I/O port of your Zoltrix radio card. +ADS Cadet AM/FM Tuner +CONFIG_RADIO_CADET + Say Y here if this is your AM/FM radio card. + + 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 + http://roadrunner.swansea.uk.linux.org/v4l.shtml; to browse the WWW, + you need to have access to a machine on the Internet that has a + program like lynx or netscape. + + If you want to compile this 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 radio-cadet.o + Miro PCM20 Radio CONFIG_RADIO_MIROPCM20 - Choose Y here if you have this FM radio card. You also need the - PCM12/PCM20 ACI mixer in additional low level sound drivers for this - to work. + Choose Y here if you have this FM radio card. You also need to say Y + to "ACI mixer (miroPCM12/PCM20)" (in "additional low level sound + drivers") for this to work. In order to control your radio card, you will need to use programs that are compatible with the Video for Linux API. Information on @@ -10712,6 +11152,9 @@ from the running kernel whenever you want). If you want to compile it as a module, say M here and read Documentation/modules.txt. +# +# ARM options +# CPU Optimization CONFIG_CPU_ARM2 This selects the processor type of your CPU. This is only used to @@ -10728,57 +11171,177 @@ to set this option to, please consult any information supplied with your system. -Include support for CATS boards +Include support for Chalice CATS boards CONFIG_CATS - Say Y here if you wish to include support for the extra hardware found - in Chalice CATS machines. The resulting kernel will still run on an - EBSA-285 but will be slightly larger. If in doubt say N. + Say Y here if you intend to run this kernel on a CATS system. + +Include support for Intel EBSA285 +CONFIG_ARCH_EBSA285 + Say Y here if you intend to run this kernel on an EBSA-285 evaluation + board. -Debug kernel errors +Include support for the NetWinder +CONFIG_ARCH_NETWINDER + Say Y here if you intend to run this kernel on the NetWinder. + +Math emulation +CONFIG_NWFPE + Say Y to include the NWFPE floating point emulator in the kernel. This + is necessary to run most binaries. Linux does not currently support + floating point hardware so you need to say Y here even if your machine + has an FPA or floating point co-processor podule. + + It is also possible to say M to build the emulator as a module + (nwfpe.o) or indeed to leave it out altogether. However, unless you + know what you are doing this can easily render your machine unbootable. + Saying Y is the safe option. + + You may say N here if you are going to load the Acorn FPEmulator + early in the bootup. + +DS1620 Thermometer support +CONFIG_DS1620 + Say Y here to include support for the thermal management hardware + found in the NetWinder. This driver allows the user to control the + temperature set points and to read the current temperature. + + It is also possible to say M here to build it as a module (ds1620.o) + It is recommended to be used on a NetWinder, but it is not a + necessity. + +Verbose kernel error messages CONFIG_DEBUG_ERRORS - This option controls verbose debugging information which can be printed - when the kernel detects an internal error. Verbose debugging information - is useful when tracking down kernel problems, but it will be meaning less - for non-kernel hackers. It's safe for everyone to say Y. - -Build Tools Selection -CONFIG_BINUTILS_NEW - Say Y here if and only if you're using GCC 2.8.1/EGCS with a - binutils version >= 2.8.1 to compile the kernel (check with "gcc - --version" and "ld -v"). + This option controls verbose debugging information which can be + printed when the kernel detects an internal error. This debugging + information is useful to kernel hackers when tracking down problems, + but mostly meaningless to other people. It's safe to say Y unless + you are concerned with the code size or don't want to see these + messages. Compile kernel with frame pointer CONFIG_FRAME_POINTER - If you say Y here, the resulting kernel will be slightly larger, but - it will give useful debugging/error results. If you don't debug the - kernel, you can say N. + If you say Y here, the resulting kernel will be slightly larger and + slower, but it will give useful debugging information. If you don't + debug the kernel, you can say N. + +User fault debugging +CONFIG_DEBUG_USER + When a user program crashes due to an exception, the kernel can print + a brief message explaining what the problem was. This is sometimes + helpful for debugging but serves no purpose on a production system. + Most people should say N here. + +Include gdb debugging information in kernel binary +CONFIG_DEBUG_INFO + Say Y here to include source-level debugging information in the + `vmlinux' binary image. This is handy if you want to use gdb or + addr2line to debug the kernel. It has no impact on the in-memory + footprint of the running kernel but it can increase the amount of + time and disk space needed for compilation. If in doubt say N. + +Split initialisation functions into discardable section +CONFIG_TEXT_SECTIONS + Normally code that is only used during initialisation is collected + into a special area of the kernel so that it can be discarded and + the memory reclaimed when initialisation is complete. In addition, + if the kernel you wish to build is able to run on multiple + architectures, it allows the unused code to be discarded. Some + versions of binutils, however, have a bug that causes the kernel + to crash during startup when this option is enabled. Say Y unless + you experience problems that you suspect may be caused by this. + +Disable pgtable cache +CONFIG_NO_PGT_CACHE + Normally the kernel maintains a `quicklist' of preallocated pagetable + structures in order to increase performance. On machines with very + few pages this may however be a loss. Say Y here to disable the pgtable + cache. + +RISC OS personality +CONFIG_ARTHUR + Say Y here to include the kernel code necessary if you want to run + Acorn RISC OS/Arthur binaries under Linux. This code is still very + experimental; if this sounds frightening, say N and sleep in peace. + You can also say M here to compile this support as a module (which + will be called arthur.o). Initial kernel command line CONFIG_CMDLINE - On some architectures (EBSA285, EBSA110 and Corel NetWinder), there is - currently no way for the boot loader to pass arguments to the kernel. - For these architectures, you should supply some command-line options - at build time by entering them here. As a minimum, you should specify - the memory size and the root device (eg, mem=64M root=/dev/nfs) + On some architectures (EBSA110 and CATS), there is currently no way + for the boot loader to pass arguments to the kernel. For these + architectures, you should supply some command-line options at build + time by entering them here. As a minimum, you should specify the + memory size and the root device (eg, mem=64M root=/dev/nfs) + +Hardware alignment trap +CONFIG_ALIGNMENT_TRAP + ARM processors can not fetch/store information which is not naturally + aligned on the bus, ie, a 4 byte fetch must start at an address divisable + by 4. On 32-bit ARM processors, these instructions can be emulated in + software with a severe performance impact. This is necessary for correct + operation of some network protocols. With an IP-only configuration + it is safe to say N, otherwise say Y. + +21285 serial port support +CONFIG_SERIAL_21285 + If you have a machine based on a 21285 (Footbridge) StrongARM/PCI + bridge you can enable its onboard serial port by enabling this + option. The device has major ID 4, minor 64. + +Console on 21285 serial port +CONFIG_SERIAL_21285_CONSOLE + If you have enabled the serial port on the 21285 footbridge you can + make it the console by answering 'Y' to this option. + +Footbridge Mode +CONFIG_HOST_FOOTBRIDGE + The 21285 Footbridge chip can operate in either `host mode' or + `add-in' mode. Say Y if your 21285 is in host mode, and therefore + is the configuration master, otherwise say N. + +MFM harddisk support +CONFIG_BLK_DEV_MFM + Support the MFM hard drives on the Acorn Archimedes both + on-board the A4x0 motherboards and via the Acorn MFM podules. + Drives upto 64MB are supported. If you haven't got one of these + machines or drives just say 'N'. + +Old Archimedes floppy (1772) support +CONFIG_BLK_DEV_FD1772 + Support the floppy drive on the Acorn Archimedes (A300, A4x0, A540, + R140 and R260) series of computers; it supports only 720K floppies + at the moment. If you don't have one of these machines just answer + 'N'. + +Autodetect hard drive geometry +CONFIG_BLK_DEV_MFM_AUTODETECT + If you answer 'Y' the MFM code will attempt to automatically detect + the cylinders/heads/sectors count on your hard drive. WARNING: This + sometimes doesn't work and it also does some dodgy stuff which + potentially might damage your drive. IrDA Protocols CONFIG_IRDA - Say Y here if you want to build support for the IrDA (TM) - protocols. The Infrared Data Associations (tm) specifies standards - for wireless infrared communication and is supported by most laptops - and PDA's If you want to compile it as a module, say M here and read - Documentation/modules.txt. + Say Y here if you want to build support for the IrDA (TM) protocols. + The Infrared Data Associations (tm) specifies standards for wireless + infrared communication and is supported by most laptops and PDA's. To use Linux support for the IrDA (tm) protocols, you will also need some user-space utilities like the irmanager and probably irattach - as well. For more information, visit - http://www.cs.uit.no/~dagb/irda/ + as well. For more information, see the file + Documentation/networking/irda.txt. You also want to read the + IR-HOWTO, available from + ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. + + This support is also available as a module. If you want to compile + it as a module, say M here and read Documentation/modules.txt. The + module will be called IrDA Cache last LSAP CONFIG_IRDA_CACHE_LAST_LSAP Say Y here if you want IrLMP to cache the last LSAP used. This makes - sense since most frames will be sent/received on the same connection. - Enabling this option will save a hash-lookup per frame. + sense since most frames will be sent/received on the same + connection. Enabling this option will save a hash-lookup per frame. If unsure, say Y. @@ -10786,8 +11349,8 @@ CONFIG_IRDA_FAST_RR Say Y here is you want IrLAP to send fast RR (Receive Ready) frames when acting as a primary station. This will make IrLAP send out a RR - frame immediately when receiving a frame if its own transmit queue is - currently empty. This will give a lot of speed improvement when + frame immediately when receiving a frame if its own transmit queue + is currently empty. This will give a lot of speed improvement when receiving much data since the secondary station will not have to wait the max. turn around time before it is allowed to transmit the next time. If the transmit queue of the secondary is also empty the @@ -10798,21 +11361,10 @@ If unsure, say N. -IrDA Recycle RR's -CONFIG_IRDA_RECYCLE_RR - In the normal life of the IrLAP protocol, it sends a lot of small RR - (Receive Ready) frames over the link (at least when it has nothing - else to do). Saying Y to this option will make IrLAP recycle these - frames thus avoiding many alloc_skb's and kfree_skb's. To do this it - will only buffer one of these frame which is enough for the normal - case. - - If unsure, say Y. - IrDA Debug CONFIG_IRDA_DEBUG - Say Y here if you want the IrDA subsystem to write debug information to - your syslog. You can change the debug level in + Say Y here if you want the IrDA subsystem to write debug information + to your syslog. You can change the debug level in /proc/sys/net/irda/debug If unsure, say Y (since it makes it easier to find the bugs). @@ -10822,54 +11374,32 @@ Compression is _not_ part of the IrDA(tm) protocol specification, but it's working great! Linux is the first to try out compression support at the IrLAP layer. This means that you will only benefit - from compression if you are running a Linux <-> Linux configuration + from compression if you are running a Linux <-> Linux configuration. + + If you say Y here, you also need to say Y or M to a compression + protocol below. IrLAP Deflate Compression Protocol CONFIG_IRDA_DEFLATE Say Y here if you want to build support for the Deflate compression - protocol. If you want to compile it as a module, say M here and read - Documentation/modules.txt. The deflate compression (GZIP) is exactly - the same as used by the PPP protocol. Enabling this option will - build a module called irda_deflate.o + protocol. The deflate compression (GZIP) is exactly + the same as the one used by the PPP protocol. + + If you want to compile this compression support as a module, say M + here and read Documentation/modules.txt. The module will be called + irda_deflate.o. IrLAN Protocol CONFIG_IRLAN Say Y here if you want to build support for the IrLAN protocol. If you want to compile it as a module, say M here and read Documentation/modules.txt. IrLAN emulates an Ethernet and makes it - possible to put up an wireless LAN using infrared beams. + possible to put up a wireless LAN using infrared beams. -IrLAN Client Protocol -CONFIG_IRLAN_CLIENT - Say Y here if you want to build support for the IrLAN client - protocol. If you want to compile it as a module, say M here and read - Documentation/modules.txt. The IrLAN client protocol can be used to - talk with infrared access points like the HP NetbeamIR, or the ESI - JetEye NET. You can also connect to another Linux machine running - the IrLAN server protocol for ac-hoc networking! - -IrLAN Server Protocol -CONFIG_IRLAN_SERVER - Say Y here if you want to build support for infrared LAN access. If - you want to compile it as a module, say M here and read - Documentation/modules.txt. The IrLAN server protocol makes it - possible to set up a wireless LAN with a machine running the IrLAN - client protocol. Notice that the IrLAN server protocol currently - only emulates an access point and does not implement the ad-hoc - specification of IrLAN, but this will not be noticeable for the - user. - -IrOBEX Protocol -CONFIG_IROBEX - Say Y here if you want to build support for the IrOBEX protocol. If - you want to compile it as a module, say M here and read - Documentation/modules.txt. The module does not actually implement - the IrOBEX protocol since that protocol lives in userspace, but it - contains the necessary functions to interface the user-space stuff - with the kernel. So you will need to have the user-space library and - programs that can use this library installed as well to be able to - use the IrOBEX protocol. This module will hopefully be replaced by - IrDA sockets in the future. + The IrLAN protocol can be used to talk with infrared access points + like the HP NetbeamIR, or the ESI JetEye NET. You can also connect + to another Linux machine running the IrLAN protocol for ad-hoc + networking! IrCOMM Protocol CONFIG_IRCOMM @@ -10921,11 +11451,11 @@ Winbond W83977AF IrDA Device Driver CONFIG_WINBOND_FIR - Say Y here if you want to build IrDA support for the Winbond W83977AF - super-io chipset. If you want to compile it as a module, say M here - and read Documentation/modules.txt. This driver should be used for - the IrDA chipset in the Corel NetWinder. The driver supports SIR, - MIR and FIR (4Mbps) speeds. + Say Y here if you want to build IrDA support for the Winbond + W83977AF super-io chipset. If you want to compile it as a module, + say M here and read Documentation/modules.txt. This driver should be + used for the IrDA chipset in the Corel NetWinder. The driver + supports SIR, MIR and FIR (4Mbps) speeds. NSC PC87108 IrDA Device Driver CONFIG_NSC_FIR @@ -10970,6 +11500,15 @@ used by IrTTY. To activate support for Tekram dongles you will have to insert "irattach -d tekram" in the /etc/irda/drivers script. +Greenwich GIrBIL dongle +CONFIG_GIRBIL_DONGLE + Say Y here if you want to build support for the Greenwich GIrBIL + dongle. If you want to compile it as a module, say M here and read + Documentation/modules.txt. The Greenwich dongle attaches to the + normal 9-pin serial port connector, and can currently only be used + by IrTTY. To activate support for Greenwich dongles you will have to + insert "irattach -d girbil" in the /etc/irda/drivers script. + VME (Motorola and BVM) support CONFIG_VME Say Y here if you want to build a kernel for a 680x0 based VME @@ -11050,11 +11589,13 @@ # # A couple of things I keep forgetting: -# capitalize: AppleTalk, Ethernet, DMA, FTP, Internet, Intel, IRQ, -# Linux, NetWare, NFS, PCI, SCSI, SPARC +# capitalize: AppleTalk, Ethernet, DOS, DMA, FAT, FTP, Internet, +# Intel, IRQ, Linux, MSDOS, NetWare, NetWinder, NFS, +# PCI, SCSI, SPARC # two words: hard drive, hard disk, sound card, home page # other: it's safe to save; daemon; use --, not - or --- # +# # This is used by Emacs' spell checker ispell.el: # # LocalWords: CONFIG coprocessor DX Pentium SX lilo loadlin HOWTO ftp metalab @@ -11077,7 +11618,7 @@ # LocalWords: COM ELPLUS Com EtherLinkIII VLB Arcnet Cabletron DEPCA DE carlos # LocalWords: depca EtherWorks EWRK ewrk SEEQ EtherExpress EEXPRESS NI xxx dia # LocalWords: EtherExpress WaveLAN wavelan PCLAN HPLAN VG SK Ansel Xen de ZNET -# LocalWords: PCMCIA cb stanford pcmcia LAN TEC RealTek ATP atp DLINK NetTools +# LocalWords: PCMCIA cb stanford LAN TEC RealTek ATP atp DLINK NetTools VISWS # LocalWords: TR Sony CDU caddyless cdu Mitsumi MCD cd mcd XA MultiSession CDA # LocalWords: Matsushita Panasonic SBPCD Soundblaster Longshine sbpcd Aztech # LocalWords: Okano Wearnes AZTCD CDD SE aztcd sonycd Goldstar GSCD Philips fs @@ -11107,7 +11648,7 @@ # LocalWords: PMAX MILO Alphas Multia Tseng linuxelf endian mipsel mips drv HT # LocalWords: kerneld callouts AdvanSys advansys Admin WDT DataStor EP verden # LocalWords: wdt hdb hdc bugfix SiS vlb Acculogic CSA DTC dtc Holtek ht QDI -# LocalWords: QD qd UMC umc ALI ali lena fnet fr azstarnet axplinux cdr fb MDA +# LocalWords: QD qd UMC umc ALI ali lena fnet fr azstarnet cdr fb MDA ps esdi # LocalWords: Avanti XL AlphaStations Jensen DECpc AXPpci UDB Cabriolet MCA RC # LocalWords: AlphaPC mca AOUT OUTput PPro sipx gwdg lo nwe FourPort Boca unm # LocalWords: Keepalive linefill RELCOM keepalive analogue CDR conf CDI INIT @@ -11256,4 +11797,21 @@ # LocalWords: PowerMacs Winbond Algorithmics ALGOR algor ECOFF IRIX SGI SGI's # LocalWords: gfx virtualized Xpmac mklinux XFree FBDev Woodhouse mvhi Seeq fp # LocalWords: SGISEEQ HIgh ADB ADBMOUSE crosscompiler CROSSCOMPILE FPE GDB gdb -# LocalWords: JOYPORT rp spoofing DawiControl NOGENSUPP EEPROM HSSI +# LocalWords: JOYPORT rp spoofing DawiControl NOGENSUPP EEPROM HSSI Alessandro +# LocalWords: singleprocessor tex MATHEMU FRIQ Maxell friq Alcor XLT AlphaBook +# LocalWords: AlphaPCI DP LX Miata Mikasa Noritake RPX UX BX Takara EV PRIMO +# LocalWords: TSC Matrox Productiva matroxfb matrox multihead ia linuxhq MFW +# LocalWords: mfw AAA MCS Initio XXU initio imm AutoDetect IZIP CTR usec HDLC +# LocalWords: COSA SRP muni cz kas cosa Alteon AceNIC acenic VTOC OSes GMT SAx +# LocalWords: Inspiron localtime INTS Thinkpads Ralf Brown's Flightstick NNN +# LocalWords: Xterminator Blackhawk NN mpu ioports DCA HPDCA HPLANCE DIO Corel +# LocalWords: GemTek gemtek CMDLINE IrDA PDA's irmanager irattach RR AVA DN rg +# LocalWords: uit dagb irda LSAP IrLMP RR's IrLAP IR alloc skb's kfree skb's +# LocalWords: GZIP IrLAN NetbeamIR ESI JetEye IrOBEX IrCOMM TTY's minicom dti +# LocalWords: ircomm ircomm pluto thiguchi IrTTY Linux's bps NetWinder MIR NSC +# LocalWords: ACTiSYS Dongle dongle dongles esi actisys IrMate tekram BVM MVME +# LocalWords: BVME BVME WRITETHROUGH copyback writethrough fwmark syncookie tu +# LocalWords: alphalinux GOBIOS csn chemnitz nat ACARD AMI MegaRAID megaraid +# LocalWords: QNXFS ISI isicom xterms Apollos VPN RCPCI rcpci sgi visws pcmcia +# LocalWords: IrLPT UIRCC Tecra + diff -ur --new-file old/linux/Documentation/arm/Netwinder new/linux/Documentation/arm/Netwinder --- old/linux/Documentation/arm/Netwinder Thu Jan 1 01:00:00 1970 +++ new/linux/Documentation/arm/Netwinder Sun May 2 18:51:16 1999 @@ -0,0 +1,78 @@ +NetWinder specific documentation +================================ + +The NetWinder is a small low-power computer, primarily designed +to run Linux. It is based around the StrongARM RISC processor, +DC21285 PCI bridge, with PC-type hardware glued around it. + +Port usage +========== + +Min - Max Description +--------------------------- +0x0000 - 0x000f DMA1 +0x0020 - 0x0021 PIC1 +0x0060 - 0x006f Keyboard +0x0070 - 0x007f RTC +0x0080 - 0x0087 DMA1 +0x0088 - 0x008f DMA2 +0x00a0 - 0x00a3 PIC2 +0x00c0 - 0x00df DMA2 +0x0180 - 0x0187 IRDA +0x01f0 - 0x01f6 ide0 +0x0201 Game port +0x0203 RWA010 configuration read +0x0220 - ? SoundBlaster +0x0250 - ? WaveArtist +0x0279 RWA010 configuration index +0x02f8 - 0x02ff Serial ttyS1 +0x0300 - 0x031f Ether10 +0x0338 GPIO1 +0x033a GPIO2 +0x0370 - 0x0371 W83977F configuration registers +0x0388 - ? AdLib +0x03c0 - 0x03df VGA +0x03f6 ide0 +0x03f8 - 0x03ff Serial ttyS0 +0x0400 - 0x0408 DC21143 +0x0480 - 0x0487 DMA1 +0x0488 - 0x048f DMA2 +0x0a79 RWA010 configuration write +0xe800 - 0xe80f ide0/ide1 BM DMA + + +Interrupt usage +=============== + +IRQ type Description +--------------------------- + 0 ISA 100Hz timer + 1 ISA Keyboard + 2 ISA cascade + 3 ISA Serial ttyS1 + 4 ISA Serial ttyS0 + 5 ISA PS/2 mouse + 6 ISA IRDA + 7 ISA Printer + 8 ISA RTC alarm + 9 ISA +10 ISA GP10 (Orange reset button) +11 ISA +12 ISA WaveArtist +13 ISA +14 ISA hda1 +15 ISA + +DMA usage +========= + +DMA type Description +--------------------------- + 0 ISA IRDA + 1 ISA + 2 ISA cascade + 3 ISA WaveArtist + 4 ISA + 5 ISA + 6 ISA + 7 ISA WaveArtist diff -ur --new-file old/linux/Documentation/arm/README new/linux/Documentation/arm/README --- old/linux/Documentation/arm/README Thu Jan 1 01:00:00 1970 +++ new/linux/Documentation/arm/README Sun May 2 18:51:16 1999 @@ -0,0 +1,139 @@ + ARM Linux 2.2.3 + =============== + + * NOTE * The ARM support in the mainstream Linux kernel sources + is not up to date. Please check ftp.arm.uk.linux.org:/pub/armlinux + for latest updates. + +Compilation of kernel +--------------------- + + In order to compile ARM Linux, you will need a compiler capable of + generating ARM ELF code with GNU extensions. GCC-2.7.2.2 ELF, GCC 2.8.1 + and EGCS are good compilers. Note that GCC-2.7.2.2 ELF is rare, and + you probably don't have it. + + To build ARM Linux natively, you shouldn't have to alter the ARCH = line in + the top level Makefile. However, if you don't have the ARM Linux ELF tools + installed as default, then you should change the CROSS_COMPILE line as + detailed below. + + If you wish to cross-compile, then alter the following lines in the top + level make file: + + ARCH = + with + ARCH = arm + + and + + CROSS_COMPILE= + to + CROSS_COMPILE= + eg. + CROSS_COMPILE=arm-linux- + + Do a 'make config', followed by 'make dep', and finally 'make Image' to + build the kernel (arch/arm/boot/Image). A compressed image can be built + by doing a 'make zImage' instead of 'make Image'. + + +Bug reports etc +--------------- + + Please send patches, bug reports and code for the ARM Linux project + to linux@arm.linux.org.uk Patches will not be included into future + kernels unless they come to me (or the relevant person concerned). + + When sending bug reports, please ensure that they contain all relevant + information, eg. the kernel messages that were printed before/during + the problem, what you were doing, etc. + + For patches, please include some explanation as to what the patch does + and why (if relevant). + + +Modules +------- + + Although modularisation is supported (and required for the FP emulator), + each module on an arm2/arm250/arm3 machine when is loaded will take + memory up to the next 32k boundary due to the size of the pages. Hence is + modularisation on these machines really worth it? + + However, arm6 and up machines allow modules to take multiples of 4k, and + as such Acorn RiscPCs and other architectures using these processors can + make good use of modularisation. + + +ADFS Image files +---------------- + + You can access image files on your ADFS partitions by mounting the ADFS + partition, and then using the loopback device driver. You must have + losetup installed. + + Please note that the PCEmulator DOS partitions have a partition table at + the start, and as such, you will have to give '-o offset' to losetup. + + +Request to developers +--------------------- + + When writing device drivers which include a separate assembler file, please + include it in with the C file, and not the arch/arm/lib directory. This + allows the driver to be compiled as a loadable module without requiring + half the code to be compiled into the kernel image. + + In general, try to avoid using assembler unless it is really necessary. It + makes drivers far less easy to port to other hardware. + + +ST506 hard drives +----------------- + + The ST506 hard drive controllers seem to be working fine (if a little + slowly). At the moment they will only work off the controllers on an + A4x0's motherboard, but for it to work off a Podule just requires + someone with a podule to add the addresses for the IRQ mask and the + HDC base to the source. + + As of 31/3/96 it works with two drives (you should get the ADFS + *configure harddrive set to 2). I've got an internal 20MB and a great + big external 5.25" FH 64MB drive (who could ever want more :-) ). + + I've just got 240K/s off it (a dd with bs=128k); thats about half of what + RiscOS gets; but it's a heck of a lot better than the 50K/s I was getting + last week :-) + + Known bug: Drive data errors can cause a hang; including cases where + the controller has fixed the error using ECC. (Possibly ONLY + in that case...hmm). + + +1772 Floppy +----------- + This also seems to work OK, but hasn't been stressed much lately. It + hasn't got any code for disc change detection in there at the moment which + could be a bit of a problem! Suggestions on the correct way to do this + are welcome. + + +Kernel entry (head-armv.S) +-------------------------- + The initial entry into the kernel made via head-armv.S uses architecture + independent code. The architecture is selected by the value of 'r1' on + entry, which must be kept unique. You can register a new architecture + by mailing the following details to rmk@arm.uk.linux.org. Please give + the mail a subject of 'Register new architecture': + + Name: + ARCHDIR: + Description: + + + Please follow this format - it is an automated system. You should + receive a reply the next day. + +--- +Russell King (27/03/1999) diff -ur --new-file old/linux/Documentation/arm/nwfpe/NOTES new/linux/Documentation/arm/nwfpe/NOTES --- old/linux/Documentation/arm/nwfpe/NOTES Thu Jan 1 01:00:00 1970 +++ new/linux/Documentation/arm/nwfpe/NOTES Sun May 2 18:51:16 1999 @@ -0,0 +1,29 @@ +There seems to be a problem with exp(double) and our emulator. I haven't +been able to track it down yet. This does not occur with the emulator +supplied by Russell King. + +I also found one oddity in the emulator. I don't think it is serious but +will point it out. The ARM calling conventions require floating point +registers f4-f7 to be preserved over a function call. The compiler quite +often uses an stfe instruction to save f4 on the stack upon entry to a +function, and an ldfe instruction to restore it before returning. + +I was looking at some code, that calculated a double result, stored it in f4 +then made a function call. Upon return from the function call the number in +f4 had been converted to an extended value in the emulator. + +This is a side effect of the stfe instruction. The double in f4 had to be +converted to extended, then stored. If an lfm/sfm combination had been used, +then no conversion would occur. This has performance considerations. The +result from the function call and f4 were used in a multiplication. If the +emulator sees a multiply of a double and extended, it promotes the double to +extended, then does the multiply in extended precision. + +This code will cause this problem: + +double x, y, z; +z = log(x)/log(y); + +The result of log(x) (a double) will be calculated, returned in f0, then +moved to f4 to preserve it over the log(y) call. The division will be done +in extended precision, due to the stfe instruction used to save f4 in log(y). diff -ur --new-file old/linux/Documentation/arm/nwfpe/README new/linux/Documentation/arm/nwfpe/README --- old/linux/Documentation/arm/nwfpe/README Thu Jan 1 01:00:00 1970 +++ new/linux/Documentation/arm/nwfpe/README Sun May 2 18:51:16 1999 @@ -0,0 +1,70 @@ +This directory contains the version 0.92 test release of the NetWinder +Floating Point Emulator. + +The majority of the code was written by me, Scott Bambrough It is +written in C, with a small number of routines in inline assembler +where required. It was written quickly, with a goal of implementing a +working version of all the floating point instructions the compiler +emits as the first target. I have attempted to be as optimal as +possible, but there remains much room for improvement. + +I have attempted to make the emulator as portable as possible. One of +the problems is with leading underscores on kernel symbols. Elf +kernels have no leading underscores, a.out compiled kernels do. I +have attempted to use the C_SYMBOL_NAME macro wherever this may be +important. + +Another choice I made was in the file structure. I have attempted to +contain all operating system specfic code in one module (fpmodule.*). +All the other files contain emulator specific code. This should allow +others to port the emulator to NetBSD for instance relatively easily. + +The floating point operations are based on SoftFloat Release 2, by +John Hauser. SoftFloat is a software implementation of floating-point +that conforms to the IEC/IEEE Standard for Binary Floating-point +Arithmetic. As many as four formats are supported: single precision, +double precision, extended double precision, and quadruple precision. +All operations required by the standard are implemented, except for +conversions to and from decimal. We use only the single precision, +double precision and extended double precision formats. The port of +SoftFloat to the ARM was done by Phil Blundell, based on an earlier +port of SoftFloat version 1 by Neil Carson for NetBSD/arm32. + +The file README.FPE contains a description of what has been implemented +so far in the emulator. The file TODO contains a information on what +remains to be done, and other ideas for the emulator. + +Bug reports, comments, suggestions should be directed to me at +. General reports of "this program doesn't +work correctly when your emulator is installed" are useful for +determining that bugs still exist; but are virtually useless when +attempting to isolate the problem. Please report them, but don't +expect quick action. Bugs still exist. The problem remains in isolating +which instruction contains the bug. Small programs illustrating a specific +problem are a godsend. + +Legal Notices +------------- + +The NetWinder Floating Point Emulator is free software. Everything Corel +has written is provided under the GNU GPL. See the file COPYING for copying +conditions. Excluded from the above is the SoftFloat code. John Hauser's +legal notice for SoftFloat is included below. + +------------------------------------------------------------------------------- +SoftFloat Legal Notice + +SoftFloat was written by John R. Hauser. This work was made possible in +part by the International Computer Science Institute, located at Suite 600, +1947 Center Street, Berkeley, California 94704. Funding was partially +provided by the National Science Foundation under grant MIP-9311980. The +original version of this code was written as part of a project to build +a fixed-point vector processor in collaboration with the University of +California at Berkeley, overseen by Profs. Nelson Morgan and John Wawrzynek. + +THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort +has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT +TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO +PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY +AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE. +------------------------------------------------------------------------------- diff -ur --new-file old/linux/Documentation/arm/nwfpe/README.FPE new/linux/Documentation/arm/nwfpe/README.FPE --- old/linux/Documentation/arm/nwfpe/README.FPE Thu Jan 1 01:00:00 1970 +++ new/linux/Documentation/arm/nwfpe/README.FPE Sun May 2 18:51:16 1999 @@ -0,0 +1,156 @@ +The following describes the current state of the NetWinder's floating point +emulator. + +In the following nomenclature is used to describe the floating point +instructions. It follows the conventions in the ARM manual. + + = , no default +{P|M|Z} = {round to +infinity,round to -infinity,round to zero}, + default = round to nearest + +Note: items enclosed in {} are optional. + +Floating Point Coprocessor Data Transfer Instructions (CPDT) +------------------------------------------------------------ + +LDF/STF - load and store floating + +{cond} Fd, Rn +{cond} Fd, [Rn, #]{!} +{cond} Fd, [Rn], # + +These instructions are fully implemented. + +LFM/SFM - load and store multiple floating + +Form 1 syntax: +{cond} Fd, , [Rn] +{cond} Fd, , [Rn, #]{!} +{cond} Fd, , [Rn], # + +Form 2 syntax: +{cond} Fd, , [Rn]{!} + +These instructions are fully implemented. They store/load three words +for each floating point register into the memory location given in the +instruction. The format in memory is unlikely to be compatible with +other implementations, in particular the actual hardware. Specific +mention of this is made in the ARM manuals. + +Floating Point Coprocessor Register Transfer Instructions (CPRT) +---------------------------------------------------------------- + +Conversions, read/write status/control register instructions + +FLT{cond}{P,M,Z} Fn, Rd Convert integer to floating point +FIX{cond}{P,M,Z} Rd, Fn Convert floating point to integer +WFS{cond} Rd Write floating point status register +RFS{cond} Rd Read floating point status register +WFC{cond} Rd Write floating point control register +RFC{cond} Rd Read floating point control register + +FLT/FIX are fully implemented. + +RFS/WFS are fully implemented. + +RFC/WFC are fully implemented. RFC/WFC are supervisor only instructions, and +presently check the CPU mode, and do an invalid instruction trap if not called +from supervisor mode. + +Compare instructions + +CMF{cond} Fn, Fm Compare floating +CMFE{cond} Fn, Fm Compare floating with exception +CNF{cond} Fn, Fm Compare negated floating +CNFE{cond} Fn, Fm Compare negated floating with exception + +These are fully implemented. + +Floating Point Coprocessor Data Instructions (CPDT) +--------------------------------------------------- + +Dyadic operations: + +ADF{cond}{P,M,Z} Fd, Fn, - add +SUF{cond}{P,M,Z} Fd, Fn, - subtract +RSF{cond}{P,M,Z} Fd, Fn, - reverse subtract +MUF{cond}{P,M,Z} Fd, Fn, - multiply +DVF{cond}{P,M,Z} Fd, Fn, - divide +RDV{cond}{P,M,Z} Fd, Fn, - reverse divide + +These are fully implemented. + +FML{cond}{P,M,Z} Fd, Fn, - fast multiply +FDV{cond}{P,M,Z} Fd, Fn, - fast divide +FRD{cond}{P,M,Z} Fd, Fn, - fast reverse divide + +These are fully implemented as well. They use the same algorithm as the +non-fast versions. Hence, in this implementation their performance is +equivalent to the MUF/DVF/RDV instructions. This is acceptable according +to the ARM manual. The manual notes these are defined only for single +operands, on the actual FPA11 hardware they do not work for double or +extended precision operands. The emulator currently does not check +the requested permissions conditions, and performs the requested operation. + +RMF{cond}{P,M,Z} Fd, Fn, - IEEE remainder + +This is fully implemented. + +Monadic operations: + +MVF{cond}{P,M,Z} Fd, - move +MNF{cond}{P,M,Z} Fd, - move negated + +These are fully implemented. + +ABS{cond}{P,M,Z} Fd, - absolute value +SQT{cond}{P,M,Z} Fd, - square root +RND{cond}{P,M,Z} Fd, - round + +These are fully implemented. + +URD{cond}{P,M,Z} Fd, - unnormalized round +NRM{cond}{P,M,Z} Fd, - normalize + +These are implemented. URD is implemented using the same code as the RND +instruction. Since URD cannot return a unnormalized number, NRM becomes +a NOP. + +Library calls: + +POW{cond}{P,M,Z} Fd, Fn, - power +RPW{cond}{P,M,Z} Fd, Fn, - reverse power +POL{cond}{P,M,Z} Fd, Fn, - polar angle (arctan2) + +LOG{cond}{P,M,Z} Fd, - logarithm to base 10 +LGN{cond}{P,M,Z} Fd, - logarithm to base e +EXP{cond}{P,M,Z} Fd, - exponent +SIN{cond}{P,M,Z} Fd, - sine +COS{cond}{P,M,Z} Fd, - cosine +TAN{cond}{P,M,Z} Fd, - tangent +ASN{cond}{P,M,Z} Fd, - arcsine +ACS{cond}{P,M,Z} Fd, - arccosine +ATN{cond}{P,M,Z} Fd, - arctangent + +These are not implemented. They are not currently issued by the compiler, +and are handled by routines in libc. These are not implemented by the FPA11 +hardware, but are handled by the floating point support code. They should +be implemented in future versions. + +Signalling: + +Signals are implemented. However current ELF kernels produced by Corel +Computer have a bug in them that prevents the module from generating a +SIGFPE. This is caused by a failure to alias fp_current to the kernel +variable current_set[0] correctly. + +The kernel provided with this distribution (vmlinux-nwfpe-0.93) contains +a fix for this problem and also incorporates the current version of the +emulator directly. It is possible to run with no floating point module +loaded with this kernel. It is provided as a demonstration of the +technology and for those who want to do floating point work that depends +on signals. It is not strictly necessary to use the module. + +A module (either the one provided by Russell King, or the one in this +distribution) can be loaded to replace the functionality of the emulator +built into the kernel. diff -ur --new-file old/linux/Documentation/arm/nwfpe/TODO new/linux/Documentation/arm/nwfpe/TODO --- old/linux/Documentation/arm/nwfpe/TODO Thu Jan 1 01:00:00 1970 +++ new/linux/Documentation/arm/nwfpe/TODO Sun May 2 18:51:16 1999 @@ -0,0 +1,67 @@ +TODO LIST +--------- + +POW{cond}{P,M,Z} Fd, Fn, - power +RPW{cond}{P,M,Z} Fd, Fn, - reverse power +POL{cond}{P,M,Z} Fd, Fn, - polar angle (arctan2) + +LOG{cond}{P,M,Z} Fd, - logarithm to base 10 +LGN{cond}{P,M,Z} Fd, - logarithm to base e +EXP{cond}{P,M,Z} Fd, - exponent +SIN{cond}{P,M,Z} Fd, - sine +COS{cond}{P,M,Z} Fd, - cosine +TAN{cond}{P,M,Z} Fd, - tangent +ASN{cond}{P,M,Z} Fd, - arcsine +ACS{cond}{P,M,Z} Fd, - arccosine +ATN{cond}{P,M,Z} Fd, - arctangent + +These are not implemented. They are not currently issued by the compiler, +and are handled by routines in libc. These are not implemented by the FPA11 +hardware, but are handled by the floating point support code. They should +be implemented in future versions. + +There are a couple of ways to approach the implementation of these. One +method would be to use accurate table methods for these routines. I have +a couple of papers by S. Gal from IBM's research labs in Haifa, Israel that +seem to promise extreme accuracy (in the order of 99.8%) and reasonable speed. +These methods are used in GLIBC for some of the transcendental functions. + +Another approach, which I know little about is CORDIC. This stands for +Coordinate Rotation Digital Computer, and is a method of computing +transcendental functions using mostly shifts and adds and a few +multiplications and divisions. The ARM excels at shifts and adds, +so such a method could be promising, but requires more research to +determine if it is feasible. + +Rounding Methods + +The IEEE standard defines 4 rounding modes. Round to nearest is the +default, but rounding to + or - infinity or round to zero are also allowed. +Many architectures allow the rounding mode to be specified by modifying bits +in a control register. Not so with the ARM FPA11 architecture. To change +the rounding mode one must specify it with each instruction. + +This has made porting some benchmarks difficult. It is possible to +introduce such a capability into the emulator. The FPCR contains +bits describing the rounding mode. The emulator could be altered to +examine a flag, which if set forced it to ignore the rounding mode in +the instruction, and use the mode specified in the bits in the FPCR. + +This would require a method of getting/setting the flag, and the bits +in the FPCR. This requires a kernel call in ArmLinux, as WFC/RFC are +supervisor only instructions. If anyone has any ideas or comments I +would like to hear them. + +[NOTE: pulled out from some docs on ARM floating point, specifically + for the Acorn FPE, but not limited to it: + + The floating point control register (FPCR) may only be present in some + implementations: it is there to control the hardware in an implementation- + specific manner, for example to disable the floating point system. The user + mode of the ARM is not permitted to use this register (since the right is + reserved to alter it between implementations) and the WFC and RFC + instructions will trap if tried in user mode. + + Hence, the answer is yes, you could do this, but then you will run a high + risk of becoming isolated if and when hardware FP emulation comes out + -- Russell]. diff -ur --new-file old/linux/Documentation/cdrom/cdrom-standard.tex new/linux/Documentation/cdrom/cdrom-standard.tex --- old/linux/Documentation/cdrom/cdrom-standard.tex Mon Jan 18 21:47:33 1999 +++ new/linux/Documentation/cdrom/cdrom-standard.tex Mon Mar 22 03:37:56 1999 @@ -25,7 +25,7 @@ \author{David van Leeuwen\\{\normalsize\tt david@ElseWare.cistron.nl} \\{\footnotesize updated by Erik Andersen {\tt(andersee@debian.org)}} \\{\footnotesize updated by Jens Axboe {\tt(axboe@image.dk)}}} -\date{11 January 1999} +\date{12 March 1999} \maketitle @@ -549,7 +549,9 @@ CDROMREADAUDIO, CDROMREADRAW, CDROMREADCOOKED, CDROMSEEK, CDROMPLAY\-BLK and CDROM\-READALL}. + \subsection{\cdrom\ capabilities} +\label{capability} Instead of just implementing some $ioctl$ calls, the interface in \cdromc\ supplies the possibility to indicate the {\em capabilities\/} @@ -944,6 +946,13 @@ \item[CDROM_CHANGER_NSLOTS] Returns the number of slots in a juke-box. \item[CDROMRESET] Reset the drive. +\item[CDROM_GET_CAPABILITY] Returns the $capability$ flags for the + drive. Refer to section \ref{capability} for more information on + these flags. +\item[CDROM_LOCKDOOR] Locks the door of the drive. $arg == \rm0$ + unlocks the door, any other value locks it. +\item[CDROM_DEBUG] Turns on debugging info. Only root is allowed + to do this. Same semantics as CDROM_LOCKDOOR. \end{description} \subsubsection{Device dependent $ioctl$s} diff -ur --new-file old/linux/Documentation/digiboard.txt new/linux/Documentation/digiboard.txt --- old/linux/Documentation/digiboard.txt Thu Jan 7 17:41:54 1999 +++ new/linux/Documentation/digiboard.txt Thu Apr 29 20:53:41 1999 @@ -111,7 +111,7 @@ Boot-time configuration when linked into the kernel --------------------------------------------------- -Per Board to be configured, pass a digi= commandline parameter to the +Per board to be configured, pass a digi= command-line parameter to the kernel using lilo or loadlin. It consists of a string of comma separated identifiers or integers. The 6 values in order are: @@ -142,7 +142,7 @@ append="digi=1,0,0,16,512,851968" -If you don't give a digi= commandline, the compiled-in defaults of +If you don't give a digi= command line, the compiled-in defaults of board 1: io=0x200, membase=0xd0000, altpin=off and numports=16 are used. If you have the resources (io&mem) free for use, configure your board to @@ -153,9 +153,9 @@ Sources of Information ---------------------- -Webpage: http://private.fuller.edu/clameter/digi.html +Web page: http://private.fuller.edu/clameter/digi.html -Mailing List: digiboard@list.fuller.edu +Mailing list: digiboard@list.fuller.edu (Write e-mail to that address to subscribe. Common ListServ commands work. Archive of messages available) diff -ur --new-file old/linux/Documentation/digiepca.txt new/linux/Documentation/digiepca.txt --- old/linux/Documentation/digiepca.txt Thu Jan 7 17:41:54 1999 +++ new/linux/Documentation/digiepca.txt Thu Apr 29 20:53:41 1999 @@ -11,7 +11,7 @@ The Linux MAKEDEV command does not support generating the Digiboard Devices. Users executing digiConfig to setup EISA and PC series cards -will have their device nodes automaticly constructed (cud?? for ~CLOCAL, +will have their device nodes automatically constructed (cud?? for ~CLOCAL, and ttyD?? for CLOCAL). Users wishing to boot their board from the LILO prompt, or those users booting PCI cards may use buildDIGI to construct the necessary nodes. @@ -19,7 +19,7 @@ Notes: ------ This driver may be configured via LILO. For users who have already configured -their driver using digiConfig, configuring from lilo will override previous +their driver using digiConfig, configuring from LILO will override previous settings. Multiple boards may be configured by issuing multiple LILO command lines. For examples see the bottom of this document. diff -ur --new-file old/linux/Documentation/fb/matroxfb.txt new/linux/Documentation/fb/matroxfb.txt --- old/linux/Documentation/fb/matroxfb.txt Fri Jan 15 22:56:49 1999 +++ new/linux/Documentation/fb/matroxfb.txt Thu Apr 29 20:53:41 1999 @@ -1,6 +1,6 @@ [This file is cloned from VesaFB. Thanks go to Gerd Knorr] -what is matroxfb? +What is matroxfb? ================= This is a driver for a graphic framebuffer for Matrox devices on @@ -95,11 +95,11 @@ ======= Driver contains SVGALib compatibility code. It is turned on by choosing textual -mode for console. You can do it at boottime by using videomode +mode for console. You can do it at boot time by using videomode 2,3,7,0x108-0x10C or 0x1C0. At runtime, `fbset -depth 0' does this work. Unfortunately, after SVGALib application exits, screen contents is corrupted. -Switching to another console and back fixes it. I hope that it is SVGALib and -not mine problem, but I'm not sure. +Switching to another console and back fixes it. I hope that it is SVGALib's +problem and not mine, but I'm not sure. Configuration @@ -113,7 +113,7 @@ mem:X - size of memory (X can be in megabytes, kilobytes or bytes) You can only decrease value determined by driver because of it always probe for memory. Default is to use whole detected - memory usable for on-screen display (i.e. max. 8MB). + memory usable for on-screen display (i.e. max. 8 MB). disabled - do not load driver; you can use also `off', but `disabled' is here too. enabled - load driver, if you have `video=matrox:disabled' in LILO @@ -159,7 +159,7 @@ inv24 - change timings parameters for 24bpp modes on Millenium and Millenium II. Specify this if you see strange color shadows around characters. -noinv24 - use standard timmings. It is default. +noinv24 - use standard timings. It is the default. inverse - invert colors on screen (for LCD displays) noinverse - show true colors on screen. It is default. dev:X - bind driver to device X. Driver numbers device from 0 up to N, @@ -221,6 +221,8 @@ sync:X - sync. pulse - bit 0 inverts HSYNC polarity, bit 1 VSYNC polarity. If bit 3 (value 0x08) is set, composite sync instead of HSYNC is generated. If bit 5 (value 0x20) is set, sync on green is turned on. + Do not forget that if you want sync on green, you also probably + want composite sync. Default depends on `vesa'. depth:X - Bits per pixel: 0=text, 4,8,15,16,24 or 32. Default depends on `vesa'. @@ -250,25 +252,25 @@ access to /dev/fb* - everyone with access to this device can destroy your monitor, believe me...). + 24bpp does not support correctly XF-FBDev on big-endian architectures. - + interlaced text mode is not supported; it looks like hardware limitiation, + + interlaced text mode is not supported; it looks like hardware limitation, but I'm not sure. + G200 SGRAM/SDRAM is not autodetected. + maybe more... And following misfeatures: + SVGALib does not restore screen on exit. + pixclock for text modes is limited by hardware to - 83MHz on G200 - 66MHz on Millenium I - 60MHz on Millenium II - Because of I have not access to other devices, I do not know specific + 83 MHz on G200 + 66 MHz on Millennium I + 60 MHz on Millennium II + Because I have no access to other devices, I do not know specific frequencies for them. So driver does not check this and allows you to - set frequency higher that this. It cause sparks, black holes and other - pretty effects on screen. Device was not destroyed during tests :-) - + my Millenium G200 oscillator has frequency range from 35MHz to 380MHz - (and it works with 8bpp on about 320MHz dotclocks (and changed mclk)). - But Matrox says on product sheet that VCO limit is 50-250MHz, so I believe - them (maybe that chip overheates, but it has very big cooler (G100 has - not one), so it should work). + set frequency higher that this. It causes sparks, black holes and other + pretty effects on screen. Device was not destroyed during tests. :-) + + my Millennium G200 oscillator has frequency range from 35 MHz to 380 MHz + (and it works with 8bpp on about 320 MHz dotclocks (and changed mclk)). + But Matrox says on product sheet that VCO limit is 50-250 MHz, so I believe + them (maybe that chip overheats, but it has a very big cooler (G100 has + none), so it should work). + special mixed video/graphics videomodes of Mystique and Gx00 - 2G8V16 and G16V16 are not supported + color keying is not supported @@ -279,16 +281,14 @@ specify vslen=4000 and so on). + maybe more... And following features: - + 4bpp is available only on Millenium I and Millenium II. It is hardware - limitiation. + + 4bpp is available only on Millennium I and Millennium II. It is hardware + limitation. + current fbset is not able to set 15bpp videomode: you must specify depth==16 and green.length==5. fbset does not allow you to set green.length. - + hardware cursor is available only in accelerated videomodes. Maybe that - this is misfeature and not feature. + text mode uses 6 bit VGA palette instead of 8 bit (one of 262144 colors instead of one of 16M colors). It is due to hardware limitation of - MilleniumI/II and SVGALib compatibility. + Millennium I/II and SVGALib compatibility. Benchmarks @@ -296,14 +296,14 @@ It is time to redraw whole screen 1000 times in 1024x768, 60Hz. It is time for draw 6144000 characters on screen through /dev/vcsa (for 32bpp it is about 3GB of data (exactly 3000 MB); for 8x16 font in -16 seconds, i.e. 187MBps). +16 seconds, i.e. 187 MBps). Times were obtained from one older version of driver, now they are about 3% -faster, it is kernel-space only time on P-II/350MHz, Millenium I in 33MHz +faster, it is kernel-space only time on P-II/350 MHz, Millennium I in 33 MHz PCI slot, G200 in AGP 2x slot. I did not test vgacon. NOACCEL 8x16 12x22 - MilleniumI G200 MilleniumI G200 + Millennium I G200 Millennium I G200 8bpp 16.42 9.54 12.33 9.13 16bpp 21.00 15.70 19.11 15.02 24bpp 36.66 36.66 35.00 35.00 @@ -311,7 +311,7 @@ ACCEL, nofastfont 8x16 12x22 6x11 - MilleniumI G200 MilleniumI G200 MilleniumI G200 + Millennium I G200 Millennium I G200 Millennium I G200 8bpp 7.79 7.24 13.55 7.78 30.00 21.01 16bpp 9.13 7.78 16.16 7.78 30.00 21.01 24bpp 14.17 10.72 18.69 10.24 34.99 21.01 @@ -319,7 +319,7 @@ ACCEL, fastfont 8x16 12x22 6x11 - MilleniumI G200 MilleniumI G200 MilleniumI G200 + Millennium I G200 Millennium I G200 Millennium I G200 8bpp 8.41 6.01 6.54 4.37 16.00 10.51 16bpp 9.54 9.12 8.76 6.17 17.52 14.01 24bpp 15.00 12.36 11.67 10.00 22.01 18.32 @@ -327,10 +327,10 @@ TEXT 8x16 - MilleniumI G200 + Millennium I G200 TEXT 3.29 1.50 -* Yes, it is slower than Millenium I. +* Yes, it is slower than Millennium I. -- Petr Vandrovec diff -ur --new-file old/linux/Documentation/fb/vesafb.txt new/linux/Documentation/fb/vesafb.txt --- old/linux/Documentation/fb/vesafb.txt Fri Jan 15 07:53:02 1999 +++ new/linux/Documentation/fb/vesafb.txt Thu Apr 29 20:53:41 1999 @@ -10,8 +10,8 @@ This means we decide at boot time whenever we want to run in text or graphics mode. Switching mode later on (in protected mode) is -impossible; BIOS calls work in real mode only. VESA BIOS Extentions -Version 2.0 are required, becauce we need a linear frame buffer. +impossible; BIOS calls work in real mode only. VESA BIOS Extensions +Version 2.0 are required, because we need a linear frame buffer. Advantages: @@ -66,16 +66,16 @@ mode at the "vga=ask" prompt. For example if you like to use 1024x768x256 colors you have to say "305" at this prompt. -If this does not work, this might be becauce your BIOS does not support -linear framebuffers or becauce it does not support this mode at all. +If this does not work, this might be because your BIOS does not support +linear framebuffers or because it does not support this mode at all. Even if your board does, it might be the BIOS which does not. VESA BIOS -Extentions v2.0 are required, 1.2 is NOT sufficient. You will get a +Extensions v2.0 are required, 1.2 is NOT sufficient. You will get a "bad mode number" message if something goes wrong. 1. Note: LILO cannot handle hex, for booting directly with "vga=mode-number" you have to transform the numbers to decimal. 2. Note: Some newer versions of LILO appear to work with those hex values, - if you set the 0x infront of the numbers. + if you set the 0x in front of the numbers. X11 === @@ -88,25 +88,63 @@ with a broken console (and vesafb cannot do anything about this). +Refresh rates +============= + +There is no way to change the vesafb video mode and/or timings after +booting linux. If you are not happy with the 60 Hz refresh rate, you +have these options: + + * configure and load the DOS-Tools for your the graphics board (if + available) and boot linux with loadlin. + * use a native driver (matroxfb/atyfb) instead if vesafb. If none + is available, write a new one! + * VBE 3.0 might work too. I have neither a gfx board with VBE 3.0 + support nor the specs, so I have not checked this yet. + + Configuration ============= -You can pass kernel command line options to vesafb with -"video=vesa:option1". Multiple options should be separated -by comma. Accepted options: - -invers - no comment... -redraw - scroll by redrawing the affected part of the screen -ypan - enable display panning using the VESA protected mode - interface. This enables the Shift-PgUp scrollback - thing and greatly speeds up fullscreen scrolling. - It is slower than "redraw" when scrolling only a halve - screen. This is the default. -ywrap - If your gfx board supports wrap-around, use this one - instead of ypan. -nopal - Don't use the protected mode interface for palette - changes. vesafb will try the standard vga registers - instead. +The VESA BIOS provides protected mode interface for changing +some parameters. vesafb can use it for palette changes and +to pan the display. It is turned off by default because it +seems not to work with some BIOS versions, but there are options +to turn it on. + +You can pass options to vesafb using "video=vesa:option" on +the kernel command line. Multiple options should be separated +by comma, like this: "video=vesa:ypan,invers" + +Accepted options: + +invers no comment... + +ypan enable display panning using the VESA protected mode + interface. The visible screen is just a window of the + video memory, console scrolling is done by changing the + start of the window. + pro: * scrolling (fullscreen) is fast, because there is + no need to copy around data. + * You'll get scrollback (the Shift-PgUp thing), + the video memory can be used as scrollback buffer + kontra: * scrolling only parts of the screen causes some + ugly flicker effects (boot logo flickers for + example). + +ywrap Same as ypan, but assumes your gfx board can wrap-around + the video memory (i.e. starts reading from top if it + reaches the end of video memory). Faster than ypan. + +redraw scroll by redrawing the affected part of the screen, this + is the safe (and slow) default. + + +vgapal Use the standard vga registers for palette changes. + This is the default. +pmipal Use the protected mode interface for palette changes. + +mtrr setup memory type range registers for the vesafb framebuffer. Have fun! @@ -114,7 +152,7 @@ Gerd -- -Gerd Knorr +Gerd Knorr Minor (mostly typo) changes by Nico Schmoigl diff -ur --new-file old/linux/Documentation/filesystems/00-INDEX new/linux/Documentation/filesystems/00-INDEX --- old/linux/Documentation/filesystems/00-INDEX Wed Jun 24 23:30:07 1998 +++ new/linux/Documentation/filesystems/00-INDEX Sun May 2 18:51:16 1999 @@ -1,5 +1,7 @@ 00-INDEX - this file (info on some of the filesystems supported by linux). +adfs.txt + - info and mount options for the Acorn Advanced Disc Filing System. affs.txt - info and mount options for the Amiga Fast File System. coda.txt @@ -20,6 +22,8 @@ - info on using filesystems with the SMB protocol (Windows 3.11 and NT) sysv-fs.txt - info on the SystemV/Coherent filesystem. +ufs.txt + - info on the ufs filesystem. umsdos.txt - info on the umsdos extensions to the msdos filesystem. vfat.txt diff -ur --new-file old/linux/Documentation/filesystems/adfs.txt new/linux/Documentation/filesystems/adfs.txt --- old/linux/Documentation/filesystems/adfs.txt Thu Jan 1 01:00:00 1970 +++ new/linux/Documentation/filesystems/adfs.txt Sun May 2 18:51:16 1999 @@ -0,0 +1,57 @@ +Mount options for ADFS +---------------------- + + uid=nnn All files in the partition will be owned by + user id nnn. Default 0 (root). + gid=nnn All files in the partition willbe in group + nnn. Default 0 (root). + ownmask=nnn The permission mask for ADFS 'owner' permissions + will be nnn. Default 0700. + othmask=nnn The permission mask for ADFS 'other' permissions + will be nnn. Default 0077. + +Mapping of ADFS permissions to Linux permissions +------------------------------------------------ + + ADFS permissions consist of the following: + + Owner read + Owner write + Other read + Other write + + (In older versions, an 'execute' permission did exist, but this + does not hold the same meaning as the Linux 'execute' permission + and is now obsolete). + + The mapping is performed as follows: + + Owner read -> -r--r--r-- + Owner write -> --w--w---w + Owner read and filetype UnixExec -> ---x--x--x + These are then masked by ownmask, eg 700 -> -rwx------ + Possible owner mode permissions -> -rwx------ + + Other read -> -r--r--r-- + Other write -> --w--w--w- + Other read and filetype UnixExec -> ---x--x--x + These are then masked by othmask, eg 077 -> ----rwxrwx + Possible other mode permissions -> ----rwxrwx + + Hence, with the default masks, if a file is owner read/write, and + not a UnixExec filetype, then the permissions will be: + + -rw------- + + However, if the masks were ownmask=0770,othmask=0007, then this would + be modified to: + -rw-rw---- + + There is no restriction on what you can do with these masks. You may + wish that either read bits give read access to the file for all, but + keep the default write protection (ownmask=0755,othmask=0577): + + -rw-r--r-- + + You can therefore tailor the permission translation to whatever you + desire the permissions should be under Linux. diff -ur --new-file old/linux/Documentation/filesystems/affs.txt new/linux/Documentation/filesystems/affs.txt --- old/linux/Documentation/filesystems/affs.txt Wed Jun 24 23:30:07 1998 +++ new/linux/Documentation/filesystems/affs.txt Sun Mar 21 16:11:36 1999 @@ -151,6 +151,28 @@ /etc/fstab entry: /dev/sdb5 /amiga/Workbench affs noauto,user,exec,verbose 0 0 +IMPORTANT NOTE +============== + +If you boot Windows 95 (don't know about 3.x, 98 and NT) while you +have an Amiga harddisk connected to your PC, it will overwrite +the bytes 0x00dc..0x00df of block 0 with garbage, thus invalidating +the Rigid Disk Block. Sheer luck has it that this is an unused +area of the RDB, so only the checksum doesn's match anymore. +Linux will ignore this garbage and recognize the RDB anyway, but +before you connect that drive to your Amiga again, you must +restore or repair your RDB. So please do make a backup copy of it +before booting Windows! + +If the damage is already done, the following should fix the RDB +(where is the device name). +DO AT YOUR OWN RISK: + + dd if=/dev/ of=rdb.tmp count=1 + cp rdb.tmp rdb.fixed + dd if=/dev/zero of=rdb.fixed bs=1 seek=220 count=4 + dd if=rdb.fixed of=/dev/ + Bugs, Restrictions, Caveats =========================== @@ -185,9 +207,8 @@ no way to fix a garbled filesystem without an Amiga (disk validator) or manually (who would do this?). Maybe later. -A fsck.affs and mkfs.affs will probably be available in the future. -If you mount them on system startup, you may want to tell fsck -that the fs should not be checked (place a '0' in the sixth field +If you mount affs partitions on system startup, you may want to tell +fsck that the fs should not be checked (place a '0' in the sixth field of /etc/fstab). It's not possible to read floppy disks with a normal PC or workstation diff -ur --new-file old/linux/Documentation/filesystems/coda.txt new/linux/Documentation/filesystems/coda.txt --- old/linux/Documentation/filesystems/coda.txt Wed Jun 24 23:30:07 1998 +++ new/linux/Documentation/filesystems/coda.txt Thu Apr 29 20:53:41 1999 @@ -776,7 +776,7 @@ indicate confusion between the system call creat and the VFS operation create. The VFS operation create is only called to create new objects. This create call differs from the Unix one in that it is not invoked - to return a file descriptor. The trunctate and exclusive options, + to return a file descriptor. The truncate and exclusive options, together with the mode, could simply be part of the mode as it is under Unix. There should be no flags argument; this is used in open (2) to return a file descriptor for READ or WRITE mode. diff -ur --new-file old/linux/Documentation/filesystems/fat_cvf.txt new/linux/Documentation/filesystems/fat_cvf.txt --- old/linux/Documentation/filesystems/fat_cvf.txt Wed Jun 24 23:30:07 1998 +++ new/linux/Documentation/filesystems/fat_cvf.txt Sun Feb 28 18:47:37 1999 @@ -1,4 +1,4 @@ -This is the main documentation for the CVF-FAT filesystem extension. 31DEC1997 +This is the main documentation for the CVF-FAT filesystem extension. 18Nov1998 Table of Contents: @@ -37,14 +37,9 @@ CVF filesystems cannot do bmap. It's impossible in principle. Thus all actions that require bmap do not work (swapping, writable mmapping). Read-only mmapping works because the FAT driver has a hack for this - situation :) Well, with some tricks writable mmapping could work, - (proof: they did under old dmsdos), but..... (hint: readpage/writepage - interface functions) ...... but the FAT driver has to support them - first without bmap :-) - - We'll see. If someone points me to an application that needs this, I - might be persuaded to implement it :). CVF-FAT is already prepared - for using readpage. + situation :) Well, writable mmapping should now work using the readpage + interface function which has been hacked into the FAT driver just for + CVF-FAT :) - attention, DOSEmu users @@ -66,11 +61,28 @@ cvf_format=xxx Forces the driver to use the CVF module "xxx" instead of auto-detection. - This is only necessary if the CVF format is not recognized correctly + Without this option, the CVF-FAT interface asks all currently loaded + CVF modules whether they recognize the CVF. Therefore, this option is + only necessary if the CVF format is not recognized correctly because of bugs or incompatibilities in the CVF modules. (It skips the detect_cvf call.) "xxx" may be the text "none" (without the quotes) to inhibit using any of the loaded CVF modules, just in case a CVF - module insists on mounting plain FAT filesystems by misunderstanding :) + module insists on mounting plain FAT filesystems by misunderstanding. + "xxx" may also be the text "autoload", which has a special meaning for + a module loader, but does not skip auto-detection. + + If the kernel supports kmod, the cvf_format=xxx option also controls + on-demand CVF module loading. Without this option, nothing is loaded + on demand. With cvf_format=xxx, a module "xxx" is requested automatically + before mounting the compressed filesystem (unless "xxx" is "none"). In + case there is a difference between the CVF format name and the module + name, setup aliases in your modules configuration. If the string "xxx" + is "autoload", a non-existent module "cvf_autoload" is requested which + can be used together with a special modules configuration (alias and + pre-install statements) in order to load more than one CVF module, let + them detect automatically which kind of CVF is to be mounted, and only + keep the "right" module in memory. For examples please refer to the + dmsdos documentation (ftp and http addresses see below). cvf_options=yyy Option string passed to the CVF module. I.e. only the "yyy" is passed @@ -80,8 +92,8 @@ misinterpretation by the FAT driver, which would recognize the text after a comma as a FAT driver option and might get confused or print strange error messages. The documentation for the CVF module should - offer a different separation symbol, for example the dot ".", which - is only valid inside the string "yyy". + offer a different separation symbol, for example the dot "." or the + plus sign "+", which is only valid inside the string "yyy". 4. Description of the CVF-FAT interface @@ -120,11 +132,11 @@ is set, mmap is set to generic_file_mmap and readpage is caught and redirected to the cvf_readpage function. If it is not set, readpage is set to generic_readpage and mmap is caught and redirected - to cvf_mmap. + to cvf_mmap. (If you want writable mmap use the readpage interface.) - detect_cvf: A function that is called to decide whether the filesystem is a CVF of the type the module supports. The detect_cvf function must return 0 - for "NO, I DON'T KNOW THIS GARBAGE" or anything !=0 for "YES, THIS IS + for "NO, I DON'T KNOW THIS GARBAGE" or anything >0 for "YES, THIS IS THE KIND OF CVF I SUPPORT". The function must maintain the module usage counters for safety, i.e. do MOD_INC_USE_COUNT at the beginning and MOD_DEC_USE_COUNT at the end. The function *must not* assume that @@ -180,11 +192,19 @@ that has not been previously registered. The code uses the version id to distinguish the modules, so be sure to keep it unique. -5. CVS Modules +5. CVF Modules ------------------------------------------------------------------------------ Refer to the dmsdos module (the successor of the dmsdos filesystem) for a sample implementation. It can currently be found at - ftp://fb9nt.uni-duisburg.de/pub/linux/dmsdos + ftp://fb9nt.uni-duisburg.de/pub/linux/dmsdos/dmsdos-x.y.z.tgz + ftp://sunsite.unc.edu/pub/Linux/system/Filesystems/dosfs/dmsdos-x.y.z.tgz + ftp://ftp.uni-stuttgart.de/pub/systems/linux/local/system/dmsdos-x.y.z.tgz + +(where x.y.z is to be replaced with the actual version number). Full +documentation about dmsdos is included in the dmsdos package, but can also +be found at + http://fb9nt.uni-duisburg.de/mitarbeiter/gockel/software/dmsdos/index.html + http://www.yk.rim.or.jp/~takafumi/dmsdos/index.html (in Japanese). diff -ur --new-file old/linux/Documentation/filesystems/smbfs.txt new/linux/Documentation/filesystems/smbfs.txt --- old/linux/Documentation/filesystems/smbfs.txt Wed Jan 21 19:09:31 1998 +++ new/linux/Documentation/filesystems/smbfs.txt Thu Apr 29 20:53:41 1999 @@ -1,7 +1,7 @@ Smbfs is a filesystem that implements the SMB protocol, which is the protocol used by Windows for Workgroups, Windows 95 and Windows NT. Smbfs was inspired by Samba, the program written by Andrew Tridgell -that turns any unix host into a file server for DOS or Windows clients. +that turns any Unix host into a file server for DOS or Windows clients. See ftp://nimbus.anu.edu.au/pub/tridge/samba/ for this interesting program suite and much more information on SMB, NetBIOS over TCP/IP, and explanations for concepts like netbios name or share. diff -ur --new-file old/linux/Documentation/filesystems/ufs.txt new/linux/Documentation/filesystems/ufs.txt --- old/linux/Documentation/filesystems/ufs.txt Thu Jan 1 01:00:00 1970 +++ new/linux/Documentation/filesystems/ufs.txt Fri Apr 16 17:20:23 1999 @@ -0,0 +1,49 @@ +USING UFS +========= + +mount -t ufs -o ufstype=type_of_ufs device dir + + +UFS OPTIONS +=========== + +ufstype=type_of_ufs + UFS is a file system widely used in different operating systems. + The problem are differencies among implementations. Features of + some implementations are undocumented, so its hard to recognize + type of ufs automatically. That's why user must specify type of + ufs manually by mount option ufstype. Possible values are: + + old old format of ufs + default value, supported os read-only + + 44bsd used in FreeBSD, NetBSD, OpenBSD + supported os read-write + + sun used in SunOS (Solaris) + supported as read-write + + sunx86 used in SunOS for Intel (Solarisx86) + supported as read-write + + nextstep + used in NextStep + supported as read-only + + openstep + used in OpenStep + supported as read-only + + +POSSIBLE PROBLEMS +================= + +There is still bug in reallocation of fragment, in file fs/ufs/balloc.c, +line 364. But it seem working on current buffer cache configuration. + + +BUG REPORTS +=========== + +Any ufs bug report you can send to daniel.pirkl@email.cz (do not send +partition tables bug reports.) diff -ur --new-file old/linux/Documentation/filesystems/vfat.txt new/linux/Documentation/filesystems/vfat.txt --- old/linux/Documentation/filesystems/vfat.txt Wed Jun 24 23:30:07 1998 +++ new/linux/Documentation/filesystems/vfat.txt Thu Apr 29 20:53:41 1999 @@ -177,7 +177,7 @@ Because the extended FAT system is backward compatible, it is possible for old software to modify directory entries. Measures must -be taken to insure the validity of slots. An extended FAT system can +be taken to ensure the validity of slots. An extended FAT system can verify that a slot does in fact belong to an 8.3 directory entry by the following: diff -ur --new-file old/linux/Documentation/filesystems/vfs.txt new/linux/Documentation/filesystems/vfs.txt --- old/linux/Documentation/filesystems/vfs.txt Sat Jun 27 09:11:52 1998 +++ new/linux/Documentation/filesystems/vfs.txt Tue Apr 27 18:24:34 1999 @@ -4,7 +4,7 @@ Richard Gooch - 27-JUN-1998 + 23-APR-1999 Conventions used in this document
@@ -129,7 +129,7 @@ name: the name of the filesystem type, such as "ext2", "iso9660", "msdos" and so on - fs_flags: various flags (i.e. if it is a read-only FS) + fs_flags: various flags (i.e. FS_REQUIRES_DEV, FS_NO_DCACHE, etc.) read_super: the method to call when a new instance of this filesystem should be mounted diff -ur --new-file old/linux/Documentation/ftape.txt new/linux/Documentation/ftape.txt --- old/linux/Documentation/ftape.txt Thu May 21 03:54:34 1998 +++ new/linux/Documentation/ftape.txt Mon May 10 22:00:10 1999 @@ -267,9 +267,9 @@ ii. Hardware setup BASE is the base address of your floppy disk controller, - IRQ and DMA give its interrupt and dma channel, respectively. - BOOL is an integer, "0" means: "NO!", any other value means: - "YES!". You don't need to specify anything if connecting your tape + IRQ and DMA give its interrupt and DMA channel, respectively. + BOOL is an integer, "0" means "no"; any other value means + "yes". You don't need to specify anything if connecting your tape drive to the standard floppy disk controller. All of these values have reasonable defaults. The defaults can be modified during kernel configuration, i.e. while running "make config", diff -ur --new-file old/linux/Documentation/kbuild/00-INDEX new/linux/Documentation/kbuild/00-INDEX --- old/linux/Documentation/kbuild/00-INDEX Thu Jan 1 01:00:00 1970 +++ new/linux/Documentation/kbuild/00-INDEX Mon Feb 1 21:03:20 1999 @@ -0,0 +1,8 @@ +00-INDEX + - this file: info on the kernel build process +bug-list.txt + - known bugs in kbuild programs +commands.txt + - overview of kbuild commands +config-language.txt + - specification of Config Language, the language in Config.in files diff -ur --new-file old/linux/Documentation/kbuild/bug-list.txt new/linux/Documentation/kbuild/bug-list.txt --- old/linux/Documentation/kbuild/bug-list.txt Thu Jan 1 01:00:00 1970 +++ new/linux/Documentation/kbuild/bug-list.txt Mon Feb 1 21:03:20 1999 @@ -0,0 +1,22 @@ +Bug List +21 January 1999 +Michael Elizabeth Chastain, + +- If a variable has a value of "m" in the previous .config file, + and a type of bool in the Config script, then all the interpreters + get confused. This happens frequently when someone changes a + tristate option to a bool option and people in the field have + .config files with a value of 'm'. For example: CONFIG_PSMOUSE. + +- CONFIG_MODVERSIONS has incorrect dependencies. If you have a + problem building the kernel, and you have CONFIG_MODVERSIONS turned + on, do a 'make dep' followed by 'make clean' before you try anything + else. + +- 'make dep' uses multistage dependencies, so the .hdepend file contains + 'touch' commands. As a result, building a kernel often touches files + in include/linux/*.h. This messes up CVS and other systems which like + to rely on file dates. + +- 'make dep' fails for C files which include other C files, such as + drivers/cdrom/sbpcd2.c. diff -ur --new-file old/linux/Documentation/kbuild/commands.txt new/linux/Documentation/kbuild/commands.txt --- old/linux/Documentation/kbuild/commands.txt Thu Jan 1 01:00:00 1970 +++ new/linux/Documentation/kbuild/commands.txt Mon Feb 1 21:03:20 1999 @@ -0,0 +1,113 @@ +Overview of Kbuild Commands +24 January 1999 +Michael Elizabeth Chastain, + + + +=== Introduction + +Someday we'll get our arms around all this stuff and clean it up +a little! Meanwhile, this file describes the system as it is today. + + + +=== Quick Start + +If you are building a kernel for the first time, here are the commands +you need: + + make config + make dep + make bzImage + +Instead of 'make config', you can run 'make menuconfig' for a full-screen +text interface, or 'make xconfig' for an X interface using TCL/TK. + +'make bzImage' will leave your new kernel image in arch/i386/boot/bzImage. +You can also use 'make bzdisk' or 'make bzlilo'. + +See the lilo documentation for more information on how to use lilo. +You can also use the 'loadlin' program to boot Linux from MS-DOS. + +Some computers won't work with 'make bzImage', either due to hardware +problems or very old versions of lilo or loadlin. If your kernel image +is small, you may use 'make zImage', 'make zdisk', or 'make zlilo' +on theses systems. + +If you find a file name 'vmlinux' in the top directory of the source tree, +just ignore it. This is an intermediate file and you can't boot from it. + +Other architectures: the information above is oriented towards the +i386. On other architectures, there are no 'bzImage' files; simply +use 'zImage' or 'vmlinux' as appropriate for your architecture. + +Note: the difference between 'zImage' files and 'bzImage' files is that +'bzImage' uses a different layout and a different loading algorithm, +and thus has a larger capacity. Both files use gzip compression. +The 'bz' in 'bzImage' stands for 'big zImage', not for 'bzip'! + + + +=== Top Level Makefile targets + +Here are the targets available at the top level: + + make config, make oldconfig, make menuconfig, make xconfig + + Configure the Linux kernel. You must do this before almost + anything else. + + config line-oriented interface + oldconfig line-oriented interface, re-uses old values + menuconfig curses-based full-screen interface + xconfig X window system interface + + make checkconfig + + This runs a little perl script that checks the source tree for + missing instances of #include . Someone needs to + do this occasionally, because the C preprocessor will silently give + bad results if these symbols haven't been included (it treats + undefined symbols in preprocessor directives as defined to 0). + Superfluous uses of #include are also reported, + but you can ignore these, because smart CONFIG_* dependencies + make them harmless. + + You can run 'make checkconfig' without configuring the kernel. + Also, 'make checkconfig' does not modify any files. + + make checkhelp + + This runs another little perl script that checks the source tree + for options that are in Config.in files but are not documented + in scripts/Configure.help. Again, someone needs to do this + occasionally. If you are adding configuration options, it's + nice if you do it before you publish your patch! + + You can run 'make checkhelp' withoug configuring the kernel. + Also, 'make checkhelp' does not modify any files. + + make dep, make depend + + 'make dep' is a synonym for the long form, 'make depend'. + + This command does two things. First, it computes dependency + information about which .o files depend on which .h files. + It records this information in a top-level file named .hdepend + and in one file per source directory named .depend. + + Second, if you have CONFIG_MODVERSIONS enabled, 'make dep' + computes symbol version information for all of the files that + export symbols (note that both resident and modular files may + export symbols). + + If you do not enable CONFIG_MODVERSIONS, you only have to run + 'make dep' once, right after the first time you configure + the kernel. The .hdepend files and the .depend file are + independent of your configuration. + + If you do enable CONFIG_MODVERSIONS, you must run 'make dep' + every time you change your configuration, because the module + symbol version information depends on the configuration. + +[to be continued ...] diff -ur --new-file old/linux/Documentation/kbuild/config-language.txt new/linux/Documentation/kbuild/config-language.txt --- old/linux/Documentation/kbuild/config-language.txt Thu Jan 1 01:00:00 1970 +++ new/linux/Documentation/kbuild/config-language.txt Mon Feb 1 21:03:20 1999 @@ -0,0 +1,630 @@ +Config Language Specification +21 January 1999 +Michael Elizabeth Chastain, + + + +=== Introduction + +Config Language is not 'bash'. + +This document describes Config Language, the Linux Kernel Configuration +Language. config.in and Config.in files are written in this language. + +Although it looks, and usually acts, like a subset of the 'sh' language, +Config Language has a restricted syntax and different semantics. + +Here is a basic guideline for Config Language programming: use only the +programming idioms that you see in existing Config.in files. People often +draw on their shell programming experience to invent idioms that look +reasonable to shell programmers, but silently fail in Config Language. + +Config Language is not 'bash'. + + + +=== Interpreters + +Four different configuration programs read Config Language: + + scripts/Configure make config, make oldconfig + scripts/Menuconfig make menuconfig + scripts/tkparse make xconfig + mconfig (in development) + +'Configure' is a bash script which interprets Config.in files by sourcing +them. Some of the Config Language commands are native bash commands; +simple bash functions implement the rest of the commands. + +'Menuconfig' is another bash script. It scans the input files with a +small awk script, builds a shell function for each menu, sources the +shell functions that it builds, and then executes the shell functions +in a user-driven order. Menuconfig uses 'lxdialog', a back-end utility +program, to perform actual screen output. 'lxdialog' is a C program +which uses curses. + +'scripts/tkparse' is a C program with an ad hoc parser which translates +a Config Language script to a huge TCL/TK program. 'make xconfig' +then hands this TCL/TK program to 'wish', which executes it. + +'mconfig' is the next generation of Config Language interpreters. It is a +C program with a bison parser which translates a Config Language script +into an internal syntax tree and then hands the syntax tree to one of +several user-interface front ends. + +This document describes the behaviour of all four interpreters, even though +mconfig has not been released at the time of writing. + + + +=== Statements + +A Config Language script is a list of statements. There are 21 simple +statements; an 'if' statement; menu blocks; and a 'source' statement. + +A '\' at the end of a line marks a line continuation. + +'#' usually introduces a comment, which continues to the end of the line. +Lines of the form '# ... is not set', however, are not comments. They +are semantically meaningful, and all four config interpreters implement +this meaning. + +Newlines are significant. You may not substitute semicolons for newlines. +The 'if' statement does accept a semicolon in one position; you may use +a newline in that position instead. + +Here are the basic grammar elements. + + A /prompt/ is a single-quoted string or a double-quoted string. + If the word is double-quoted, it may not have any $ substitutions. + + A /word/ is a single unquoted word, a single-quoted string, or a + double-quoted string. If the word is unquoted or double quoted, + then $-substition will be performed on the word. + + A /symbol/ is a single unquoted word. + + A /dep/ is a dependency. Syntactically, it is a /word/. At run + time, a /dep/ must evaluate to "y", "m", "n", or "". + + An /expr/ is a bash-like expression using the operators + '=', '!=', '-a', '-o', and '!'. + +Here are all the statements: + + Text statements: + + mainmenu_name /prompt/ + comment /prompt/ + text /prompt/ + + Ask statements: + + bool /prompt/ /symbol/ + hex /prompt/ /symbol/ /word/ + int /prompt/ /symbol/ /word/ + string /prompt/ /symbol/ /word/ + tristate /prompt/ /symbol/ + + Define statements: + + define_bool /symbol/ /word/ + define_hex /symbol/ /word/ + define_int /symbol/ /word/ + define_string /symbol/ /word/ + define_tristate /symbol/ /word/ + + Dependent statements: + + dep_bool /prompt/ /symbol/ /dep/ ... + dep_hex /prompt/ /symbol/ /word/ /dep/ ... + dep_int /prompt/ /symbol/ /word/ /dep/ ... + dep_string /prompt/ /symbol/ /word/ /dep/ ... + dep_tristate /prompt/ /symbol/ /dep/ ... + + Unset statement: + + unset /symbol/ ... + + Choice statements: + + choice /prompt/ /word/ /word/ + nchoice /prompt/ /symbol/ /prompt/ /symbol/ ... + + If statements: + + if [ /expr/ ] ; then + /statement/ + ... + fi + + if [ /expr/ ] ; then + /statement/ + ... + else + /statement/ + ... + fi + + Menu block: + + mainmenu_option next_comment + comment /prompt/ + /statement/ + ... + endmenu + + Source statement: + + source /word/ + + + +=== mainmenu_name /prompt/ + +This verb is a lot less important than it looks. It specifies the top-level +name of this Config Language file. + +Configure: ignores this line +Menuconfig: ignores this line +Xconfig: uses /prompt/ for the label window. +mconfig: ignores this line (mconfig does a better job without it). + +Example: + + # arch/sparc/config.in + mainmenu_name "Linux/SPARC Kernel Configuration" + + + +=== comment /prompt/ + +This verb displays its prompt to the user during the configuration process +and also echoes it to the output files during output. Note that the +prompt, like all prompts, is a quoted string with no dollar substitution. + +The 'comment' verb is not a Config Language comment. It causes the +user interface to display text, and it causes output to appear in the +output files. + +Configure: implemented +Menuconfig: implemented +Xconfig: does not display, but writes to output files +mconfig: implemented + +Example: + + # drivers/net/Config.in + comment 'CCP compressors for PPP are only built as modules.' + + + +=== text /prompt/ + +This verb displays the prompt to the user with no adornment whatsoever. +It does not echo the prompt to the output file. mconfig uses this verb +internally for its help facility. + +Configure: not implemented +Menuconfig: not implemented +Xconfig: not implemented +mconfig: implemented + +Example: + + # mconfig internal help text + text 'Here are all the mconfig command line options.' + + + +=== bool /prompt/ /symbol/ + +This verb displays /prompt/ to the user, accepts a value from the user, +and assigns that value to /symbol/. The legal input values are "n" and +"y". + +Note that the bool verb does not have a default value. People keep +trying to write Config Language scripts with a default value for bool, +but *all* of the existing language interpreters discard additional values. +Feel free to submit a multi-interpreter patch to linux-kbuild if you +want to implement this as an enhancment. + +Configure: implemented +Menuconfig: implemented +Xconfig: implemented +mconfig: implemented + +Example: + + # arch/i386/config.in + bool 'Symmetric multi-processing support' CONFIG_SMP + + + +=== hex /prompt/ /symbol/ /word/ + +This verb displays /prompt/ to the user, accepts a value from the user, +and assigns that value to /symbol/. Any hexadecimal number is a legal +input value. /word/ is the default value. + +The hex verb does not accept range parameters. + +Configure: implemented +Menuconfig: implemented +Xconfig: implemented +mconfig: implemented + +Example: + + # drivers/sound/Config.in + hex 'I/O base for SB Check from manual of the card' CONFIG_SB_BASE 220 + + + +=== int /prompt/ /symbol/ /word/ + +This verb displays /prompt/ to the user, accepts a value from the user, +and assigns that value to /symbol/. /word/ is the default value. +Any decimal number is a legal input value. + +The int verb does not accept range parameters. + +Configure: implemented +Menuconfig: implemented +Xconfig: implemented +mconfig: implemented + +Example: + + # drivers/char/Config.in + int 'Maximum number of Unix98 PTYs in use (0-2048)' \ + CONFIG_UNIX98_PTY_COUNT 256 + + + +=== string /prompt/ /symbol/ /word/ + +This verb displays /prompt/ to the user, accepts a value from the user, +and assigns that value to /symbol/. /word/ is the default value. Legal +input values are any ASCII string, except for the characters '"' and '\\'. + +The default value is mandatory. + +Configure: implemented +Menuconfig: implemented +Xconfig: implemented +mconfig: implemented + +Example: + + # drivers/sound/Config.in + string ' Full pathname of DSPxxx.LD firmware file' \ + CONFIG_PSS_BOOT_FILE /etc/sound/dsp001.ld + + + +=== tristate /prompt/ /symbol/ + +This verb displays /prompt/ to the user, accepts a value from the user, +and assigns that value to /symbol/. Legal values are "n", "m", or "y". + +The value "m" stands for "module"; it indicates that /symbol/ should +be built as a kernel module. The value "m" is legal only if the symbol +CONFIG_MODULES currently has the value "y". + +The tristate verb does not have a default value. + +Configure: implemented +Menuconfig: implemented +Xconfig: implemented +mconfig: implemented + +Example: + + # fs/Config.in + tristate 'NFS filesystem support' CONFIG_NFS_FS + + + +=== define_bool /symbol/ /word/ + +This verb the value of /word/ to /symbol/. Legal values are "n" or "y". + +For compatibility reasons, the value of "m" is also legal, because it +will be a while before define_tristate is implemented everywhere. + +Configure: implemented +Menuconfig: implemented +Xconfig: implemented +mconfig: implemented + +Example: + + # arch/alpha/config.in + if [ "$CONFIG_ALPHA_GENERIC" = "y" ] + then + define_bool CONFIG_PCI y + define_bool CONFIG_ALPHA_NEED_ROUNDING_EMULATION y + fi + + + +=== define_hex /symbol/ /word/ + +This verb assigns the value of /word/ to /symbol/. Any hexadecimal +number is a legal value. + +Configure: implemented +Menuconfig: not implemented +Xconfig: not implemented +mconfig: implemented + +Example: + + # Not from the corpus + bool 'Specify custom serial port' CONFIG_SERIAL_PORT_CUSTOM + if [ "$CONFIG_SERIAL_PORT_CUSTOM" = "y" ]; then + hex 'Serial port number' CONFIG_SERIAL_PORT + else + define_hex CONFIG_SERIAL_PORT 0x3F8 + fi + + + +=== define_int /symbol/ /word/ + +This verb assigns /symbol/ the value /word/. Any decimal number is a +legal value. + +Configure: implemented +Menuconfig: not implemented +Xconfig: not implemented +mconfig: implemented + +Example: + + # Not from the corpus + define_int CONFIG_UID_TORVALDS 2026 + + + +=== define_string /symbol/ /word/ + +This verb assigns the value of /word/ to /symbol/. Legal input values +are any ASCII string, except for the characters '"' and '\\'. + +Configure: implemented +Menuconfig: not implemented +Xconfig: not implemented +mconfig: implemented + +Example + + # Not from the corpus + define_string CONFIG_VERSION "2.2.0" + + + +=== define_tristate /symbol/ /word/ + +This verb assigns the value of /word/ to /symbol/. Legal input values +are "n", "m", and "y". + +As soon as this verb is implemented in all interpreters, please use it +instead of define_bool to define tristate values. This aids in static +type checking. + +Configure: not implemented +Menuconfig: not implemented +Xconfig: not implemented +mconfig: implemented + +Example: + + # not from the corpus + if [ "$CONFIG_ZFTAPE" != "n" ]; then + comment 'The compressor will be built as a module only!' + define_tristate CONFIG_ZFT_COMPRESSOR m + fi + + + +=== dep_bool /prompt/ /symbol/ /dep/ ... + +This verb evaluates all of the dependencies in the dependency list. +Any dependency which has a value of "y" does not restrict the input +range. Any dependency which has a value of "n", or which has some +other value, restricts the input range to "n". + +If the input range is restricted to the single choice "n", dep_bool +silently assigns "n" to /symbol/. If the input range has more than +one choice, dep_bool displays /prompt/ to the user, accepts a value +from the user, and assigns that value to /symbol/. + +Configure: not implemented +Menuconfig: not implemented +XConfig: not implemented +mconfig: implemented + + # not from the corpus + dep_bool 'RZ1000 chipset bugfix/support' CONFIG_BLK_DEV_RZ1000 $CONFIG_PCI + + + +=== dep_hex /prompt/ /symbol/ /word/ /dep/ ... +=== dep_int /prompt/ /symbol/ /word/ /dep/ ... +=== dep_string /prompt/ /symbol/ /word/ /dep/ ... + +I am still thinking about the semantics of these verbs. + +Configure: not implemented +Menuconfig: not implemented +XConfig: not implemented +mconfig: not implemented + + + +=== dep_tristate /prompt/ /symbol /dep/ ... + +This verb evaluates all of the dependencies in the dependency list. +Any dependency which as a value of "y" does not restrict the input range. +Any dependency which has a value of "m" restricts the input range to +"m" or "n". Any dependency which has a value of "n", or which has some +other value, restricts the input range to "n". + +If the input range is restricted to the single choice "n", dep_tristate +silently assigns "n" to /symbol/. If the input range has more than +one choice, dep_tristate displays /prompt/ to the user, accepts a value +from the user, and assigns that value to /symbol/. + +Configure: implemented +Menuconfig: implemented (but silently ignores dependencies after the first) +Xconfig: implemented (but silently ignores dependencies after the first) +mconfig: implemented + + + +=== unset /symbol/ ... + +This verb assigns the value "" to /symbol/, but does not cause /symbol/ +to appear in the output. The existence of this verb is a hack; it covers +up deeper problems with variable semantics in a random-execution language. + +Configure: implemented +Menuconfig: implemented +Xconfig: not implemented +mconfig: implemented + + + +=== choice /prompt/ /word/ /word/ + +This verb implements a choice list or "radio button list" selection. +It displays /prompt/ to the user, as well as a group of sub-prompts +which have corresponding symbols. + +When the user selects a value, the choice verb sets the corresponding +symbol to "y" and sets all the other symbols in the choice list to "n". + +The second argument is a single-quoted or double-quoted word that +describes a series of sub-prompts and symbol names. The interpreter +breaks up the word at white space boundaries into a list of sub-words. +The first sub-word is the first prompt; the second sub-word is the +first symbol. The third sub-word is the second prompt; the fourth +sub-word is the second symbol. And so on, for all the sub-words. + +The third word is a literal word. Its value must be a unique abbreviation +for exactly one of the prompts. The symbol corresponding to this prompt +is the default enabled symbol. + +Note that because of the syntax of the choice verb, the sub-prompts +may not have spaces in them. + +Configure: implemented +Menuconfig: implemented +Xconfig: implemented +mconfig: implemented + + + +=== nchoice /prompt/ /symbol/ /prompt/ /symbol/ ... + +This verb has the same semantics as the choice verb, but with a sensible +syntax. + +The first /prompt/ is the master prompt for the entire choice list. + +The first /symbol/ is the default symbol to enable (notice that this +is a symbol, not a unique prompt abbreviation). + +The subsequent /prompt/ and /symbol/ pairs are the prompts and symbols +for the choice list. + +Configure: not implemented +Menuconfig: not implemented +XConfig: not implemented +mconfig: implemented + + + +=== if [ /expr/ ] ; then + +This is a conditional statement, with an optional 'else' clause. You may +substitute a newline for the semicolon if you choose. + +/expr/ may contain the following atoms and operators. Note that, unlike +shell, you must use double quotes around every atom. + + "..." a literal + "$..." a variable + + /atom/ = /atom/ true if atoms have identical value + /atom/ != /atom/ true if atoms have different value + + /expr/ -o /expr/ true if either expression is true + /expr/ -a /expr/ true if both expressions are true + ! /expr/ true if expression is not true + +Configure: implemented +Menuconfig: implemented +XConfig: implemented, with bugs +mconfig: implemented + +Xconfig has several known bugs, and probably some unknown bugs too: + +- In a comparison, if the left-hand atom is a variable and that variable + is from a choice list, the right-hand atom must be "y". + +- In a comparison, if the right-hand atom is a variable and that variable + is from a choice list, you lose. tkparse will throw a segmentation + violation, silently generate bizarre TCL code, or something else. + +- tkparse gives the wrong precedence to -o, -a, and !. Don't use both + -o and -a in an expression. Don't use ! at all. + + + +=== mainmenu_option next_comment + +This verb introduces a new menu. The next statement must have a comment +verb. The /prompt/ of that comment verb becomes the title of the menu. +(I have no idea why the original designer didn't create a 'menu ...' verb). + +Statements outside the scope of any menu are in the implicit top menu. +The title of the top menu comes from a variety of sources, depending on +the interpreter. + +Configure: implemented +Menuconfig: implemented +Xconfig: implemented +mconfig: implemented + + + +=== endmenu + +This verb closes the scope of a menu. + +Configure: implemented +Menuconfig: implemented +Xconfig: implemented +mconfig: implemented + + + +=== source /word/ + +This verb interprets the literal /word/ as a filename, and interpolates +the contents of that file. The word must be a single unquoted literal +word. + +Some interpreters interpret this verb at run time; some interpreters +interpret it at parse time. + +Inclusion is textual inclusion, like the C preprocessor #include facility. +The source verb does not imply a submenu or any kind of block nesting. + +Configure: implemented (run time) +Menuconfig: implemented (parse time) +Xconfig: implemented (parse time) +mconfig: implemented (parse time) diff -ur --new-file old/linux/Documentation/kernel-docs.txt new/linux/Documentation/kernel-docs.txt --- old/linux/Documentation/kernel-docs.txt Mon Jan 4 20:37:29 1999 +++ new/linux/Documentation/kernel-docs.txt Mon May 10 22:00:10 1999 @@ -18,7 +18,7 @@ Fortunately, as more and more people get to GNU/Linux, more and more get interested in the Kernel. But reading the sources is not always enough. It is easy to understand the code, but miss the concepts, the - philosophy and design decissions behind this code. + philosophy and design decisions behind this code. Unfortunately, not many documents are available for beginners to start. And, even if they exist, there was no "well-known" place which @@ -33,7 +33,7 @@ The papers that follow are listed in no particular order. All are catalogued with the following fields: the document's "Title", the "Author"/s, the "URL" where they can be found, some "Keywords" - helpfull when searching for specific topics, and a brief "Description" + helpful when searching for specific topics, and a brief "Description" of the Document. Enjoy! @@ -170,9 +170,9 @@ http://anchor.cs.binghamton.edu/courses/cs628/linux-net.html Keywords: files, sk_buffs. Description: A short description of files under the net/ - directory. Each file has a one or two lines paragrahp - description. sk_buffs explained, too, with some beatiful - pictures. A little bit outdated. + directory. Each file has a one- or two-line paragraph to + describe it. Also, sk_buffs is explained with some + beautiful pictures. A little bit outdated. + Title: "Linux ioctl() Primer" Author: Vipul Gupta. @@ -222,7 +222,7 @@ ftp://ftp.llp.fu-berlin.de/pub/linux/LINUX-LAB/whitepapers/dr ivers.ps.gz Keywords: character device drivers, I/O, signals, DMA, - accesing ports in user space, kernel environment. + accessing ports in user space, kernel environment. Description: 68 pages paper on writing character drivers. A little bit old (1.993, 1.994) although still useful. @@ -298,7 +298,7 @@ Description: The title says it all. There's a fixed kernel section summarizing developers' work, bug fixes, new features and versions produced during the week. Published every - thursday. + Thursday. + Name: CuTTiNG.eDGe.LiNuX. URL: http://edge.linuxhq.com diff -ur --new-file old/linux/Documentation/m68k/kernel-options.txt new/linux/Documentation/m68k/kernel-options.txt --- old/linux/Documentation/m68k/kernel-options.txt Thu Jan 7 17:41:54 1999 +++ new/linux/Documentation/m68k/kernel-options.txt Tue May 11 18:57:14 1999 @@ -3,10 +3,10 @@ Command Line Options for Linux/m68k =================================== -Last Update: Nov 28, 1997 -Linux/m68k version: 2.1.64 +Last Update: 2 May 1999 +Linux/m68k version: 2.2.6 Author: Roman.Hodek@informatik.uni-erlangen.de (Roman Hodek) -Update: jds@kom.auc.dk (Jes Sorensen) +Update: jds@kom.auc.dk (Jes Sorensen) and faq@linux-m68k.org (Chris Lawrence) 0) Introduction =============== @@ -145,7 +145,7 @@ These two options tell the kernel whether it should mount the root filesystem read-only or read-write. The default is read-only, except -for ramdisks which are read-write. +for ramdisks, which default to read-write. 2.3) debug @@ -216,23 +216,10 @@ 2.7) swap= ------------ - -Syntax: swap=,,,,,,\ - , -(All optional) - -TODO - - 2.8) buff= ----------- -Syntax: buff=,,,,, -(All optional) - -TODO - + I can't find any sign of these options in 2.2.6. 3) General Device Options (Amiga and Atari) @@ -311,7 +298,7 @@ ========================= 4.1) video= --------------- +----------- Syntax: video=: @@ -322,8 +309,8 @@ NB: Please notice that this option was renamed from `atavideo' to `video' during the development of the 1.3.x kernels, thus you - might need to update your boot-scripts if upgrading to 2.0.x from - an 1.2.13ply kernel. + might need to update your boot-scripts if upgrading to 2.x from + an 1.2.x kernel. NBB: The behavior of video= was changed in 2.1.57 so the recommended option is to specify the name of the frame buffer. @@ -705,10 +692,11 @@ Syntax: video=: The parameter specifies the name of the frame buffer, valid -options are `amifb', `cyberfb', `retz3' and `clgen', provided that the -respective frame buffer devices have been compiled into the kernel (or -compiled as loadable modules). The behavior of the option was -changed in 2.1.57 so it is now recommended to specify this option. +options are `amifb', `cyber', 'virge', `retz3' and `clgen', provided +that the respective frame buffer devices have been compiled into the +kernel (or compiled as loadable modules). The behavior of the +option was changed in 2.1.57 so it is now recommended to specify this +option. The is a comma-separated list of the sub-options listed below. This option is organized similar to the Atari version of the @@ -762,8 +750,8 @@ 5.1.3) inverse -------------- -Use inverted display. Functionally the same as the "inverse" -sub-option for the Atari. +Use inverted display (black on white). Functionally the same as the +"inverse" sub-option for the Atari. 5.1.4) font ----------- @@ -787,7 +775,7 @@ your monitor can work with, in Hz. and are the same for the horizontal frequency, in kHz. - The defaults are 50;90;15;38 (Generic Amiga monitor). + The defaults are 50;90;15;38 (Generic Amiga multisync monitor). 5.2) fd_def_df0= @@ -804,6 +792,9 @@ Syntax: wd33c93= +These options affect the A590/A2091, A3000 and GVP Series II SCSI +controllers. + The is a comma-separated list of the sub-options listed below. @@ -861,7 +852,7 @@ ----------- No argument. Used to separate blocks of keywords when there's more -than one host adapter in the system. +than one wd33c93-based host adapter in the system. 5.3.7) nodma ------------ @@ -903,6 +894,69 @@ 32 bit address range for DMA. The correct setting depends on your controller and should be autodetected by the driver. An example is the 24 bit region which is specified by a mask of 0x00fffffe. + + +5.5) 53c7xx= +------------ + +Syntax: 53c7xx= + +These options affect the A4000T, A4091, WarpEngine, Blizzard 603e+, +and GForce 040/060 SCSI controllers on the Amiga, as well as the +builtin MVME 16x SCSI controller. + +The is a comma-separated list of the sub-options listed +below. + +5.5.1) nosync +------------- + +Syntax: nosync:0 + + Disables sync negotiation for all devices. Any value after the + colon is acceptable (and has the same effect). + +5.5.2) noasync +-------------- + +Syntax: noasync:0 + + Disables async and sync negotiation for all devices. Any value + after the colon is acceptable (and has the same effect). + +5.5.3) nodisconnect +------------------- + +Syntax: nodisconnect:0 + + Disables SCSI disconnects. Any value after the colon is acceptable + (and has the same effect). + +5.5.4) validids +--------------- + +Syntax: validids:0xNN + + Specify which SCSI ids the driver should pay attention to. This is + a bitmask (i.e. to only pay attention to ID#4, you'd use 0x10). + Default is 0x7f (devices 0-6). + +5.5.5) opthi +5.5.6) optlo +------------ + +Syntax: opthi:M,optlo:N + + Specify options for "hostdata->options". The acceptable definitions + are listed in drivers/scsi/53c7xx.h; the 32 high bits should be in + opthi and the 32 low bits in optlo. They must be specified in the + order opthi=M,optlo=N. + +5.5.7) next +----------- + + No argument. Used to separate blocks of keywords when there's more + than one 53c7xx host adapter in the system. /* Local Variables: */ diff -ur --new-file old/linux/Documentation/mtrr.txt new/linux/Documentation/mtrr.txt --- old/linux/Documentation/mtrr.txt Sun May 3 02:42:08 1998 +++ new/linux/Documentation/mtrr.txt Mon May 10 19:32:45 1999 @@ -62,6 +62,23 @@ ioctl() interface, so users won't have to do anything. If you use a commercial X server, lobby your vendor to add support for MTRRs. =============================================================================== +Creating overlapping MTRRs: + +%echo "base=0xfb000000 size=0x1000000 type=write-combining" >/proc/mtrr +%echo "base=0xfb000000 size=0x1000 type=uncachable" >/proc/mtrr + +And the results: cat /proc/mtrr +reg00: base=0x00000000 ( 0MB), size= 64MB: write-back, count=1 +reg01: base=0xfb000000 (4016MB), size= 16MB: write-combining, count=1 +reg02: base=0xfb000000 (4016MB), size= 4kB: uncachable, count=1 + +Some cards (especially Voodoo Graphics boards) need this 4 kB area +excluded from the beginning of the region because it is used for +registers. + +NOTE: You can only create type=uncachable region, if the first +region that you created is type=write-combining. +=============================================================================== Removing MTRRs from the shell: % echo "disable=2" >! /proc/mtrr =============================================================================== diff -ur --new-file old/linux/Documentation/networking/filter.txt new/linux/Documentation/networking/filter.txt --- old/linux/Documentation/networking/filter.txt Fri Jun 5 07:53:50 1998 +++ new/linux/Documentation/networking/filter.txt Thu Apr 29 20:53:41 1999 @@ -12,7 +12,7 @@ attach a filter onto any socket and allow or disallow certain types of data to come through the socket. LSF follows exactly the same filter code structure as the BSD Berkeley Packet Filter -(BPF), so refering to the BSD bpf.4 manpage is very helpful in +(BPF), so referring to the BSD bpf.4 manpage is very helpful in creating filters. LSF is much simpler than BPF. One does not have to worry about diff -ur --new-file old/linux/Documentation/networking/ip-sysctl.txt new/linux/Documentation/networking/ip-sysctl.txt --- old/linux/Documentation/networking/ip-sysctl.txt Tue Jan 5 00:31:35 1999 +++ new/linux/Documentation/networking/ip-sysctl.txt Mon May 10 18:55:25 1999 @@ -96,7 +96,7 @@ Enable timestamps as defined in RFC1323. tcp_sack - BOOLEAN - Enable select acknowledgements. + Enable select acknowledgments. tcp_retrans_collapse - BOOLEAN Bug-to-bug compatibility with some broken printers. @@ -119,7 +119,7 @@ icmp_paramprob_rate - INTEGER icmp_timeexceed_rate - INTEGER icmp_echoreply_rate - INTEGER (not enabled per default) - Limit the maximal rates for sending ICMP packets to specifc targets. + Limit the maximal rates for sending ICMP packets to specific targets. 0 to disable any limiting, otherwise the maximal rate in jiffies(1) See the source for more information. @@ -173,7 +173,7 @@ bootp_relay - BOOLEAN Accept packets with source address 0.b.c.d destined not to this host as local ones. It is supposed, that - BOOTP relay deamon will catch and forward such packets. + BOOTP relay daemon will catch and forward such packets. default FALSE Not Implemented Yet. @@ -211,4 +211,4 @@ Updated by: Andi Kleen ak@muc.de -$Id: ip-sysctl.txt,v 1.8 1999/01/02 16:37:06 davem Exp $ +$Id: ip-sysctl.txt,v 1.9 1999/05/08 02:58:44 davem Exp $ diff -ur --new-file old/linux/Documentation/networking/ipddp.txt new/linux/Documentation/networking/ipddp.txt --- old/linux/Documentation/networking/ipddp.txt Tue Apr 28 23:22:04 1998 +++ new/linux/Documentation/networking/ipddp.txt Thu Apr 29 20:53:41 1999 @@ -14,7 +14,7 @@ IP over an AppleTalk network or you can provide IP gatewaying functions for your AppleTalk users. -You can currently Encapsulate or Decapsulate AppleTalk-IP on LocalTalk, +You can currently encapsulate or decapsulate AppleTalk-IP on LocalTalk, EtherTalk and PPPTalk. The only limit on the protocol is that of what kernel AppleTalk layer and drivers are available. @@ -23,22 +23,22 @@ Compiling AppleTalk-IP Decapsulation/Encapsulation ================================================= -AppleTalk-IP Decapsulation needs to be compiled into your kernel. You -will need to turn on Appletalk-IP driver support. Then you will need to -select ONE of the two options; IP to AppleTalk-IP Encapsulation support or -AppleTalk-IP to IP Decapsulation support. If you compile the driver +AppleTalk-IP decapsulation needs to be compiled into your kernel. You +will need to turn on AppleTalk-IP driver support. Then you will need to +select ONE of the two options; IP to AppleTalk-IP encapsulation support or +AppleTalk-IP to IP decapsulation support. If you compile the driver statically you will only be able to use the driver for the function you have enabled in the kernel. If you compile the driver as a module you can select what mode you want it to run in via a module loading param. -ipddp_mode=1 for AppleTalk-IP Encapsulation and ipddp_mode=2 for -AppleTalk-IP to IP Decapsulation. +ipddp_mode=1 for AppleTalk-IP encapsulation and ipddp_mode=2 for +AppleTalk-IP to IP decapsulation. Basic instructions for user space tools ======================================= -To enable AppleTalk-IP Decapsulation/Encapsulation you will need the -proper tools. You can get the tools for Decapsulation from -http://spacs1.spacs.k12.wi.us/~jschlst/MacGate and for Encapsulation +To enable AppleTalk-IP decapsulation/encapsulation you will need the +proper tools. You can get the tools for decapsulation from +http://spacs1.spacs.k12.wi.us/~jschlst/MacGate and for encapsulation from http://www.maths.unm.edu/~bradford/ltpc.html I will briefly describe the operation of the tools, but you will @@ -61,8 +61,8 @@ Common Uses of ipddp.c ---------------------- -Of course AppleTalk-IP Decapsulation and Encapsulation, but specificly -Decapsulation is being used most for connecting LocalTalk networks to +Of course AppleTalk-IP decapsulation and encapsulation, but specifically +decapsulation is being used most for connecting LocalTalk networks to IP networks. Although it has been used on EtherTalk networks to allow Macs that are only able to tunnel IP over EtherTalk. @@ -73,6 +73,6 @@ Further Assistance ------------------- You can contact me (Jay Schulist ) with any -questions reguarding Decapsulation or Encapsulation. Bradford W. Johnson +questions regarding decapsulation or encapsulation. Bradford W. Johnson originally wrote the ipddp.c driver for IP encapsulation in AppleTalk. diff -ur --new-file old/linux/Documentation/networking/lapb-module.txt new/linux/Documentation/networking/lapb-module.txt --- old/linux/Documentation/networking/lapb-module.txt Thu May 21 03:54:34 1998 +++ new/linux/Documentation/networking/lapb-module.txt Mon May 10 22:00:10 1999 @@ -216,7 +216,7 @@ This is called by the LAPB module when an event occurs after the device driver has called lapb_disconnect_request (see above). The reason indicates -what has happended. In all cases the LAPB link can be regarded as being +what has happened. In all cases the LAPB link can be regarded as being terminated. The values for reason are: LAPB_OK The LAPB link was terminated normally. diff -ur --new-file old/linux/Documentation/networking/pt.txt new/linux/Documentation/networking/pt.txt --- old/linux/Documentation/networking/pt.txt Tue Apr 28 23:22:04 1998 +++ new/linux/Documentation/networking/pt.txt Mon May 10 22:00:10 1999 @@ -2,7 +2,7 @@ ALPHA for Linux 1.3.43. These files will allow you to talk to the PackeTwin (now know as PT) and -connect through it just like a pair of TNC's. To do this you will also +connect through it just like a pair of TNCs. To do this you will also require the AX.25 code in the kernel enabled. There are four files in this archive; this readme, a patch file, a .c file diff -ur --new-file old/linux/Documentation/networking/routing.txt new/linux/Documentation/networking/routing.txt --- old/linux/Documentation/networking/routing.txt Thu May 14 19:26:22 1998 +++ new/linux/Documentation/networking/routing.txt Mon May 10 22:00:10 1999 @@ -1,6 +1,6 @@ The directory ftp.inr.ac.ru:/ip-routing contains: -- iproute.c - "professional" routing table maintainance utility. +- iproute.c - "professional" routing table maintenance utility. - rdisc.tar.gz - rdisc daemon, ported from Sun. STRONGLY RECOMMENDED FOR ALL HOSTS. diff -ur --new-file old/linux/Documentation/parport.txt new/linux/Documentation/parport.txt --- old/linux/Documentation/parport.txt Mon Jul 20 05:40:43 1998 +++ new/linux/Documentation/parport.txt Fri Mar 26 22:23:24 1999 @@ -87,7 +87,7 @@ If you have configured the /proc filesystem into your kernel, you will see a new directory entry: /proc/parport. In there will be a directory entry for each parallel port for which parport is -configured. In each of those directories are three files describing +configured. In each of those directories are four files describing that parallel port. For example: File: Contents: diff -ur --new-file old/linux/Documentation/powerpc/ppc_htab.txt new/linux/Documentation/powerpc/ppc_htab.txt --- old/linux/Documentation/powerpc/ppc_htab.txt Wed Apr 15 02:33:40 1998 +++ new/linux/Documentation/powerpc/ppc_htab.txt Thu Mar 11 06:49:10 1999 @@ -114,10 +114,5 @@ 3. Bugs - Doing a 'less' or 'more' on ppc_htab results in a segmentation violation. - I'm not sure of the cause but in the mean time 'cat' works adequately for - reading the file. - The PMC1 and PMC2 counters can overflow and give no indication of that in /proc/ppc_htab. - diff -ur --new-file old/linux/Documentation/powerpc/smp.txt new/linux/Documentation/powerpc/smp.txt --- old/linux/Documentation/powerpc/smp.txt Sat Oct 10 18:53:24 1998 +++ new/linux/Documentation/powerpc/smp.txt Thu Apr 29 21:39:07 1999 @@ -5,11 +5,10 @@ (Cort Dougan, cort@cs.nmt.edu) please email me if you have questions, comments or corrections. -Last Change: 10.8.98 +Last Change: 3.31.99 -SMP support for Linux/PPC is still in its early stages and likely to -be buggy for a while. If you want to help by writing code or testing -different hardware please email me! +If you want to help by writing code or testing different hardware please +email me! 1. State of Supported Hardware @@ -29,3 +28,7 @@ BeBox BeBox support hasn't been added to the 2.1.X kernels from 2.0.X but work is being done and SMP support for BeBox is in the works. + + CHRP + CHRP SMP works and is fairly solid. It's been tested on the IBM F50 + with 4 processors for quite some time now. diff -ur --new-file old/linux/Documentation/proc.txt new/linux/Documentation/proc.txt --- old/linux/Documentation/proc.txt Thu Jan 28 21:16:40 1999 +++ new/linux/Documentation/proc.txt Sat Feb 6 21:46:20 1999 @@ -50,7 +50,7 @@ the work back to the Linux community. This work is based on the 2.1.132 and 2.2.0-pre-kernel versions. I'm afraid it's still far from complete, but we hope it will be useful. As far as we know, it is the -first 'all-in-one’ document about the /proc file system. It is +first 'all-in-one' document about the /proc file system. It is focused on the Intel x86 hardware, so if you are looking for PPC, ARM, SPARC, APX, etc., features, you probably won't find what you are looking for. It also only covers IPv4 networking, not IPv6 nor other @@ -657,7 +657,7 @@ sg-big-buff This file shows the size of the generic SCSI (sg) buffer. At this - point, you can’t tune it yet, but you can change it at compile time + point, you can't tune it yet, but you can change it at compile time by editing include/scsi/sg.h and changing the value of SG_BIG_BUFF. @@ -794,9 +794,9 @@ swap_cluster This is probably the greatest influence on system performance. swap_cluster is the number of pages kswapd writes in - one turn. You’ll want this value to be large so that kswapd does - its I/O in large chunks and the disk doesn’t have to seek as - often., but you don’t want it to be too large since that would + one turn. You'll want this value to be large so that kswapd does + its I/O in large chunks and the disk doesn't have to seek as + often., but you don't want it to be too large since that would flood the request queue. overcommit_memory @@ -1140,7 +1140,7 @@ accept_source_route Should source routed packages be accepted or declined. The default is dependent on the kernel configuration. It's 'yes' for - routers and 'np' for hosts. + routers and 'no' for hosts. bootp_relay Accept packets with source address 0.b.c.d destined not to this diff -ur --new-file old/linux/Documentation/scsi-generic.txt new/linux/Documentation/scsi-generic.txt --- old/linux/Documentation/scsi-generic.txt Thu Jan 1 01:00:00 1970 +++ new/linux/Documentation/scsi-generic.txt Sun Apr 25 02:49:37 1999 @@ -0,0 +1,636 @@ + Notes on Linux's SG driver version 2.1.30 + ----------------------------------------- + 990328 + +Introduction +============ +These are notes on the Linux SCSI generic packet device driver (sg) +describing version 2.1.30 . The original driver was written by Lawrence +Foard and has remained in place with minimal changes since circa 1992. +Version 2 of this driver remains backward compatible (binary and +source **) with the original. It adds scatter gather, command queuing, +per file descriptor sequencing, asynchronous notification and better +error reporting. + +Sg is one of the four "high level" SCSI device drivers along with +sd, st and sr (disk, tape and CDROM respectively). Sg is more generalized +(but lower level) than its sibling and tends to be used on SCSI devices +that don't fit into the already serviced categories. Thus sg is used for +scanners, cd writers and reading audio cds amongst other things. + +The interface and usage of the original sg driver has been documented +by Heiko Eissfeldt in a HOWTO called SCSI-Programming-HOWTO. My copy +of the document is version 1.5 dated 7th May 1996. It can found at +ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO/SCSI-Programming-HOWTO . +Amongst other things it has a lot of tables from the SCSI-2 standard +that are very useful for programming this interface. + +** It is possible to write applications that perform differently +depending on whether they are using the original or this version of +the sg device driver. The author is not aware of any useful applications +that have problems with version 2 (yet). + + +Architecture +============ +The SCSI generic packet device driver (sg) is a character based device. +It is one of the four high level device driver in the SCSI sub-system; +the others are sd (for direct-access devices - disks), st (for tapes) +and sr (for data cdroms). The other three devices are block devices. + +The unifying layer of the SCSI sub-system in the so-called mid-level. +Below that are all the drivers for the various adapters supported by +Linux. + +Since sg is a character device it supports the traditional Unix +system calls of open(), close(), read(), write() and ioctl(). Two other +related system calls: poll() and fcntl() are added to this list and +how they interact with the sg device driver is documented later. + +An SG device is accessed by write()ing SCSI commands plus any associated +outgoing data to it; the resulting status codes and any incoming data are +then obtained by a read() call. The device can be opened O_NONBLOCK +(non-blocking) and poll() used to monitor its progress. The device may be +opened O_EXCL which excludes other "sg" users from this device (but not +"sd", "st" or "sr" users). The buffer given to the write() call is made +up as follows: + - struct sg_header image (see below) + - scsi command (6, 10 or 12 bytes long) + - data to be written to the device (if any) + +The buffer received from the corresponding read() call contains: + - struct sg_header image (check status/errors + sense_buffer) + - data read back from device (if any) + +The given SCSI command has its LUN field overwritten by the LUN value of +the associated sg device that has been open()ed. + + +sg_header +========= +This is the name of the control structure that conveys information +about the length of data to be read/written by the associated SCSI +command. It also conveys error and status information from the +read() call. An instance of this structure is the first thing that +is placed in the data buffers of both write() and read(). + +In its original form it looked like this: +struct sg_header { + int pack_len; + int reply_len; + int pack_id; + int result; + unsigned int twelve_byte:1; + unsigned int other_flags:31; + unsigned char sense_buffer[16]; +}; /* this structure is 36 bytes long */ + +The 'pack_len' is bizzare and ends up having the 'reply_len' put in it +(perhaps it had a use at some stage). + +The 'reply_len' is the length of the data the corresponding read() +will/should request (including the sg_header). + +The 'pack_id' is not acted upon by the sg device driver but is conveyed +back to the corresponding read() so it can be used for sequencing by an +application. + +The 'result' is also bizzare, turning certain types of host codes it 0 (no +error), EBUSY or EIO. With better error reporting now available, the +'result' is best ignored. + +The 'twelve_byte' field overrides the internal SCSI command length "guessing" +algorithm for group 6 and 7 commands (ie when 1st byte >= 0xc0) and forces +a command lenth of 12 bytes. +The command length "guessing" algorithm is as follows: +Group: 0 1 2 3 4 5 6 7 +Length: 6 10 10 12 12 12 10 10 + +'other_flags' was originally documented as "not used" but some current +applications assume it has 0 placed in it. + +The 'sense_buffer' is the first 16 bytes of SCSI sense buffer that is +returned when the target returns a SCSI status code of CHECK_CONDITION +or COMMAND_TERMINATED [or (driver_status & DRIVER_SENSE) is true]. This +buffer should be at least 18 bytes long and arguably 32 bytes; unfortunately +this is unlikely to happen in the 2.2.x series of kernels. + +The new sg_header offered in this driver is: +#define SG_MAX_SENSE 16 +struct sg_header +{ + int pack_len; /* [o] reply_len (ie useless) ignored as input */ + int reply_len; /* [i] max length of expected reply (inc. sg_header) */ + int pack_id; /* [io] id number of packet (use ints >= 0) */ + int result; /* [o] 0==ok, else (+ve) Unix errno code (e.g. EIO) */ + unsigned int twelve_byte:1; + /* [i] Force 12 byte command length for group 6 & 7 commands */ + unsigned int target_status:5; /* [o] scsi status from target */ + unsigned int host_status:8; /* [o] host status (see "DID" codes) */ + unsigned int driver_status:8; /* [o] driver status+suggestion */ + unsigned int other_flags:10; /* unused */ + unsigned char sense_buffer[SG_MAX_SENSE]; /* [o] when target_status is + CHECK_CONDITION or COMMAND_TERMINATED this is output. */ +}; /* This structure is 36 bytes long on i386 */ + +Firstly the new header is binary compatible with the original. This is +important for keeping existing apps working without recompilation. + +Only those elements (or fields) that are new or in some way different +from the original are documented below. + +'pack_id' becomes input to a read() when ioctl(sg_fd, SG_SET_FORCE_PACK_ID, +&one) is active. A 'pack_id' of -1 is interpreted as fetch the oldest +waiting packet; any other value will cause the read() to wait (or yield +EAGAIN) until a packet with that 'pack_id' becomes available. In all cases +the value of 'pack_id' available after a read() is the value given to that +variable in the prior, corresponding write(). + +The 'target_status' field is always output and is the (masked and shifted +1 bit right) SCSI status code from the target device. The allowable +values are (found in ): +/* N.B. 1 bit offset from usual SCSI status values */ +#define GOOD 0x00 +#define CHECK_CONDITION 0x01 +#define CONDITION_GOOD 0x02 +#define BUSY 0x04 +#define INTERMEDIATE_GOOD 0x08 +#define INTERMEDIATE_C_GOOD 0x0a +#define RESERVATION_CONFLICT 0x0c +#define COMMAND_TERMINATED 0x11 +#define QUEUE_FULL 0x14 +When the 'target_status' is CHECK_CONDITION or COMMAND_TERMINATED the +'sense_buffer' is output. Note that when (driver_status & DRIVER_SENSE) +is true then the 'sense_buffer' is also output (this seems to occur when +the scsi ide emulation is used). When the 'sense_buffer' is output the +SCSI Sense Key can be found at (sense_buffer[2] & 0x0f) . + +The 'host_status' field is always output and has the following values +whose "defines" are not visible outside the kernel (unfortunately): +#define DID_OK 0x00 /* NO error */ +#define DID_NO_CONNECT 0x01 /* Couldn't connect before timeout period */ +#define DID_BUS_BUSY 0x02 /* BUS stayed busy through time out period */ +#define DID_TIME_OUT 0x03 /* TIMED OUT for other reason */ +#define DID_BAD_TARGET 0x04 /* BAD target. */ +#define DID_ABORT 0x05 /* Told to abort for some other reason */ +#define DID_PARITY 0x06 /* Parity error */ +#define DID_ERROR 0x07 /* Internal error */ +#define DID_RESET 0x08 /* Reset by somebody. */ +#define DID_BAD_INTR 0x09 /* Got an interrupt we weren't expecting. */ +#define DID_PASSTHROUGH 0x0a /* Force command past mid-layer */ +#define DID_SOFT_ERROR 0x0b /* The low level driver just wish a retry */ + +The 'driver_status' field is always output. When ('driver_status' & +DRIVER_SENSE) is true the 'sense_buffer' is also output. The following +values whose "defines" are not visible outside the kernel (unfortunately) +can occur: +#define DRIVER_OK 0x00 /* Typically no suggestion */ +#define DRIVER_BUSY 0x01 +#define DRIVER_SOFT 0x02 +#define DRIVER_MEDIA 0x03 +#define DRIVER_ERROR 0x04 +#define DRIVER_INVALID 0x05 +#define DRIVER_TIMEOUT 0x06 +#define DRIVER_HARD 0x07 +#define DRIVER_SENSE 0x08 +/* above status 'or'ed with one of the following suggestions */ +#define SUGGEST_RETRY 0x10 +#define SUGGEST_ABORT 0x20 +#define SUGGEST_REMAP 0x30 +#define SUGGEST_DIE 0x40 +#define SUGGEST_SENSE 0x80 + +'other_flags' still remains as a 10 bit field, so code that places 0 in it +will still be happy. It is not used. + + +memory +====== +Memory is a scarce resource in any computer. Sg needs to reserve memory +suitable for DMA roughly equal in size to the maximum of the write and +read data buffers for each packet. This DMA memory is obtained at the time +of a write() and released when the corresponding read() is called (although +if memory is tight it may be using the buffer reserved by the open() ). + +Linux obtaining memory a challenge for several reasons. The memory pool +that sg uses is in common with all other device drivers and all user +processes. In this environment the only way to 99.9% guarantee a driver +will have memory in Linux is to build it into the kernel (ie not as a +module) and then reserve it on initialization before user processes get +a chance. [Of course, another driver initialized before sg could take +all available memory ...] Another problem is the biggest contiguous +chunk of memory that can be obtained from the kernel is 32 * PAGE_SIZE +(which is 128KBytes on i386). As memory gets "splintered" there is a good +chance that buffers won't be available (my machine has 64 MBytes of RAM +and has 3 available at the moment). + +The original sg driver used the following technique: grab a SG_BIG_BUFF +sized buffer at driver initialization and use it for all requests greater +than PAGE_SIZE (4096 bytes on i386). By default SG_BIG_BUFF is set to +32 KBytes in the origianl driver but many applications suggest that the +user increases this number. Linux limits the biggest single buffer of +this type to 32 * PAGE_SIZE (128KBytes on i386). Unfortunately if the +sg driver is a module then there is a high chance a contiguous block of +that large size will not be available at module initialization. + +The author has found no "silver bullet" solution but uses multiple +techniques hoping that at least one is able provide memory at the critical +time. Listed below are some of these techniques: + - use scatter gather: then instead of one large buffer needing to + be found, multiple smaller buffer can be used + - use memory above the 16MByte level: the original driver limited + itself to obtaining memory below the 16MByte level (on the i386) + due to the shortcomings of DMA on ISA adapters. Yet more and more + people use PCI adapters that don't have this problem. So make + the decision based on the capabilities of the host adpater + associated with the current SCSI device + - reserve some memory at open() for emergencies but otherwise + fetch and release it on a per packet basis + - if the kernel is short of memory then dip into the SCSI DMA + pool (maintained by the mid-level driver) to a limited amount + + + +System Calls +============ +What follows are descriptions of the characteristics of the standard +Unix operating system calls when applied to a SCSI generic device +using this version of the device driver. + +open +---- +The filename should be an 'sg' device such as +/dev/sg[a-z] +/dev/sg[0,1,2,...] +or a symbolic link to one of these. [Devfs has its own sub-directory for +sg devices.] It seems as though SCSI devices are allocated to sg minor +numbers in the same order as they appear in 'cat /proc/scsi/scsi'. +Sg is a "character" based Linux device driver. This means it has an +open/close/read/write/ioctl type interface. + +Flags can be either O_RDONLY or O_RDWR or-ed with either +O_EXCL waits for other opens on sg device to be closed before + proceeding. If O_NONBLOCK is set then yields EBUSY when + someone else has the sg device open. The combination of + O_RDONLY and O_EXCL is disallowed. +O_NONBLOCK Sets non-blocking mode. Calls that would otherwise block + yield EAGAIN (eg read() ) or EBUSY (eg open() ). + +The original version of sg did not allow the O_RDONLY (yielding a EACCES +error). This version allows it for accessing ioctls (e.g. doing an sg +device scan with the SG_GET_SCSI_ID ioctl) but write()s will not be +allowed. + +By default, sequencing is per file descriptor in this version of sg. This +means, for example that 2 processes can independently manipulate the same +sg device at the same time. This may or may not make sense depending on +the application: 2 processes (logically) reading from the same direct access +device (ie a disk) is ok while running 2 instances of cd writing software +on the same device at the same time probably wouldn't be a good idea. The +previous version of sg supported only per device sequencing and this can +still be selected with the SG_SET_MERGE_FD,1 ioctl(). + +The driver will attempt to reserve SG_SCATTER_SZ bytes (32KBytes in the +current sg.h) on open() for "emergency" situations. If this is unavailable +it will halve its request and try again. It gives up if PAGE_SIZE bytes +(4096 bytes on i386) cannot be obtained so no memory is reserved. In this +case open() will still return successfully. The actual amount of memory +reserved can be found with the SG_GET_RESERVED_SIZE ioctl(). + +Returns a file descriptor if >= 0 , otherwise -1 implies an error. + +Error codes (value in 'errno' after -1 returned): +ENODEV sg not compiled into kernel or the kernel cannot find the + sg module (or it can't initialize itself (low memory??)) +ENXIO either scsi sub-system is currently processing some error + (eg doing a device reset) or the sg driver/module removed + or corrupted +EBUSY O_NONBLOCK set and some user of this sg device has O_EXCL + set while someone is already using this device +EINTR while waiting for an "exclusive" lock to clear, a signal + is received, just try again ... +ENOMEM An attempt to get memory to store this open's context + failed (this was _not_ a request to reserve DMA memory) +EACCES An attempt to use both O_RDONLY and O_EXCL + + +write +----- +Even though sg is a character-based device driver it sends and receives +packets to/from the associated scsi device. Write() is used to send a +packet containing 2 mandatory parts and 1 optional part. The mandatory +parts are: + - a control block (an instance of struct sg_header) + - a SCSI command (6, 10 or 12 bytes long) +The optional part is: + - outgoing data (eg if a SCSI write command is being sent) +These should appear as one contiguous string in the buffer given to +write() in the above order with no pad characters. + +If a write() accepts this packet then at some later time the user should +call a read() to get the result of the SCSI command. The previous sg +driver enforced a strict write()/read()/write()/read() regime so that a +second write() would block until first read() was finished. This sg +driver relaxes that condition and thereby allows command queuing +(limit is SG_MAX_QUEUE (16) outstanding packets per file descriptor). +However, for backward compatibility, command queuing is turned off +by default (#define SG_DEF_COMMAND_Q 0 in sg.h). This can be changed +via the the SG_SET_COMMAND_Q ioctl() [or by recompiling after changing +the above define to 1]. + +In this sg driver a write() should return more or less immediately. + +Returns number of bytes written if > 0 , otherwise -1 implies an error. + +Error codes (value in 'errno' after -1 returned): +ENXIO either scsi sub-system is currently processing some error + (eg doing a device reset) or the sg driver/module removed + or corrupted +EACCES opened with RD_ONLY flag +EIO incoming buffer too short. It should be at least (6 + + sizeof(struct sg_header))==42 bytes long +EDOM a) command queuing off: a packet is already queued + b) command queuing on: too many packets queued + (SG_MAX_QUEUE exceeded) +EAGAIN SCSI mid-level out of command blocks (rare), try again. + This is more likely to happen when queuing commands, + so wait a bit (eg usleep(10000) ) before trying again +ENOMEM can't get memory for DMA. Take evasive action ... + (see section on memory) + + +read +---- +Read() is used to receive a packet containing 1 mandatory part and 1 +optional part. The mandatory part is: + - a control block (an instance of struct sg_header) +The optional part is: + - incoming data (eg if a SCSI read command was sent by earlier write() ) +The buffer given to a read() and its corresponding count should be +sufficient to accommodate this packet to avoid truncation. Truncation has +occurred if count < sg_header::replylen . + +By default, read() will return the oldest packet queued up. If the +SG_SET_FORCE_PACK_ID,1 ioctl() is active then read() will attempt to +fetch the packet whose pack_id (given earlier to write()) matches the +sg_header::pack_id given to this read(). If not available it will either +wait or yield EAGAIN. As a special case, -1 in sg_header::pack_id given +to read() will match the oldest packet. + + +Returns number of bytes read if > 0 , otherwise -1 implies an error. +Unfortunately the return value in the non-error case is simply the +same as the count argument. It is not the actual number of bytes +DMA-ed by the SCSI device. This driver is currently unable to provide +such an underrun indication. + +Error codes (value in 'errno' after -1 returned): +ENXIO either scsi sub-system is currently processing some error + (eg doing a device reset) or the sg driver/module removed + or corrupted +EAGAIN either no waiting packet or requested packet is not + available while O_NONBLOCK flag was set +EINTR while waiting for a packet, a signal is received, just + try again ... +EIO if the 'count' given to read() is < sizeof(struct sg_header) + and the 'result' element in sg_header is non-zero. Not a + recommended error reporting technique + + +close +----- +Preferably a close() should be done after all issued write()s have had +their corresponding read() calls completed. Unfortunately this is not +always possible. The semantics of close() in Unix are to return more +or less immediately (ie not wait on any event) so the driver needs to +arrange to an orderly cleanup of those packets that are still "in +flight". + +A process that has an open file descriptor to an sg device may be aborted +(eg by a kill signal). In this case, the kernel automatically calls close +(which is called 'sg_release()' in the version 2 driver) to facilitate +the cleanup mentioned above. + +A problem persists in version 2.1.8 if the sg driver is a module and is +removed while packets are still "in flight". Hopefully this will be soon +fixed. + +Returns 0 if successful, otherwise -1 implies an error. + +Error codes (value in 'errno' after -1 returned): +ENXIO sg driver/module removed or corrupted + +ioctl (sg specific) +------------------- +Ken Thompson (or perhaps some other Unix luminary) described ioctl() as +the "garbage bin of Unix". This driver compounds the situation by adding +around 18 more commands. These commands either yield state information (10 +of them), change the driver's characteristics (8 of them) or allow direct +communication with the common SCSI mid-level driver. + +Those commands with an appended "+" are new in version 2. + +Those commands with an appended "W" are only accessible from file +descriptors opened with O_RDWR. They will yield EACCES otherwise. + +SG_GET_TIMEOUT: +Ignores its 3rd argument and _returns_ the timeout value (which will be +>= 0 ). The unit of this timeout is "jiffies" which are currently 10 +millisecond intervals on i386 (less on an alpha). Linux supplies +a manifest constant HZ which is the number of "jiffies" in 1 second. + +SG_SET_TIMEOUT: +Assumes 3rd argument points to an int containing the new timeout value +for this file descriptor. The unit is a "jiffy". Packets that are +already "in flight" will not be effected. The default value is set +on open() and is SG_DEFAULT_TIMEOUT (defined in sg.h). + +SG_EMULATED_HOST: +Assumes 3rd argument points to an int and outputs a flag indicating +whether the host (adapter) is connected to a real SCSI bus or is +emulated one (eg ide-scsi device driver). A value of 1 means emulated +while 0 is not. + +SG_SET_FORCE_LOW_DMA +: +Assumes 3rd argument points to an int containing 0 or 1. 0 (default) +means sg decides whether to use memory above 16 Mbyte level (on i386) +based on the host adapter being used by this SCSI device. Typically +PCI SCSI adapters will indicate they can DMA to the whole 32 bit address +space. +If 1 is given then the host adapter is overridden and only memory below +the 16MB level is used for DMA. A requirement for this should be +extremely rare. If the "reserve" buffer allocated on open() is not in +use then it will be de-allocated and re-allocated under the 16MB level +(and the latter operation could fail yielding ENOMEM). +Only the current file descriptor is effected. + +SG_GET_LOW_DMA +: +Assumes 3rd argument points to an int and places 0 or 1 in it. 0 +indicates the whole 32 bit address space is being used for DMA transfers +on this file descriptor. 1 indicates the memory below the 16MB level +(on i386) is being used (and this may be the case because the host +adapters setting has been overridden by SG_SET_FORCE_LOW_DMA,1 . + +SG_GET_SCSI_ID +: +Assumes 3rd argument is pointing to an object of type Sg_scsi_id and +populates it. That structure contains ints for host_no, channel, +scsi_id, lun and scsi_type. Most of this information is available from +other sources (eg SCSI_IOCTL_GET_IDLUN and SCSI_IOCTL_GET_BUS_NUMBER) +but tends to be awkward to collect. + +SG_SET_FORCE_PACK_ID +: +Assumes 3rd argument is pointing to an int. 0 (default) instructs read() +to return the oldest (written) packet if multiple packets are +waiting to be read (when command queuing is being used). +1 instructs read() to view the sg_header::pack_id as input and return the +oldest packet matching that pack_id or wait until it arrives (or yield +EAGAIN if O_NONBLOCK is in force). As a special case the pack_id of -1 +given to read() in the mode will match the oldest packet. +Only the current file descriptor is effected by this command. + +SG_GET_LOW_DMA +: +Assumes 3rd argument points to an int and places the pack_id of the +oldest (written) packet in it. If no packet is waiting to be read then +yields -1. + +SG_GET_NUM_WAITING +: +Assumes 3rd argument points to an int and places the number of packets +waiting to be read in it. + +SG_GET_SG_TABLESIZE +: +Assumes 3rd argument points to an int and places the maximum number of +scatter gather elements supported by the host adapter. 0 indicates that +the adapter does support scatter gather. + +SG_SET_RESERVED_SIZE +W: +This is not currently implemented. It is intended for reserving either a +large buffer or scatter gather list that will be available until the +current file descriptor is closed. The requested amount of memory may +not be available so SG_GET_RESERVED_SIZE should be used after this call +to see how much was reserved. (EBUSY error possible) + +SG_GET_RESERVED_SIZE +: +Assumes 3rd argument points to an int and places the size in bytes of +the DMA buffer reserved on open() for emergencies. If this is 0 then it +is probably not wise to attempt on operation like burning a CD on this +file descriptor. + +SG_SET_MERGE_FD +W: +Assumes 3rd argument is pointing to an int. 0 (the default) causes all +subsequent sequencing to be per file descriptor. 1 causes all subsequent +sequencing to be per device. If this command tries to change the current +state and the is one or more _other_ file descriptors using this sg +device then an EBUSY error occurs. Also if this file descriptor was not +open()ed with the O_RDWR flag then an EACCES error occurs. +Per device sequencing was the original semantics and allowed, for example +different processes to "share" the device, one perhaps write()ing with +the other one read()ing. This command is supplied if anyone needs those +semantics. Per file descriptor sequencing, perhaps with the usage of +the O_EXCL flag, seems more sensible. + +SG_GET_MERGE_FD +: +Assumes 3rd argument points to an int and places 0 or 1 in it. 0 implies +sequencing is per file descriptor. 1 implies sequencing is per device +(original sg driver's semantics). + +SG_SET_COMMAND_Q +: +Assumes 3rd argument is pointing to an int. 0 (current default, set by +SG_DEF_COMMAND_Q in sg.h) disables command queuing. Attempts to write() +a packet while one is already queued will result in a EDOM error. +1 turns command queuing on. +Changing the queuing state only effects write()s done after the change. +Only the current file descriptor is effected by this command. + +SG_GET_COMMAND_Q +: +Assumes 3rd argument points to an int and places 0 or 1 in it. 0 implies +that command queuing is off on this file descriptor. 1 implies command +queuing is on. + +SG_SET_DEBUG +: +Assumes 3rd argument is pointing to an int. 0 (default) turns debugging +off. Values > 0 cause the SCSI sense buffer to be decoded and output +to the console/log when a SCSI device error occurs. Values > 8 cause +the current sg device driver's state to be output to the console/log +(this is a "one off" effect). +If you need a _lot_ of the SCSI sub-system debug information (mainly from +the mid-level) then try 'echo "scsi dump 0" > /proc/scsi/scsi' and lots of +debug will appear in your console/log. + +ioctl (in common with sd, st + sr) +---------------------------------- +The following ioctl()s can be called from any high-level scsi device +driver (ie sd, st, sr + sg). Access permissions may differ a bit from +one device to another, the access information given below is specific to +the sg device driver. + +SCSI_IOCTL_GET_IDLUN: +SCSI_IOCTL_GET_BUS_NUMBER: + +SCSI_IOCTL_SEND_COMMAND: W +If open()ed O_RDONLY yields an EACCESS error. Otherwise is forwarded onto +the SCSI mid-level driver for processing. +Don't know much about this one but it looks pretty powerful and +dangerous. Some comments says it is also deprecated. + +: W +If open()ed O_RDONLY yields an EACCESS error. Otherwise is forwarded onto +the SCSI mid-level driver for processing. + + +poll +---- +This is a native call in Linux 2.2 but most of its capabilities are available +through the older select() call. Given a choice poll() should probably be +used. Typically poll() is used when a sg scsi device is open()ed O_NONBLOCK +for polling; or alternatively with asynchronous notification using the +fcntl() system call (below) and the SIGPOLL (aka SIGIO) signal. +Only if something drastically is wrong (eg file handle gone stale) will +POLLERR ever be set. POLLPRI, POLLHUP and POLLNVAL are never set. +POLLIN is set when there is one or more packets waiting to be read. +When POLLIN is set it implies that a read() will not block (or yield +EAGAIN in non-blocking mode) but return a packet immediately. +POLLOUT (aka POLLWRNORM) is set when write() is able to accept a packet +(ie will _not_ yield an EDOM error). The setting of POLLOUT is effected +by the SG_SET_COMMAND_Q state: if the state is on then POLLOUT will remain +set until the number of queued packets reaches SG_MAX_QUEUE, if the +state is off then POLLOUT is only set when no packets are queued. +Note that a packet can be queued after write()ing but not available to be +read(); this typically happens when a SCSI read command is issued while +the data is being retreaved. +Poll() is per file descriptor unless SG_SET_MERGE_FD is set in which case +it is per device. + + +fcntl +----- +There are several uses for this system call in association with a sg +file descriptor. The first pseudo code shows code that is useful for +scanning the sg devices, taking care not to be caught in a wait for +an O_EXCL lock by another process, and when the appropriate device is +found switching to normal blocked io. A working example of this logic +is in the sg_scan.c utility program. + +open("/dev/sga", O_RDONLY | O_NONBLOCK) +/* check device, EBUSY means some other process has O_EXCL lock on it */ +/* one the device you want is found then ... */ +flags = fcntl(sg_fd, F_GETFL) +fcntl(sg_fd, F_SETFL, flags & (~ O_NONBLOCK)) +/* for simple apps is is easier to use normal blocked io */ + + +Some work has to be done in Linux to set up for asynchronous notification. +This is a non-blocking mode of operation in which when the driver receives +data back from a device so that a read() can be done, it sends a SIGPOLL +(aka SIGIO) signal to the owning process. A working example of this logic +is in the sg_poll.c test program. + +sigemptyset(&sig_set) +sigaddset(&sig_set, SIGPOLL) +sigaction(SIGPOLL, &s_action, 0) +fcntl(sg_fd, F_SETOWN, getpid()) +flags = fcntl(sg_fd, F_GETFL); +fcntl(sg_fd, F_SETFL, flags | O_ASYNC) + + +Utility and Test Programs +========================= diff -ur --new-file old/linux/Documentation/sound/AD1816 new/linux/Documentation/sound/AD1816 --- old/linux/Documentation/sound/AD1816 Wed Dec 16 21:52:00 1998 +++ new/linux/Documentation/sound/AD1816 Mon May 10 22:00:10 1999 @@ -70,7 +70,16 @@ - Acer FX-3D - SY-1816 - Highscreen Sound-Boostar 32 Wave 3D -- ... +- Highscreen Sound-Boostar 16 +- AVM Apex Pro card +- (Aztech SC-16 3D) +- (Newcom SC-16 3D) +- (Terratec EWS64S) + +Cards listed in brackets are not supported reliable. If you have such a card +you should add the extra parameter: + options=1 +when loading the ad1816 module via modprobe. Troubleshooting: @@ -105,7 +114,7 @@ As the driver is still experimental and under development, you should watch out for updates. Updates of the driver are available on the -internet from one of my home pages: +Internet from one of my home pages: http://www.student.informatik.tu-darmstadt.de/~tek/projects/linux.html or: http://www.tu-darmstadt.de/~tek01/projects/linux.html @@ -115,4 +124,4 @@ Thorsten Knabe - Last modified: 1998/11/06 + Last modified: 1999/05/02 diff -ur --new-file old/linux/Documentation/sound/AWE32 new/linux/Documentation/sound/AWE32 --- old/linux/Documentation/sound/AWE32 Mon Jan 4 21:01:19 1999 +++ new/linux/Documentation/sound/AWE32 Thu Apr 29 20:53:41 1999 @@ -53,7 +53,7 @@ (IO 2 (BASE 0x0E20)) (ACT Y) ))" Resources 0x0620, 0x0A20 and 0x0E20 should work. Other on-board devices: -Gameport and StereoEnhance are not required to be inited. +Gameport and StereoEnhance are not required to be initialized. Now you can execute "isapnp /etc/isapnp.conf". No errors should be reported. If you correctly installed isapnptools, then isapnp will run every boot time. diff -ur --new-file old/linux/Documentation/sound/AudioExcelDSP16 new/linux/Documentation/sound/AudioExcelDSP16 --- old/linux/Documentation/sound/AudioExcelDSP16 Thu Jan 7 17:41:55 1999 +++ new/linux/Documentation/sound/AudioExcelDSP16 Thu Apr 29 20:53:41 1999 @@ -80,7 +80,7 @@ 2) Install your new kernel as the default boot kernel. 3) Boot MS-DOS and configure the audio card with the boot time device driver, for MSS irq10 dma3 in our example. -4) -- and boot Linux. This will mantain the DOS configuration +4) -- and boot Linux. This will maintain the DOS configuration and will boot the new kernel with sound driver. The sound driver will find the audio card and will recognize and attach it. diff -ur --new-file old/linux/Documentation/sound/CMI8330 new/linux/Documentation/sound/CMI8330 --- old/linux/Documentation/sound/CMI8330 Thu Jan 1 01:00:00 1970 +++ new/linux/Documentation/sound/CMI8330 Mon Mar 8 00:22:06 1999 @@ -0,0 +1,86 @@ +How to enable CMI 8330 soundchip on Linux +------------------------------------------ +Stefan Laudat + +Hello folks, + + The CMI8330 soundchip is a very small chip found on many recent + motherboards. In order to use it you just have to use a proper + isapnp.conf and a little bit of patience. + + Of course you will have to compile kernel sound support as module, + as shown below: + +CONFIG_SOUND=m +CONFIG_SOUND_OSS=m +CONFIG_SOUND_SB=m +CONFIG_SOUND_ADLIB=m +CONFIG_SOUND_MPU401=m +# Just for fun :) +CONFIG_SOUND_MSS=m + + The /etc/isapnp.conf file will be: + + + +(READPORT 0x0203) +(ISOLATE PRESERVE) +(IDENTIFY *) +(VERBOSITY 2) +(CONFLICT (IO FATAL)(IRQ FATAL)(DMA FATAL)(MEM FATAL)) # or WARNING +(VERIFYLD N) +# WSS + +(CONFIGURE CMI0001/16777472 (LD 0 +(IO 0 (SIZE 8) (BASE 0x0530)) +(IO 1 (SIZE 8) (BASE 0x0388)) +(INT 0 (IRQ 5 (MODE +E))) +(DMA 0 (CHANNEL 0)) +(NAME "CMI0001/16777472[0]{CMI8330/C3D Audio Adapter}") +(ACT Y) +)) + +# Control device ? + +(CONFIGURE CMI0001/16777472 (LD 1 +(IO 0 (SIZE 2) (BASE 0x0330)) +(INT 0 (IRQ 11 (MODE +E))) +(NAME "CMI0001/16777472[1]{CMI8330/C3D Audio Adapter}") +(ACT Y) +)) + +# Joystick + +(CONFIGURE CMI0001/16777472 (LD 2 +(IO 0 (SIZE 8) (BASE 0x0200)) +(NAME "CMI0001/16777472[2]{CMI8330/C3D Audio Adapter}") +(ACT Y) +)) + +# SB... +(CONFIGURE CMI0001/16777472 (LD 3 +(IO 0 (SIZE 16) (BASE 0x0220)) +(INT 0 (IRQ 7 (MODE +E))) +(DMA 0 (CHANNEL 1)) +(DMA 1 (CHANNEL 5)) +(NAME "CMI0001/16777472[3]{CMI8330/C3D Audio Adapter}") +(ACT Y) +)) + + +(WAITFORKEY) + + + + The module sequence is trivial: + +/sbin/modprobe sound +# You need to load the ad1848 module first. That matters, otherwise the +# chip falls into soundblaster compatibility and you won't get it back out +/sbin/insmod ad1848 io=0x530 dma=0 irq=5 soundpro=1 +/sbin/insmod uart401 +/sbin/insmod sb io=0x220 irq=5 dma=1 dma16=-1 +/sbin/insmod mpu401 io=0x330 +/sbin/insmod opl3 io=0x388 + + The soundchip is now fully initialized. Enjoy it. diff -ur --new-file old/linux/Documentation/sound/ChangeLog.awe new/linux/Documentation/sound/ChangeLog.awe --- old/linux/Documentation/sound/ChangeLog.awe Wed Dec 16 21:52:00 1998 +++ new/linux/Documentation/sound/ChangeLog.awe Thu Apr 29 20:53:41 1999 @@ -81,7 +81,7 @@ ver.0.3.3b - Fix version number in awe_version.h - - Fix a small bug in noteoff/relese all + - Fix a small bug in noteoff/release all ver.0.3.3a - Fix all notes/sounds off diff -ur --new-file old/linux/Documentation/sound/ESS new/linux/Documentation/sound/ESS --- old/linux/Documentation/sound/ESS Thu Jan 1 01:00:00 1970 +++ new/linux/Documentation/sound/ESS Mon Feb 1 23:04:39 1999 @@ -0,0 +1,33 @@ +Documentation for the ESS AudioDrive chips + +In 2.2 kernels the SoundBlaster driver not only tries to detect an ESS chip, it +tries to detect the type of ESS chip too. The correct detection of the chip +doesn't always succeed however, so the default behaviour is 2.0 behaviour +which means: only detect ES688 and ES1688. + +All ESS chips now have a recording level setting. This is a need-to-have for +people who want to use their ESS for recording sound. + +Every chip that's detected as a later-than-es1688 chip has a 6 bits logarithmic +master volume control. + +Every chip that's detected as a ES1887 now has Full Duplex support. Made a +little testprogram that showes that is works, haven't seen a real program that +needs this however. + +For ESS chips an additional parameter "esstype" can be specified. This controls +the (auto) detection of the ESS chips. It can have 3 kinds of values: + +-1 Act like 2.0 kernels: only detect ES688 or ES1688. +0 Try to auto-detect the chip (may fail for ES1688) +688 The chip will be treated as ES688 +1688 ,, ,, ,, ,, ,, ,, ES1688 +1868 ,, ,, ,, ,, ,, ,, ES1868 +1869 ,, ,, ,, ,, ,, ,, ES1869 +1788 ,, ,, ,, ,, ,, ,, ES1788 +1887 ,, ,, ,, ,, ,, ,, ES1887 +1888 ,, ,, ,, ,, ,, ,, ES1888 + +Because Full Duplex is supported for ES1887 you can specify a second DMA +channel by specifying module parameter dma16. It can be one of: 0, 1, 3 or 5. + diff -ur --new-file old/linux/Documentation/sound/INSTALL.awe new/linux/Documentation/sound/INSTALL.awe --- old/linux/Documentation/sound/INSTALL.awe Wed Dec 16 21:52:00 1998 +++ new/linux/Documentation/sound/INSTALL.awe Thu Apr 29 20:53:41 1999 @@ -17,7 +17,7 @@ http://www-jcr.lmh.ox.ac.uk/~pnp/ ---------------------------------------------------------------- -* Installation on RedHat 5.0 Sound Driver +* Installation on Red Hat 5.0 Sound Driver Please use install-rh.sh under RedHat5.0 directory. DO NOT USE install.sh below. @@ -31,7 +31,7 @@ % su 2. If you have never configured the kernel tree yet, run make config - once (to make depencies and symlinks). + once (to make dependencies and symlinks). # cd /usr/src/linux # make xconfig @@ -40,7 +40,7 @@ # sh ./install.sh - 4. Configure your kenrel + 4. Configure your kernel (for Linux 2.[01].x user) # cd /usr/src/linux @@ -77,7 +77,7 @@ do it by isapnp tools. Otherwise, skip to 8. This section described only a brief explanation. For more - detaills, please see AWE64-Mini-HOWTO or isapnp tools FAQ. + details, please see the AWE64-Mini-HOWTO or isapnp tools FAQ. 7a. If you have no isapnp.conf file, generate it by pnpdump. Otherwise, skip to 7d. diff -ur --new-file old/linux/Documentation/sound/Introduction new/linux/Documentation/sound/Introduction --- old/linux/Documentation/sound/Introduction Wed Dec 16 21:52:00 1998 +++ new/linux/Documentation/sound/Introduction Thu Apr 29 20:53:41 1999 @@ -214,7 +214,7 @@ 3) In /etc/conf.modules when using modprobe. -4) Via RedHat's /usr/sbin/sndconfig program (text based). +4) Via Red Hat's /usr/sbin/sndconfig program (text based). 5) Via the OSS soundconf program (with the commercial version of the OSS driver. @@ -240,7 +240,7 @@ 6) The comments and code in linux/drivers/sound. -7) The sndconfig and rhsound documentation from RedHat. +7) The sndconfig and rhsound documentation from Red Hat. 8) The Linux-sound mailing list: sound-list@redhat.com diff -ur --new-file old/linux/Documentation/sound/MAD16 new/linux/Documentation/sound/MAD16 --- old/linux/Documentation/sound/MAD16 Thu Apr 9 00:34:23 1998 +++ new/linux/Documentation/sound/MAD16 Thu Apr 29 20:53:41 1999 @@ -23,3 +23,12 @@ alias char-major-14 mad16 options sb mad16=1 options mad16 io=0x530 irq=7 dma=0 dma16=1 && /usr/local/bin/aumix -w 15 -p 20 -m 0 -1 0 -2 0 -3 0 -i 0 + + +To get the built in mixer to work this needs to be: + +options adlib_card io=0x388 # FM synthesizer +options sb mad16=1 +options mad16 io=0x530 irq=7 dma=0 dma16=1 mpu_io=816 mpu_irq=5 && /usr/local/bin/aumix -w 15 -p 20 -m 0 -1 0 -2 0 -3 0 -i 0 + +The addition of the "mpu_io=816 mpu_irq=5" to the mad16 options line is diff -ur --new-file old/linux/Documentation/sound/OPL3-SA new/linux/Documentation/sound/OPL3-SA --- old/linux/Documentation/sound/OPL3-SA Sun Aug 9 21:15:49 1998 +++ new/linux/Documentation/sound/OPL3-SA Thu Apr 29 20:53:41 1999 @@ -2,8 +2,7 @@ --- Note: This howto only describes how to setup the OPL3-SA1 chip; this info -does not apply to the SA2, SA3, or SA4. Contact hannu@opensound.com for -the support details of these other SAx chips. +does not apply to the SA2, SA3, or SA4. --- The Yamaha OPL3-SA1 sound chip is usually found built into motherboards, and @@ -16,7 +15,7 @@ You'll need to know all of the relevant info (irq, dma, and io port) for the chip's WSS mode, since that is the mode the kernel sound driver uses, and of course you'll also need to know about where the MPU401 and OPL3 ports and -irq's are if you want to use those. +IRQs are if you want to use those. Here's the skinny on how to load it as a module: @@ -25,14 +24,14 @@ Module options in detail: io: This is the WSS's port base. - irq: This is the WSS's irq. - dma: This is the WSS's dma line. In my BIOS setup screen this was + irq: This is the WSS's IRQ. + dma: This is the WSS's DMA line. In my BIOS setup screen this was listed as "WSS Play DMA" - dma2: This is the WSS's secondary dma line. My BIOS calls it the + dma2: This is the WSS's secondary DMA line. My BIOS calls it the "WSS capture DMA" mpu_io: This is the MPU401's port base. - mpu_irq: This is the MPU401's irq. + mpu_irq: This is the MPU401's IRQ. If you'd like to use the OPL3 FM Synthesizer, make sure you enable CONFIG_YM3812 (in 'make config'). That'll build the opl3.o module. @@ -44,7 +43,7 @@ Say 'y' or 'm' to "SoftOSS software wave table engine" in make config. -If you said yes, the software synth is availible once you boot your new +If you said yes, the software synth is available once you boot your new kernel. If you chose to build it as a module, just insmod the resulting softoss2.o diff -ur --new-file old/linux/Documentation/sound/PCM1-pro new/linux/Documentation/sound/PCM1-pro --- old/linux/Documentation/sound/PCM1-pro Thu Jan 1 01:00:00 1970 +++ new/linux/Documentation/sound/PCM1-pro Tue Apr 13 01:18:27 1999 @@ -0,0 +1,17 @@ +In Documentation/sound/README.OSS was a remark saying noone was sure the +mixer on the PCM1-pro worked with the ACI driver. Well, it does. +I've been using the drivers for the MAD16 and the driver for the mixer +since kernel 2.0.32 with a MiroSound PCM1-pro and it works great. + +I've got it working with the following configuration: + +MAD16 audio I/O base = 530 +MAD16 audio IRQ = 7 +MAD16 Audio DMA = 1 +MAD16 MIDI I/O = 330 +MAD16 MIDI IRQ = 9 + +And I've enabled the ACI mixer (miro PCM12) . + + +Bas van der Linden. diff -ur --new-file old/linux/Documentation/sound/README.OSS new/linux/Documentation/sound/README.OSS --- old/linux/Documentation/sound/README.OSS Mon Jan 18 03:23:01 1999 +++ new/linux/Documentation/sound/README.OSS Thu Apr 29 20:53:41 1999 @@ -58,7 +58,7 @@ Mika Liljeberg uLaw encoding and decoding routines Jeff Tranter Linux SOUND HOWTO document Greg Lee Volume computation algorithm for the GUS and - lot's of valuable suggestions. + lots of valuable suggestions. Andy Warner ISC port Jim Lowe, Amancio Hasty Jr FreeBSD/NetBSD port @@ -96,7 +96,7 @@ or before even starting to do any work. Tell me what you suggest to be changed or what you have planned to do. Also ensure you are using the very latest (development) version of OSS/Free since the change may already be -implemented there. In general it's major waste of time to try to improve +implemented there. In general it's a major waste of time to try to improve a several months old version. Information about the latest version can be found from http://www.opensound.com/ossfree. In general there is no point in sending me patches relative to production kernels. @@ -1314,8 +1314,8 @@ This ESS proprietary feature is supported only by OSS/Linux. There are ES1688 based cards which use different interrupt pin assignment than -recommended by ESS (5, 7, 9/2 and 10). In this case all IRQ's don't work. -At least a card called (Pearl?) Hypersound 16 supports IRQ15 but it doesn't +recommended by ESS (5, 7, 9/2 and 10). In this case all IRQs don't work. +At least a card called (Pearl?) Hypersound 16 supports IRQ 15 but it doesn't work. ES1868 is a PnP chip which is (supposed to be) compatible with ESS1688 diff -ur --new-file old/linux/Documentation/sound/README.awe new/linux/Documentation/sound/README.awe --- old/linux/Documentation/sound/README.awe Wed Dec 16 21:52:00 1998 +++ new/linux/Documentation/sound/README.awe Thu Apr 29 20:53:41 1999 @@ -9,8 +9,8 @@ This is a sound driver extension for SoundBlaster AWE32 and other compatible cards (AWE32-PnP, SB32, SB32-PnP, AWE64 & etc) to enable -the wave synth operations. The driver is provided for both Linux -1.2.x and 2.[01].x kernels, and also FreeBSD, on Intel x86 and DEC +the wave synth operations. The driver is provided for Linux 1.2.x +and 2.[012].x kernels, as well as FreeBSD, on Intel x86 and DEC Alpha systems. This driver was written by Takashi Iwai , @@ -76,7 +76,7 @@ % sfxload synthgm % drvmidi -L 2mbgmgs foo.mid -This makes a big differece (believe me)! For more details, please +This makes a big difference (believe me)! For more details, please refer to the FAQ list which is available on the URL above. The current chorus, reverb and equalizer status can be changed by @@ -97,14 +97,14 @@ shell script. - AWE_MODULE_SUPPORT - indicates your linux kernel supports module for each soundcard - (in recent 2.1 kernels and unofficial patched 2.0 kernels as - distributed in the RH5.0 package). + indicates your Linux kernel supports module for each sound card + (in recent 2.1 or 2.2 kernels and unofficial patched 2.0 kernels + as distributed in the RH5.0 package). This flag is automatically set when you're using 2.1.x kernels. You can pass the base address and memory size via the following module options, io = base I/O port address (eg. 0x620) - memsize = DRAM size in Kbyes (eg. 512) + memsize = DRAM size in kilobytes (eg. 512) As default, AWE driver probes these values automatically. @@ -117,15 +117,15 @@ 0 means to autodetect the address. - AWE_DEFAULT_MEM_SIZE (default: not defined) - specifies the memory size of your AWE32 card in kilo bytes. + specifies the memory size of your AWE32 card in kilobytes. -1 means to autodetect its size. [Sample Table Size] From ver.0.4.0, sample tables are allocated dynamically (except Linux-1.2.x system), so you need NOT to touch these parameters. -Linux-1.2.x users may need to increase these values to apropriate size -if larger DRAM is equipped with the soundcard. +Linux-1.2.x users may need to increase these values to appropriate size +if the sound card is equipped with more DRAM. - AWE_MAX_SF_LISTS, AWE_MAX_SAMPLES, AWE_MAX_INFOS @@ -139,7 +139,7 @@ passthrough channels. - AWE_DEBUG_ON (default: defined) - turns on debuggin messages if defined. + turns on debugging messages if defined. - AWE_HAS_GUS_COMPATIBILITY (default: defined) Enables GUS compatibility mode if defined, reading GUS patches and @@ -170,7 +170,7 @@ - AWE_ALLOW_SAMPLE_SHARING (default: defined) Allow sample sharing for differently loaded patches. This function is available only together with awesfx-0.4.3p3. - Note that this is still an experimantal option. + Note that this is still an experimental option. - DEF_FM_CHORUS_DEPTH (default: 0x10) The default strength to be sent to the chorus effect engine. @@ -183,8 +183,8 @@ * ACKNOWLEDGMENTS -Thanks to Witold Jachimczyk (witek@xfactor.wpi.edu) for many advices -to programming of AWE32. Many codes are brought from his AWE32-native +Thanks to Witold Jachimczyk (witek@xfactor.wpi.edu) for much advice +on programming of AWE32. Much code is brought from his AWE32-native MOD player, ALMP. The port of awedrv to FreeBSD is done by Randall Hopper (rhh@ct.picker.com). diff -ur --new-file old/linux/Documentation/sound/VIBRA16 new/linux/Documentation/sound/VIBRA16 --- old/linux/Documentation/sound/VIBRA16 Thu Jan 1 01:00:00 1970 +++ new/linux/Documentation/sound/VIBRA16 Mon Mar 8 00:22:06 1999 @@ -0,0 +1,80 @@ +Sound Blaster 16X Vibra addendum +-------------------------------- +by Marius Ilioaea + Stefan Laudat + +Sat Mar 6 23:55:27 EET 1999 + + Hello again, + + Playing with a SB Vibra 16x soundcard we found it very difficult +to setup because the kernel reported a lot of DMA errors and wouldn't +simply play any sound. + A good starting point is that the vibra16x chip full-duplex facility +is neither still exploited by the sb driver found in the linux kernel +(tried it with a 2.2.2-ac7), nor in the commercial OSS package (it reports +it as half-duplex soundcard). Oh, I almost forgot, the RedHat sndconfig +failed detecting it ;) + So, the big problem still remains, because the sb module wants a +8-bit and a 16-bit dma, which we could not allocate for vibra... it supports +only two 8-bit dma channels, the second one will be passed to the module +as a 16 bit channel, the kernel will yield about that but everything will +be okay, trust us. + The only inconvenient you may find is that you will have +some sound playing jitters if you have HDD dma support enabled - but this +will happen with almost all soundcards... + + A fully working isapnp.conf is just here: + + + +(READPORT 0x0203) +(ISOLATE PRESERVE) +(IDENTIFY *) +(VERBOSITY 2) +(CONFLICT (IO FATAL)(IRQ FATAL)(DMA FATAL)(MEM FATAL)) # or WARNING +# SB 16 and OPL3 devices +(CONFIGURE CTL00f0/-1 (LD 0 +(INT 0 (IRQ 5 (MODE +E))) +(DMA 0 (CHANNEL 1)) +(DMA 1 (CHANNEL 3)) +(IO 0 (SIZE 16) (BASE 0x0220)) +(IO 2 (SIZE 4) (BASE 0x0388)) +(NAME "CTL00f0/-1[0]{Audio }") +(ACT Y) +)) + +# Joystick device - only if you need it :-/ + +(CONFIGURE CTL00f0/-1 (LD 1 +(IO 0 (SIZE 1) (BASE 0x0200)) +(NAME "CTL00f0/-1[1]{Game }") +(ACT Y) +)) +(WAITFORKEY) + + + + So, after a good kernel modules compilation and a 'depmod -a kernel_ver' +you may want to: + +modprobe sb io=0x220 irq=5 dma=1 dma16=3 + + Or, take the hard way: + +insmod souncore +insmod sound +insmod uart401 +insmod sb io=0x220 irq=5 dma=1 dma16=3 +# do you need MIDI? +insmod opl3=0x388 + + Just in case, the kernel sound support should be: + +CONFIG_SOUND=m +CONFIG_SOUND_OSS=m +CONFIG_SOUND_SB=m + + Enjoy your new noisy Linux box! ;) + + diff -ur --new-file old/linux/Documentation/sound/Wavefront new/linux/Documentation/sound/Wavefront --- old/linux/Documentation/sound/Wavefront Fri Sep 11 01:37:25 1998 +++ new/linux/Documentation/sound/Wavefront Thu Apr 29 20:53:41 1999 @@ -149,7 +149,7 @@ . . . - make modules_isntall + make modules_install Here's my autoconf.h SOUND section: diff -ur --new-file old/linux/Documentation/sound/mwave new/linux/Documentation/sound/mwave --- old/linux/Documentation/sound/mwave Fri Jul 10 23:03:35 1998 +++ new/linux/Documentation/sound/mwave Tue Apr 13 01:18:27 1999 @@ -1,14 +1,8 @@ How to try to survive an IBM Mwave under Linux SB drivers -* IBM refuses to provide documentation. If anyone can ever find out what - MWD50430.EXE actually does to load firmware then this comedy could go - away. - -* If you'd like to ask IBM why they don't release Mwave information. - phone IBM (425-556-8822) and ask them why they still haven't - released any documentation. - [http://204.200.238.31/cgi-bin/link.pl?co=i&cl=/ts/ibm/contact.html] ++ IBM have now released documentation of sorts and Torsten is busy + trying to make the Mwave work. This is not however a trivial task. ---------------------------------------------------------------------------- diff -ur --new-file old/linux/Documentation/stallion.txt new/linux/Documentation/stallion.txt --- old/linux/Documentation/stallion.txt Fri Oct 23 17:26:03 1998 +++ new/linux/Documentation/stallion.txt Sun Mar 28 19:02:27 1999 @@ -2,10 +2,10 @@ Stallion Multiport Serial Driver Readme --------------------------------------- -Copyright (C) 1994-1998, Stallion Technologies (support@stallion.com). +Copyright (C) 1994-1999, Stallion Technologies (support@stallion.com). -Version: 5.4.7 -Date: 23OCT98 +Version: 5.5.1 +Date: 28MAR99 @@ -15,28 +15,28 @@ multiport serial boards. One is for the Stallion smart boards - that is EasyIO, EasyConnection 8/32 and EasyConnection 8/64-PCI, the other for the true Stallion intelligent multiport boards - EasyConnection 8/64 -(ISA and EISA), ONboard and Brumby. +(ISA, EISA, MCA), EasyConnection/RA-PCI, ONboard and Brumby. If you are using any of the Stallion intelligent multiport boards (Brumby, -ONboard, EasyConnection 8/64 (ISA or EISA)) with Linux you will need to -get the driver utility package. This package is available at most of the -Linux archive sites (and on CD-ROMs that contain these archives). The file -will be called stallion-X.X.X.tar.gz where X.X.X will be the version -number. In particular this package contains the board embedded executable -images that are required for these boards. It also contains the downloader -program. These boards cannot be used without this. +ONboard, EasyConnection 8/64 (ISA, EISA, MCA), EasyConnection/RA-PCI) with +Linux you will need to get the driver utility package. This package is +available at most of the Linux archive sites (and on CD-ROMs that contain +these archives). The file will be called stallion-X.X.X.tar.gz where X.X.X +will be the version number. In particular this package contains the board +embedded executable images that are required for these boards. It also +contains the downloader program. These boards cannot be used without this. The Stallion Technologies ftp site, ftp.stallion.com, will always have the latest version of the driver utility package. Other sites that usually have the latest version are tsx-11.mit.edu, sunsite.unc.edu and their mirrors. -ftp.stallion.com:/drivers/ata5/Linux/v544.tar.gz -tsx-11.mit.edu:/pub/linux/packages/stallion/stallion-5.4.4.tar.gz -sunsite.unc.edu:/pub/Linux/kernel/patches/serial/stallion-5.4.4.tar.gz +ftp.stallion.com:/drivers/ata5/Linux/v550.tar.gz +tsx-11.mit.edu:/pub/linux/packages/stallion/stallion-5.5.0.tar.gz +sunsite.unc.edu:/pub/Linux/kernel/patches/serial/stallion-5.5.0.tar.gz As of the printing of this document the latest version of the driver -utility package is 5.4.4. If a later version is now available then you +utility package is 5.5.0. If a later version is now available then you should use the latest version. If you are using the EasyIO, EasyConnection 8/32 or EasyConnection 8/64-PCI @@ -44,7 +44,7 @@ script to create the /dev device nodes for these boards, and a serial stats display program. -If you require DIP switch settings, EISA/MCA configuration files, or any +If you require DIP switch settings, EISA or MCA configuration files, or any other information related to Stallion boards then have a look at Stallion's web pages at http://www.stallion.com. @@ -55,12 +55,101 @@ The drivers can be used as loadable modules or compiled into the kernel. You can choose which when doing a "config" on the kernel. -All ISA, EISA and MCA boards that you want to use need to be entered into -the driver(s) configuration structures. All PCI boards will be automatically -detected when you load the driver - so they do not need to be entered into -the driver(s) configuration structure. (Note that kernel PCI BIOS32 support -is required to use PCI boards.) +All ISA, EISA and MCA boards that you want to use need to be configured into +the driver(s). All PCI boards will be automatically detected when you load +the driver - so they do not need to be entered into the driver(s) +configuration structure. Note that kernel PCI support is required to use PCI +boards. +There are two methods of configuring ISA, EISA and MCA boards into the drivers. +If using the driver as a loadable module then the simplist method is to pass +the driver configuration as module arguments. The other method is to modify +the driver source to add configuration lines for each board in use. + +If you have pre-built Stallion driver modules then the module argument +configuration method should be used. A lot of Linux distributions come with +pre-built driver modules in /lib/modules/X.Y.Z/misc for the kernel in use. +That makes things pretty simple to get going. + + +2.1 MODULE DRIVER CONFIGURATION: + +The simplest configuration for modules is to use the module load arguments +to configure any ISA, EISA or MCA boards. PCI boards are automatically +detected, so do not need any additional configuration at all. + +If using EasyIO, EasyConnection 8/32 ISA or MCA, or EasyConnection 8/63-PCI +boards then use the "stallion" driver module, Otherwise if you are using +an EasyConnection 8/64 ISA, EISA or MCA, EasyConnection/RA-PCI, ONboard, +Brumby or original Stallion board then use the "istallion" driver module. + +Typically to load up the smart board driver use: + + insmod stallion.o + +This will load the EasyIO and EasyConnection 8/32 driver. It will output a +message to say that it loaded and print the driver version number. It will +also print out whether it found the configured boards or not. These messages +may not appear on the console, but typically are always logged to +/var/adm/messages or /var/log/syslog files - depending on how the klogd and +syslogd daemons are setup on your system. + +To load the intelligent board driver use: + + insmod istallion.o + +It will output similar messages to the smart board driver. + +If not using an auto-detectable board type (that is a PCI board) then you +will also need to supply command line arguments to the "insmod" command +when loading the driver. The general form of the configuration argument is + + board?=[,[,][,]] + +where: + + board? -- specifies the arbitary board number of this board, + can be in the range 0 to 3. + + name -- textual name of this board. The board name is the comman + board name, or any "shortened" version of that. The board + type number may also be used here. + + ioaddr -- specifies the I/O address of this board. This argument is + optional, but should generally be specified. + + addr -- optional second address argument. Some board types require + a second I/O address, some require a memory address. The + exact meaning of this argument depends on the board type. + + irq -- optional IRQ line used by this board. + +Up to 4 board configuration arguments can be specified on the load line. +Here is some examples: + + insmod stallion.o board0=easyio,0x2a0,5 + +This configures an EasyIO board as board 0 at I/O address 0x2a0 and IRQ 5. + + insmod istallion.o board3=ec8/64,0x2c0,0xcc000 + +This configures an EasyConnection 8/64 ISA as board 3 at I/O address 0x2c0 at +memory address 0xcc000. + + insmod stallion.o board1=ec8/32-at,0x2a0,0x280,10 + +This configures an EasyConnection 8/32 ISA board at primary I/O address 0x2a0, +secondary address 0x280 and IRQ 10. + +You will probably want to enter this module load and configuration information +into your system startup scripts so that the drivers are loaded and configured +on each system boot. Typically the start up script would be something line +/etc/rc.d/rc.modules. + + +2.2 STATIC DRIVER CONFIGURATION: + +For static driver configuration you need to modify the driver source code. Entering ISA, EISA and MCA boards into the driver(s) configuration structure involves editing the driver(s) source file. It's pretty easy if you follow the instructions below. Both drivers can support up to 4 boards. The smart @@ -96,14 +185,16 @@ driver will emit some kernel trace messages about whether the configured boards were detected or not. Depending on how your system logger is set up these may come out on the console, or just be logged to -/var/adm/messages. You should check the messages to confirm that all is well. +/var/adm/messages or /var/log/syslog. You should check the messages to +confirm that all is well. -2.1 SHARING INTERRUPTS +2.3 SHARING INTERRUPTS It is possible to share interrupts between multiple EasyIO and -EasyConnection 8/32 boards in an EISA system. To do this you will need to -do a couple of things: +EasyConnection 8/32 boards in an EISA system. To do this you must be using +static driver configuration, modifying the driver source code to add driver +configuration. Then a couple of extra things are required: 1. When entering the board resources into the stallion.c file you need to mark the boards as using level triggered interrupts. Do this by replacing @@ -130,7 +221,7 @@ sharing interrupts. -2.2 USING HIGH SHARED MEMORY +2.4 USING HIGH SHARED MEMORY The EasyConnection 8/64-EI, ONboard and Stallion boards are capable of using shared memory addresses above the usual 640K - 1Mb range. The ONboard @@ -145,16 +236,18 @@ -2.3 TROUBLE SHOOTING +2.5 TROUBLE SHOOTING If a board is not found by the driver but is actually in the system then the -most likely problem is that the I/O address is wrong. Change it in the driver -stallion.c or istallion.c configuration structure and rebuild the kernel or -modules, or change it on the board. On EasyIO and EasyConnection 8/32 boards -the IRQ is software programmable, so if there is a conflict you may need to -change the IRQ used for a board in the stallion.c configuration structure. -There are no interrupts to worry about for ONboard, Brumby or EasyConnection -8/64 (ISA, EISA and MCA) boards. The memory region on EasyConnection 8/64 and +most likely problem is that the I/O address is wrong. Change the module load +argument for the loadable module form. Or change it in the driver stallion.c +or istallion.c configuration structure and rebuild the kernel or modules, or +change it on the board. + +On EasyIO and EasyConnection 8/32 boards the IRQ is software programmable, so +if there is a conflict you may need to change the IRQ used for a board. There +are no interrupts to worry about for ONboard, Brumby or EasyConnection 8/64 +(ISA, EISA and MCA) boards. The memory region on EasyConnection 8/64 and ONboard boards is software programmable, but not on the Brumby boards. @@ -167,9 +260,13 @@ to them. This is done via a user level application supplied in the driver utility package called "stlload". Compile this program wherever you dropped the package files, by typing "make". In its simplest form you can then type + ./stlload -i cdk.sys + in this directory and that will download board 0 (assuming board 0 is an -EasyConnection 8/64 board). To download to an ONboard, Brumby or Stallion do: +EasyConnection 8/64 or EasyConnection/RA board). To download to an +ONboard, Brumby or Stallion do: + ./stlload -i 2681.sys Normally you would want all boards to be downloaded as part of the standard @@ -182,6 +279,7 @@ and put the cdk.sys and 2681.sys files in it. (It's a convenient place to put them anyway). As an example your /etc/rc.d/rc.S file might have the following lines added to it (if you had 3 boards): + /usr/sbin/stlload -b 0 -i /usr/lib/stallion/cdk.sys /usr/sbin/stlload -b 1 -i /usr/lib/stallion/2681.sys /usr/sbin/stlload -b 2 -i /usr/lib/stallion/2681.sys diff -ur --new-file old/linux/Documentation/sysctl/README new/linux/Documentation/sysctl/README --- old/linux/Documentation/sysctl/README Thu Jan 7 17:41:55 1999 +++ new/linux/Documentation/sysctl/README Mon Apr 12 19:10:27 1999 @@ -1,5 +1,5 @@ -Documentation for /proc/sys/ kernel version 2.1.128 - (c) 1998, Rik van Riel +Documentation for /proc/sys/ kernel version 2.2.5 + (c) 1998, 1999, Rik van Riel 'Why', I hear you ask, 'would anyone even _want_ documentation for them sysctl files? If anybody really needs it, it's all in @@ -12,9 +12,6 @@ Furthermore, the programmers who built sysctl have built it to be actually used, not just for the fun of programming it :-) -If you prefer HTML, feel free to visit the Linux-MM homepage -... - ============================================================== Legal blurb: @@ -34,7 +31,7 @@ you're the last RTFMing person to screw up. In short, e-mail your suggestions, corrections and / or horror -stories to: +stories to: Rik van Riel. @@ -68,6 +65,7 @@ net/ networking stuff, for documentation look in: proc/ +sunrpc/ SUN Remote Procedure Call (NFS) vm/ memory management tuning buffer and cache management diff -ur --new-file old/linux/Documentation/sysctl/fs.txt new/linux/Documentation/sysctl/fs.txt --- old/linux/Documentation/sysctl/fs.txt Fri Nov 13 19:07:26 1998 +++ new/linux/Documentation/sysctl/fs.txt Mon Apr 12 19:10:27 1999 @@ -1,12 +1,12 @@ -Documentation for /proc/sys/fs/* kernel version 2.1.128 - (c) 1998, Rik van Riel +Documentation for /proc/sys/fs/* kernel version 2.2.5 + (c) 1998, 1999, Rik van Riel For general info and legal blurb, please look in README. ============================================================== This file contains documentation for the sysctl files in -/proc/sys/fs/ and is valid for Linux kernel version 2.1. +/proc/sys/fs/ and is valid for Linux kernel version 2.2. The files in this directory can be used to tune and monitor miscellaneous and general things in the operation of the Linux @@ -23,6 +23,8 @@ - inode-max - inode-nr - inode-state +- super-max +- super-nr Documentation for the files in /proc/sys/fs/binfmt_misc is in Documentation/binfmt_misc.txt. @@ -113,4 +115,12 @@ system needs to prune the inode list instead of allocating more. +============================================================== + +super-max & super-nr: +These numbers control the maximum number of superblocks, and +thus the maximum number of mounted filesystems the kernel +can have. You only need to increase super-max if you need to +mount more filesystems than the current value in super-max +allows you to. diff -ur --new-file old/linux/Documentation/sysctl/kernel.txt new/linux/Documentation/sysctl/kernel.txt --- old/linux/Documentation/sysctl/kernel.txt Thu Dec 31 20:55:19 1998 +++ new/linux/Documentation/sysctl/kernel.txt Mon Apr 12 19:10:27 1999 @@ -1,12 +1,12 @@ -Documentation for /proc/sys/kernel/* kernel version 2.1.128 - (c) 1998, Rik van Riel +Documentation for /proc/sys/kernel/* kernel version 2.2.5 + (c) 1998, 1999, Rik van Riel For general info and legal blurb, please look in README. ============================================================== This file contains documentation for the sysctl files in -/proc/sys/kernel/ and is valid for Linux kernel version 2.1. +/proc/sys/kernel/ and is valid for Linux kernel version 2.2. The files in this directory can be used to tune and monitor miscellaneous and general things in the operation of the Linux @@ -24,6 +24,7 @@ - htab-reclaim [ PPC only ] - java-appletviewer [ binfmt_java, obsolete ] - java-interpreter [ binfmt_java, obsolete ] +- l2cr [ PPC only ] - modprobe ==> Documentation/kmod.txt - osrelease - ostype @@ -32,6 +33,8 @@ - printk - real-root-dev ==> Documentation/initrd.txt - reboot-cmd [ SPARC only ] +- rtsig-nr +- rtsig-max - sg-big-buff [ generic SCSI device (sg) ] - shmmax [ sysv ipc ] - version @@ -90,6 +93,13 @@ ============================================================== +l2cr: (PPC only) + +This flag controls the L2 cache of G3 processor boards. If +0, the cache is disabled. Enabled if nonzero. + +============================================================== + osrelease, ostype & version: # cat osrelease @@ -152,6 +162,16 @@ ??? This seems to be a way to give an argument to the Sparc ROM/Flash boot loader. Maybe to tell it what to do after rebooting. ??? + +============================================================== + +rtsig-max & rtsig-nr: + +The file rtsig-max can be used to tune the maximum number +of POSIX realtime (queued) signals that can be outstanding +in the system. + +Rtsig-nr shows the number of RT signals currently queued. ============================================================== diff -ur --new-file old/linux/Documentation/sysctl/sunrpc.txt new/linux/Documentation/sysctl/sunrpc.txt --- old/linux/Documentation/sysctl/sunrpc.txt Thu Jan 1 01:00:00 1970 +++ new/linux/Documentation/sysctl/sunrpc.txt Mon Apr 12 19:10:27 1999 @@ -0,0 +1,20 @@ +Documentation for /proc/sys/sunrpc/* kernel version 2.2.5 + (c) 1998, 1999, Rik van Riel + +For general info and legal blurb, please look in README. + +============================================================== + +This file contains the documentation for the sysctl files in +/proc/sys/sunrpc and is valid for Linux kernel version 2.2. + +The files in this directory can be used to (re)set the debug +flags of the SUN Remote Procedure Call (RPC) subsystem in +the Linux kernel. This stuff is used for NFS, KNFSD and +maybe a few other things as well. + +The files in there are used to control the debugging flags: +rpc_debug, nfs_debug, nfsd_debug and nlm_debug. + +These flags are for kernel hackers only. You should read the +source code in net/sunrpc/ for more information. diff -ur --new-file old/linux/Documentation/sysctl/vm.txt new/linux/Documentation/sysctl/vm.txt --- old/linux/Documentation/sysctl/vm.txt Fri Nov 13 19:07:26 1998 +++ new/linux/Documentation/sysctl/vm.txt Thu Apr 29 20:53:41 1999 @@ -1,27 +1,30 @@ -Documentation for /proc/sys/vm/* kernel version 2.1.128 - (c) 1998, Rik van Riel +Documentation for /proc/sys/vm/* kernel version 2.2.5 + (c) 1998, 1999, Rik van Riel For general info and legal blurb, please look in README. ============================================================== This file contains the documentation for the sysctl files in -/proc/sys/vm and is valid for Linux kernel version 2.1. +/proc/sys/vm and is valid for Linux kernel version 2.2. The files in this directory can be used to tune the operation of the virtual memory (VM) subsystem of the Linux kernel, and one of the files (bdflush) also has a little influence on disk usage. +Default values and initialization routines for most of these +files can be found in mm/swap.c. + Currently, these files are in /proc/sys/vm: - bdflush - buffermem - freepages - kswapd - overcommit_memory +- page-cluster - pagecache - pagetable_cache -- swapctl ============================================================== @@ -100,12 +103,8 @@ The values are: min_percent -- this is the minimum percentage of memory that should be spent on buffer memory -borrow_percent -- when Linux is short on memory, and the - buffer cache uses more memory than this, - the MM subsystem will prune the buffercache - more heavily than other memory -max_percent -- this is the maximum amount of memory that - can be used for buffer memory +borrow_percent -- UNUSED +max_percent -- UNUSED ============================================================== freepages: @@ -162,40 +161,28 @@ overcommit_memory: -This file contains only one value. The following algorithm -is used to decide if there's enough memory. If the value -of overcommit_memory > 0, then there's always enough -memory :-). This is a useful feature, since programs often -malloc() huge amounts of memory 'just in case', while they -only use a small part of it. Leaving this value at 0 will -lead to the failure of such a huge malloc(), when in fact -the system has enough memory for the program to run... -On the other hand, enabling this feature can cause you to -run out of memory and thrash the system to death, so large -and/or important servers will want to set this value to 0. +This value contains a flag that enables memory overcommitment. +When this flag is 0, the kernel checks before each malloc() +to see if there's enough memory left. If the flag is nonzero, +the system pretends there's always enough memory. -From linux/mm/mmap.c: --------------------------------------------------------------- -static inline int vm_enough_memory(long pages) -{ - /* This stupid algorithm decides whether we have enough memory: - * while simple, it should work in most obvious cases. It's - * easily fooled, but this should catch most mistakes. - */ - long freepages; - - /* Sometimes we want to use more memory than we have. */ - if (sysctl_overcommit_memory) - return 1; - - freepages = buffermem >> PAGE_SHIFT; - freepages += page_cache_size; - freepages >>= 1; - freepages += nr_free_pages; - freepages += nr_swap_pages; - freepages -= num_physpages >> 4; - return freepages > pages; -} +This feature can be very useful because there are a lot of +programs that malloc() huge amounts of memory "just-in-case" +and don't much of it. + +Look at: mm/mmap.c::vm_enough_memory() for more information. + +============================================================== + +page-cluster: + +The Linux VM subsystem avoids excessive disk seeks by reading +multiple pages on a page fault. The number of pages it reads +is dependent on the amount of memory in your machine. + +The number of pages the kernel reads in at once is equal to +2 ^ page-cluster. Values above 2 ^ 5 don't make much sense +for swap because we only cluster swap data in 32-page groups. ============================================================== @@ -203,12 +190,17 @@ This file does exactly the same as buffermem, only this file controls the struct page_cache, and thus controls -the amount of memory allowed for memory mapping and generic -caching of files. +the amount of memory used for the page cache. -You don't want the minimum level to be too low, otherwise -your system might thrash when memory is tight or fragmentation -is high... +In 2.2, the page cache is used for 3 main purposes: +- caching read() data from files +- caching mmap()ed data and executable files +- swap cache + +When your system is both deep in swap and high on cache, +it probably means that a lot of the swaped data is being +cached, making for more efficient swapping than possible +with the 2.0 kernel. ============================================================== @@ -226,63 +218,4 @@ For large systems, the settings are probably OK. For normal systems they won't hurt a bit. For small systems (<16MB ram) it might be advantageous to set both values to 0. - -============================================================== - -swapctl: - -This file contains no less than 8 variables. -All of these values are used by kswapd, and the usage can be -found in linux/mm/vmscan.c. - -From linux/include/linux/swapctl.h: --------------------------------------------------------------- -typedef struct swap_control_v5 -{ - unsigned int sc_max_page_age; - unsigned int sc_page_advance; - unsigned int sc_page_decline; - unsigned int sc_page_initial_age; - unsigned int sc_age_cluster_fract; - unsigned int sc_age_cluster_min; - unsigned int sc_pageout_weight; - unsigned int sc_bufferout_weight; -} swap_control_v5; --------------------------------------------------------------- - -The first four variables are used to keep track of Linux's -page aging. Page aging is a bookkeeping method to keep track -of which pages of memory are used often, and which pages can -be swapped out without consequences. - -When a page is swapped in, it starts at sc_page_initial_age -(default 3) and when the page is scanned by kswapd, its age -is adjusted according to the following scheme: -- if the page was used since the last time we scanned, its - age is increased by sc_page_advance (default 3) up to a maximum - of sc_max_page_age (default 20) -- else (it wasn't used) its age is decreased by sc_page_decline - (default 1) -And when a page reaches age 0, it's ready to be swapped out. - -The next four variables can be used to control kswapd's -aggressiveness in swapping out pages. - -sc_age_cluster_fract is used to calculate how many pages from -a process are to be scanned by kswapd. The formula used is -sc_age_cluster_fract/1024 * RSS, so if you want kswapd to scan -the whole process, sc_age_cluster_fract needs to have a value -of 1024. The minimum number of pages kswapd will scan is -represented by sc_age_cluster_min, this is done so kswapd will -also scan small processes. - -The values of sc_pageout_weight and sc_bufferout_weight are -used to control how many tries kswapd will make in order -to swapout one page / buffer. These values can be used to -fine-tune the ratio between user pages and buffer/cache memory. -When you find that your Linux system is swapping out too many -process pages in order to satisfy buffer memory demands, you -might want to either increase sc_bufferout_weight, or decrease -the value of sc_pageout_weight. - diff -ur --new-file old/linux/Documentation/video4linux/bttv/INSTALL new/linux/Documentation/video4linux/bttv/INSTALL --- old/linux/Documentation/video4linux/bttv/INSTALL Sun Nov 8 23:36:46 1998 +++ new/linux/Documentation/video4linux/bttv/INSTALL Mon May 10 22:00:10 1999 @@ -38,9 +38,12 @@ 7: Matrix Vision MV-Delta 8: Fly Video II 9: TurboTV - 10: Newer Hauppage (Bt878) + 10: Newer Hauppauge (Bt878) 11: Miro PCTV Pro 12: ADS Tech Channel Surfer TV (and maybe TV+FM) + 13: AVerMedia TVCapture 98 + 14: Aimslab VHX + 15: Zoltrix TV-Max - You may have to adjust BTTV_MAJOR to a different number depending on your kernel version. The official number 81 does not work on some setups. diff -ur --new-file old/linux/Documentation/video4linux/bttv/README.FIRST new/linux/Documentation/video4linux/bttv/README.FIRST --- old/linux/Documentation/video4linux/bttv/README.FIRST Sun Aug 23 22:32:25 1998 +++ new/linux/Documentation/video4linux/bttv/README.FIRST Sat Feb 6 21:46:20 1999 @@ -1,4 +1,4 @@ o Please direct queries about the in kernel version of this driver to Alan Cox first not to Ralph, or better yet join the video4linux mailing - list (mail majordomo@phunk.org with "subscribe video4linux") + list (mail video4linux-list-request@redhat.com with "subscribe") diff -ur --new-file old/linux/MAINTAINERS new/linux/MAINTAINERS --- old/linux/MAINTAINERS Wed Jan 20 22:27:17 1999 +++ new/linux/MAINTAINERS Sat May 8 21:49:46 1999 @@ -229,8 +229,8 @@ DIGI INTL. EPCA DRIVER P: Daniel Taylor M: support@dgii.com -M: digilnux@dgii.com -L: digiboard@list.fuller.edu +M: danielt@dgii.com +L: digilnux@dgii.com S: Maintained DIGI RIGHTSWITCH NETWORK DRIVER @@ -246,6 +246,12 @@ L: linux-kernel@vger.rutgers.edu S: Maintained +DOUBLETALK DRIVER +P: James R. Van Zandt +M: jrv@vanzandt.mv.com +L: blinux-list@redhat.com +S: Maintained + EATA-DMA SCSI DRIVER P: Michael Neuffer M: mike@i-Connect.Net @@ -324,7 +330,7 @@ M: arobinso@nyx.net L: linux-kernel@vger.rutgers.edu W: http://www.nyx.net/~arobinso -S: Maintainted +S: Maintained HFS FILESYSTEM P: Adrian Sun @@ -389,7 +395,7 @@ P: Dag Brattli M: Dag Brattli L: linux-irda@list.uit.no -W: http://www.cs.uit.no/~dagb/irda/ +W: http://www.cs.uit.no/linux-irda/ S: Maintained ISDN SUBSYSTEM @@ -522,7 +528,7 @@ NETWORKING [IPv4/IPv6] P: David S. Miller -M: davem@dm.cobaltmicro.com +M: davem@redhat.com P: Andi Kleen M: ak@muc.de P: Alexey Kuznetsov @@ -530,6 +536,12 @@ L: netdev@roxanne.nuclecu.unam.mx S: Maintained +NFS CLIENT +P: Trond Myklebust +M: trond.myklebust@fys.uio.no +L: linux-kernel@vger.rutgers.edu +S: Maintained + NI5010 NETWORK DRIVER P: Jan-Pascal van Best and Andreas Mohr M: jvbest@qv3pluto.leidenuniv.nl (Best) @@ -631,6 +643,18 @@ L: linux-kernel@vger.rutgers.edu S: Maintained +SCSI SG DRIVER +P: Doug Gilbert +M: dgilbert@interlog.com +L: linux-scsi@vger.rutgers.edu +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 @@ -672,9 +696,18 @@ S: Supported SPARC: +P: David S. Miller +M: davem@redhat.com P: Eddie C. Dost M: ecd@skynet.be +P: Jakub Jelinek +M: jj@sunsite.ms.mff.cuni.cz +P: Anton Blanchard +M: anton@progsoc.uts.edu.au L: sparclinux@vger.rutgers.edu +L: ultralinux@vger.rutgers.edu +W: http://ultra.linux.cz +W: http://www.geog.ubc.ca/s_linux.html S: Maintained SPECIALIX IO8+ MULTIPORT SERIAL CARD DRIVER @@ -698,10 +731,8 @@ S: Supported STARMODE RADIO IP (STRIP) PROTOCOL DRIVER -P: Stuart Cheshire -M: cheshire@cs.stanford.edu W: http://mosquitonet.Stanford.EDU/strip.html -S: Maintained +S: Unsupported ? SVGA HANDLING P: Martin Mares @@ -745,6 +776,20 @@ L: linux-kernel@vger.rutgers.edu S: Maintained +USB HUB AND UHCI DRIVERS +P: Johannes Erdfelt +M: jerdfelt@sventech.com +L: linux-usb@suse.com +S: Maintained + +USB OHCI DRIVER +P: Gregory P. Smith +M: greg@electricrain.com +M: greg@suitenine.com +L: linux-usb@suse.com +S: Maintained (not yet usable) +W: http://suitenine.com/usb/ + VFAT FILESYSTEM: P: Gordon Chaffee M: chaffee@cs.berkeley.edu @@ -758,9 +803,9 @@ W: http://roadrunner.swansea.linux.org.uk/v4l.shtml S: Maintained -WAN ROUTER AND SANGOMA WANPIPE DRIVERS (X.25, FRAME RELAY, PPP) -P: Gene Kozin -M: genek@compuserve.com +WAN ROUTER & SANGOMA WANPIPE DRIVERS & API (X.25, FRAME RELAY, PPP, CISCO HDLC) +P: Jaspreet Singh +M: jaspreet@sangoma.com M: dm@sangoma.com W: http://www.sangoma.com S: Supported @@ -798,4 +843,4 @@ THE REST P: Linus Torvalds -S: Buried alive in diapers +S: Buried alive in reporters diff -ur --new-file old/linux/Makefile new/linux/Makefile --- old/linux/Makefile Thu Jun 3 02:11:11 1999 +++ new/linux/Makefile Thu Jun 3 02:12:03 1999 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 2 -SUBLEVEL = 1 +SUBLEVEL = 9 EXTRAVERSION = ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/) @@ -179,7 +179,7 @@ endif ifeq ($(CONFIG_USB),y) -DRIVERS := $(DRIVERS) drivers/uusbd/usb.a +DRIVERS := $(DRIVERS) drivers/usb/usb.a endif ifeq ($(CONFIG_I2O),y) @@ -225,35 +225,27 @@ mkdir include/linux/modules; \ fi -oldconfig: symlinks scripts/split-include +oldconfig: symlinks $(CONFIG_SHELL) scripts/Configure -d arch/$(ARCH)/config.in - if [ -r include/linux/autoconf.h ]; then \ - scripts/split-include include/linux/autoconf.h include/config; \ - fi -xconfig: symlinks scripts/split-include +xconfig: symlinks $(MAKE) -C scripts kconfig.tk wish -f scripts/kconfig.tk - if [ -r include/linux/autoconf.h ]; then \ - scripts/split-include include/linux/autoconf.h include/config; \ - fi -menuconfig: include/linux/version.h symlinks scripts/split-include +menuconfig: include/linux/version.h symlinks $(MAKE) -C scripts/lxdialog all $(CONFIG_SHELL) scripts/Menuconfig arch/$(ARCH)/config.in - if [ -r include/linux/autoconf.h ]; then \ - scripts/split-include include/linux/autoconf.h include/config; \ - fi -config: symlinks scripts/split-include +config: symlinks $(CONFIG_SHELL) scripts/Configure arch/$(ARCH)/config.in - if [ -r include/linux/autoconf.h ]; then \ - scripts/split-include include/linux/autoconf.h include/config; \ - fi + +include/config/MARKER: scripts/split-include include/linux/autoconf.h + scripts/split-include include/linux/autoconf.h include/config + @ touch include/config/MARKER linuxsubdirs: $(patsubst %, _dir_%, $(SUBDIRS)) -$(patsubst %, _dir_%, $(SUBDIRS)) : dummy +$(patsubst %, _dir_%, $(SUBDIRS)) : dummy include/config/MARKER $(MAKE) -C $(patsubst _dir_%, %, $@) $(TOPDIR)/include/linux/version.h: include/linux/version.h @@ -290,10 +282,10 @@ @echo '#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))' >>.ver @mv -f .ver $@ -init/version.o: init/version.c include/linux/compile.h +init/version.o: init/version.c include/linux/compile.h include/config/MARKER $(CC) $(CFLAGS) -DUTS_MACHINE='"$(ARCH)"' -c -o init/version.o init/version.c -init/main.o: init/main.c +init/main.o: init/main.c include/config/MARKER $(CC) $(CFLAGS) $(PROFILING) -c -o $*.o $< fs lib mm ipc kernel drivers net: dummy @@ -356,7 +348,8 @@ clean: archclean rm -f kernel/ksyms.lst include/linux/compile.h - rm -f core `find . -name '*.[oas]' ! -regex '.*lxdialog/.*' -print` + rm -f core `find . -name '*.[oas]' ! -regex '.*lxdialog/.*' \ + ! -regex '.*ksymoops/.*' -print` rm -f core `find . -type f -name 'core' -print` rm -f core `find . -name '.*.flags' -print` rm -f vmlinux System.map @@ -380,6 +373,7 @@ rm -f .version .config* config.in config.old rm -f scripts/tkparse scripts/kconfig.tk scripts/kconfig.tmp rm -f scripts/lxdialog/*.o scripts/lxdialog/lxdialog + rm -f scripts/ksymoops/*.o scripts/ksymoops/ksymoops rm -f .menuconfig.log rm -f include/asm rm -rf include/config @@ -392,8 +386,8 @@ distclean: mrproper rm -f core `find . \( -name '*.orig' -o -name '*.rej' -o -name '*~' \ - -o -name '*.bak' -o -name '#*#' -o -name '.*.orig' \ - -o -name '.*.rej' -o -name '.SUMS' -o -size 0 \) -print` TAGS + -o -name '*.bak' -o -name '#*#' -o -name '.*.orig' \ + -o -name '.*.rej' -o -name '.SUMS' -o -size 0 \) -print` TAGS backup: mrproper cd .. && tar cf - linux/ | gzip -9 > backup.gz diff -ur --new-file old/linux/REPORTING-BUGS new/linux/REPORTING-BUGS --- old/linux/REPORTING-BUGS Fri Jan 15 07:53:02 1999 +++ new/linux/REPORTING-BUGS Thu Apr 29 20:53:41 1999 @@ -1,6 +1,6 @@ [Some of this is taken from Frohwalt Egerer's original linux-kernel FAQ] - What follows is a suggested proceedure for reporting Linux bugs. You + What follows is a suggested procedure for reporting Linux bugs. You aren't obliged to use the bug reporting format, it is provided as a guide to the kind of information that can be useful to developers - no more. @@ -23,11 +23,11 @@ This is a suggested format for a bug report sent to the Linux kernel mailing list. Having a standardized bug report form makes it easier for you not to overlook things, and easier for the developers to find the pieces of -information they're really interested in. +information they're really interested in. Don't feel you have to follow it. First run the ver_linux script included as scripts/ver_linux or at It checks out -the version of some important subsystems. Run it with the commnd +the version of some important subsystems. Run it with the command "sh scripts/ver_linux" Use that information to fill in all fields of the bug report form, and diff -ur --new-file old/linux/arch/alpha/boot/main.c new/linux/arch/alpha/boot/main.c --- old/linux/arch/alpha/boot/main.c Sun Aug 4 12:37:59 1996 +++ new/linux/arch/alpha/boot/main.c Thu Feb 25 19:46:51 1999 @@ -22,61 +22,27 @@ extern int vsprintf(char *, const char *, va_list); extern unsigned long switch_to_osf_pal(unsigned long nr, struct pcb_struct * pcb_va, struct pcb_struct * pcb_pa, - unsigned long vptb, unsigned long *kstk); - -int printk(const char * fmt, ...) -{ - va_list args; - int i, j, written, remaining, num_nl; - static char buf[1024]; - char * str; - - va_start(args, fmt); - i = vsprintf(buf, fmt, args); - va_end(args); - - /* expand \n into \r\n: */ - - num_nl = 0; - for (j = 0; j < i; ++j) { - if (buf[j] == '\n') - ++num_nl; - } - remaining = i + num_nl; - for (j = i - 1; j >= 0; --j) { - buf[j + num_nl] = buf[j]; - if (buf[j] == '\n') { - --num_nl; - buf[j + num_nl] = '\r'; - } - } - - str = buf; - do { - written = puts(str, remaining); - remaining -= written; - str += written; - } while (remaining > 0); - return i; -} - -#define hwrpb (*INIT_HWRPB) + unsigned long *vptb); +struct hwrpb_struct *hwrpb = INIT_HWRPB; +static struct pcb_struct pcb_va[1]; /* * Find a physical address of a virtual object.. * * This is easy using the virtual page table address. */ -struct pcb_struct * find_pa(unsigned long *vptb, struct pcb_struct * pcb) + +static inline void * +find_pa(unsigned long *vptb, void *ptr) { - unsigned long address = (unsigned long) pcb; + unsigned long address = (unsigned long) ptr; unsigned long result; result = vptb[address >> 13]; result >>= 32; result <<= 13; result |= address & 0x1fff; - return (struct pcb_struct *) result; + return (void *) result; } /* @@ -88,30 +54,19 @@ * code has the L1 page table identity-map itself in the second PTE * in the L1 page table. Thus the L1-page is virtually addressable * itself (through three levels) at virtual address 0x200802000. - * - * As we don't want it there anyway, we also move the L1 self-map - * up as high as we can, so that the last entry in the L1 page table - * maps the page tables. - * - * As a result, the OSF/1 pal-code will instead use a virtual page table - * map located at 0xffffffe00000000. */ -#define pcb_va ((struct pcb_struct *) 0x20000000) -#define old_vptb (0x0000000200000000UL) -#define new_vptb (0xfffffffe00000000UL) -void pal_init(void) + +#define VPTB ((unsigned long *) 0x200000000) +#define L1 ((unsigned long *) 0x200802000) + +void +pal_init(void) { - unsigned long i, rev, sum; - unsigned long *L1, *l; + unsigned long i, rev; struct percpu_struct * percpu; struct pcb_struct * pcb_pa; - /* Find the level 1 page table and duplicate it in high memory */ - L1 = (unsigned long *) 0x200802000UL; /* (1<<33 | 1<<23 | 1<<13) */ - L1[1023] = L1[1]; - - percpu = (struct percpu_struct *) (hwrpb.processor_offset + (unsigned long) &hwrpb), - + /* Create the dummy PCB. */ pcb_va->ksp = 0; pcb_va->usp = 0; pcb_va->ptbr = L1[1] >> 32; @@ -119,39 +74,32 @@ pcb_va->pcc = 0; pcb_va->unique = 0; pcb_va->flags = 1; - pcb_pa = find_pa((unsigned long *) old_vptb, pcb_va); - printk("Switching to OSF PAL-code .. "); + pcb_va->res1 = 0; + pcb_va->res2 = 0; + pcb_pa = find_pa(VPTB, pcb_va); + /* * a0 = 2 (OSF) - * a1 = return address, but we give the asm the virtual addr of the PCB + * a1 = return address, but we give the asm the vaddr of the PCB * a2 = physical addr of PCB * a3 = new virtual page table pointer - * a4 = KSP (but we give it 0, asm sets it) + * a4 = KSP (but the asm sets it) */ - i = switch_to_osf_pal( - 2, - pcb_va, - pcb_pa, - new_vptb, - 0); + srm_printk("Switching to OSF PAL-code .. "); + + i = switch_to_osf_pal(2, pcb_va, pcb_pa, VPTB); if (i) { - printk("failed, code %ld\n", i); + srm_printk("failed, code %ld\n", i); halt(); } + + percpu = (struct percpu_struct *) + (INIT_HWRPB->processor_offset + (unsigned long) INIT_HWRPB); rev = percpu->pal_revision = percpu->palcode_avail[2]; - hwrpb.vptb = new_vptb; + srm_printk("Ok (rev %lx)\n", rev); - /* update checksum: */ - sum = 0; - for (l = (unsigned long *) &hwrpb; l < (unsigned long *) &hwrpb.chksum; ++l) - sum += *l; - hwrpb.chksum = sum; - - printk("Ok (rev %lx)\n", rev); - /* remove the old virtual page-table mapping */ - L1[1] = 0; - flush_tlb_all(); + tbia(); /* do it directly in case we are SMP */ } static inline long openboot(void) @@ -159,15 +107,15 @@ char bootdev[256]; long result; - result = dispatch(CCB_GET_ENV, ENV_BOOTED_DEV, bootdev, 255); + result = srm_dispatch(CCB_GET_ENV, ENV_BOOTED_DEV, bootdev, 255); if (result < 0) return result; - return dispatch(CCB_OPEN, bootdev, result & 255); + return srm_dispatch(CCB_OPEN, bootdev, result & 255); } static inline long close(long dev) { - return dispatch(CCB_CLOSE, dev); + return srm_dispatch(CCB_CLOSE, dev); } static inline long load(long dev, unsigned long addr, unsigned long count) @@ -176,15 +124,15 @@ extern char _end; long result, boot_size = &_end - (char *) BOOT_ADDR; - result = dispatch(CCB_GET_ENV, ENV_BOOTED_FILE, bootfile, 255); + result = srm_dispatch(CCB_GET_ENV, ENV_BOOTED_FILE, bootfile, 255); if (result < 0) return result; result &= 255; bootfile[result] = '\0'; if (result) - printk("Boot file specification (%s) not implemented\n", + srm_printk("Boot file specification (%s) not implemented\n", bootfile); - return dispatch(CCB_READ, dev, count, addr, boot_size/512 + 1); + return srm_dispatch(CCB_READ, dev, count, addr, boot_size/512 + 1); } /* @@ -208,27 +156,27 @@ int nbytes; char envval[256]; - printk("Linux/AXP bootloader for Linux " UTS_RELEASE "\n"); - if (hwrpb.pagesize != 8192) { - printk("Expected 8kB pages, got %ldkB\n", hwrpb.pagesize >> 10); + srm_printk("Linux/AXP bootloader for Linux " UTS_RELEASE "\n"); + if (INIT_HWRPB->pagesize != 8192) { + srm_printk("Expected 8kB pages, got %ldkB\n", INIT_HWRPB->pagesize >> 10); return; } pal_init(); dev = openboot(); if (dev < 0) { - printk("Unable to open boot device: %016lx\n", dev); + srm_printk("Unable to open boot device: %016lx\n", dev); return; } dev &= 0xffffffff; - printk("Loading vmlinux ..."); + srm_printk("Loading vmlinux ..."); i = load(dev, START_ADDR, KERNEL_SIZE); close(dev); if (i != KERNEL_SIZE) { - printk("Failed (%lx)\n", i); + srm_printk("Failed (%lx)\n", i); return; } - nbytes = dispatch(CCB_GET_ENV, ENV_BOOTED_OSFLAGS, + nbytes = srm_dispatch(CCB_GET_ENV, ENV_BOOTED_OSFLAGS, envval, sizeof(envval)); if (nbytes < 0) { nbytes = 0; @@ -236,7 +184,7 @@ envval[nbytes] = '\0'; strcpy((char*)ZERO_PAGE, envval); - printk(" Ok\nNow booting the kernel\n"); + srm_printk(" Ok\nNow booting the kernel\n"); runkernel(); for (i = 0 ; i < 0x100000000 ; i++) /* nothing */; diff -ur --new-file old/linux/arch/alpha/config.in new/linux/arch/alpha/config.in --- old/linux/arch/alpha/config.in Thu Jun 3 02:11:11 1999 +++ new/linux/arch/alpha/config.in Thu Jun 3 02:12:04 1999 @@ -54,12 +54,10 @@ unset CONFIG_ALPHA_LCA CONFIG_ALPHA_APECS CONFIG_ALPHA_CIA unset CONFIG_ALPHA_T2 CONFIG_ALPHA_PYXIS CONFIG_ALPHA_POLARIS unset CONFIG_ALPHA_TSUNAMI CONFIG_ALPHA_MCPCIA -unset CONFIG_ALPHA_NEED_ROUNDING_EMULATION if [ "$CONFIG_ALPHA_GENERIC" = "y" ] then define_bool CONFIG_PCI y - define_bool CONFIG_ALPHA_NEED_ROUNDING_EMULATION y fi if [ "$CONFIG_ALPHA_BOOK1" = "y" ] then @@ -108,7 +106,7 @@ then define_bool CONFIG_ALPHA_EV5 y else - define_bool CONFIG_ALPHA_EV4 y + define_bool CONFIG_ALPHA_EV4 y fi define_bool CONFIG_ALPHA_T2 y fi @@ -141,11 +139,6 @@ then define_bool CONFIG_ALPHA_EV4 y fi -if [ "$CONFIG_ALPHA_EV4" = "y" ] -then - # EV45 and older do not support all rounding modes in hw: - define_bool CONFIG_ALPHA_NEED_ROUNDING_EMULATION y -fi if [ "$CONFIG_ALPHA_CABRIOLET" = "y" -o "$CONFIG_ALPHA_AVANTI" = "y" \ -o "$CONFIG_ALPHA_EB64P" = "y" -o "$CONFIG_ALPHA_JENSEN" = "y" \ @@ -246,7 +239,7 @@ endmenu mainmenu_option next_comment -comment 'CD-ROM drivers (not for SCSI or IDE/ATAPI drives)' +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 diff -ur --new-file old/linux/arch/alpha/defconfig new/linux/arch/alpha/defconfig --- old/linux/arch/alpha/defconfig Wed Dec 23 16:34:11 1998 +++ new/linux/arch/alpha/defconfig Thu Feb 25 19:46:46 1999 @@ -91,7 +91,6 @@ # CONFIG_PACKET is not set # CONFIG_NETLINK is not set # CONFIG_FIREWALL is not set -# CONFIG_NET_ALIAS is not set # CONFIG_FILTER is not set CONFIG_UNIX=y CONFIG_INET=y diff -ur --new-file old/linux/arch/alpha/kernel/entry.S new/linux/arch/alpha/kernel/entry.S --- old/linux/arch/alpha/kernel/entry.S Thu Jan 21 20:26:30 1999 +++ new/linux/arch/alpha/kernel/entry.S Mon May 10 18:55:21 1999 @@ -6,8 +6,6 @@ #include -#define halt .long PAL_halt -#define rti .long PAL_rti #define SIGCHLD 20 #define NR_SYSCALLS 371 @@ -98,7 +96,7 @@ call_pal PAL_swpipl; \ stq $21,HAE_CACHE($19); \ stq $21,0($20); \ - bis $0,$0,$16; \ + mov $0,$16; \ call_pal PAL_swpipl; \ ldq $0,0($30); \ ldq $1,8($30); \ @@ -127,8 +125,8 @@ entInt: SAVE_ALL lda $8,0x3fff - bic $30,$8,$8 lda $26,ret_from_sys_call + bic $30,$8,$8 jsr $31,do_entInt .end entInt @@ -170,8 +168,8 @@ entArith: SAVE_ALL lda $8,0x3fff - bic $30,$8,$8 lda $26,ret_from_sys_call + bic $30,$8,$8 jsr $31,do_entArith .end entArith @@ -181,11 +179,23 @@ entIF: SAVE_ALL lda $8,0x3fff - bic $30,$8,$8 lda $26,ret_from_sys_call + bic $30,$8,$8 jsr $31,do_entIF .end entIF +.align 3 +.globl entDbg +.ent entDbg +entDbg: + SAVE_ALL + lda $8,0x3fff + lda $26,ret_from_sys_call + bic $30,$8,$8 + jsr $31,do_entDbg +.end entDbg + + /* * Fork() is one of the special system calls: it needs to * save the callee-saved regs so that the regs can be found @@ -200,18 +210,18 @@ kernel_clone: .frame $30, 0, $26 .prologue 0 - subq $30,6*8,$30 - stq $31,0($30) - stq $26,8($30) - stq $29,16($30) - stq $16,24($30) - stq $17,32($30) - stq $18,40($30) - bis $31,2,$0 /* Register v0: syscall nr for fork() */ + subq $30,6*8,$30 + stq $31,0($30) + stq $26,8($30) + stq $29,16($30) + stq $16,24($30) + stq $17,32($30) + stq $18,40($30) + bis $31,2,$0 /* Register v0: syscall nr for fork() */ SAVE_ALL - bsr $26,sys_clone - stq $0,0($30) - br $31,ret_from_sys_call + bsr $26,sys_clone + stq $0,0($30) + br ret_from_sys_call .end kernel_clone /* @@ -221,32 +231,32 @@ .globl __kernel_thread .ent __kernel_thread __kernel_thread: - ldgp $29,0($27) /* we can be called from a module */ + ldgp $29,0($27) /* we can be called from a module */ .frame $30, 4*8, $26 - subq $30,4*8,$30 - stq $10,16($30) - stq $9,8($30) - stq $26,0($30) + subq $30,4*8,$30 + stq $10,16($30) + stq $9,8($30) + stq $26,0($30) .prologue 1 - bis $17,$17,$9 /* save fn */ - bis $18,$18,$10 /* save arg */ - bsr $26,kernel_clone - bne $20,1f /* $20 is non-zero in child */ - ldq $26,0($30) - ldq $9,8($30) - ldq $10,16($30) - addq $30,4*8,$30 - ret $31,($26),1 + mov $17,$9 /* save fn */ + mov $18,$10 /* save arg */ + bsr $26,kernel_clone + bne $20,1f /* $20 is non-zero in child */ + ldq $26,0($30) + ldq $9,8($30) + ldq $10,16($30) + addq $30,4*8,$30 + ret $31,($26),1 /* this is in child: look out as we don't have any stack here.. */ -1: bis $9,$9,$27 /* get fn */ - lda $8,0x3fff - bis $10,$10,$16 /* get arg */ - bic $30,$8,$8 /* get current */ - jsr $26,($27) +1: mov $9,$27 /* get fn */ + lda $8,0x3fff + mov $10,$16 /* get arg */ + bic $30,$8,$8 /* get current */ + jsr $26,($27) ldgp $29,0($26) - bis $0,$0,$16 - jsr $26,sys_exit - call_pal PAL_halt + mov $0,$16 + mov $31,$26 + jsr $31,sys_exit .end __kernel_thread /* @@ -274,202 +284,199 @@ .align 3 .ent do_switch_stack do_switch_stack: - lda $30,-SWITCH_STACK_SIZE($30) - stq $9,0($30) - stq $10,8($30) - stq $11,16($30) - stq $12,24($30) - stq $13,32($30) - stq $14,40($30) - stq $15,48($30) - stq $26,56($30) - stt $f0,64($30) - stt $f1,72($30) - stt $f2,80($30) - stt $f3,88($30) - stt $f4,96($30) - stt $f5,104($30) - stt $f6,112($30) - stt $f7,120($30) - stt $f8,128($30) - stt $f9,136($30) - stt $f10,144($30) - stt $f11,152($30) - stt $f12,160($30) - stt $f13,168($30) - stt $f14,176($30) - stt $f15,184($30) - stt $f16,192($30) - stt $f17,200($30) - stt $f18,208($30) - stt $f19,216($30) - stt $f20,224($30) - stt $f21,232($30) - stt $f22,240($30) - stt $f23,248($30) - stt $f24,256($30) - stt $f25,264($30) - stt $f26,272($30) - stt $f27,280($30) - mf_fpcr $f0 # get fpcr - stt $f28,288($30) - stt $f29,296($30) - stt $f30,304($30) - stt $f0,312($30) # save fpcr in slot of $f31 - ldt $f0,64($30) # dont let "do_switch_stack" change fp state. - ret $31,($1),1 + lda $30,-SWITCH_STACK_SIZE($30) + stq $9,0($30) + stq $10,8($30) + stq $11,16($30) + stq $12,24($30) + stq $13,32($30) + stq $14,40($30) + stq $15,48($30) + stq $26,56($30) + stt $f0,64($30) + stt $f1,72($30) + stt $f2,80($30) + stt $f3,88($30) + stt $f4,96($30) + stt $f5,104($30) + stt $f6,112($30) + stt $f7,120($30) + stt $f8,128($30) + stt $f9,136($30) + stt $f10,144($30) + stt $f11,152($30) + stt $f12,160($30) + stt $f13,168($30) + stt $f14,176($30) + stt $f15,184($30) + stt $f16,192($30) + stt $f17,200($30) + stt $f18,208($30) + stt $f19,216($30) + stt $f20,224($30) + stt $f21,232($30) + stt $f22,240($30) + stt $f23,248($30) + stt $f24,256($30) + stt $f25,264($30) + stt $f26,272($30) + stt $f27,280($30) + mf_fpcr $f0 # get fpcr + stt $f28,288($30) + stt $f29,296($30) + stt $f30,304($30) + stt $f0,312($30) # save fpcr in slot of $f31 + ldt $f0,64($30) # dont let "do_switch_stack" change fp state. + ret $31,($1),1 .end do_switch_stack .align 3 .ent undo_switch_stack undo_switch_stack: - ldq $9,0($30) - ldq $10,8($30) - ldq $11,16($30) - ldq $12,24($30) - ldq $13,32($30) - ldq $14,40($30) - ldq $15,48($30) - ldq $26,56($30) - ldt $f30,312($30) # get saved fpcr - ldt $f0,64($30) - ldt $f1,72($30) - ldt $f2,80($30) - ldt $f3,88($30) - mt_fpcr $f30 # install saved fpcr - ldt $f4,96($30) - ldt $f5,104($30) - ldt $f6,112($30) - ldt $f7,120($30) - ldt $f8,128($30) - ldt $f9,136($30) - ldt $f10,144($30) - ldt $f11,152($30) - ldt $f12,160($30) - ldt $f13,168($30) - ldt $f14,176($30) - ldt $f15,184($30) - ldt $f16,192($30) - ldt $f17,200($30) - ldt $f18,208($30) - ldt $f19,216($30) - ldt $f20,224($30) - ldt $f21,232($30) - ldt $f22,240($30) - ldt $f23,248($30) - ldt $f24,256($30) - ldt $f25,264($30) - ldt $f26,272($30) - ldt $f27,280($30) - ldt $f28,288($30) - ldt $f29,296($30) - ldt $f30,304($30) - lda $30,SWITCH_STACK_SIZE($30) - ret $31,($1),1 + ldq $9,0($30) + ldq $10,8($30) + ldq $11,16($30) + ldq $12,24($30) + ldq $13,32($30) + ldq $14,40($30) + ldq $15,48($30) + ldq $26,56($30) + ldt $f30,312($30) # get saved fpcr + ldt $f0,64($30) + ldt $f1,72($30) + ldt $f2,80($30) + ldt $f3,88($30) + mt_fpcr $f30 # install saved fpcr + ldt $f4,96($30) + ldt $f5,104($30) + ldt $f6,112($30) + ldt $f7,120($30) + ldt $f8,128($30) + ldt $f9,136($30) + ldt $f10,144($30) + ldt $f11,152($30) + ldt $f12,160($30) + ldt $f13,168($30) + ldt $f14,176($30) + ldt $f15,184($30) + ldt $f16,192($30) + ldt $f17,200($30) + ldt $f18,208($30) + ldt $f19,216($30) + ldt $f20,224($30) + ldt $f21,232($30) + ldt $f22,240($30) + ldt $f23,248($30) + ldt $f24,256($30) + ldt $f25,264($30) + ldt $f26,272($30) + ldt $f27,280($30) + ldt $f28,288($30) + ldt $f29,296($30) + ldt $f30,304($30) + lda $30,SWITCH_STACK_SIZE($30) + ret $31,($1),1 .end undo_switch_stack .align 3 .globl entUna .ent entUna entUna: - lda $30,-256($30) - stq $0,0($30) - ldq $0,256($30) /* get PS */ - stq $1,8($30) - stq $2,16($30) - stq $3,24($30) - and $0,8,$0 /* user mode? */ - stq $4,32($30) - bne $0,entUnaUser /* yup -> do user-level unaligned fault */ - stq $5,40($30) - stq $6,48($30) - stq $7,56($30) - stq $8,64($30) - stq $9,72($30) - stq $10,80($30) - stq $11,88($30) - stq $12,96($30) - stq $13,104($30) - stq $14,112($30) - stq $15,120($30) + lda $30,-256($30) + stq $0,0($30) + ldq $0,256($30) /* get PS */ + stq $1,8($30) + stq $2,16($30) + stq $3,24($30) + and $0,8,$0 /* user mode? */ + stq $4,32($30) + bne $0,entUnaUser /* yup -> do user-level unaligned fault */ + stq $5,40($30) + stq $6,48($30) + stq $7,56($30) + stq $8,64($30) + stq $9,72($30) + stq $10,80($30) + stq $11,88($30) + stq $12,96($30) + stq $13,104($30) + stq $14,112($30) + stq $15,120($30) /* 16-18 PAL-saved */ - stq $19,152($30) - stq $20,160($30) - stq $21,168($30) - stq $22,176($30) - stq $23,184($30) - stq $24,192($30) - stq $25,200($30) - stq $26,208($30) - stq $27,216($30) - stq $28,224($30) - stq $29,232($30) - stq $30,240($30) - stq $31,248($30) - lda $8,0x3fff - bic $30,$8,$8 - jsr $26,do_entUna - ldq $0,0($30) - ldq $1,8($30) - ldq $2,16($30) - ldq $3,24($30) - ldq $4,32($30) - ldq $5,40($30) - ldq $6,48($30) - ldq $7,56($30) - ldq $8,64($30) - ldq $9,72($30) - ldq $10,80($30) - ldq $11,88($30) - ldq $12,96($30) - ldq $13,104($30) - ldq $14,112($30) - ldq $15,120($30) + stq $19,152($30) + stq $20,160($30) + stq $21,168($30) + stq $22,176($30) + stq $23,184($30) + stq $24,192($30) + stq $25,200($30) + stq $26,208($30) + stq $27,216($30) + stq $28,224($30) + stq $29,232($30) + lda $8,0x3fff + stq $31,248($30) + bic $30,$8,$8 + jsr $26,do_entUna + ldq $0,0($30) + ldq $1,8($30) + ldq $2,16($30) + ldq $3,24($30) + ldq $4,32($30) + ldq $5,40($30) + ldq $6,48($30) + ldq $7,56($30) + ldq $8,64($30) + ldq $9,72($30) + ldq $10,80($30) + ldq $11,88($30) + ldq $12,96($30) + ldq $13,104($30) + ldq $14,112($30) + ldq $15,120($30) /* 16-18 PAL-saved */ - ldq $19,152($30) - ldq $20,160($30) - ldq $21,168($30) - ldq $22,176($30) - ldq $23,184($30) - ldq $24,192($30) - ldq $25,200($30) - ldq $26,208($30) - ldq $27,216($30) - ldq $28,224($30) - ldq $29,232($30) - ldq $30,240($30) - lda $30,256($30) - rti + ldq $19,152($30) + ldq $20,160($30) + ldq $21,168($30) + ldq $22,176($30) + ldq $23,184($30) + ldq $24,192($30) + ldq $25,200($30) + ldq $26,208($30) + ldq $27,216($30) + ldq $28,224($30) + ldq $29,232($30) + lda $30,256($30) + call_pal PAL_rti .end entUna .align 3 .ent entUnaUser entUnaUser: - ldq $0,0($30) /* restore original $0 */ - lda $30,256($30) /* pop entUna's stack frame */ - SAVE_ALL /* setup normal kernel stack */ - lda $30,-56($30) - stq $9,0($30) - stq $10,8($30) - stq $11,16($30) - stq $12,24($30) - stq $13,32($30) - stq $14,40($30) - stq $15,48($30) - lda $8,0x3fff - addq $30,56,$19 - bic $30,$8,$8 - jsr $26,do_entUnaUser - ldq $9,0($30) - ldq $10,8($30) - ldq $11,16($30) - ldq $12,24($30) - ldq $13,32($30) - ldq $14,40($30) - ldq $15,48($30) - lda $30,56($30) - br $31,ret_from_sys_call - + ldq $0,0($30) /* restore original $0 */ + lda $30,256($30) /* pop entUna's stack frame */ + SAVE_ALL /* setup normal kernel stack */ + lda $30,-56($30) + stq $9,0($30) + stq $10,8($30) + stq $11,16($30) + stq $12,24($30) + stq $13,32($30) + stq $14,40($30) + stq $15,48($30) + lda $8,0x3fff + addq $30,56,$19 + bic $30,$8,$8 + jsr $26,do_entUnaUser + ldq $9,0($30) + ldq $10,8($30) + ldq $11,16($30) + ldq $12,24($30) + ldq $13,32($30) + ldq $14,40($30) + ldq $15,48($30) + lda $30,56($30) + br ret_from_sys_call .end entUnaUser /* @@ -479,36 +486,36 @@ .globl sys_fork .ent sys_fork sys_fork: - bsr $1,do_switch_stack - bis $31,SIGCHLD,$16 - bis $31,$31,$17 - bis $30,$30,$18 - jsr $26,alpha_clone - bsr $1,undo_switch_stack - ret $31,($26),1 + bsr $1,do_switch_stack + bis $31,SIGCHLD,$16 + mov $31,$17 + mov $30,$18 + jsr $26,alpha_clone + bsr $1,undo_switch_stack + ret $31,($26),1 .end sys_fork .align 3 .globl sys_clone .ent sys_clone sys_clone: - bsr $1,do_switch_stack + bsr $1,do_switch_stack /* arg1 and arg2 come from the user */ - bis $30,$30,$18 - jsr $26,alpha_clone - bsr $1,undo_switch_stack - ret $31,($26),1 + mov $30,$18 + jsr $26,alpha_clone + bsr $1,undo_switch_stack + ret $31,($26),1 .end sys_clone .align 3 .globl sys_vfork .ent sys_vfork sys_vfork: - bsr $1,do_switch_stack - bis $30,$30,$16 - jsr $26,alpha_vfork - bsr $1,undo_switch_stack - ret $31,($26),1 + bsr $1,do_switch_stack + mov $30,$16 + jsr $26,alpha_vfork + bsr $1,undo_switch_stack + ret $31,($26),1 .end sys_vfork .align 3 @@ -516,12 +523,12 @@ .ent alpha_switch_to alpha_switch_to: .prologue 0 - bsr $1,do_switch_stack + bsr $1,do_switch_stack call_pal PAL_swpctx - lda $16,-2($31) - call_pal PAL_tbi - bsr $1,undo_switch_stack - ret $31,($26),1 + unop + bsr $1,undo_switch_stack + mov $17,$0 + ret $31,($26),1 .end alpha_switch_to /* @@ -580,7 +587,7 @@ bne $5,signal_return restore_all: RESTORE_ALL - rti + call_pal PAL_rti /* PTRACE syscall handler */ @@ -608,7 +615,7 @@ s8addq $0,$2,$2 beq $1,1f ldq $27,0($2) -1: jsr $26,($27),alpha_ni_syscall +1: jsr $26,($27),sys_gettimeofday ldgp $29,0($26) /* check return.. */ @@ -634,15 +641,15 @@ stq $1,72($30) /* a3 for return */ bsr $1,do_switch_stack - bis $19,$19,$9 /* save old syscall number */ - bis $20,$20,$10 /* save old a3 */ + mov $19,$9 /* save old syscall number */ + mov $20,$10 /* save old a3 */ jsr $26,syscall_trace - bis $9,$9,$19 - bis $10,$10,$20 + mov $9,$19 + mov $10,$20 bsr $1,undo_switch_stack - bis $31,$31,$26 /* tell "ret_from_sys_call" that we can restart */ - br $31,ret_from_sys_call + mov $31,$26 /* tell "ret_from_sys_call" we can restart */ + br ret_from_sys_call .align 3 handle_bottom_half: @@ -653,7 +660,7 @@ ldq $19,0($30) ldq $20,8($30) addq $30,16,$30 - br $31,ret_from_handle_bh + br ret_from_handle_bh .align 3 syscall_error: @@ -671,38 +678,35 @@ subq $31,$0,$0 /* with error in v0 */ addq $31,1,$1 /* set a3 for errno return */ stq $0,0($30) - bis $31,$31,$26 /* tell "ret_from_sys_call" we can restart */ + mov $31,$26 /* tell "ret_from_sys_call" we can restart */ stq $1,72($30) /* a3 for return */ - br $31,ret_from_sys_call + br ret_from_sys_call ret_success: stq $0,0($30) stq $31,72($30) /* a3=0 => no error */ - br $31,ret_from_sys_call + br ret_from_sys_call .align 3 signal_return: - bis $30,$30,$17 + mov $30,$17 br $1,do_switch_stack - bis $30,$30,$18 - bis $31,$31,$16 + mov $30,$18 + mov $31,$16 jsr $26,do_signal bsr $1,undo_switch_stack - br $31,restore_all + br restore_all .end entSys #ifdef __SMP__ - .globl ret_from_smpfork + .globl ret_from_smp_fork .align 3 -.ent ret_from_smpfork -ret_from_smpfork: - .set at - mb /* Make the changed data visible before the freed lock. */ - stq $31,scheduler_lock +.ent ret_from_smp_fork +ret_from_smp_fork: lda $26,ret_from_sys_call + mov $17,$16 jsr $31,schedule_tail - .set noat -.end ret_from_smpfork +.end ret_from_smp_fork #endif /* __SMP__ */ .align 3 @@ -715,51 +719,51 @@ ldq $19,0($30) ldq $20,8($30) addq $30,16,$30 - br $31,ret_from_reschedule + br ret_from_reschedule .end reschedule .align 3 .ent sys_sigreturn sys_sigreturn: - bis $30,$30,$17 + mov $30,$17 + lda $18,-SWITCH_STACK_SIZE($30) lda $30,-SWITCH_STACK_SIZE($30) - bis $30,$30,$18 jsr $26,do_sigreturn br $1,undo_switch_stack - br $31,ret_from_sys_call + br ret_from_sys_call .end sys_sigreturn .align 3 .ent sys_rt_sigreturn sys_rt_sigreturn: - bis $30,$30,$17 + mov $30,$17 + lda $18,-SWITCH_STACK_SIZE($30) lda $30,-SWITCH_STACK_SIZE($30) - bis $30,$30,$18 jsr $26,do_rt_sigreturn br $1,undo_switch_stack - br $31,ret_from_sys_call + br ret_from_sys_call .end sys_rt_sigreturn .align 3 .ent sys_sigsuspend sys_sigsuspend: - bis $30,$30,$17 + mov $30,$17 br $1,do_switch_stack - bis $30,$30,$18 + mov $30,$18 jsr $26,do_sigsuspend lda $30,SWITCH_STACK_SIZE($30) - br $31,ret_from_sys_call + br ret_from_sys_call .end sys_sigsuspend .align 3 .ent sys_rt_sigsuspend sys_rt_sigsuspend: - bis $30,$30,$18 + mov $30,$18 br $1,do_switch_stack - bis $30,$30,$19 + mov $30,$19 jsr $26,do_rt_sigsuspend lda $30,SWITCH_STACK_SIZE($30) - br $31,ret_from_sys_call + br ret_from_sys_call .end sys_rt_sigsuspend .data diff -ur --new-file old/linux/arch/alpha/kernel/osf_sys.c new/linux/arch/alpha/kernel/osf_sys.c --- old/linux/arch/alpha/kernel/osf_sys.c Thu Jan 21 01:07:26 1999 +++ new/linux/arch/alpha/kernel/osf_sys.c Mon May 10 18:55:21 1999 @@ -37,6 +37,7 @@ #include #include #include +#include extern int do_mount(kdev_t, const char *, const char *, char *, int, void *); extern int do_pipe(int *); @@ -140,6 +141,7 @@ struct inode *inode; struct osf_dirent_callback buf; + lock_kernel(); error = -EBADF; file = fget(fd); if (!file) @@ -172,6 +174,7 @@ out_putf: fput(file); out: + unlock_kernel(); return error; } @@ -317,8 +320,8 @@ struct super_block * sb = inode->i_sb; int error; - error = -ENOSYS; - if (sb->s_op->statfs) { + error = -ENODEV; + if (sb && sb->s_op && sb->s_op->statfs) { set_fs(KERNEL_DS); error = sb->s_op->statfs(sb, &linux_stat, sizeof(linux_stat)); set_fs(USER_DS); @@ -762,14 +765,10 @@ asmlinkage int osf_sigstack(struct sigstack *uss, struct sigstack *uoss) { unsigned long usp = rdusp(); - unsigned long oss_sp, oss_os; + unsigned long oss_sp = current->sas_ss_sp + current->sas_ss_size; + unsigned long oss_os = on_sig_stack(usp); int error; - if (uoss) { - oss_sp = current->sas_ss_sp + current->sas_ss_size; - oss_os = on_sig_stack(usp); - } - if (uss) { void *ss_sp; @@ -880,11 +879,27 @@ int *start, void *arg) { unsigned long w; + struct percpu_struct *cpu; switch (op) { case GSI_IEEE_FP_CONTROL: /* Return current software fp control & status bits. */ - w = current->tss.flags & IEEE_SW_MASK; + /* Note that DU doesn't verify available space here. */ + + /* EV6 implements most of the bits in hardware. If + UNDZ is not set, UNFD is maintained in software. */ + if (implver() == IMPLVER_EV6) { + unsigned long fpcr = rdfpcr(); + w = ieee_fpcr_to_swcr(fpcr); + if (!(fpcr & FPCR_UNDZ)) { + w &= ~IEEE_TRAP_ENABLE_UNF; + w |= current->tss.flags & IEEE_TRAP_ENABLE_UNF; + } + } else { + /* Otherwise we are forced to do everything in sw. */ + w = current->tss.flags & IEEE_SW_MASK; + } + if (put_user(w, (unsigned long *) buffer)) return -EFAULT; return 0; @@ -898,10 +913,28 @@ break; case GSI_UACPROC: + if (nbytes < sizeof(unsigned int)) + return -EINVAL; w = (current->tss.flags >> UAC_SHIFT) & UAC_BITMASK; if (put_user(w, (unsigned int *)buffer)) return -EFAULT; - return 0; + return 1; + + case GSI_PROC_TYPE: + if (nbytes < sizeof(unsigned long)) + return -EINVAL; + cpu = (struct percpu_struct*) + ((char*)hwrpb + hwrpb->processor_offset); + if (put_user(w, (unsigned long *)buffer)) + return -EFAULT; + return 1; + + case GSI_GET_HWRPB: + if (nbytes < sizeof(*hwrpb)) + return -EINVAL; + if (copy_to_user(buffer, hwrpb, nbytes) != 0) + return -EFAULT; + return 1; default: break; @@ -916,7 +949,7 @@ { switch (op) { case SSI_IEEE_FP_CONTROL: { - unsigned long swcr, fpcr; + unsigned long swcr, fpcr, undz; /* * Alpha Architecture Handbook 4.7.7.3: @@ -931,11 +964,12 @@ current->tss.flags &= ~IEEE_SW_MASK; current->tss.flags |= swcr & IEEE_SW_MASK; - /* Update the real fpcr. For exceptions that are disabled in - software but have not been seen, enable the exception in - hardware so that we can update our software status mask. */ - fpcr = rdfpcr() & (~FPCR_MASK | FPCR_DYN_MASK); - fpcr |= ieee_swcr_to_fpcr(swcr | (~swcr & IEEE_STATUS_MASK)>>16); + /* Update the real fpcr. Keep UNFD off if not UNDZ. */ + fpcr = rdfpcr(); + undz = (fpcr & FPCR_UNDZ); + fpcr &= ~(FPCR_MASK | FPCR_DYN_MASK | FPCR_UNDZ); + fpcr |= ieee_swcr_to_fpcr(swcr); + fpcr &= ~(undz << 1); wrfpcr(fpcr); return 0; @@ -1390,8 +1424,9 @@ copy_from_user(&txc.tick, &txc_p->tick, sizeof(struct timex32) - offsetof(struct timex32, time))) return -EFAULT; - - if ((ret = do_adjtimex(&txc))) + + ret = do_adjtimex(&txc); + if (ret < 0) return ret; /* copy back to timex32 */ @@ -1401,5 +1436,5 @@ (put_tv32(&txc_p->time, &txc.time))) return -EFAULT; - return 0; + return ret; } diff -ur --new-file old/linux/arch/alpha/kernel/process.c new/linux/arch/alpha/kernel/process.c --- old/linux/arch/alpha/kernel/process.c Wed Jan 20 20:08:43 1999 +++ new/linux/arch/alpha/kernel/process.c Mon May 10 18:55:21 1999 @@ -237,10 +237,13 @@ void flush_thread(void) { - /* Arrange for each exec'ed process to start off with a - clean slate with respect to the FPU. */ + /* Arrange for each exec'ed process to start off with a clean slate + with respect to the FPU. This is all exceptions disabled. Note + that EV6 defines UNFD valid only with UNDZ, which we don't want + for IEEE conformance -- so that disabled bit remains in software. */ + current->tss.flags &= ~IEEE_SW_MASK; - wrfpcr(FPCR_DYN_NORMAL); + wrfpcr(FPCR_DYN_NORMAL | FPCR_INVD | FPCR_DZED | FPCR_OVFD | FPCR_INED); } void release_thread(struct task_struct *dead_task) @@ -270,8 +273,6 @@ (struct pt_regs *) (swstack+1)); } -extern void ret_from_sys_call(void); -extern void ret_from_smpfork(void); /* * Copy an alpha thread.. * @@ -282,9 +283,13 @@ * Use the passed "regs" pointer to determine how much space we need * for a kernel fork(). */ + int copy_thread(int nr, unsigned long clone_flags, unsigned long usp, struct task_struct * p, struct pt_regs * regs) { + extern void ret_from_sys_call(void); + extern void ret_from_smp_fork(void); + struct pt_regs * childregs; struct switch_stack * childstack, *stack; unsigned long stack_offset; @@ -292,18 +297,18 @@ stack_offset = PAGE_SIZE - sizeof(struct pt_regs); if (!(regs->ps & 8)) stack_offset = (PAGE_SIZE-1) & (unsigned long) regs; - childregs = (struct pt_regs *) (stack_offset + PAGE_SIZE + (unsigned long)p); + childregs = (struct pt_regs *) (stack_offset + PAGE_SIZE + (long)p); *childregs = *regs; childregs->r0 = 0; childregs->r19 = 0; - childregs->r20 = 1; /* OSF/1 has some strange fork() semantics.. */ + childregs->r20 = 1; /* OSF/1 has some strange fork() semantics. */ regs->r20 = 0; stack = ((struct switch_stack *) regs) - 1; childstack = ((struct switch_stack *) childregs) - 1; *childstack = *stack; #ifdef __SMP__ - childstack->r26 = (unsigned long) ret_from_smpfork; + childstack->r26 = (unsigned long) ret_from_smp_fork; #else childstack->r26 = (unsigned long) ret_from_sys_call; #endif @@ -328,10 +333,12 @@ dump->start_code = current->mm->start_code; dump->start_data = current->mm->start_data; dump->start_stack = rdusp() & ~(PAGE_SIZE - 1); - dump->u_tsize = (current->mm->end_code - dump->start_code) >> PAGE_SHIFT; - dump->u_dsize = (current->mm->brk + (PAGE_SIZE - 1) - dump->start_data) >> PAGE_SHIFT; - dump->u_ssize = - (current->mm->start_stack - dump->start_stack + PAGE_SIZE - 1) >> PAGE_SHIFT; + dump->u_tsize = ((current->mm->end_code - dump->start_code) + >> PAGE_SHIFT); + dump->u_dsize = ((current->mm->brk + PAGE_SIZE-1 - dump->start_data) + >> PAGE_SHIFT); + dump->u_ssize = (current->mm->start_stack - dump->start_stack + + PAGE_SIZE-1) >> PAGE_SHIFT; /* * We store the registers in an order/format that is diff -ur --new-file old/linux/arch/alpha/kernel/proto.h new/linux/arch/alpha/kernel/proto.h --- old/linux/arch/alpha/kernel/proto.h Sun Jan 10 18:59:59 1999 +++ new/linux/arch/alpha/kernel/proto.h Mon Feb 22 04:06:36 1999 @@ -165,7 +165,7 @@ extern void SMC93x_Init(void); /* smc37c669.c */ -extern void SMC669_Init(void); +extern void SMC669_Init(int); /* es1888.c */ extern void es1888_init(void); @@ -187,6 +187,7 @@ extern void entMM(void); extern void entSys(void); extern void entUna(void); +extern void entDbg(void); /* process.c */ extern void generic_kill_arch (int mode, char *reboot_cmd); diff -ur --new-file old/linux/arch/alpha/kernel/setup.c new/linux/arch/alpha/kernel/setup.c --- old/linux/arch/alpha/kernel/setup.c Thu Jan 14 19:21:40 1999 +++ new/linux/arch/alpha/kernel/setup.c Sun Apr 25 02:54:08 1999 @@ -183,6 +183,11 @@ vec = get_sysvec_byname(p+9); continue; } + + if (strncmp(p, "cycle=", 6) == 0) { + est_cycle_freq = simple_strtol(p+6, NULL, 0); + continue; + } } /* Replace the command line, not that we've killed it with strtok. */ @@ -721,8 +726,8 @@ (char*)cpu->serial_no, systype_name, sysvariation_name, hwrpb->sys_revision, (char*)hwrpb->ssn, - hwrpb->cycle_freq ? : est_cycle_freq, - hwrpb->cycle_freq ? "" : "est.", + est_cycle_freq ? : hwrpb->cycle_freq, + est_cycle_freq ? "est." : "", hwrpb->intr_freq / 4096, (100 * hwrpb->intr_freq / 4096) % 100, hwrpb->pagesize, diff -ur --new-file old/linux/arch/alpha/kernel/smc37c669.c new/linux/arch/alpha/kernel/smc37c669.c --- old/linux/arch/alpha/kernel/smc37c669.c Wed Nov 25 23:52:22 1998 +++ new/linux/arch/alpha/kernel/smc37c669.c Mon Feb 22 04:06:36 1999 @@ -862,7 +862,7 @@ */ SMC37c669_CONFIG_REGS *SMC37c669_detect( - void + int ); unsigned int SMC37c669_enable_device( @@ -1015,6 +1015,29 @@ }; /* +** The following definition is for the MONET (XP1000) IRQ +** translation table. +*/ +static SMC37c669_IRQ_TRANSLATION_ENTRY SMC37c669_monet_irq_table[] +__initdata = + { + { SMC37c669_DEVICE_IRQ_A, -1 }, + { SMC37c669_DEVICE_IRQ_B, -1 }, + { SMC37c669_DEVICE_IRQ_C, 6 }, + { SMC37c669_DEVICE_IRQ_D, 7 }, + { SMC37c669_DEVICE_IRQ_E, 4 }, + { SMC37c669_DEVICE_IRQ_F, 3 }, + { SMC37c669_DEVICE_IRQ_H, -1 }, + { -1, -1 } /* End of table */ + }; + +static SMC37c669_IRQ_TRANSLATION_ENTRY *SMC37c669_irq_tables[] __initdata = + { + SMC37c669_default_irq_table, + SMC37c669_monet_irq_table + }; + +/* ** DRQ Translation Table ** ** The DRQ translation table is a list of SMC37c669 device and @@ -1163,7 +1186,7 @@ ** **-- */ -SMC37c669_CONFIG_REGS * __init SMC37c669_detect( void ) +SMC37c669_CONFIG_REGS * __init SMC37c669_detect( int index ) { int i; SMC37c669_DEVICE_ID_REGISTER id; @@ -1196,7 +1219,7 @@ /* ** Initialize the IRQ and DRQ translation tables. */ - SMC37c669_irq_table = SMC37c669_default_irq_table; + SMC37c669_irq_table = SMC37c669_irq_tables[ index ]; SMC37c669_drq_table = SMC37c669_default_drq_table; /* ** erfix @@ -2516,13 +2539,13 @@ * None * */ -void __init SMC669_Init ( void ) +void __init SMC669_Init ( int index ) { SMC37c669_CONFIG_REGS *SMC_base; unsigned long flags; __save_and_cli(flags); - if ( ( SMC_base = SMC37c669_detect( ) ) != NULL ) { + if ( ( SMC_base = SMC37c669_detect( index ) ) != NULL ) { #if SMC_DEBUG SMC37c669_config_mode( TRUE ); SMC37c669_dump_registers( ); diff -ur --new-file old/linux/arch/alpha/kernel/smp.c new/linux/arch/alpha/kernel/smp.c --- old/linux/arch/alpha/kernel/smp.c Sun Jan 17 02:02:50 1999 +++ new/linux/arch/alpha/kernel/smp.c Mon May 10 18:55:21 1999 @@ -37,7 +37,18 @@ #define DBGS(args) #endif -struct ipi_msg_flush_tb_struct ipi_msg_flush_tb __cacheline_aligned; +struct ipi_msg_flush_tb_struct { + volatile unsigned int flush_tb_mask; + union { + struct mm_struct * flush_mm; + struct vm_area_struct * flush_vma; + } p; + unsigned long flush_addr; + unsigned long flush_end; +}; + +static struct ipi_msg_flush_tb_struct ipi_msg_flush_tb __cacheline_aligned; +static spinlock_t flush_tb_lock = SPIN_LOCK_UNLOCKED; struct cpuinfo_alpha cpu_data[NR_CPUS]; @@ -499,6 +510,7 @@ return; } mdelay(1); + barrier(); } DBGS(("secondary_cpu_start: SUCCESS for CPU %d!!!\n", cpuid)); } @@ -541,6 +553,7 @@ if (!(hwrpb->txrdy & cpumask)) goto ready1; udelay(100); + barrier(); } goto timeout; @@ -549,6 +562,7 @@ if (!(hwrpb->txrdy & cpumask)) goto ready2; udelay(100); + barrier(); } goto timeout; @@ -783,7 +797,7 @@ unsigned long to_whom = cpu_present_map ^ (1 << smp_processor_id()); long timeout = 1000000; - spin_lock_own(&kernel_flag, "flush_tlb_all"); + spin_lock(&flush_tb_lock); ipi_msg_flush_tb.flush_tb_mask = to_whom; send_ipi_message(to_whom, IPI_TLB_ALL); @@ -800,6 +814,8 @@ ipi_msg_flush_tb.flush_tb_mask); ipi_msg_flush_tb.flush_tb_mask = 0; } + + spin_unlock(&flush_tb_lock); } void @@ -808,7 +824,7 @@ unsigned long to_whom = cpu_present_map ^ (1 << smp_processor_id()); long timeout = 1000000; - spin_lock_own(&kernel_flag, "flush_tlb_mm"); + spin_lock(&flush_tb_lock); ipi_msg_flush_tb.flush_tb_mask = to_whom; ipi_msg_flush_tb.p.flush_mm = mm; @@ -830,6 +846,8 @@ ipi_msg_flush_tb.flush_tb_mask); ipi_msg_flush_tb.flush_tb_mask = 0; } + + spin_unlock(&flush_tb_lock); } void @@ -840,7 +858,7 @@ struct mm_struct * mm = vma->vm_mm; int timeout = 1000000; - spin_lock_own(&kernel_flag, "flush_tlb_page"); + spin_lock(&flush_tb_lock); ipi_msg_flush_tb.flush_tb_mask = to_whom; ipi_msg_flush_tb.p.flush_vma = vma; @@ -863,6 +881,8 @@ ipi_msg_flush_tb.flush_tb_mask); ipi_msg_flush_tb.flush_tb_mask = 0; } + + spin_unlock(&flush_tb_lock); } void diff -ur --new-file old/linux/arch/alpha/kernel/sys_dp264.c new/linux/arch/alpha/kernel/sys_dp264.c --- old/linux/arch/alpha/kernel/sys_dp264.c Sun Jan 10 18:59:59 1999 +++ new/linux/arch/alpha/kernel/sys_dp264.c Mon Feb 22 04:06:36 1999 @@ -316,7 +316,7 @@ { layout_all_busses(DEFAULT_IO_BASE, DEFAULT_MEM_BASE); common_pci_fixup(dp264_map_irq, common_swizzle); - SMC669_Init(); + SMC669_Init(0); } static void __init @@ -325,7 +325,7 @@ layout_all_busses(DEFAULT_IO_BASE, DEFAULT_MEM_BASE); common_pci_fixup(monet_map_irq, monet_swizzle); /* es1888_init(); */ /* later? */ - SMC669_Init(); + SMC669_Init(1); } static void __init @@ -333,7 +333,7 @@ { layout_all_busses(DEFAULT_IO_BASE, DEFAULT_MEM_BASE); common_pci_fixup(webbrick_map_irq, common_swizzle); - SMC669_Init(); + SMC669_Init(0); } diff -ur --new-file old/linux/arch/alpha/kernel/sys_miata.c new/linux/arch/alpha/kernel/sys_miata.c --- old/linux/arch/alpha/kernel/sys_miata.c Wed Nov 25 23:52:22 1998 +++ new/linux/arch/alpha/kernel/sys_miata.c Mon Feb 22 04:06:36 1999 @@ -267,7 +267,7 @@ { layout_all_busses(DEFAULT_IO_BASE, DEFAULT_MEM_BASE); common_pci_fixup(miata_map_irq, miata_swizzle); - SMC669_Init(); /* it might be a GL (fails harmlessly if not) */ + SMC669_Init(0); /* it might be a GL (fails harmlessly if not) */ es1888_init(); } diff -ur --new-file old/linux/arch/alpha/kernel/sys_sx164.c new/linux/arch/alpha/kernel/sys_sx164.c --- old/linux/arch/alpha/kernel/sys_sx164.c Mon Oct 12 20:40:12 1998 +++ new/linux/arch/alpha/kernel/sys_sx164.c Mon Feb 22 04:06:36 1999 @@ -183,7 +183,7 @@ { layout_all_busses(DEFAULT_IO_BASE, DEFAULT_MEM_BASE); common_pci_fixup(sx164_map_irq, common_swizzle); - SMC669_Init(); + SMC669_Init(0); } diff -ur --new-file old/linux/arch/alpha/kernel/time.c new/linux/arch/alpha/kernel/time.c --- old/linux/arch/alpha/kernel/time.c Tue Jan 19 19:19:38 1999 +++ new/linux/arch/alpha/kernel/time.c Sun Apr 25 02:54:08 1999 @@ -18,6 +18,9 @@ * fixed tick loss calculation in timer_interrupt * (round system clock to nearest tick instead of truncating) * fixed algorithm in time_init for getting time from CMOS clock + * 1999-04-16 Thorsten Kranzkowski (dl8bcu@gmx.net) + * fixed algorithm in do_gettimeofday() for calculating the precise time + * from processor cycle counter (now taking lost_ticks into account) */ #include #include @@ -223,7 +226,7 @@ { void (*irq_handler)(int, void *, struct pt_regs *); unsigned int year, mon, day, hour, min, sec, cc1, cc2; - unsigned long cycle_freq; + unsigned long cycle_freq, diff, one_percent; /* * The Linux interpretation of the CMOS clock register contents: @@ -237,19 +240,30 @@ /* Read cycle counter exactly on falling edge of update flag */ cc1 = rpcc(); - /* If our cycle frequency isn't valid, go another round and give - a guess at what it should be. */ - cycle_freq = hwrpb->cycle_freq; - if (cycle_freq == 0) { - printk("HWRPB cycle frequency bogus. Estimating... "); - + if (!est_cycle_freq) { + /* Sometimes the hwrpb->cycle_freq value is bogus. + Go another round to check up on it and see. */ do { } while (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)); do { } while (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP); cc2 = rpcc(); - est_cycle_freq = cycle_freq = cc2 - cc1; + est_cycle_freq = cc2 - cc1; cc1 = cc2; + } - printk("%lu Hz\n", cycle_freq); + /* If the given value is within 1% of what we calculated, + accept it. Otherwise, use what we found. */ + cycle_freq = hwrpb->cycle_freq; + one_percent = cycle_freq / 100; + diff = cycle_freq - est_cycle_freq; + if (diff < 0) + diff = -diff; + if (diff > one_percent) { + cycle_freq = est_cycle_freq; + printk("HWRPB cycle frequency bogus. Estimated %lu Hz\n", + cycle_freq); + } + else { + est_cycle_freq = 0; } /* From John Bowman : allow the values @@ -314,8 +328,10 @@ void do_gettimeofday(struct timeval *tv) { - unsigned long flags, now, delta_cycles, delta_usec; + unsigned long flags, delta_cycles, delta_usec; unsigned long sec, usec; + __u32 now; + extern volatile unsigned long lost_ticks; /*kernel/sched.c*/ now = rpcc(); save_and_cli(flags); @@ -337,9 +353,15 @@ * with no clear gain. */ - delta_usec = delta_cycles * state.scaled_ticks_per_cycle * 15625; + delta_usec = (delta_cycles * state.scaled_ticks_per_cycle + + state.partial_tick + + (lost_ticks << FIX_SHIFT) ) * 15625; delta_usec = ((delta_usec / ((1UL << (FIX_SHIFT-6-1)) * HZ)) + 1) / 2; + /* the 'lost_tics' term above implements this: + * delta_usec += lost_ticks * (1000000 / HZ); + */ + usec += delta_usec; if (usec >= 1000000) { sec += 1; @@ -357,7 +379,6 @@ xtime = *tv; time_adjust = 0; /* stop active adjtime() */ time_status |= STA_UNSYNC; - time_state = TIME_ERROR; /* p. 24, (a) */ time_maxerror = NTP_PHASE_LIMIT; time_esterror = NTP_PHASE_LIMIT; sti(); diff -ur --new-file old/linux/arch/alpha/kernel/traps.c new/linux/arch/alpha/kernel/traps.c --- old/linux/arch/alpha/kernel/traps.c Mon Oct 12 20:40:12 1998 +++ new/linux/arch/alpha/kernel/traps.c Mon May 10 18:55:21 1999 @@ -121,17 +121,20 @@ #endif asmlinkage void -do_entArith(unsigned long summary, unsigned long write_mask, unsigned long a2, - unsigned long a3, unsigned long a4, unsigned long a5, - struct pt_regs regs) +do_entArith(unsigned long summary, unsigned long write_mask, + unsigned long a2, unsigned long a3, unsigned long a4, + unsigned long a5, struct pt_regs regs) { - if ((summary & 1)) { - /* - * Software-completion summary bit is set, so try to - * emulate the instruction. - */ - if (alpha_fp_emul_imprecise(®s, write_mask)) { - return; /* emulation was successful */ + if (summary & 1) { + /* Software-completion summary bit is set, so try to + emulate the instruction. */ + if (implver() == IMPLVER_EV6) { + /* Whee! EV6 has precice exceptions. */ + if (alpha_fp_emul(regs.pc - 4)) + return; + } else { + if (alpha_fp_emul_imprecise(®s, write_mask)) + return; } } @@ -141,22 +144,26 @@ current->comm, regs.pc, summary, write_mask); #endif die_if_kernel("Arithmetic fault", ®s, 0, 0); - force_sig(SIGFPE, current); + send_sig(SIGFPE, current, 1); unlock_kernel(); } -asmlinkage void do_entIF(unsigned long type, unsigned long a1, - unsigned long a2, unsigned long a3, unsigned long a4, - unsigned long a5, struct pt_regs regs) +asmlinkage void +do_entIF(unsigned long type, unsigned long a1, + unsigned long a2, unsigned long a3, unsigned long a4, + unsigned long a5, struct pt_regs regs) { - lock_kernel(); die_if_kernel("Instruction fault", ®s, type, 0); switch (type) { case 0: /* breakpoint */ if (ptrace_cancel_bpt(current)) { regs.pc -= 4; /* make pc point to former bpt */ } - force_sig(SIGTRAP, current); + send_sig(SIGTRAP, current, 1); + break; + + case 1: /* bugcheck */ + send_sig(SIGTRAP, current, 1); break; case 2: /* gentrap */ @@ -170,14 +177,13 @@ switch ((long) regs.r16) { case GEN_INTOVF: case GEN_INTDIV: case GEN_FLTOVF: case GEN_FLTDIV: case GEN_FLTUND: case GEN_FLTINV: - case GEN_FLTINE: - force_sig(SIGFPE, current); + case GEN_FLTINE: case GEN_ROPRAND: + send_sig(SIGFPE, current, 1); break; case GEN_DECOVF: case GEN_DECDIV: case GEN_DECINV: - case GEN_ROPRAND: case GEN_ASSERTERR: case GEN_NULPTRERR: case GEN_STKOVF: @@ -192,44 +198,50 @@ case GEN_SUBRNG5: case GEN_SUBRNG6: case GEN_SUBRNG7: - force_sig(SIGILL, current); + send_sig(SIGTRAP, current, 1); break; } break; - case 1: /* bugcheck */ case 3: /* FEN fault */ - force_sig(SIGILL, current); + send_sig(SIGILL, current, 1); break; case 4: /* opDEC */ -#ifdef CONFIG_ALPHA_NEED_ROUNDING_EMULATION - { - unsigned int opcode; - - /* get opcode of faulting instruction: */ - get_user(opcode, (__u32*)(regs.pc - 4)); - opcode >>= 26; - if (opcode == 0x16) { - /* - * It's a FLTI instruction, emulate it - * (we don't do no stinkin' VAX fp...) - */ - if (!alpha_fp_emul(regs.pc - 4)) - force_sig(SIGFPE, current); - break; - } + if (implver() == IMPLVER_EV4) { + /* EV4 does not implement anything except normal + rounding. Everything else will come here as + an illegal instruction. Emulate them. */ + if (alpha_fp_emul(regs.pc - 4)) + return; } -#endif - force_sig(SIGILL, current); + send_sig(SIGILL, current, 1); break; default: panic("do_entIF: unexpected instruction-fault type"); } +} + +/* There is an ifdef in the PALcode in MILO that enables a + "kernel debugging entry point" as an unprivilaged call_pal. + + We don't want to have anything to do with it, but unfortunately + several versions of MILO included in distributions have it enabled, + and if we don't put something on the entry point we'll oops. */ + +asmlinkage void +do_entDbg(unsigned long type, unsigned long a1, + unsigned long a2, unsigned long a3, unsigned long a4, + unsigned long a5, struct pt_regs regs) +{ + lock_kernel(); + die_if_kernel("Instruction fault", ®s, type, 0); + force_sig(SIGILL, current); unlock_kernel(); } + /* * entUna has a different register layout to be reasonably simple. It * needs access to all the integer registers (the kernel doesn't use @@ -857,14 +869,14 @@ give_sigsegv: regs->pc -= 4; /* make pc point to faulting insn */ lock_kernel(); - force_sig(SIGSEGV, current); + send_sig(SIGSEGV, current, 1); unlock_kernel(); return; give_sigbus: regs->pc -= 4; lock_kernel(); - force_sig(SIGBUS, current); + send_sig(SIGBUS, current, 1); unlock_kernel(); return; } @@ -895,4 +907,5 @@ wrent(entIF, 3); wrent(entUna, 4); wrent(entSys, 5); + wrent(entDbg, 6); } diff -ur --new-file old/linux/arch/alpha/lib/clear_user.S new/linux/arch/alpha/lib/clear_user.S --- old/linux/arch/alpha/lib/clear_user.S Sun Nov 30 19:59:02 1997 +++ new/linux/arch/alpha/lib/clear_user.S Sun Apr 25 02:54:08 1999 @@ -80,6 +80,7 @@ ret $31, ($28), 1 # .. e1 : __do_clear_user: + ldgp $29,0($27) # we do exceptions -- we need the gp. and $6, 7, $4 # e0 : find dest misalignment beq $0, $zerolength # .. e1 : addq $0, $4, $1 # e0 : bias counter diff -ur --new-file old/linux/arch/alpha/lib/copy_user.S new/linux/arch/alpha/lib/copy_user.S --- old/linux/arch/alpha/lib/copy_user.S Sun Apr 26 07:35:18 1998 +++ new/linux/arch/alpha/lib/copy_user.S Fri Apr 30 17:22:19 1999 @@ -46,6 +46,8 @@ .globl __copy_user .ent __copy_user __copy_user: + ldgp $29,0($27) # we do exceptions -- we need the gp. + .prologue 1 and $6,7,$3 beq $0,$35 beq $3,$36 @@ -107,7 +109,7 @@ $66: EXI( ldq $1,0($7) ) subq $4,8,$4 - stq $1,0($6) + EXO( stq $1,0($6) ) addq $7,8,$7 subq $0,8,$0 addq $6,8,$6 diff -ur --new-file old/linux/arch/alpha/lib/io.c new/linux/arch/alpha/lib/io.c --- old/linux/arch/alpha/lib/io.c Sun Sep 6 19:34:33 1998 +++ new/linux/arch/alpha/lib/io.c Thu Apr 15 14:42:31 1999 @@ -405,15 +405,16 @@ * Copy data from "real" memory space to IO memory space. * This needs to be optimized. */ -void _memcpy_toio(unsigned long to, void * from, long count) +void _memcpy_toio(unsigned long to, const void * from, long count) { /* Optimize co-aligned transfers. Everything else gets handled a byte at a time. */ + /* FIXME -- align FROM. */ if (count >= 8 && (to & 7) == ((long)from & 7)) { count -= 8; do { - writeq(*(u64 *)from, to); + writeq(*(const u64 *)from, to); count -= 8; to += 8; from += 8; @@ -424,7 +425,7 @@ if (count >= 4 && (to & 3) == ((long)from & 3)) { count -= 4; do { - writel(*(u32 *)from, to); + writel(*(const u32 *)from, to); count -= 4; to += 4; from += 4; @@ -435,7 +436,7 @@ if (count >= 2 && (to & 1) == ((long)from & 1)) { count -= 2; do { - writew(*(u16 *)from, to); + writew(*(const u16 *)from, to); count -= 2; to += 2; from += 2; @@ -444,7 +445,7 @@ } while (count > 0) { - writeb(*(u8 *) from, to); + writeb(*(const u8 *) from, to); count--; to++; from++; diff -ur --new-file old/linux/arch/alpha/lib/strlen_user.S new/linux/arch/alpha/lib/strlen_user.S --- old/linux/arch/alpha/lib/strlen_user.S Wed Jun 24 23:30:08 1998 +++ new/linux/arch/alpha/lib/strlen_user.S Sun Apr 25 02:54:08 1999 @@ -27,7 +27,8 @@ .align 3 __strlen_user: - .prologue 0 + ldgp $29,0($27) # we do exceptions -- we need the gp. + .prologue 1 EX( ldq_u t0, 0(a0) ) # load first quadword (a0 may be misaligned) lda t1, -1(zero) diff -ur --new-file old/linux/arch/alpha/lib/strncpy_from_user.S new/linux/arch/alpha/lib/strncpy_from_user.S --- old/linux/arch/alpha/lib/strncpy_from_user.S Thu Feb 6 13:48:45 1997 +++ new/linux/arch/alpha/lib/strncpy_from_user.S Sun Apr 25 02:54:08 1999 @@ -31,6 +31,7 @@ .globl __strncpy_from_user .ent __strncpy_from_user .frame $30, 0, $26 + .prologue 1 .align 3 $aligned: @@ -99,6 +100,7 @@ /*** The Function Entry Point ***/ .align 3 __strncpy_from_user: + ldgp $29, 0($27) # we do exceptions -- we need the gp. mov a0, v0 # save the string start beq a2, $zerolength diff -ur --new-file old/linux/arch/alpha/math-emu/fp-emul.c new/linux/arch/alpha/math-emu/fp-emul.c --- old/linux/arch/alpha/math-emu/fp-emul.c Sun Aug 9 21:09:06 1998 +++ new/linux/arch/alpha/math-emu/fp-emul.c Mon May 10 18:55:21 1999 @@ -13,6 +13,7 @@ #define OPC_INTL 0x11 #define OPC_INTS 0x12 #define OPC_INTM 0x13 +#define OPC_FLTC 0x14 #define OPC_FLTV 0x15 #define OPC_FLTI 0x16 #define OPC_FLTL 0x17 @@ -21,33 +22,37 @@ #define OPC_JSR 0x1a +#define OP_FUN(OP,FUN) ((OP << 26) | (FUN << 5)) + /* - * "Base" function codes for the FLTI-class instructions. These - * instructions all have opcode 0x16. Note that in most cases these - * actually correspond to the "chopped" form of the instruction. Not - * to worry---we extract the qualifier bits separately and deal with - * them separately. Notice that base function code 0x2c is used for - * both CVTTS and CVTST. The other bits in the function code are used - * to distinguish the two. + * "Base" function codes for the FLTI-class instructions. + * Note that in most cases these actually correspond to the "chopped" + * form of the instruction. Not to worry---we extract the qualifier + * bits separately and deal with them separately. Notice that base + * function code 0x2c is used for both CVTTS and CVTST. The other bits + * in the function code are used to distinguish the two. */ -#define FLTI_FUNC_ADDS 0x000 -#define FLTI_FUNC_ADDT 0x020 -#define FLTI_FUNC_CMPTEQ 0x025 -#define FLTI_FUNC_CMPTLT 0x026 -#define FLTI_FUNC_CMPTLE 0x027 -#define FLTI_FUNC_CMPTUN 0x024 -#define FLTI_FUNC_CVTTS_or_CVTST 0x02c -#define FLTI_FUNC_CVTTQ 0x02f -#define FLTI_FUNC_CVTQS 0x03c -#define FLTI_FUNC_CVTQT 0x03e -#define FLTI_FUNC_DIVS 0x003 -#define FLTI_FUNC_DIVT 0x023 -#define FLTI_FUNC_MULS 0x002 -#define FLTI_FUNC_MULT 0x022 -#define FLTI_FUNC_SUBS 0x001 -#define FLTI_FUNC_SUBT 0x021 +#define FLTI_FUNC_ADDS OP_FUN(OPC_FLTI, 0x000) +#define FLTI_FUNC_ADDT OP_FUN(OPC_FLTI, 0x020) +#define FLTI_FUNC_CMPTEQ OP_FUN(OPC_FLTI, 0x025) +#define FLTI_FUNC_CMPTLT OP_FUN(OPC_FLTI, 0x026) +#define FLTI_FUNC_CMPTLE OP_FUN(OPC_FLTI, 0x027) +#define FLTI_FUNC_CMPTUN OP_FUN(OPC_FLTI, 0x024) +#define FLTI_FUNC_CVTTS_or_CVTST OP_FUN(OPC_FLTI, 0x02c) +#define FLTI_FUNC_CVTTQ OP_FUN(OPC_FLTI, 0x02f) +#define FLTI_FUNC_CVTQS OP_FUN(OPC_FLTI, 0x03c) +#define FLTI_FUNC_CVTQT OP_FUN(OPC_FLTI, 0x03e) +#define FLTI_FUNC_DIVS OP_FUN(OPC_FLTI, 0x003) +#define FLTI_FUNC_DIVT OP_FUN(OPC_FLTI, 0x023) +#define FLTI_FUNC_MULS OP_FUN(OPC_FLTI, 0x002) +#define FLTI_FUNC_MULT OP_FUN(OPC_FLTI, 0x022) +#define FLTI_FUNC_SUBS OP_FUN(OPC_FLTI, 0x001) +#define FLTI_FUNC_SUBT OP_FUN(OPC_FLTI, 0x021) + +#define FLTC_FUNC_SQRTS OP_FUN(OPC_FLTC, 0x00B) +#define FLTC_FUNC_SQRTT OP_FUN(OPC_FLTC, 0x02B) -#define FLTI_FUNC_CVTQL 0x030 /* opcode 0x17 */ +#define FLTL_FUNC_CVTQL OP_FUN(OPC_FLTL, 0x030) #define MISC_TRAPB 0x0000 #define MISC_EXCB 0x0400 @@ -101,7 +106,7 @@ long alpha_fp_emul (unsigned long pc) { - unsigned long opcode, fa, fb, fc, func, mode; + unsigned long op_fun, fa, fb, fc, func, mode; unsigned long fpcw = current->tss.flags; unsigned long va, vb, vc, res, fpcr; __u32 insn; @@ -110,10 +115,11 @@ get_user(insn, (__u32*)pc); fc = (insn >> 0) & 0x1f; /* destination register */ - func = (insn >> 5) & 0x7ff; fb = (insn >> 16) & 0x1f; fa = (insn >> 21) & 0x1f; - opcode = insn >> 26; + func = (insn >> 5) & 0x7ff; + mode = (insn >> 5) & 0xc0; + op_fun = insn & OP_FUN(0x3f, 0x3f); va = alpha_read_fp_reg(fa); vb = alpha_read_fp_reg(fb); @@ -123,7 +129,6 @@ * Try the operation in software. First, obtain the rounding * mode... */ - mode = func & 0xc0; if (mode == 0xc0) { /* dynamic---get rounding mode from fpcr: */ mode = ((fpcr & FPCR_DYN_MASK) >> FPCR_DYN_SHIFT) << ROUND_SHIFT; @@ -135,8 +140,7 @@ something_is_wrong(); } - /* least 6 bits contain operation code: */ - switch (func & 0x3f) { + switch (op_fun) { case FLTI_FUNC_CMPTEQ: res = ieee_CMPTEQ(va, vb, &vc); break; @@ -153,7 +157,7 @@ res = ieee_CMPTUN(va, vb, &vc); break; - case FLTI_FUNC_CVTQL: + case FLTL_FUNC_CVTQL: /* * Notice: We can get here only due to an integer * overflow. Such overflows are reported as invalid @@ -222,6 +226,14 @@ res = ieee_CVTTQ(mode, vb, &vc); break; + case FLTC_FUNC_SQRTS: + res = ieee_SQRTS(mode, vb, &vc); + break; + + case FLTC_FUNC_SQRTT: + res = ieee_SQRTT(mode, vb, &vc); + break; + default: printk("alpha_fp_emul: unexpected function code %#lx at %#lx\n", func & 0x3f, pc); @@ -247,7 +259,7 @@ /* Update hardware control register */ fpcr &= (~FPCR_MASK | FPCR_DYN_MASK); - fpcr |= ieee_swcr_to_fpcr(fpcw | (~fpcw&IEEE_STATUS_MASK)>>16); + fpcr |= ieee_swcr_to_fpcr(fpcw); wrfpcr(fpcr); /* Do we generate a signal? */ @@ -319,6 +331,7 @@ write_mask &= ~(1UL << rc); break; + case OPC_FLTC: case OPC_FLTV: case OPC_FLTI: case OPC_FLTL: @@ -326,13 +339,11 @@ break; } if (!write_mask) { - if ((opcode == OPC_FLTI || opcode == OPC_FLTL) - && alpha_fp_emul(trigger_pc)) - { - /* re-execute insns in trap-shadow: */ - regs->pc = trigger_pc + 4; - MOD_DEC_USE_COUNT; - return 1; + if (alpha_fp_emul(trigger_pc)) { + /* re-execute insns in trap-shadow: */ + regs->pc = trigger_pc + 4; + MOD_DEC_USE_COUNT; + return 1; } break; } diff -ur --new-file old/linux/arch/alpha/math-emu/ieee-math.c new/linux/arch/alpha/math-emu/ieee-math.c --- old/linux/arch/alpha/math-emu/ieee-math.c Sun Sep 6 19:34:33 1998 +++ new/linux/arch/alpha/math-emu/ieee-math.c Mon May 10 18:55:21 1999 @@ -22,6 +22,7 @@ * functions are used on exceptional numbers only (well, assuming you * don't turn on the "trap on inexact"...). */ +#include #include "ieee-math.h" #define STICKY_S 0x20000000 /* both in longword 0 of fraction */ @@ -1339,4 +1340,42 @@ normalize(&op_c); op_c.e -= 9; /* remove excess exp from original shift */ return round_t_ieee(f, &op_c, c); +} + +/* + * Sqrt a = b, where a and b are ieee s-floating numbers. "f" + * contains the rounding mode etc. + */ +unsigned long +ieee_SQRTS (int f, unsigned long a, unsigned long *b) +{ + fpclass_t a_type; + EXTENDED op_a, op_b; + + *b = IEEE_QNaN; + a_type = extend_ieee(a, &op_a, SINGLE); + if (op_a.s == 0) { + /* FIXME -- handle positive denormals. */ + send_sig(SIGFPE, current, 1); + } + return FPCR_INV; +} + +/* + * Sqrt a = b, where a and b are ieee t-floating numbers. "f" + * contains the rounding mode etc. + */ +unsigned long +ieee_SQRTT (int f, unsigned long a, unsigned long *b) +{ + fpclass_t a_type; + EXTENDED op_a, op_b; + + *b = IEEE_QNaN; + a_type = extend_ieee(a, &op_a, DOUBLE); + if (op_a.s == 0) { + /* FIXME -- handle positive denormals. */ + send_sig(SIGFPE, current, 1); + } + return FPCR_INV; } diff -ur --new-file old/linux/arch/alpha/math-emu/ieee-math.h new/linux/arch/alpha/math-emu/ieee-math.h --- old/linux/arch/alpha/math-emu/ieee-math.h Fri Dec 22 07:22:05 1995 +++ new/linux/arch/alpha/math-emu/ieee-math.h Mon May 10 18:55:21 1999 @@ -48,5 +48,7 @@ unsigned long *c); extern unsigned long ieee_DIVT (int rm, unsigned long a, unsigned long b, unsigned long *c); +extern unsigned long ieee_SQRTS (int rm, unsigned long a, unsigned long *b); +extern unsigned long ieee_SQRTT (int rm, unsigned long a, unsigned long *b); #endif /* __ieee_math_h__ */ diff -ur --new-file old/linux/arch/arm/defconfig new/linux/arch/arm/defconfig --- old/linux/arch/arm/defconfig Wed Aug 5 08:42:22 1998 +++ new/linux/arch/arm/defconfig Thu Feb 25 19:46:46 1999 @@ -80,7 +80,6 @@ # CONFIG_PACKET is not set # CONFIG_NETLINK is not set # CONFIG_FIREWALL is not set -# CONFIG_NET_ALIAS is not set # CONFIG_FILTER is not set CONFIG_UNIX=y CONFIG_INET=y diff -ur --new-file old/linux/arch/arm/kernel/sys_arm.c new/linux/arch/arm/kernel/sys_arm.c --- old/linux/arch/arm/kernel/sys_arm.c Thu Dec 17 18:05:42 1998 +++ new/linux/arch/arm/kernel/sys_arm.c Sat May 8 20:14:01 1999 @@ -77,12 +77,14 @@ goto out; if (!(a.flags & MAP_ANONYMOUS)) { error = -EBADF; - if (a.fd >= current->files->max_fds || - !(file = current->files->fd[a.fd])) + file = fget(a.fd); + if (!file) goto out; } a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); error = do_mmap(file, a.addr, a.len, a.prot, a.flags, a.offset); + if (file) + fput(file); out: unlock_kernel(); return error; diff -ur --new-file old/linux/arch/arm/kernel/time.c new/linux/arch/arm/kernel/time.c --- old/linux/arch/arm/kernel/time.c Tue Jan 19 19:19:41 1999 +++ new/linux/arch/arm/kernel/time.c Fri Mar 12 08:24:55 1999 @@ -127,7 +127,6 @@ xtime = *tv; time_adjust = 0; /* stop active adjtime() */ time_status |= STA_UNSYNC; - time_state = TIME_ERROR; /* p. 24, (a) */ time_maxerror = NTP_PHASE_LIMIT; time_esterror = NTP_PHASE_LIMIT; sti (); diff -ur --new-file old/linux/arch/arm/mm/Makefile new/linux/arch/arm/mm/Makefile --- old/linux/arch/arm/mm/Makefile Fri May 8 09:42:38 1998 +++ new/linux/arch/arm/mm/Makefile Sat May 8 20:06:56 1999 @@ -8,37 +8,30 @@ # Note 2! The CFLAGS definition is now in the main makefile... all: lib first_rule -ifeq ($(MACHINE),a5k) -MMARCH=arc -else -MMARCH=$(MACHINE) -endif O_TARGET := mm.o -O_OBJS := init.o extable.o fault-$(PROCESSOR).o mm-$(MMARCH).o +O_OBJS := init.o extable.o fault-$(PROCESSOR).o small_page.o ifeq ($(PROCESSOR),armo) O_OBJS += proc-arm2,3.o endif ifeq ($(PROCESSOR),armv) - O_OBJS += small_page.o proc-arm6,7.o proc-sa110.o + O_OBJS += mm-$(MACHINE).o proc-arm6,7.o proc-sa110.o ioremap.o endif include $(TOPDIR)/Rules.make -proc-arm2,3.o: ../lib/constants.h -proc-arm6,7.o: ../lib/constants.h -proc-sa110.o: ../lib/constants.h - %.o: %.S -ifneq ($(CONFIG_BINUTILS_NEW),y) - $(CC) $(CFLAGS) -D__ASSEMBLY__ -E $< | tr ';$$' '\n#' > ..$@.tmp.s - $(CC) $(CFLAGS:-pipe=) -c -o $@ ..$@.tmp.s - $(RM) ..$@.tmp.s -else $(CC) $(CFLAGS) -D__ASSEMBLY__ -c -o $@ $< -endif .PHONY: lib lib:; @$(MAKE) -C ../lib constants.h + +# Special dependencies +fault-armv.o: fault-common.c +fault-armo.o: fault-common.c +proc-arm2,3.o: ../lib/constants.h +proc-arm6,7.o: ../lib/constants.h +proc-sa110.o: ../lib/constants.h + diff -ur --new-file old/linux/arch/arm/mm/fault-armo.c new/linux/arch/arm/mm/fault-armo.c --- old/linux/arch/arm/mm/fault-armo.c Thu Dec 17 18:05:42 1998 +++ new/linux/arch/arm/mm/fault-armo.c Sat May 8 20:06:56 1999 @@ -1,11 +1,10 @@ /* - * linux/arch/arm/mm/fault.c + * linux/arch/arm/mm/fault-armo.c * * Copyright (C) 1995 Linus Torvalds - * Modifications for ARM processor (c) 1995, 1996 Russell King + * Modifications for ARM processor (c) 1995-1999 Russell King */ -#include #include #include #include @@ -15,8 +14,7 @@ #include #include #include -#include -#include +#include #include #include @@ -27,35 +25,32 @@ #define FAULT_CODE_WRITE 0x02 #define FAULT_CODE_USER 0x01 -struct pgtable_cache_struct quicklists; +#define DO_COW(m) ((m) & (FAULT_CODE_WRITE|FAULT_CODE_FORCECOW)) +#define READ_FAULT(m) (!((m) & FAULT_CODE_WRITE)) -void __bad_pmd(pmd_t *pmd) +#include "fault-common.c" + +static void *alloc_table(int size, int prio) { - printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd)); -#ifdef CONFIG_DEBUG_ERRORS - __backtrace(); -#endif - set_pmd(pmd, mk_pmd(BAD_PAGETABLE)); + if (size != 128) + printk("invalid table size\n"); + return (void *)get_page_8k(prio); } -void __bad_pmd_kernel(pmd_t *pmd) +void free_table(void *table) { - printk("Bad pmd in pte_alloc_kernel: %08lx\n", pmd_val(*pmd)); -#ifdef CONFIG_DEBUG_ERRORS - __backtrace(); -#endif - set_pmd(pmd, mk_pmd(BAD_PAGETABLE)); + free_page_8k((unsigned long)table); } pgd_t *get_pgd_slow(void) { - pgd_t *pgd = (pgd_t *) kmalloc(PTRS_PER_PGD * BYTES_PER_PTR, GFP_KERNEL); + pgd_t *pgd = (pgd_t *)alloc_table(PTRS_PER_PGD * BYTES_PER_PTR, GFP_KERNEL); pgd_t *init; - + if (pgd) { init = pgd_offset(&init_mm, 0); - memzero (pgd, USER_PTRS_PER_PGD * BYTES_PER_PTR); - memcpy (pgd + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD, + memzero(pgd, USER_PTRS_PER_PGD * BYTES_PER_PTR); + memcpy(pgd + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD, (PTRS_PER_PGD - USER_PTRS_PER_PGD) * BYTES_PER_PTR); } return pgd; @@ -65,17 +60,17 @@ { pte_t *pte; - pte = (pte_t *) kmalloc (PTRS_PER_PTE * BYTES_PER_PTR, GFP_KERNEL); + pte = (pte_t *)alloc_table(PTRS_PER_PTE * BYTES_PER_PTR, GFP_KERNEL); if (pmd_none(*pmd)) { if (pte) { - memzero (pte, PTRS_PER_PTE * BYTES_PER_PTR); + memzero(pte, PTRS_PER_PTE * BYTES_PER_PTR); set_pmd(pmd, mk_pmd(pte)); return pte + offset; } set_pmd(pmd, mk_pmd(BAD_PAGETABLE)); return NULL; } - kfree (pte); + free_table((void *)pte); if (pmd_bad(*pmd)) { __bad_pmd(pmd); return NULL; @@ -83,126 +78,22 @@ return (pte_t *) pmd_page(*pmd) + offset; } -extern void die_if_kernel(char *msg, struct pt_regs *regs, unsigned int err, unsigned int ret); - -static void kernel_page_fault (unsigned long addr, int mode, struct pt_regs *regs, - struct task_struct *tsk, struct mm_struct *mm) -{ - /* - * Oops. The kernel tried to access some bad page. We'll have to - * terminate things with extreme prejudice. - */ - pgd_t *pgd; - if (addr < PAGE_SIZE) - printk (KERN_ALERT "Unable to handle kernel NULL pointer dereference"); - else - printk (KERN_ALERT "Unable to handle kernel paging request"); - printk (" at virtual address %08lx\n", addr); - printk (KERN_ALERT "current->tss.memmap = %08lX\n", tsk->tss.memmap); - pgd = pgd_offset (mm, addr); - printk (KERN_ALERT "*pgd = %08lx", pgd_val (*pgd)); - if (!pgd_none (*pgd)) { - pmd_t *pmd; - pmd = pmd_offset (pgd, addr); - printk (", *pmd = %08lx", pmd_val (*pmd)); - if (!pmd_none (*pmd)) - printk (", *pte = %08lx", pte_val (*pte_offset (pmd, addr))); - } - printk ("\n"); - die_if_kernel ("Oops", regs, mode, SIGKILL); - do_exit (SIGKILL); -} - -static void -handle_dataabort (unsigned long addr, int mode, struct pt_regs *regs) -{ - struct task_struct *tsk; - struct mm_struct *mm; - struct vm_area_struct *vma; - unsigned long fixup; - - lock_kernel(); - tsk = current; - mm = tsk->mm; - - down(&mm->mmap_sem); - vma = find_vma (mm, addr); - if (!vma) - goto bad_area; - if (addr >= vma->vm_start) - goto good_area; - if (!(vma->vm_flags & VM_GROWSDOWN) || expand_stack (vma, addr)) - goto bad_area; - - /* - * Ok, we have a good vm_area for this memory access, so - * we can handle it.. - */ -good_area: - if (!(mode & FAULT_CODE_WRITE)) { /* write? */ - if (!(vma->vm_flags & (VM_READ|VM_EXEC))) - goto bad_area; - } else { - if (!(vma->vm_flags & VM_WRITE)) - goto bad_area; - } - handle_mm_fault (tsk, vma, addr, mode & (FAULT_CODE_WRITE|FAULT_CODE_FORCECOW)); - up(&mm->mmap_sem); - goto out; - - /* - * Something tried to access memory that isn't in our memory map.. - * Fix it, but check if it's kernel or user first.. - */ -bad_area: - up(&mm->mmap_sem); - if (mode & FAULT_CODE_USER) { -//extern int console_loglevel; -//cli(); - tsk->tss.error_code = mode; - tsk->tss.trap_no = 14; -//console_loglevel = 9; - printk ("%s: memory violation at pc=0x%08lx, lr=0x%08lx (bad address=0x%08lx, code %d)\n", - tsk->comm, regs->ARM_pc, regs->ARM_lr, addr, mode); -//#ifdef DEBUG - show_regs (regs); - c_backtrace (regs->ARM_fp, 0); -//#endif - force_sig(SIGSEGV, tsk); -//while (1); - goto out; - } - - /* Are we prepared to handle this kernel fault? */ - if ((fixup = search_exception_table(instruction_pointer(regs))) != 0) { - printk(KERN_DEBUG "%s: Exception at [<%lx>] addr=%lx (fixup: %lx)\n", - tsk->comm, regs->ARM_pc, addr, fixup); - regs->ARM_pc = fixup; - goto out; - } - - - kernel_page_fault (addr, mode, regs, tsk, mm); -out: - unlock_kernel(); -} - /* * Handle a data abort. Note that we have to handle a range of addresses * on ARM2/3 for ldm. If both pages are zero-mapped, then we have to force - * a copy-on-write + * a copy-on-write. However, on the second page, we always force COW. */ asmlinkage void -do_DataAbort (unsigned long min_addr, unsigned long max_addr, int mode, struct pt_regs *regs) +do_DataAbort(unsigned long min_addr, unsigned long max_addr, int mode, struct pt_regs *regs) { - handle_dataabort (min_addr, mode, regs); + do_page_fault(min_addr, mode, regs); if ((min_addr ^ max_addr) >> PAGE_SHIFT) - handle_dataabort (max_addr, mode | FAULT_CODE_FORCECOW, regs); + do_page_fault(max_addr, mode | FAULT_CODE_FORCECOW, regs); } asmlinkage int -do_PrefetchAbort (unsigned long addr, int mode, struct pt_regs *regs) +do_PrefetchAbort(unsigned long addr, struct pt_regs *regs) { #if 0 if (the memc mapping for this page exists - can check now...) { @@ -210,6 +101,6 @@ return 0; } #endif - handle_dataabort (addr, mode, regs); + do_page_fault(addr, FAULT_CODE_USER|FAULT_CODE_PREFETCH, regs); return 1; } diff -ur --new-file old/linux/arch/arm/mm/fault-armv.c new/linux/arch/arm/mm/fault-armv.c --- old/linux/arch/arm/mm/fault-armv.c Thu Dec 17 18:05:42 1998 +++ new/linux/arch/arm/mm/fault-armv.c Sat May 8 20:06:56 1999 @@ -1,10 +1,11 @@ /* - * linux/arch/arm/mm/fault.c + * linux/arch/arm/mm/fault-armv.c * * Copyright (C) 1995 Linus Torvalds - * Modifications for ARM processor (c) 1995, 1996 Russell King + * Modifications for ARM processor (c) 1995-1999 Russell King */ +#include #include #include #include @@ -14,43 +15,37 @@ #include #include #include -#include -#include +#include +#include +#include #include #include #include +#include #define FAULT_CODE_READ 0x02 #define FAULT_CODE_USER 0x01 -struct pgtable_cache_struct quicklists; +#define DO_COW(m) (!((m) & FAULT_CODE_READ)) +#define READ_FAULT(m) ((m) & FAULT_CODE_READ) -void __bad_pmd(pmd_t *pmd) -{ - printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd)); - set_pmd(pmd, mk_user_pmd(BAD_PAGETABLE)); -} - -void __bad_pmd_kernel(pmd_t *pmd) -{ - printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd)); - set_pmd(pmd, mk_kernel_pmd(BAD_PAGETABLE)); -} +#include "fault-common.c" pgd_t *get_pgd_slow(void) { /* * need to get a 16k page for level 1 */ - pgd_t *pgd = (pgd_t *) __get_free_pages(GFP_KERNEL,2); + pgd_t *pgd = (pgd_t *)__get_free_pages(GFP_KERNEL,2); pgd_t *init; - + if (pgd) { init = pgd_offset(&init_mm, 0); - memzero ((void *)pgd, USER_PTRS_PER_PGD * BYTES_PER_PTR); - memcpy (pgd + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD, + memzero(pgd, USER_PTRS_PER_PGD * BYTES_PER_PTR); + memcpy(pgd + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD, (PTRS_PER_PGD - USER_PTRS_PER_PGD) * BYTES_PER_PTR); + clean_cache_area(pgd, PTRS_PER_PGD * BYTES_PER_PTR); } return pgd; } @@ -59,17 +54,19 @@ { pte_t *pte; - pte = (pte_t *) get_small_page(GFP_KERNEL); + pte = (pte_t *)get_page_2k(GFP_KERNEL); if (pmd_none(*pmd)) { if (pte) { - memzero (pte, PTRS_PER_PTE * BYTES_PER_PTR); + memzero(pte, 2 * PTRS_PER_PTE * BYTES_PER_PTR); + clean_cache_area(pte, PTRS_PER_PTE * BYTES_PER_PTR); + pte += PTRS_PER_PTE; set_pmd(pmd, mk_user_pmd(pte)); return pte + offset; } set_pmd(pmd, mk_user_pmd(BAD_PAGETABLE)); return NULL; } - free_small_page ((unsigned long) pte); + free_page_2k((unsigned long)pte); if (pmd_bad(*pmd)) { __bad_pmd(pmd); return NULL; @@ -81,17 +78,19 @@ { pte_t *pte; - pte = (pte_t *) get_small_page(GFP_KERNEL); + pte = (pte_t *)get_page_2k(GFP_KERNEL); if (pmd_none(*pmd)) { if (pte) { - memzero (pte, PTRS_PER_PTE * BYTES_PER_PTR); + memzero(pte, 2 * PTRS_PER_PTE * BYTES_PER_PTR); + clean_cache_area(pte, PTRS_PER_PTE * BYTES_PER_PTR); + pte += PTRS_PER_PTE; set_pmd(pmd, mk_kernel_pmd(pte)); return pte + offset; } set_pmd(pmd, mk_kernel_pmd(BAD_PAGETABLE)); return NULL; } - free_small_page ((unsigned long) pte); + free_page_2k((unsigned long)pte); if (pmd_bad(*pmd)) { __bad_pmd_kernel(pmd); return NULL; @@ -99,10 +98,8 @@ return (pte_t *) pmd_page(*pmd) + offset; } -extern void die_if_kernel(char *msg, struct pt_regs *regs, unsigned int err, unsigned int ret); - #ifdef DEBUG -static int sp_valid (unsigned long *sp) +static int sp_valid(unsigned long *sp) { unsigned long addr = (unsigned long) sp; @@ -114,187 +111,371 @@ } #endif -static void kernel_page_fault (unsigned long addr, int mode, struct pt_regs *regs, - struct task_struct *tsk, struct mm_struct *mm) +#ifdef CONFIG_ALIGNMENT_TRAP +/* + * 32-bit misaligned trap handler (c) 1998 San Mehat (CCC) -July 1998 + * /proc/sys/debug/alignment, modified and integrated into + * Linux 2.1 by Russell King + * + * NOTE!!! This is not portable onto the ARM6/ARM7 processors yet. Also, + * it seems to give a severe performance impact (1 abort/ms - NW runs at + * ARM6 speeds) with GCC 2.7.2.2 - needs checking with a later GCC/EGCS. + * + * IMHO, I don't think that the trap handler is advantageous on ARM6,7 + * processors (they'll run like an ARM3). We'll see. + */ +#define CODING_BITS(i) (i & 0x0e000000) + +#define LDST_I_BIT(i) (i & (1 << 26)) /* Immediate constant */ +#define LDST_P_BIT(i) (i & (1 << 24)) /* Preindex */ +#define LDST_U_BIT(i) (i & (1 << 23)) /* Add offset */ +#define LDST_W_BIT(i) (i & (1 << 21)) /* Writeback */ +#define LDST_L_BIT(i) (i & (1 << 20)) /* Load */ + +#define LDSTH_I_BIT(i) (i & (1 << 22)) /* half-word immed */ +#define LDM_S_BIT(i) (i & (1 << 22)) /* write CPSR from SPSR */ + +#define RN_BITS(i) ((i >> 16) & 15) /* Rn */ +#define RD_BITS(i) ((i >> 12) & 15) /* Rd */ +#define RM_BITS(i) (i & 15) /* Rm */ + +#define REGMASK_BITS(i) (i & 0xffff) +#define OFFSET_BITS(i) (i & 0x0fff) + +#define IS_SHIFT(i) (i & 0x0ff0) +#define SHIFT_BITS(i) ((i >> 7) & 0x1f) +#define SHIFT_TYPE(i) (i & 0x60) +#define SHIFT_LSL 0x00 +#define SHIFT_LSR 0x20 +#define SHIFT_ASR 0x40 +#define SHIFT_RORRRX 0x60 + +static unsigned long ai_user; +static unsigned long ai_sys; +static unsigned long ai_skipped; +static unsigned long ai_half; +static unsigned long ai_word; +static unsigned long ai_multi; + +static int proc_alignment_read(char *page, char **start, off_t off, + int count, int *eof, void *data) { - /* - * Oops. The kernel tried to access some bad page. We'll have to - * terminate things with extreme prejudice. - */ - pgd_t *pgd; - if (addr < PAGE_SIZE) - printk (KERN_ALERT "Unable to handle kernel NULL pointer dereference"); - else - printk (KERN_ALERT "Unable to handle kernel paging request"); - printk (" at virtual address %08lx\n", addr); - printk (KERN_ALERT "current->tss.memmap = %08lX\n", tsk->tss.memmap); - pgd = pgd_offset (mm, addr); - printk (KERN_ALERT "*pgd = %08lx", pgd_val (*pgd)); - if (!pgd_none (*pgd)) { - pmd_t *pmd; - pmd = pmd_offset (pgd, addr); - printk (", *pmd = %08lx", pmd_val (*pmd)); - if (!pmd_none (*pmd)) - printk (", *pte = %08lx", pte_val (*pte_offset (pmd, addr))); - } - printk ("\n"); - die_if_kernel ("Oops", regs, mode, SIGKILL); - do_exit (SIGKILL); + char *p = page; + int len; + + p += sprintf(p, "User:\t\t%li\n", ai_user); + p += sprintf(p, "System:\t\t%li\n", ai_sys); + p += sprintf(p, "Skipped:\t%li\n", ai_skipped); + p += sprintf(p, "Half:\t\t%li\n", ai_half); + p += sprintf(p, "Word:\t\t%li\n", ai_word); + p += sprintf(p, "Multi:\t\t%li\n", ai_multi); + + len = (p - page) - off; + if (len < 0) + len = 0; + + *eof = (len <= count) ? 1 : 0; + *start = page + off; + + return len; } -static void page_fault (unsigned long addr, int mode, struct pt_regs *regs) +/* + * This needs to be done after sysctl_init, otherwise sys/ + * will be overwritten. + */ +void __init alignment_init(void) { - struct task_struct *tsk; - struct mm_struct *mm; - struct vm_area_struct *vma; - unsigned long fixup; - - lock_kernel(); - tsk = current; - mm = tsk->mm; - - down(&mm->mmap_sem); - vma = find_vma (mm, addr); - if (!vma) - goto bad_area; - if (vma->vm_start <= addr) - goto good_area; - if (!(vma->vm_flags & VM_GROWSDOWN) || expand_stack (vma, addr)) - goto bad_area; + struct proc_dir_entry *e; - /* - * Ok, we have a good vm_area for this memory access, so - * we can handle it.. - */ -good_area: - if (mode & FAULT_CODE_READ) { /* read? */ - if (!(vma->vm_flags & (VM_READ|VM_EXEC))) - goto bad_area; - } else { - if (!(vma->vm_flags & VM_WRITE)) - goto bad_area; + e = create_proc_entry("sys/debug/alignment", S_IFREG | S_IRUGO, NULL); + + if (e) + e->read_proc = proc_alignment_read; +} + +static int +do_alignment_exception(struct pt_regs *regs) +{ + unsigned int instr, rd, rn, correction, nr_regs, regbits; + unsigned long eaddr; + union { unsigned long un; signed long sn; } offset; + + if (user_mode(regs)) { + set_cr(cr_no_alignment); + ai_user += 1; + return 0; } - handle_mm_fault (tsk, vma, addr & PAGE_MASK, !(mode & FAULT_CODE_READ)); - up(&mm->mmap_sem); - goto out; - /* - * Something tried to access memory that isn't in our memory map.. - * Fix it, but check if it's kernel or user first.. - */ -bad_area: - up(&mm->mmap_sem); - if (mode & FAULT_CODE_USER) { - tsk->tss.error_code = mode; - tsk->tss.trap_no = 14; - printk ("%s: memory violation at pc=0x%08lx, lr=0x%08lx (bad address=0x%08lx, code %d)\n", - tsk->comm, regs->ARM_pc, regs->ARM_lr, addr, mode); -#ifdef DEBUG - { - unsigned int i, j; - unsigned long *sp = (unsigned long *) (regs->ARM_sp - 128); - for (j = 0; j < 20 && sp_valid (sp); j++) { - printk ("%p: ", sp); - for (i = 0; i < 8 && sp_valid (sp); i += 1, sp++) - printk ("%08lx ", *sp); - printk ("\n"); + ai_sys += 1; + + instr = *(unsigned long *)instruction_pointer(regs); + correction = 4; /* sometimes 8 on ARMv3 */ + regs->ARM_pc += correction + 4; + + rd = RD_BITS(instr); + rn = RN_BITS(instr); + eaddr = regs->uregs[rn]; + + switch(CODING_BITS(instr)) { + case 0x00000000: + if ((instr & 0x0ff00ff0) == 0x01000090) { + ai_skipped += 1; + printk(KERN_ERR "Unaligned trap: not handling swp instruction\n"); + return 1; + } + + if (((instr & 0x0e000090) == 0x00000090) && (instr & 0x60) != 0) { + ai_half += 1; + if (LDSTH_I_BIT(instr)) + offset.un = (instr & 0xf00) >> 4 | (instr & 15); + else + offset.un = regs->uregs[RM_BITS(instr)]; + + if (LDST_P_BIT(instr)) { + if (LDST_U_BIT(instr)) + eaddr += offset.un; + else + eaddr -= offset.un; } + + if (LDST_L_BIT(instr)) + regs->uregs[rd] = get_unaligned((unsigned short *)eaddr); + else + put_unaligned(regs->uregs[rd], (unsigned short *)eaddr); + + /* signed half-word? */ + if (instr & 0x40) + regs->uregs[rd] = (long)((short) regs->uregs[rd]); + + if (!LDST_P_BIT(instr)) { + if (LDST_U_BIT(instr)) + eaddr += offset.un; + else + eaddr -= offset.un; + regs->uregs[rn] = eaddr; + } else if (LDST_W_BIT(instr)) + regs->uregs[rn] = eaddr; + break; } - show_regs (regs); - c_backtrace (regs->ARM_fp, regs->ARM_cpsr); -#endif - force_sig(SIGSEGV, tsk); - goto out; - } - /* Are we prepared to handle this kernel fault? */ - if ((fixup = search_exception_table(instruction_pointer(regs))) != 0) { - printk(KERN_DEBUG "%s: Exception at [<%lx>] addr=%lx (fixup: %lx)\n", - tsk->comm, regs->ARM_pc, addr, fixup); - regs->ARM_pc = fixup; - goto out; + default: + ai_skipped += 1; + panic("Alignment trap: not handling instruction %08X at %08lX", + instr, regs->ARM_pc - correction - 4); + break; + + case 0x04000000: + offset.un = OFFSET_BITS(instr); + goto ldr_str; + + case 0x06000000: + offset.un = regs->uregs[RM_BITS(instr)]; + + if (IS_SHIFT(instr)) { + unsigned int shiftval = SHIFT_BITS(instr); + + switch(SHIFT_TYPE(instr)) { + case SHIFT_LSL: + offset.un <<= shiftval; + break; + + case SHIFT_LSR: + offset.un >>= shiftval; + break; + + case SHIFT_ASR: + offset.sn >>= shiftval; + break; + + case SHIFT_RORRRX: + if (shiftval == 0) { + offset.un >>= 1; + if (regs->ARM_cpsr & CC_C_BIT) + offset.un |= 1 << 31; + } else + offset.un = offset.un >> shiftval | + offset.un << (32 - shiftval); + break; + } + } + + ldr_str: + ai_word += 1; + if (LDST_P_BIT(instr)) { + if (LDST_U_BIT(instr)) + eaddr += offset.un; + else + eaddr -= offset.un; + } else { + if (LDST_W_BIT(instr)) { + printk(KERN_ERR "Not handling ldrt/strt correctly\n"); + return 1; + } + } + + if (LDST_L_BIT(instr)) { + regs->uregs[rd] = get_unaligned((unsigned long *)eaddr); + if (rd == 15) + correction = 0; + } else + put_unaligned(regs->uregs[rd], (unsigned long *)eaddr); + + if (!LDST_P_BIT(instr)) { + if (LDST_U_BIT(instr)) + eaddr += offset.un; + else + eaddr -= offset.un; + + regs->uregs[rn] = eaddr; + } else if (LDST_W_BIT(instr)) + regs->uregs[rn] = eaddr; + break; + + case 0x08000000: + if (LDM_S_BIT(instr)) + panic("Alignment trap: not handling LDM with s-bit\n"); + ai_multi += 1; + + for (regbits = REGMASK_BITS(instr), nr_regs = 0; regbits; regbits >>= 1) + nr_regs += 4; + + if (!LDST_U_BIT(instr)) + eaddr -= nr_regs; + + if ((LDST_U_BIT(instr) == 0 && LDST_P_BIT(instr) == 0) || + (LDST_U_BIT(instr) && LDST_P_BIT(instr))) + eaddr += 4; + + for (regbits = REGMASK_BITS(instr), rd = 0; regbits; regbits >>= 1, rd += 1) + if (regbits & 1) { + if (LDST_L_BIT(instr)) { + regs->uregs[rd] = get_unaligned((unsigned long *)eaddr); + if (rd == 15) + correction = 0; + } else + put_unaligned(regs->uregs[rd], (unsigned long *)eaddr); + eaddr += 4; + } + + if (LDST_W_BIT(instr)) { + if (LDST_P_BIT(instr) && !LDST_U_BIT(instr)) + eaddr -= nr_regs; + else if (LDST_P_BIT(instr)) + eaddr -= 4; + else if (!LDST_U_BIT(instr)) + eaddr -= 4 + nr_regs; + regs->uregs[rn] = eaddr; + } + break; } - kernel_page_fault (addr, mode, regs, tsk, mm); -out: - unlock_kernel(); + regs->ARM_pc -= correction; + + return 0; } -/* - * Handle a data abort. Note that we have to handle a range of addresses - * on ARM2/3 for ldm. If both pages are zero-mapped, then we have to force - * a copy-on-write - */ +#endif + asmlinkage void -do_DataAbort (unsigned long addr, int fsr, int error_code, struct pt_regs *regs) +do_DataAbort(unsigned long addr, int fsr, int error_code, struct pt_regs *regs) { if (user_mode(regs)) error_code |= FAULT_CODE_USER; + #define DIE(signr,nam)\ force_sig(signr, current);\ - die_if_kernel(nam, regs, fsr, signr);\ - break; + die(nam, regs, fsr);\ + do_exit(signr);\ + break switch (fsr & 15) { - case 2: - DIE(SIGKILL, "Terminal exception") + /* + * 0 - vector exception + */ case 0: - DIE(SIGSEGV, "Vector exception") + force_sig(SIGSEGV, current); + if (!user_mode(regs)) { + die("vector exception", regs, fsr); + do_exit(SIGSEGV); + } + break; + + /* + * 15 - permission fault on page + * 5 - page-table entry descriptor fault + * 7 - first-level descriptor fault + */ + case 15: case 5: case 7: + do_page_fault(addr, error_code, regs); + break; + + /* + * 13 - permission fault on section + */ + case 13: + force_sig(SIGSEGV, current); + if (!user_mode(regs)) { + die("section permission fault", regs, fsr); + do_exit(SIGSEGV); + } else { +#ifdef CONFIG_DEBUG_USER + printk("%s: permission fault on section, " + "address=0x%08lx, code %d\n", + current->comm, addr, error_code); +#ifdef DEBUG + { + unsigned int i, j; + unsigned long *sp; + + sp = (unsigned long *) (regs->ARM_sp - 128); + for (j = 0; j < 20 && sp_valid(sp); j++) { + printk("%p: ", sp); + for (i = 0; i < 8 && sp_valid(sp); i += 1, sp++) + printk("%08lx ", *sp); + printk("\n"); + } + show_regs(regs); + c_backtrace(regs->ARM_fp, regs->ARM_cpsr); + } +#endif +#endif + } + break; + case 1: case 3: - DIE(SIGBUS, "Alignment exception") +#ifdef CONFIG_ALIGNMENT_TRAP + if (!do_alignment_exception(regs)) + break; +#endif + /* + * this should never happen + */ + DIE(SIGBUS, "Alignment exception"); + break; + + case 2: + DIE(SIGKILL, "Terminal exception"); case 12: case 14: - DIE(SIGBUS, "External abort on translation") + DIE(SIGBUS, "External abort on translation"); case 9: case 11: - DIE(SIGSEGV, "Domain fault") - case 13:/* permission fault on section */ -#ifdef DEBUG - { - unsigned int i, j; - unsigned long *sp; - - printk ("%s: section permission fault (bad address=0x%08lx, code %d)\n", - current->comm, addr, error_code); - sp = (unsigned long *) (regs->ARM_sp - 128); - for (j = 0; j < 20 && sp_valid (sp); j++) { - printk ("%p: ", sp); - for (i = 0; i < 8 && sp_valid (sp); i += 1, sp++) - printk ("%08lx ", *sp); - printk ("\n"); - } - show_regs (regs); - c_backtrace(regs->ARM_fp, regs->ARM_cpsr); - } -#endif - DIE(SIGSEGV, "Permission fault") + DIE(SIGSEGV, "Domain fault"); - case 15:/* permission fault on page */ - case 5: /* page-table entry descriptor fault */ - case 7: /* first-level descriptor fault */ - page_fault (addr, error_code, regs); - break; case 4: case 6: - DIE(SIGBUS, "External abort on linefetch") + DIE(SIGBUS, "External abort on linefetch"); case 8: case 10: - DIE(SIGBUS, "External abort on non-linefetch") + DIE(SIGBUS, "External abort on non-linefetch"); } } asmlinkage int -do_PrefetchAbort (unsigned long addr, struct pt_regs *regs) +do_PrefetchAbort(unsigned long addr, struct pt_regs *regs) { -#if 0 - /* does this still apply ? */ - if (the memc mapping for this page exists - can check now...) { - printk ("Page in, but got abort (undefined instruction?)\n"); - return 0; - } -#endif - page_fault (addr, FAULT_CODE_USER|FAULT_CODE_READ, regs); + do_page_fault(addr, FAULT_CODE_USER|FAULT_CODE_READ, regs); return 1; } - diff -ur --new-file old/linux/arch/arm/mm/fault-common.c new/linux/arch/arm/mm/fault-common.c --- old/linux/arch/arm/mm/fault-common.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/mm/fault-common.c Sat May 8 20:06:56 1999 @@ -0,0 +1,188 @@ +/* + * linux/arch/arm/mm/fault-common.c + * + * Copyright (C) 1995 Linus Torvalds + * Modifications for ARM processor (c) 1995-1999 Russell King + */ +#include + +extern void die(char *msg, struct pt_regs *regs, unsigned int err); + +void __bad_pmd(pmd_t *pmd) +{ + printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd)); +#ifdef CONFIG_DEBUG_ERRORS + __backtrace(); +#endif + set_pmd(pmd, mk_user_pmd(BAD_PAGETABLE)); +} + +void __bad_pmd_kernel(pmd_t *pmd) +{ + printk("Bad pmd in pte_alloc_kernel: %08lx\n", pmd_val(*pmd)); +#ifdef CONFIG_DEBUG_ERRORS + __backtrace(); +#endif + set_pmd(pmd, mk_kernel_pmd(BAD_PAGETABLE)); +} + +static void +kernel_page_fault(unsigned long addr, int mode, struct pt_regs *regs, + struct task_struct *tsk, struct mm_struct *mm) +{ + char *reason; + /* + * Oops. The kernel tried to access some bad page. We'll have to + * terminate things with extreme prejudice. + */ + pgd_t *pgd; + + if (addr < PAGE_SIZE) + reason = "NULL pointer dereference"; + else + reason = "paging request"; + + printk(KERN_ALERT "Unable to handle kernel %s at virtual address %08lx\n", + reason, addr); + printk(KERN_ALERT "memmap = %08lX, pgd = %p\n", tsk->tss.memmap, mm->pgd); + pgd = pgd_offset(mm, addr); + printk(KERN_ALERT "*pgd = %08lx", pgd_val(*pgd)); + + do { + pmd_t *pmd; + pte_t *pte; + + if (pgd_none(*pgd)) + break; + + if (pgd_bad(*pgd)) { + printk("(bad)\n"); + break; + } + + pmd = pmd_offset(pgd, addr); + printk(", *pmd = %08lx", pmd_val(*pmd)); + + if (pmd_none(*pmd)) + break; + + if (pmd_bad(*pmd)) { + printk("(bad)\n"); + break; + } + + pte = pte_offset(pmd, addr); + printk(", *pte = %08lx", pte_val(*pte)); + printk(", *ppte = %08lx", pte_val(pte[-PTRS_PER_PTE])); + } while(0); + + printk("\n"); + die("Oops", regs, mode); + + do_exit(SIGKILL); +} + +static void do_page_fault(unsigned long addr, int mode, struct pt_regs *regs) +{ + struct task_struct *tsk; + struct mm_struct *mm; + struct vm_area_struct *vma; + unsigned long fixup; + + tsk = current; + mm = tsk->mm; + + /* + * If we're in an interrupt or have no user + * context, we must not take the fault.. + */ + if (in_interrupt() || mm == &init_mm) + goto no_context; + + down(&mm->mmap_sem); + vma = find_vma(mm, addr); + if (!vma) + goto bad_area; + if (vma->vm_start <= addr) + goto good_area; + if (!(vma->vm_flags & VM_GROWSDOWN) || expand_stack(vma, addr)) + goto bad_area; + + /* + * Ok, we have a good vm_area for this memory access, so + * we can handle it.. + */ +good_area: + if (READ_FAULT(mode)) { /* read? */ + if (!(vma->vm_flags & (VM_READ|VM_EXEC))) + goto bad_area; + } else { + if (!(vma->vm_flags & VM_WRITE)) + goto bad_area; + } + + /* + * If for any reason at all we couldn't handle the fault, + * make sure we exit gracefully rather than endlessly redo + * the fault. + */ + if (!handle_mm_fault(tsk, vma, addr & PAGE_MASK, DO_COW(mode))) + goto do_sigbus; + + up(&mm->mmap_sem); + return; + + /* + * Something tried to access memory that isn't in our memory map.. + * Fix it, but check if it's kernel or user first.. + */ +bad_area: + up(&mm->mmap_sem); + + /* User mode accesses just cause a SIGSEGV */ + if (mode & FAULT_CODE_USER) { + tsk->tss.error_code = mode; + tsk->tss.trap_no = 14; +#ifdef CONFIG_DEBUG_USER + printk("%s: memory violation at pc=0x%08lx, lr=0x%08lx (bad address=0x%08lx, code %d)\n", + tsk->comm, regs->ARM_pc, regs->ARM_lr, addr, mode); +#endif + force_sig(SIGSEGV, tsk); + return; + } + +no_context: + /* Are we prepared to handle this kernel fault? */ + if ((fixup = search_exception_table(instruction_pointer(regs))) != 0) { +#ifdef DEBUG + printk(KERN_DEBUG "%s: Exception at [<%lx>] addr=%lx (fixup: %lx)\n", + tsk->comm, regs->ARM_pc, addr, fixup); +#endif + regs->ARM_pc = fixup; + return; + } + + kernel_page_fault(addr, mode, regs, tsk, mm); + return; + +do_sigbus: + /* + * We ran out of memory, or some other thing happened to us that made + * us unable to handle the page fault gracefully. + */ + up(&mm->mmap_sem); + + /* + * Send a sigbus, regardless of whether we were in kernel + * or user mode. + */ + tsk->tss.error_code = mode; + tsk->tss.trap_no = 14; + force_sig(SIGBUS, tsk); + + /* Kernel mode? Handle exceptions or die */ + if (!(mode & FAULT_CODE_USER)) + goto no_context; +} + + diff -ur --new-file old/linux/arch/arm/mm/init.c new/linux/arch/arm/mm/init.c --- old/linux/arch/arm/mm/init.c Thu Dec 17 18:05:42 1998 +++ new/linux/arch/arm/mm/init.c Sat May 8 20:06:56 1999 @@ -29,6 +29,9 @@ #include pgd_t swapper_pg_dir[PTRS_PER_PGD]; +#ifndef CONFIG_NO_PGT_CACHE +struct pgtable_cache_struct quicklists; +#endif extern char _etext, _stext, _edata, __bss_start, _end; extern char __init_begin, __init_end; @@ -36,6 +39,7 @@ int do_check_pgt_cache(int low, int high) { int freed = 0; +#ifndef CONFIG_NO_PGT_CACHE if(pgtable_cache_size > high) { do { if(pgd_quicklist) @@ -46,6 +50,7 @@ free_pte_slow(get_pte_fast()), freed++; } while(pgtable_cache_size > low); } +#endif return freed; } @@ -63,17 +68,18 @@ * data and COW. */ #if PTRS_PER_PTE != 1 -unsigned long *empty_bad_page_table; +pte_t *empty_bad_page_table; pte_t *__bad_pagetable(void) { - int i; pte_t bad_page; + int i; bad_page = BAD_PAGE; for (i = 0; i < PTRS_PER_PTE; i++) - empty_bad_page_table[i] = (unsigned long)pte_val(bad_page); - return (pte_t *) empty_bad_page_table; + set_pte(empty_bad_page_table + i, bad_page); + + return empty_bad_page_table; } #endif @@ -128,8 +134,11 @@ empty_bad_page = (unsigned long *)start_mem; start_mem += PAGE_SIZE; #if PTRS_PER_PTE != 1 - empty_bad_page_table = (unsigned long *)start_mem; - start_mem += PTRS_PER_PTE * sizeof (void *); +#ifdef CONFIG_CPU_32 + start_mem += PTRS_PER_PTE * BYTES_PER_PTR; +#endif + empty_bad_page_table = (pte_t *)start_mem; + start_mem += PTRS_PER_PTE * BYTES_PER_PTR; #endif memzero (empty_zero_page, PAGE_SIZE); start_mem = setup_pagetables (start_mem, end_mem); @@ -137,6 +146,9 @@ flush_tlb_all(); update_memc_all(); + end_mem &= PAGE_MASK; + high_memory = (void *)end_mem; + return free_area_init(start_mem, end_mem); } @@ -161,19 +173,18 @@ /* mark usable pages in the mem_map[] */ mark_usable_memory_areas(&start_mem, end_mem); +#define BETWEEN(w,min,max) ((w) >= (unsigned long)(min) && \ + (w) < (unsigned long)(max)) + for (tmp = PAGE_OFFSET; tmp < end_mem ; tmp += PAGE_SIZE) { if (PageReserved(mem_map+MAP_NR(tmp))) { - if (tmp >= KERNTOPHYS(_stext) && - tmp < KERNTOPHYS(_edata)) { - if (tmp < KERNTOPHYS(_etext)) - codepages++; - else - datapages++; - } else if (tmp >= KERNTOPHYS(__init_begin) - && tmp < KERNTOPHYS(__init_end)) + if (BETWEEN(tmp, &__init_begin, &__init_end)) initpages++; - else if (tmp >= KERNTOPHYS(__bss_start) - && tmp < (unsigned long) start_mem) + else if (BETWEEN(tmp, &_stext, &_etext)) + codepages++; + else if (BETWEEN(tmp, &_etext, &_edata)) + datapages++; + else if (BETWEEN(tmp, &__bss_start, start_mem)) datapages++; else reservedpages++; @@ -181,13 +192,16 @@ } atomic_set(&mem_map[MAP_NR(tmp)].count, 1); #ifdef CONFIG_BLK_DEV_INITRD - if (!initrd_start || (tmp < initrd_start || tmp >= initrd_end)) + if (!initrd_start || !BETWEEN(tmp, initrd_start, initrd_end)) #endif free_page(tmp); } - printk ("Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, %dk init)\n", + +#undef BETWEEN + + printk ("Memory: %luk/%luM available (%dk code, %dk reserved, %dk data, %dk init)\n", (unsigned long) nr_free_pages << (PAGE_SHIFT-10), - max_mapnr << (PAGE_SHIFT-10), + max_mapnr >> (20 - PAGE_SHIFT), codepages << (PAGE_SHIFT-10), reservedpages << (PAGE_SHIFT-10), datapages << (PAGE_SHIFT-10), @@ -203,17 +217,45 @@ #endif } -void free_initmem (void) +static void free_area(unsigned long addr, unsigned long end, char *s) { - unsigned long addr; + unsigned int size = (end - addr) >> 10; - addr = (unsigned long)(&__init_begin); - for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) { + for (; addr < end; addr += PAGE_SIZE) { mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved); atomic_set(&mem_map[MAP_NR(addr)].count, 1); free_page(addr); } - printk ("Freeing unused kernel memory: %dk freed\n", (&__init_end - &__init_begin) >> 10); + + if (size) + printk(" %dk %s", size, s); +} + +void free_initmem (void) +{ + printk("Freeing unused kernel memory:"); + + free_area((unsigned long)(&__init_begin), + (unsigned long)(&__init_end), + "init"); + +#ifdef CONFIG_FOOTBRIDGE + { + extern int __netwinder_begin, __netwinder_end, __ebsa285_begin, __ebsa285_end; + + if (!machine_is_netwinder()) + free_area((unsigned long)(&__netwinder_begin), + (unsigned long)(&__netwinder_end), + "netwinder"); + + if (!machine_is_ebsa285() && !machine_is_cats()) + free_area((unsigned long)(&__ebsa285_begin), + (unsigned long)(&__ebsa285_end), + "ebsa285/cats"); + } +#endif + + printk("\n"); } void si_meminfo(struct sysinfo *val) diff -ur --new-file old/linux/arch/arm/mm/ioremap.c new/linux/arch/arm/mm/ioremap.c --- old/linux/arch/arm/mm/ioremap.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/mm/ioremap.c Sat May 8 20:06:56 1999 @@ -0,0 +1,149 @@ +/* + * arch/arm/mm/ioremap.c + * + * Re-map IO memory to kernel address space so that we can access it. + * + * (C) Copyright 1995 1996 Linus Torvalds + * + * Hacked for ARM by Phil Blundell + * Hacked to allow all architectures to build, and various cleanups + * by Russell King + */ + +/* + * This allows a driver to remap an arbitrary region of bus memory into + * virtual space. One should *only* use readl, writel, memcpy_toio and + * so on with such remapped areas. + * + * Because the ARM only has a 32-bit address space we can't address the + * whole of the (physical) PCI space at once. PCI huge-mode addressing + * allows us to circumvent this restriction by splitting PCI space into + * two 2GB chunks and mapping only one at a time into processor memory. + * We use MMU protection domains to trap any attempt to access the bank + * that is not currently mapped. (This isn't fully implemented yet.) + * + * DC21285 currently has a bug in that the PCI address extension + * register affects the address of any writes waiting in the outbound + * FIFO. Unfortunately, it is not possible to tell the DC21285 to + * flush this - flushing the area causes the bus to lock. + */ + +#include +#include + +static inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned long size, + unsigned long phys_addr, pgprot_t pgprot) +{ + unsigned long end; + + address &= ~PMD_MASK; + end = address + size; + if (end > PMD_SIZE) + end = PMD_SIZE; + do { + if (!pte_none(*pte)) + printk("remap_area_pte: page already exists\n"); + set_pte(pte, mk_pte_phys(phys_addr, pgprot)); + address += PAGE_SIZE; + phys_addr += PAGE_SIZE; + pte++; + } while (address < end); +} + +static inline int remap_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size, + unsigned long phys_addr, unsigned long flags) +{ + unsigned long end; + pgprot_t pgprot; + + address &= ~PGDIR_MASK; + end = address + size; + + if (end > PGDIR_SIZE) + end = PGDIR_SIZE; + + phys_addr -= address; + pgprot = __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | L_PTE_WRITE | flags); + do { + pte_t * pte = pte_alloc_kernel(pmd, address); + if (!pte) + return -ENOMEM; + remap_area_pte(pte, address, end - address, address + phys_addr, pgprot); + address = (address + PMD_SIZE) & PMD_MASK; + pmd++; + } while (address < end); + return 0; +} + +static int remap_area_pages(unsigned long address, unsigned long phys_addr, + unsigned long size, unsigned long flags) +{ + pgd_t * dir; + unsigned long end = address + size; + + phys_addr -= address; + dir = pgd_offset(&init_mm, address); + flush_cache_all(); + while (address < end) { + pmd_t *pmd = pmd_alloc_kernel(dir, address); + if (!pmd) + return -ENOMEM; + if (remap_area_pmd(pmd, address, end - address, + phys_addr + address, flags)) + return -ENOMEM; + set_pgdir(address, *dir); + address = (address + PGDIR_SIZE) & PGDIR_MASK; + dir++; + } + flush_tlb_all(); + return 0; +} + +/* + * Remap an arbitrary physical address space into the kernel virtual + * address space. Needed when the kernel wants to access high addresses + * directly. + * + * NOTE! We need to allow non-page-aligned mappings too: we will obviously + * have to convert them into an offset in a page-aligned mapping, but the + * caller shouldn't need to know that small detail. + * + * 'flags' are the extra L_PTE_ flags that you want to specify for this + * mapping. See include/asm-arm/proc-armv/pgtable.h for more information. + */ +void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags) +{ + void * addr; + struct vm_struct * area; + unsigned long offset; + + /* + * Mappings have to be page-aligned + */ + offset = phys_addr & ~PAGE_MASK; + size = PAGE_ALIGN(size + offset); + + /* + * Don't allow mappings that wrap.. + */ + if (!size || size > phys_addr + size) + return NULL; + + /* + * Ok, go for it.. + */ + area = get_vm_area(size); + if (!area) + return NULL; + addr = area->addr; + if (remap_area_pages(VMALLOC_VMADDR(addr), phys_addr, size, flags)) { + vfree(addr); + return NULL; + } + return (void *) (offset + (char *)addr); +} + +void iounmap(void *addr) +{ + return vfree((void *) (PAGE_MASK & (unsigned long) addr)); +} diff -ur --new-file old/linux/arch/arm/mm/mm-arc.c new/linux/arch/arm/mm/mm-arc.c --- old/linux/arch/arm/mm/mm-arc.c Sat Jul 18 20:55:23 1998 +++ new/linux/arch/arm/mm/mm-arc.c Thu Jan 1 01:00:00 1970 @@ -1,82 +0,0 @@ -/* - * arch/arm/mm/mm-arc.c - * - * Extra MM routines for the Archimedes architecture - * - * Copyright (C) 1998 Russell King - */ -#include -#include -#include - -unsigned long phys_screen_end; - -/* - * This routine needs more work to make it dynamically release/allocate mem! - */ -__initfunc(unsigned long map_screen_mem(unsigned long log_start, unsigned long kmem, int update)) -{ - static int updated = 0; - - if (updated) - return 0; - - updated = update; - - if (update) { - unsigned long address = log_start, offset; - pgd_t *pgdp; - - kmem = (kmem + 3) & ~3; - - pgdp = pgd_offset (&init_mm, address); /* +31 */ - offset = SCREEN_START; - while (address < SCREEN1_END) { - unsigned long addr_pmd, end_pmd; - pmd_t *pmdp; - - /* if (pgd_none (*pgdp)) alloc pmd */ - pmdp = pmd_offset (pgdp, address); /* +0 */ - addr_pmd = address & ~PGDIR_MASK; /* 088000 */ - end_pmd = addr_pmd + SCREEN1_END - address; /* 100000 */ - if (end_pmd > PGDIR_SIZE) - end_pmd = PGDIR_SIZE; - - do { - unsigned long addr_pte, end_pte; - pte_t *ptep; - - if (pmd_none (*pmdp)) { - pte_t *new_pte = (pte_t *)kmem; - kmem += PTRS_PER_PTE * BYTES_PER_PTR; - memzero (new_pte, PTRS_PER_PTE * BYTES_PER_PTR); - set_pmd (pmdp, mk_pmd(new_pte)); - } - - ptep = pte_offset (pmdp, addr_pmd); /* +11 */ - addr_pte = addr_pmd & ~PMD_MASK; /* 088000 */ - end_pte = addr_pte + end_pmd - addr_pmd; /* 100000 */ - if (end_pte > PMD_SIZE) - end_pte = PMD_SIZE; - - do { - set_pte (ptep, mk_pte(offset, PAGE_KERNEL)); - addr_pte += PAGE_SIZE; - offset += PAGE_SIZE; - ptep++; - } while (addr_pte < end_pte); - - pmdp++; - addr_pmd = (addr_pmd + PMD_SIZE) & PMD_MASK; - } while (addr_pmd < end_pmd); - - address = (address + PGDIR_SIZE) & PGDIR_MASK; - pgdp ++; - } - - phys_screen_end = offset; - flush_tlb_all (); - update_memc_all (); - } - return kmem; -} diff -ur --new-file old/linux/arch/arm/mm/mm-armv.c new/linux/arch/arm/mm/mm-armv.c --- old/linux/arch/arm/mm/mm-armv.c Sun Sep 6 19:44:47 1998 +++ new/linux/arch/arm/mm/mm-armv.c Sat May 8 20:06:57 1999 @@ -37,7 +37,8 @@ virtual = mp->virtual; physical = mp->physical; length = mp->length; - prot = (mp->prot_read ? PTE_AP_READ : 0) | (mp->prot_write ? PTE_AP_WRITE : 0); + prot = (mp->prot_read ? L_PTE_USER : 0) | (mp->prot_write ? L_PTE_WRITE : 0) + | L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY; while ((virtual & 1048575 || physical & 1048575) && length >= PAGE_SIZE) { alloc_init_page(&start_mem, virtual, physical, mp->domain, prot); @@ -56,7 +57,8 @@ physical += 1048576; } - prot = (mp->prot_read ? PTE_AP_READ : 0) | (mp->prot_write ? PTE_AP_WRITE : 0); + prot = (mp->prot_read ? L_PTE_USER : 0) | (mp->prot_write ? L_PTE_WRITE : 0) + | L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY; while (length >= PAGE_SIZE) { alloc_init_page(&start_mem, virtual, physical, mp->domain, prot); diff -ur --new-file old/linux/arch/arm/mm/mm-ebsa285.c new/linux/arch/arm/mm/mm-ebsa285.c --- old/linux/arch/arm/mm/mm-ebsa285.c Thu Dec 17 18:05:42 1998 +++ new/linux/arch/arm/mm/mm-ebsa285.c Thu Jan 1 01:00:00 1970 @@ -1,39 +0,0 @@ -/* - * arch/arm/mm/mm-ebsa285.c - * - * Extra MM routines for the EBSA285 architecture - * - * Copyright (C) 1998 Russell King, Dave Gilbert. - */ -#include -#include -#include - -#include -#include -#include -#include -#include - -/* - * This is to allow us to fiddle with the EEPROM - * This entry will go away in time, once the fmu - * can mmap() the flash. - * - * These ones are so that we can fiddle - * with the various cards (eg VGA) - * until we're happy with them... - */ -#define MAPPING \ - { 0xd8000000, DC21285_FLASH, 0x00400000, DOMAIN_USER, 1, 1 }, /* EEPROM */ \ - { 0xdc000000, 0x7c000000, 0x00100000, DOMAIN_USER, 1, 1 }, /* VGA */ \ - { 0xe0000000, DC21285_PCI_MEM, 0x18000000, DOMAIN_USER, 1, 1 }, /* VGA */ \ - { 0xf8000000, DC21285_PCI_TYPE_0_CONFIG, 0x01000000, DOMAIN_IO , 0, 1 }, /* Type 0 Config */ \ - { 0xf9000000, DC21285_PCI_TYPE_1_CONFIG, 0x01000000, DOMAIN_IO , 0, 1 }, /* Type 1 Config */ \ - { PCI_IACK, DC21285_PCI_IACK, 0x01000000, DOMAIN_IO , 0, 1 }, /* PCI IACK */ \ - { 0xfd000000, DC21285_OUTBOUND_WRITE_FLUSH, 0x01000000, DOMAIN_IO , 0, 1 }, /* Out wrflsh */ \ - { 0xfe000000, DC21285_ARMCSR_BASE, 0x01000000, DOMAIN_IO , 0, 1 }, /* CSR */ \ - { 0xffe00000, DC21285_PCI_IO, 0x00100000, DOMAIN_IO , 0, 1 }, /* PCI I/O */ \ - { 0xfff00000, 0x40000000, 0x00100000, DOMAIN_IO , 0, 1 }, /* X-Bus */ - -#include "mm-armv.c" diff -ur --new-file old/linux/arch/arm/mm/mm-footbridge.c new/linux/arch/arm/mm/mm-footbridge.c --- old/linux/arch/arm/mm/mm-footbridge.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/mm/mm-footbridge.c Sat May 8 20:06:57 1999 @@ -0,0 +1,91 @@ +/* + * arch/arm/mm/mm-ebsa285.c + * + * Extra MM routines for the EBSA285 architecture + * + * Copyright (C) 1998 Russell King, Dave Gilbert. + */ +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* + * The first entry allows us to fiddle with the EEPROM from user-space. + * This entry will go away in time, once the fmu32 can mmap() the + * flash. It can't at the moment. + * + * If you want to fiddle with PCI VGA cards from user space, then + * change the '0, 1 }' for the PCI MEM and PCI IO to '1, 1 }' + * You can then access the PCI bus at 0xe0000000 and 0xffe00000. + */ + +#ifdef CONFIG_HOST_FOOTBRIDGE + +/* + * The mapping when the footbridge is in host mode. + */ +#define MAPPING \ + { FLASH_BASE, DC21285_FLASH, FLASH_SIZE, DOMAIN_IO, 0, 1 }, \ + { PCIMEM_BASE, DC21285_PCI_MEM, PCIMEM_SIZE, DOMAIN_IO, 0, 1 }, \ + { PCICFG0_BASE, DC21285_PCI_TYPE_0_CONFIG, PCICFG0_SIZE, DOMAIN_IO, 0, 1 }, \ + { PCICFG1_BASE, DC21285_PCI_TYPE_1_CONFIG, PCICFG1_SIZE, DOMAIN_IO, 0, 1 }, \ + { PCIIACK_BASE, DC21285_PCI_IACK, PCIIACK_SIZE, DOMAIN_IO, 0, 1 }, \ + { WFLUSH_BASE, DC21285_OUTBOUND_WRITE_FLUSH, WFLUSH_SIZE, DOMAIN_IO, 0, 1 }, \ + { ARMCSR_BASE, DC21285_ARMCSR_BASE, ARMCSR_SIZE, DOMAIN_IO, 0, 1 }, \ + { PCIO_BASE, DC21285_PCI_IO, PCIO_SIZE, DOMAIN_IO, 0, 1 }, \ + { XBUS_BASE, 0x40000000, XBUS_SIZE, DOMAIN_IO, 0, 1 } + +#else + +/* + * These two functions convert virtual addresses to PCI addresses + * and PCI addresses to virtual addresses. Note that it is only + * legal to use these on memory obtained via get_free_page or + * kmalloc. + */ +unsigned long __virt_to_bus(unsigned long res) +{ +#ifdef CONFIG_DEBUG_ERRORS + if (res < PAGE_OFFSET || res >= (unsigned long)high_memory) { + printk("__virt_to_phys: invalid virtual address 0x%08lx\n", res); + __backtrace(); + } +#endif + return (res - PAGE_OFFSET) + (*CSR_PCISDRAMBASE & 0xfffffff0); +} + +unsigned long __bus_to_virt(unsigned long res) +{ + res -= (*CSR_PCISDRAMBASE & 0xfffffff0); + res += PAGE_OFFSET; + +#ifdef CONFIG_DEBUG_ERRORS + if (res < PAGE_OFFSET || res >= (unsigned long)high_memory) { + printk("__phys_to_virt: invalid virtual address 0x%08lx\n", res); + __backtrace(); + } +#endif + return res; +} + +/* + * The mapping when the footbridge is in add-in mode. + */ +#define MAPPING \ + { PCIO_BASE, DC21285_PCI_IO, PCIO_SIZE, DOMAIN_IO, 0, 1 }, \ + { XBUS_BASE, 0x40000000, XBUS_SIZE, DOMAIN_IO, 0, 1 }, \ + { ARMCSR_BASE, DC21285_ARMCSR_BASE, ARMCSR_SIZE, DOMAIN_IO, 0, 1 }, \ + { WFLUSH_BASE, DC21285_OUTBOUND_WRITE_FLUSH, WFLUSH_SIZE, DOMAIN_IO, 0, 1 }, \ + { FLASH_BASE, DC21285_FLASH, FLASH_SIZE, DOMAIN_IO, 0, 1 }, \ + { PCIMEM_BASE, DC21285_PCI_MEM, PCIMEM_SIZE, DOMAIN_IO, 0, 1 } + +#endif + +#include "mm-armv.c" diff -ur --new-file old/linux/arch/arm/mm/mm-vnc.c new/linux/arch/arm/mm/mm-vnc.c --- old/linux/arch/arm/mm/mm-vnc.c Thu Dec 17 18:05:42 1998 +++ new/linux/arch/arm/mm/mm-vnc.c Thu Jan 1 01:00:00 1970 @@ -1,31 +0,0 @@ -/* - * arch/arm/mm/mm-vnc.c - * - * Extra MM routines for the Corel VNC architecture - * - * Copyright (C) 1998 Russell King - */ -#include -#include -#include - -#include -#include -#include -#include -#include - -/* Table describing the MMU translation mapping - * mainly used to set up the I/O mappings. - */ -#define MAPPING \ - { 0xd0000000, DC21285_FLASH, 0x00800000, DOMAIN_IO , 0, 1 }, /* Flash */ \ - { 0xe0000000, DC21285_PCI_MEM, 0x18000000, DOMAIN_IO , 0, 1 }, /* PCI Mem */ \ - { 0xf8000000, DC21285_PCI_TYPE_0_CONFIG, 0x01000000, DOMAIN_IO , 0, 1 }, /* Type 0 Config */ \ - { 0xf9000000, DC21285_PCI_TYPE_1_CONFIG, 0x01000000, DOMAIN_IO , 0, 1 }, /* Type 1 Config */ \ - { PCI_IACK, DC21285_PCI_IACK, 0x01000000, DOMAIN_IO , 0, 1 }, /* PCI IACK */ \ - { 0xfd000000, DC21285_OUTBOUND_WRITE_FLUSH, 0x01000000, DOMAIN_IO , 0, 1 }, /* Out wrflsh */ \ - { 0xfe000000, DC21285_ARMCSR_BASE, 0x01000000, DOMAIN_IO , 0, 1 }, /* CSR */ \ - { 0xffe00000, DC21285_PCI_IO, 0x00100000, DOMAIN_IO , 0, 1 }, /* PCI I/O */ \ - -#include "mm-armv.c" diff -ur --new-file old/linux/arch/arm/mm/proc-arm2,3.S new/linux/arch/arm/mm/proc-arm2,3.S --- old/linux/arch/arm/mm/proc-arm2,3.S Thu May 21 03:54:35 1998 +++ new/linux/arch/arm/mm/proc-arm2,3.S Sat May 8 20:07:16 1999 @@ -193,7 +193,7 @@ movs pc, lr _arm2_3_check_bugs: - movs pc, lr + bics pc, lr, #0x04000000 @ Clear FIQ disable bit /* * Processor specific - ARM2 @@ -206,6 +206,8 @@ * Params : prev Old task structure * : next New task structure for process to run * + * Returns : prev + * * Purpose : Perform a task switch, saving the old processes state, and restoring * the new. * @@ -218,15 +220,15 @@ str sp, [r0, #TSS_SAVE] @ Save sp_SVC ldr sp, [r1, #TSS_SAVE] @ Get saved sp_SVC mov r4, r1 - add r0, r1, #TSS_MEMCMAP @ Remap MEMC + add r7, r1, #TSS_MEMCMAP @ Remap MEMC ldr r1, LC0 ldr r1, [r1] -1: ldmia r0!, {r2, r3, r5, r6} +1: ldmia r7!, {r2, r3, r5, r6} strb r2, [r2] strb r3, [r3] strb r5, [r5] strb r6, [r6] - ldmia r0!, {r2, r3, r5, r6} + ldmia r7!, {r2, r3, r5, r6} strb r2, [r2] strb r3, [r3] strb r5, [r5] @@ -318,6 +320,8 @@ * Params : prev Old task structure * : next New task structure for process to run * + * Returns : prev + * * Purpose : Perform a task switch, saving the old processes state, and restoring * the new. * @@ -330,22 +334,22 @@ str sp, [r0, #TSS_SAVE] @ Save sp_SVC ldr sp, [r1, #TSS_SAVE] @ Get saved sp_SVC mov r4, r1 - add r0, r1, #TSS_MEMCMAP @ Remap MEMC + add r7, r1, #TSS_MEMCMAP @ Remap MEMC ldr r1, LC0 ldr r1, [r1] -1: ldmia r0!, {r2, r3, r5, r6} +1: ldmia r7!, {r2, r3, r5, r6} strb r2, [r2] strb r3, [r3] strb r5, [r5] strb r6, [r6] - ldmia r0!, {r2, r3, r5, r6} + ldmia r7!, {r2, r3, r5, r6} strb r2, [r2] strb r3, [r3] strb r5, [r5] strb r6, [r6] subs r1, r1, #8 bhi 1b - mcr p15, 0, r0, c1, c0, 0 @ flush cache + mcr p15, 0, r7, c1, c0, 0 @ flush cache ldmfd sp!, {r4 - r9, fp, pc}^ @ Load all regs saved previously /* * Function: arm3_remap_memc (struct task_struct *tsk) diff -ur --new-file old/linux/arch/arm/mm/proc-arm6,7.S new/linux/arch/arm/mm/proc-arm6,7.S --- old/linux/arch/arm/mm/proc-arm6,7.S Sun Sep 6 19:44:47 1998 +++ new/linux/arch/arm/mm/proc-arm6,7.S Sat May 8 20:07:16 1999 @@ -52,13 +52,14 @@ blt 1b mov pc, lr -@LC0: .word _current /* * Function: arm6_7_switch_to (struct task_struct *prev, struct task_struct *next) * * Params : prev Old task structure * : next New task structure for process to run * + * Returns : prev + * * Purpose : Perform a task switch, saving the old processes state, and restoring * the new. * @@ -72,15 +73,15 @@ stmfd sp!, {ip} @ Save cpsr_SVC str sp, [r0, #TSS_SAVE] @ Save sp_SVC ldr sp, [r1, #TSS_SAVE] @ Get saved sp_SVC - ldr r0, [r1, #TSK_ADDR_LIMIT] - teq r0, #0 - moveq r0, #DOM_KERNELDOMAIN - movne r0, #DOM_USERDOMAIN - mcr p15, 0, r0, c3, c0 @ Set domain reg - ldr r0, [r1, #TSS_MEMMAP] @ Page table pointer + ldr r2, [r1, #TSK_ADDR_LIMIT] + teq r2, #0 + moveq r2, #DOM_KERNELDOMAIN + movne r2, #DOM_USERDOMAIN + mcr p15, 0, r2, c3, c0 @ Set domain reg + ldr r2, [r1, #TSS_MEMMAP] @ Page table pointer mov r1, #0 mcr p15, 0, r1, c7, c0, 0 @ flush cache - mcr p15, 0, r0, c2, c0, 0 @ update page table ptr + mcr p15, 0, r2, c2, c0, 0 @ update page table ptr mcr p15, 0, r1, c5, c0, 0 @ flush TLBs ldmfd sp!, {ip} msr spsr, ip @ Save tasks CPSR into SPSR for this return @@ -369,6 +370,35 @@ mov pc, lr /* + * Function: arm6_7_set_pte(pte_t *ptep, pte_t pte) + * Params : r0 = Address to set + * : r1 = value to set + * Purpose : Set a PTE and flush it out of any WB cache + */ + .align 5 +_arm6_7_set_pte: + str r1, [r0], #-1024 @ linux version + + bic r2, r1, #0xff0 + bic r2, r2, #3 + orr r2, r2, #HPTE_TYPE_SMALL + + tst r1, #LPTE_USER | LPTE_EXEC + orrne r2, r2, #HPTE_AP_READ + + tst r1, #LPTE_WRITE + tstne r1, #LPTE_DIRTY + orrne r2, r2, #HPTE_AP_WRITE + + tst r1, #LPTE_PRESENT + tstne r1, #LPTE_YOUNG + moveq r2, #0 + + str r2, [r0] @ hardware version + mcr p15, 0, r0, c7, c10, 1 @ clean D entry (drain is done by TLB fns) + mov pc, lr + +/* * Function: _arm6_7_reset * * Notes : This sets up everything for a reset @@ -405,8 +435,12 @@ .word _arm6_7_flush_tlb_all @ 44 .word _arm6_7_flush_tlb_area @ 48 .word _arm6_set_pmd @ 52 - .word _arm6_7_reset @ 54 - .word _arm6_7_flush_cache @ 58 + .word _arm6_7_set_pte @ 56 + .word _arm6_7_reset @ 60 + .word _arm6_7_flush_cache @ 64 + + .word _arm6_7_flush_cache @ 68 + .word _arm6_7_flush_cache @ 72 /* * Purpose : Function pointers used to access above functions - all calls @@ -431,8 +465,9 @@ .word _arm6_7_flush_tlb_all @ 44 .word _arm6_7_flush_tlb_area @ 48 .word _arm7_set_pmd @ 52 - .word _arm6_7_reset @ 56 - .word _arm6_7_flush_cache @ 60 - + .word _arm6_7_set_pte @ 56 + .word _arm6_7_reset @ 60 .word _arm6_7_flush_cache @ 64 + .word _arm6_7_flush_cache @ 68 + .word _arm6_7_flush_cache @ 72 diff -ur --new-file old/linux/arch/arm/mm/proc-sa110.S new/linux/arch/arm/mm/proc-sa110.S --- old/linux/arch/arm/mm/proc-sa110.S Thu Dec 17 18:05:42 1998 +++ new/linux/arch/arm/mm/proc-sa110.S Sat May 8 20:07:16 1999 @@ -8,6 +8,7 @@ */ #include #include +#include #include "../lib/constants.h" /* This is the maximum size of an area which will be flushed. If the area @@ -21,7 +22,6 @@ /* * Function: sa110_flush_cache_all (void) - * * Purpose : Flush all cache lines */ .align 5 @@ -33,7 +33,7 @@ ands r1, r1, #1 eor r1, r1, #1 str r1, [r3] - ldr ip, =0xdf000000 + ldr ip, =FLUSH_BASE addne ip, ip, #32768 add r1, ip, #16384 @ only necessary for 16k 1: ldr r3, [ip], #32 @@ -47,11 +47,9 @@ /* * Function: sa110_flush_cache_area (unsigned long address, int end, int flags) - * * Params : address Area start address * : end Area end address * : flags b0 = I cache as well - * * Purpose : clean & flush all cache lines associated with this area of memory */ .align 5 @@ -74,10 +72,8 @@ /* * Function: sa110_cache_wback_area(unsigned long address, unsigned long end) - * * Params : address Area start address * : end Area end address - * * Purpose : ensure all dirty cachelines in the specified area have been * written out to memory (for DMA) */ @@ -99,13 +95,10 @@ /* * Function: sa110_cache_purge_area(unsigned long address, unsigned long end) - * * Params : address Area start address * : end Area end address - * * Purpose : throw away all D-cached data in specified region without - * an obligation to write it ack. - * + * an obligation to write it back. * Note : Must clean the D-cached entries around the boundaries if the * start and/or end address are not cache aligned. */ @@ -124,9 +117,7 @@ /* * Function: sa110_flush_cache_entry (unsigned long address) - * * Params : address Address of cache line to flush - * * Purpose : clean & flush an entry */ .align 5 @@ -138,24 +129,23 @@ mov pc, lr /* - * Function: sa110_flush_cache_pte (unsigned long address) - * + * Function: sa110_clean_cache_area(unsigned long start, unsigned long size) * Params : address Address of cache line to clean - * * Purpose : Ensure that physical memory reflects cache at this location * for page table purposes. */ -_sa110_flush_cache_pte: - mcr p15, 0, r0, c7, c10, 1 @ clean D entry (drain is done by TLB fns) +_sa110_clean_cache_area: +1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry (drain is done by TLB fns) + add r0, r0, #32 + subs r1, r1, #32 + bhi 1b mov pc, lr /* * Function: sa110_flush_ram_page (unsigned long page) - * * Params : address Area start address * : size size of area * : flags b0 = I cache as well - * * Purpose : clean & flush all cache lines associated with this area of memory */ .align 5 @@ -176,7 +166,6 @@ /* * Function: sa110_flush_tlb_all (void) - * * Purpose : flush all TLB entries in all caches */ .align 5 @@ -188,11 +177,9 @@ /* * Function: sa110_flush_tlb_area (unsigned long address, unsigned long end, int flags) - * * Params : address Area start address * : end Area end address * : flags b0 = I cache as well - * * Purpose : flush a TLB entry */ .align 5 @@ -212,22 +199,21 @@ .align 5 _sa110_flush_icache_area: - mov r3, #0 1: mcr p15, 0, r0, c7, c10, 1 @ Clean D entry add r0, r0, #32 - cmp r0, r1 - blt 1b + subs r1, r1, #32 + bhi 1b + mov r0, #0 + mcr p15, 0, r0, c7, c10, 4 @ drain WB mcr p15, 0, r0, c7, c5, 0 @ flush I cache mov pc, lr /* * Function: sa110_switch_to (struct task_struct *prev, struct task_struct *next) - * * Params : prev Old task structure * : next New task structure for process to run - * + * Returns : prev * Purpose : Perform a task switch, saving the old processes state, and restoring * the new. - * * Notes : We don't fiddle with the FP registers here - we postpone this until * the new task actually uses FP. This way, we don't swap FP for tasks * that do not require it. @@ -237,20 +223,30 @@ stmfd sp!, {r4 - r9, fp, lr} @ Store most regs on stack mrs ip, cpsr stmfd sp!, {ip} @ Save cpsr_SVC + ldr r2, [r0, #TSS_MEMMAP] @ Get old page tables str sp, [r0, #TSS_SAVE] @ Save sp_SVC ldr sp, [r1, #TSS_SAVE] @ Get saved sp_SVC - ldr r0, [r1, #TSK_ADDR_LIMIT] - teq r0, #0 - moveq r0, #DOM_KERNELDOMAIN - movne r0, #DOM_USERDOMAIN - mcr p15, 0, r0, c3, c0 @ Set segment - ldr r0, [r1, #TSS_MEMMAP] @ Page table pointer + ldr r4, [r1, #TSK_ADDR_LIMIT] + teq r4, #0 + moveq r4, #DOM_KERNELDOMAIN + movne r4, #DOM_USERDOMAIN + mcr p15, 0, r4, c3, c0 @ Set segment + ldr r4, [r1, #TSS_MEMMAP] @ Page table pointer +/* + * Flushing the cache is nightmarishly slow, so we take any excuse + * to get out of it. If the old page table is the same as the new, + * this is a CLONE_VM relative of the old task and there is no need + * to flush. The overhead of the tests isn't even on the radar + * compared to the cost of the flush itself. + */ + teq r4, r2 + beq 2f ldr r3, =Lclean_switch ldr r2, [r3] ands r2, r2, #1 eor r2, r2, #1 str r2, [r3] - ldr r2, =0xdf000000 + ldr r2, =FLUSH_BASE addne r2, r2, #32768 add r1, r2, #16384 @ only necessary for 16k 1: ldr r3, [r2], #32 @@ -259,19 +255,16 @@ mov r1, #0 mcr p15, 0, r1, c7, c5, 0 @ flush I cache mcr p15, 0, r1, c7, c10, 4 @ drain WB - mcr p15, 0, r0, c2, c0, 0 @ load page table pointer + mcr p15, 0, r4, c2, c0, 0 @ load page table pointer mcr p15, 0, r1, c8, c7, 0 @ flush TLBs - ldmfd sp!, {ip} +2: ldmfd sp!, {ip} msr spsr, ip @ Save tasks CPSR into SPSR for this return ldmfd sp!, {r4 - r9, fp, pc}^ @ Load all regs saved previously /* * Function: sa110_data_abort () - * * Params : r0 = address of aborted instruction - * * Purpose : obtain information about current aborted instruction - * * Returns : r0 = address of abort * : r1 = FSR * : r2 != 0 if writing @@ -288,12 +281,10 @@ mov pc, lr /* - * Function: sa110_set_pmd () - * + * Function: sa110_set_pmd(pmd_t *pmdp, pmd_t pmd) * Params : r0 = Address to set * : r1 = value to set - * - * Purpose : Set a PMD and flush it out of any WB cache + * Purpose : Set a PMD and flush it out */ .align 5 _sa110_set_pmd: str r1, [r0] @@ -301,23 +292,51 @@ mov pc, lr /* + * Function: sa110_set_pte(pte_t *ptep, pte_t pte) + * Params : r0 = Address to set + * : r1 = value to set + * Purpose : Set a PTE and flush it out + */ + .align 5 +_sa110_set_pte: str r1, [r0], #-1024 @ linux version + + eor r1, r1, #LPTE_PRESENT | LPTE_YOUNG | LPTE_WRITE | LPTE_DIRTY + + bic r2, r1, #0xff0 + bic r2, r2, #3 + orr r2, r2, #HPTE_TYPE_SMALL + + tst r1, #LPTE_USER | LPTE_EXEC @ User or Exec? + orrne r2, r2, #HPTE_AP_READ + + tst r1, #LPTE_WRITE | LPTE_DIRTY @ Write and Dirty? + orreq r2, r2, #HPTE_AP_WRITE + + tst r1, #LPTE_PRESENT | LPTE_YOUNG @ Present and Young? + movne r2, #0 + + str r2, [r0] @ hardware version + mov r0, r0 + mcr p15, 0, r0, c7, c10, 1 @ clean D entry (drain is done by TLB fns) + mov pc, lr + +/* * Function: sa110_check_bugs (void) * : sa110_proc_init (void) * : sa110_proc_fin (void) - * * Notes : This processor does not require these */ _sa110_check_bugs: mrs ip, cpsr bic ip, ip, #F_BIT msr cpsr, ip + _sa110_proc_init: _sa110_proc_fin: mov pc, lr /* * Function: sa110_reset - * * Notes : This sets up everything for a reset */ _sa110_reset: mrs r1, cpsr @@ -350,14 +369,15 @@ .word _sa110_flush_cache_all @ 24 .word _sa110_flush_cache_area @ 28 .word _sa110_flush_cache_entry @ 32 - .word _sa110_flush_cache_pte @ 36 + .word _sa110_clean_cache_area @ 36 .word _sa110_flush_ram_page @ 40 .word _sa110_flush_tlb_all @ 44 .word _sa110_flush_tlb_area @ 48 .word _sa110_set_pmd @ 52 - .word _sa110_reset @ 56 - .word _sa110_flush_icache_area @ 60 + .word _sa110_set_pte @ 56 + .word _sa110_reset @ 60 + .word _sa110_flush_icache_area @ 64 - .word _sa110_cache_wback_area @ 64 - .word _sa110_cache_purge_area @ 68 + .word _sa110_cache_wback_area @ 68 + .word _sa110_cache_purge_area @ 72 diff -ur --new-file old/linux/arch/arm/mm/small_page.c new/linux/arch/arm/mm/small_page.c --- old/linux/arch/arm/mm/small_page.c Wed Sep 9 17:56:58 1998 +++ new/linux/arch/arm/mm/small_page.c Sat May 8 20:06:57 1999 @@ -5,6 +5,8 @@ * * Changelog: * 26/01/1996 RMK Cleaned up various areas to make little more generic + * 07/02/1999 RMK Support added for 16K and 32K page sizes + * containing 8K blocks */ #include @@ -19,21 +21,32 @@ #include #include -#define SMALL_ALLOC_SHIFT (10) +#if PAGE_SIZE == 4096 +/* 2K blocks */ +#define SMALL_ALLOC_SHIFT (11) +#define NAME(x) x##_2k +#elif PAGE_SIZE == 32768 || PAGE_SIZE == 16384 +/* 8K blocks */ +#define SMALL_ALLOC_SHIFT (13) +#define NAME(x) x##_8k +#endif + #define SMALL_ALLOC_SIZE (1 << SMALL_ALLOC_SHIFT) #define NR_BLOCKS (PAGE_SIZE / SMALL_ALLOC_SIZE) +#define BLOCK_MASK ((1 << NR_BLOCKS) - 1) -#if NR_BLOCKS != 4 -#error I only support 4 blocks per page! -#endif - -#define USED(pg) ((atomic_read(&(pg)->count) >> 8) & 15) +#define USED(pg) ((atomic_read(&(pg)->count) >> 8) & BLOCK_MASK) #define SET_USED(pg,off) (atomic_read(&(pg)->count) |= 256 << off) #define CLEAR_USED(pg,off) (atomic_read(&(pg)->count) &= ~(256 << off)) +#define ALL_USED BLOCK_MASK #define IS_FREE(pg,off) (!(atomic_read(&(pg)->count) & (256 << off))) -#define PAGE_PTR(page,block) ((struct free_small_page *)((page) + \ +#define SM_PAGE_PTR(page,block) ((struct free_small_page *)((page) + \ ((block) << SMALL_ALLOC_SHIFT))) +#if NR_BLOCKS != 2 && NR_BLOCKS != 4 +#error I only support 2 or 4 blocks per page +#endif + struct free_small_page { unsigned long next; unsigned long prev; @@ -52,6 +65,7 @@ 1, /* 0001 */ 0, /* 0010 */ 2, /* 0011 */ +#if NR_BLOCKS == 4 0, /* 0100 */ 1, /* 0101 */ 0, /* 0110 */ @@ -64,6 +78,7 @@ 1, /* 1101 */ 0, /* 1110 */ 4 /* 1111 */ +#endif }; static inline void clear_page_links(unsigned long page) @@ -72,7 +87,7 @@ int i; for (i = 0; i < NR_BLOCKS; i++) { - fsp = PAGE_PTR(page, i); + fsp = SM_PAGE_PTR(page, i); fsp->next = fsp->prev = 0; } } @@ -90,7 +105,7 @@ for (i = 0; i < NR_BLOCKS; i++) { if (mask & (1 << i)) continue; - fsp = PAGE_PTR(page, i); + fsp = SM_PAGE_PTR(page, i); fsp->prev = prev; } } @@ -108,12 +123,12 @@ for (i = 0; i < NR_BLOCKS; i++) { if (mask & (1 << i)) continue; - fsp = PAGE_PTR(page, i); + fsp = SM_PAGE_PTR(page, i); fsp->next = next; } } -unsigned long get_small_page(int priority) +unsigned long NAME(get_page)(int priority) { struct free_small_page *fsp; unsigned long new_page; @@ -129,8 +144,8 @@ page = mem_map + MAP_NR(small_page_ptr); offset = offsets[USED(page)]; SET_USED(page, offset); - new_page = (unsigned long)PAGE_PTR(small_page_ptr, offset); - if (USED(page) == 15) { + new_page = (unsigned long)SM_PAGE_PTR(small_page_ptr, offset); + if (USED(page) == ALL_USED) { fsp = (struct free_small_page *)new_page; set_page_links_prev (fsp->next, 0); small_page_ptr = fsp->next; @@ -156,30 +171,31 @@ goto again; } -void free_small_page(unsigned long spage) +void NAME(free_page)(unsigned long spage) { struct free_small_page *ofsp, *cfsp; unsigned long flags; struct page *page; int offset, oldoffset; + if (!spage) + goto none; + offset = (spage >> SMALL_ALLOC_SHIFT) & (NR_BLOCKS - 1); spage -= offset << SMALL_ALLOC_SHIFT; page = mem_map + MAP_NR(spage); - if (!PageReserved(page) || !USED(page)) { - printk ("Trying to free non-small page from %p\n", __builtin_return_address(0)); - return; - } - if (IS_FREE(page, offset)) { - printk ("Trying to free free small page from %p\n", __builtin_return_address(0)); - return; - } + if (!PageReserved(page) || !USED(page)) + goto non_small; + + if (IS_FREE(page, offset)) + goto free; + save_flags_cli (flags); oldoffset = offsets[USED(page)]; CLEAR_USED(page, offset); - ofsp = PAGE_PTR(spage, oldoffset); - cfsp = PAGE_PTR(spage, offset); + ofsp = SM_PAGE_PTR(spage, oldoffset); + cfsp = SM_PAGE_PTR(spage, offset); if (oldoffset == NR_BLOCKS) { /* going from totally used to mostly used */ cfsp->prev = 0; @@ -197,4 +213,13 @@ } else *cfsp = *ofsp; restore_flags(flags); + return; + +non_small: + printk ("Trying to free non-small page from %p\n", __builtin_return_address(0)); + return; +free: + printk ("Trying to free free small page from %p\n", __builtin_return_address(0)); +none: + return; } diff -ur --new-file old/linux/arch/i386/config.in new/linux/arch/i386/config.in --- old/linux/arch/i386/config.in Thu Jun 3 02:11:11 1999 +++ new/linux/arch/i386/config.in Thu Jun 3 02:12:04 1999 @@ -161,7 +161,7 @@ endmenu mainmenu_option next_comment -comment 'CD-ROM drivers (not for SCSI or IDE/ATAPI drives)' +comment 'Old CD-ROM drivers (not SCSI, not IDE)' bool 'Support non-SCSI/IDE/ATAPI CDROM drives' CONFIG_CD_NO_IDESCSI if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then @@ -170,6 +170,8 @@ endmenu source drivers/char/Config.in + +# source drivers/usb/Config.in source fs/Config.in diff -ur --new-file old/linux/arch/i386/defconfig new/linux/arch/i386/defconfig --- old/linux/arch/i386/defconfig Wed Jan 20 20:33:56 1999 +++ new/linux/arch/i386/defconfig Mon Apr 12 22:12:57 1999 @@ -104,7 +104,6 @@ CONFIG_PACKET=y # CONFIG_NETLINK is not set # CONFIG_FIREWALL is not set -# CONFIG_NET_ALIAS is not set # CONFIG_FILTER is not set CONFIG_UNIX=y CONFIG_INET=y @@ -121,7 +120,6 @@ # (it is safe to leave these untouched) # # CONFIG_INET_RARP is not set -CONFIG_IP_NOSR=y CONFIG_SKB_LARGE=y # @@ -172,20 +170,25 @@ # 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_NCR53C8XX is not set +CONFIG_SCSI_SYM53C8XX=y CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=4 CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32 CONFIG_SCSI_NCR53C8XX_SYNC=20 # CONFIG_SCSI_NCR53C8XX_PROFILE is not set # CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set +# CONFIG_SCSI_NCR53C8XX_PQS_PDS is not set # CONFIG_SCSI_PAS16 is not set # CONFIG_SCSI_PCI2000 is not set # CONFIG_SCSI_PCI2220I is not set # CONFIG_SCSI_PSI240I is not set # CONFIG_SCSI_QLOGIC_FAS is not set # CONFIG_SCSI_QLOGIC_ISP is not set +# CONFIG_SCSI_QLOGIC_FC is not set # CONFIG_SCSI_SEAGATE is not set # CONFIG_SCSI_DC390T is not set # CONFIG_SCSI_T128 is not set @@ -241,7 +244,7 @@ # CONFIG_ISDN is not set # -# CD-ROM drivers (not for SCSI or IDE/ATAPI drives) +# Old CD-ROM drivers (not SCSI, not IDE) # # CONFIG_CD_NO_IDESCSI is not set @@ -281,6 +284,7 @@ # Joystick support # # CONFIG_JOYSTICK is not set +# CONFIG_DTLK is not set # # Ftape, the floppy tape device driver diff -ur --new-file old/linux/arch/i386/kernel/bios32.c new/linux/arch/i386/kernel/bios32.c --- old/linux/arch/i386/kernel/bios32.c Wed Jan 20 19:18:53 1999 +++ new/linux/arch/i386/kernel/bios32.c Sun Apr 25 02:49:37 1999 @@ -14,7 +14,7 @@ * Hannover, Germany * hm@ix.de * - * Copyright 1997, 1998 Martin Mares + * Copyright 1997--1999 Martin Mares * * For more information, please consult the following manuals (look at * http://www.pcisig.com/ for how to get them): @@ -71,6 +71,10 @@ * a large gallery of common hardware bug workarounds (watch the comments) * -- the PCI specs themselves are sane, but most implementors should be * hit hard with \hammer scaled \magstep5. [mj] + * + * Jan 23, 1999 : More improvements to peer host bridge logic. i450NX fixup. [mj] + * + * Feb 8, 1999 : Added UM8886BF I/O address fixup. [mj] */ #include @@ -171,6 +175,7 @@ #define PCI_NO_SORT 0x100 #define PCI_BIOS_SORT 0x200 #define PCI_NO_CHECKS 0x400 +#define PCI_NO_PEER_FIXUP 0x800 static unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2; @@ -521,6 +526,8 @@ unsigned short segment; } pci_indirect = { 0, __KERNEL_CS }; +static int pci_bios_present; + __initfunc(static int check_pcibios(void)) { u32 signature, eax, ebx, ecx; @@ -803,7 +810,7 @@ * which used BIOS ordering, we are bound to do this... */ -__initfunc(void pcibios_sort(void)) +static void __init pcibios_sort(void) { struct pci_dev *dev = pci_devices; struct pci_dev **last = &pci_devices; @@ -856,7 +863,7 @@ static int pci_last_io_addr __initdata = 0x5800; -__initfunc(void pcibios_fixup_io_addr(struct pci_dev *dev, int idx)) +static void __init pcibios_fixup_io_addr(struct pci_dev *dev, int idx) { unsigned short cmd; unsigned int reg = PCI_BASE_ADDRESS_0 + 4*idx; @@ -868,13 +875,16 @@ printk("PCI: Unassigned I/O space for %02x:%02x\n", bus, devfn); return; } - if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE && idx < 4) { + if (((dev->class >> 8) == PCI_CLASS_STORAGE_IDE && idx < 4) || + (dev->class >> 8) == PCI_CLASS_DISPLAY_VGA) { /* * In case the BIOS didn't assign an address 0--3 to an IDE * controller, we don't try to fix it as it means "use default * addresses" at least with several broken chips and the IDE * driver needs the original settings to recognize which devices * correspond to the primary controller. + * + * We don't assign VGA I/O ranges as well. */ return; } @@ -914,7 +924,7 @@ * expected to be unique) and remove the ghost devices. */ -__initfunc(void pcibios_fixup_ghosts(struct pci_bus *b)) +static void __init pcibios_fixup_ghosts(struct pci_bus *b) { struct pci_dev *d, *e, **z; int mirror = PCI_DEVFN(16,0); @@ -954,12 +964,17 @@ * the reality doesn't pass this test and the bus number is usually * set by BIOS to the first free value. */ -__initfunc(void pcibios_fixup_peer_bridges(void)) +static void __init pcibios_fixup_peer_bridges(void) { struct pci_bus *b = &pci_root; int i, n, cnt=-1; struct pci_dev *d; +#ifdef CONFIG_VISWS + pci_scan_peer_bridge(1); + return; +#endif + #ifdef CONFIG_PCI_DIRECT /* * Don't search for peer host bridges if we use config type 2 @@ -969,6 +984,7 @@ if (access_pci == &pci_direct_conf2) return; #endif + for(d=b->devices; d; d=d->sibling) if ((d->class >> 8) == PCI_CLASS_BRIDGE_HOST) cnt++; @@ -979,6 +995,20 @@ for(i=0; i<256; i += 8) if (!pcibios_read_config_word(n, i, PCI_VENDOR_ID, &l) && l != 0x0000 && l != 0xffff) { +#ifdef CONFIG_PCI_BIOS + if (pci_bios_present) { + int err, idx = 0; + u8 bios_bus, bios_dfn; + u16 d; + pcibios_read_config_word(n, i, PCI_DEVICE_ID, &d); + DBG("BIOS test for %02x:%02x (%04x:%04x)\n", n, i, l, d); + while (!(err = pci_bios_find_device(l, d, idx, &bios_bus, &bios_dfn)) && + (bios_bus != n || bios_dfn != i)) + idx++; + if (err) + break; + } +#endif DBG("Found device at %02x:%02x\n", n, i); found++; if (!pcibios_read_config_word(n, i, PCI_CLASS_DEVICE, &l) && @@ -989,13 +1019,7 @@ break; if (found) { printk("PCI: Discovered primary peer bus %02x\n", n); - b = kmalloc(sizeof(*b), GFP_KERNEL); - memset(b, 0, sizeof(*b)); - b->next = pci_root.next; - pci_root.next = b; - b->number = b->secondary = n; - b->subordinate = 0xff; - b->subordinate = pci_scan_bus(b); + b = pci_scan_peer_bridge(n); n = b->subordinate; } n++; @@ -1003,11 +1027,77 @@ } /* + * Exceptions for specific devices. Usually work-arounds for fatal design flaws. + */ + +static void __init pci_fixup_i450nx(struct pci_dev *d) +{ + /* + * i450NX -- Find and scan all secondary buses on all PXB's. + */ + int pxb, reg; + u8 busno, suba, subb; + reg = 0xd0; + for(pxb=0; pxb<2; pxb++) { + pci_read_config_byte(d, reg++, &busno); + pci_read_config_byte(d, reg++, &suba); + pci_read_config_byte(d, reg++, &subb); + DBG("i450NX PXB %d: %02x/%02x/%02x\n", pxb, busno, suba, subb); + if (busno) + pci_scan_peer_bridge(busno); /* Bus A */ + if (suba < subb) + pci_scan_peer_bridge(suba+1); /* Bus B */ + } + pci_probe |= PCI_NO_PEER_FIXUP; +} + +static void __init pci_fixup_umc_ide(struct pci_dev *d) +{ + /* + * UM8886BF IDE controller sets region type bits incorrectly, + * therefore they look like memory despite of them being I/O. + */ + int i; + + for(i=0; i<4; i++) + d->base_address[i] |= PCI_BASE_ADDRESS_SPACE_IO; +} + +struct dev_ex { + u16 vendor, device; + void (*handler)(struct pci_dev *); + char *comment; +}; + +static struct dev_ex __initdata dev_ex_table[] = { + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82451NX, pci_fixup_i450nx, "Scanning peer host bridges" }, + { PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886BF, pci_fixup_umc_ide, "Working around UM8886BF bugs" } +}; + +static void __init pcibios_scan_buglist(struct pci_bus *b) +{ + struct pci_dev *d; + int i; + + for(d=b->devices; d; d=d->sibling) + for(i=0; ivendor == d->vendor && e->device == d->device) { + printk("PCI: %02x:%02x [%04x/%04x]: %s\n", + b->number, d->devfn, d->vendor, d->device, e->comment); + e->handler(d); + } + } +} + +/* * Fix base addresses, I/O and memory enables and IRQ's (mostly work-arounds * for buggy PCI BIOS'es :-[). */ -__initfunc(void pcibios_fixup_devices(void)) +extern int skip_ioapic_setup; + +static void __init pcibios_fixup_devices(void) { struct pci_dev *dev; int i, has_io, has_mem; @@ -1059,6 +1149,7 @@ /* * Recalculate IRQ numbers if we use the I/O APIC */ + if(!skip_ioapic_setup) { int irq; unsigned char pin; @@ -1099,7 +1190,8 @@ __initfunc(void pcibios_fixup(void)) { - pcibios_fixup_peer_bridges(); + if (!(pci_probe & PCI_NO_PEER_FIXUP)) + pcibios_fixup_peer_bridges(); pcibios_fixup_devices(); #ifdef CONFIG_PCI_BIOS @@ -1111,6 +1203,7 @@ __initfunc(void pcibios_fixup_bus(struct pci_bus *b)) { pcibios_fixup_ghosts(b); + pcibios_scan_buglist(b); } /* @@ -1126,8 +1219,10 @@ struct pci_access *dir = NULL; #ifdef CONFIG_PCI_BIOS - if ((pci_probe & PCI_PROBE_BIOS) && ((bios = pci_find_bios()))) + if ((pci_probe & PCI_PROBE_BIOS) && ((bios = pci_find_bios()))) { pci_probe |= PCI_BIOS_SORT; + pci_bios_present = 1; + } #endif #ifdef CONFIG_PCI_DIRECT if (pci_probe & (PCI_PROBE_CONF1 | PCI_PROBE_CONF2)) @@ -1139,10 +1234,6 @@ access_pci = bios; } -#if !defined(CONFIG_PCI_BIOS) && !defined(CONFIG_PCI_DIRECT) -#error PCI configured with neither PCI BIOS or PCI direct access support. -#endif - __initfunc(char *pcibios_setup(char *str)) { if (!strcmp(str, "off")) { @@ -1178,5 +1269,9 @@ return NULL; } #endif + else if (!strcmp(str, "nopeer")) { + pci_probe |= PCI_NO_PEER_FIXUP; + return NULL; + } return str; } diff -ur --new-file old/linux/arch/i386/kernel/entry.S new/linux/arch/i386/kernel/entry.S --- old/linux/arch/i386/kernel/entry.S Wed Jan 20 20:05:59 1999 +++ new/linux/arch/i386/kernel/entry.S Fri Apr 30 17:13:37 1999 @@ -154,7 +154,9 @@ .globl ret_from_fork ret_from_fork: #ifdef __SMP__ + pushl %ebx call SYMBOL_NAME(schedule_tail) + addl $4, %esp #endif /* __SMP__ */ GET_CURRENT(%ebx) jmp ret_from_sys_call diff -ur --new-file old/linux/arch/i386/kernel/i386_ksyms.c new/linux/arch/i386/kernel/i386_ksyms.c --- old/linux/arch/i386/kernel/i386_ksyms.c Tue Jan 19 20:02:59 1999 +++ new/linux/arch/i386/kernel/i386_ksyms.c Mon May 10 19:32:45 1999 @@ -39,10 +39,12 @@ EXPORT_SYMBOL(local_irq_count); EXPORT_SYMBOL(enable_irq); EXPORT_SYMBOL(disable_irq); +EXPORT_SYMBOL(disable_irq_nosync); EXPORT_SYMBOL(kernel_thread); EXPORT_SYMBOL_NOVERS(__down_failed); EXPORT_SYMBOL_NOVERS(__down_failed_interruptible); +EXPORT_SYMBOL_NOVERS(__down_failed_trylock); EXPORT_SYMBOL_NOVERS(__up_wakeup); /* Networking helper routines. */ EXPORT_SYMBOL(csum_partial_copy); @@ -74,8 +76,11 @@ EXPORT_SYMBOL(cpu_data); EXPORT_SYMBOL(kernel_flag); EXPORT_SYMBOL(smp_invalidate_needed); +EXPORT_SYMBOL(cpu_number_map); EXPORT_SYMBOL(__cpu_logical_map); EXPORT_SYMBOL(smp_num_cpus); +EXPORT_SYMBOL(cpu_present_map); +EXPORT_SYMBOL(cpu_online_map); /* Global SMP irq stuff */ EXPORT_SYMBOL(synchronize_irq); @@ -87,7 +92,7 @@ EXPORT_SYMBOL(__global_sti); EXPORT_SYMBOL(__global_save_flags); EXPORT_SYMBOL(__global_restore_flags); -EXPORT_SYMBOL(mtrr_hook); +EXPORT_SYMBOL(smp_call_function); #endif #ifdef CONFIG_MCA diff -ur --new-file old/linux/arch/i386/kernel/io_apic.c new/linux/arch/i386/kernel/io_apic.c --- old/linux/arch/i386/kernel/io_apic.c Mon Dec 28 19:52:01 1998 +++ new/linux/arch/i386/kernel/io_apic.c Fri May 7 01:07:03 1999 @@ -202,7 +202,7 @@ DO_ACTION( mask, 0, |= 0x00010000, io_apic_sync()) /* mask = 1 */ DO_ACTION( unmask, 0, &= 0xfffeffff, ) /* mask = 0 */ -static void __init clear_IO_APIC_pin(unsigned int pin) +static void clear_IO_APIC_pin(unsigned int pin) { struct IO_APIC_route_entry entry; @@ -215,6 +215,13 @@ io_apic_write(0x11 + 2 * pin, *(((int *)&entry) + 1)); } +static void clear_IO_APIC (void) +{ + int pin; + + for (pin = 0; pin < nr_ioapic_registers; pin++) + clear_IO_APIC_pin(pin); +} /* * support for broken MP BIOSs, enables hand-redirection of PIRQ0-7 to @@ -286,7 +293,8 @@ for (i = 0; i < mp_irq_entries; i++) { int lbus = mp_irqs[i].mpc_srcbus; - if ((mp_bus_id_to_type[lbus] == MP_BUS_ISA) && + if ((mp_bus_id_to_type[lbus] == MP_BUS_ISA || + mp_bus_id_to_type[lbus] == MP_BUS_EISA) && (mp_irqs[i].mpc_irqtype == type) && (mp_irqs[i].mpc_srcbusirq == 0x00)) @@ -319,20 +327,7 @@ } /* - * Unclear documentation on what a "conforming ISA interrupt" means. - * - * Should we, or should we not, take the ELCR register into account? - * It's part of the EISA specification, but maybe it should only be - * used if the interrupt is actually marked as EISA? - * - * Oh, well. Don't do it until somebody tells us what the right thing - * to do is.. - */ -#undef USE_ELCR_TRIGGER_LEVEL -#ifdef USE_ELCR_TRIGGER_LEVEL - -/* - * ISA Edge/Level control register, ELCR + * EISA Edge/Level control register, ELCR */ static int __init EISA_ELCR(unsigned int irq) { @@ -342,18 +337,22 @@ } printk("Broken MPtable reports ISA irq %d\n", irq); return 0; -} +} -#define default_ISA_trigger(idx) (EISA_ELCR(mp_irqs[idx].mpc_dstirq)) -#define default_ISA_polarity(idx) (0) +/* EISA interrupts are always polarity zero and can be edge or level + * trigger depending on the ELCR value. If an interrupt is listed as + * EISA conforming in the MP table, that means its trigger type must + * be read in from the ELCR */ -#else +#define default_EISA_trigger(idx) (EISA_ELCR(mp_irqs[idx].mpc_dstirq)) +#define default_EISA_polarity(idx) (0) + +/* ISA interrupts are always polarity zero edge triggered, even when + * listed as conforming in the MP table. */ #define default_ISA_trigger(idx) (0) #define default_ISA_polarity(idx) (0) -#endif - static int __init MPBIOS_polarity(int idx) { int bus = mp_irqs[idx].mpc_srcbus; @@ -373,6 +372,11 @@ polarity = default_ISA_polarity(idx); break; } + case MP_BUS_EISA: + { + polarity = default_EISA_polarity(idx); + break; + } case MP_BUS_PCI: /* PCI pin */ { polarity = 1; @@ -432,6 +436,11 @@ trigger = default_ISA_trigger(idx); break; } + case MP_BUS_EISA: + { + trigger = default_EISA_trigger(idx); + break; + } case MP_BUS_PCI: /* PCI pin, level */ { trigger = 1; @@ -496,6 +505,7 @@ switch (mp_bus_id_to_type[bus]) { case MP_BUS_ISA: /* ISA pin */ + case MP_BUS_EISA: { irq = mp_irqs[idx].mpc_srcbusirq; break; @@ -562,6 +572,9 @@ printk("WARNING: ASSIGN_IRQ_VECTOR wrapped back to %02X\n", current_vector); } + if (current_vector == SYSCALL_VECTOR) + panic("ran out of interrupt sources!"); + IO_APIC_VECTOR(irq) = current_vector; return current_vector; } @@ -625,7 +638,7 @@ /* * Set up a certain pin as ExtINT delivered interrupt */ -void __init setup_ExtINT_pin(unsigned int pin) +void __init setup_ExtINT_pin(unsigned int pin, int irq) { struct IO_APIC_route_entry entry; @@ -635,11 +648,16 @@ memset(&entry,0,sizeof(entry)); entry.delivery_mode = dest_ExtINT; - entry.dest_mode = 1; /* logical delivery */ + entry.dest_mode = 0; /* physical delivery */ entry.mask = 0; /* unmask IRQ now */ - entry.dest.logical.logical_dest = 0x01; /* logical CPU #0 */ + /* + * We use physical delivery to get the timer IRQ + * to the boot CPU. 'boot_cpu_id' is the physical + * APIC ID of the boot CPU. + */ + entry.dest.physical.physical_dest = boot_cpu_id; - entry.vector = 0; /* it's ignored */ + entry.vector = assign_irq_vector(irq); entry.polarity = 0; entry.trigger = 0; @@ -681,9 +699,11 @@ printk(".... register #01: %08X\n", *(int *)®_01); printk("....... : max redirection entries: %04X\n", reg_01.entries); - if ( (reg_01.entries != 0x0f) && /* ISA-only Neptune boards */ - (reg_01.entries != 0x17) && /* ISA+PCI boards */ - (reg_01.entries != 0x3F) /* Xeon boards */ + if ( (reg_01.entries != 0x0f) && /* older (Neptune) boards */ + (reg_01.entries != 0x17) && /* typical ISA+PCI boards */ + (reg_01.entries != 0x1b) && /* Compaq Proliant boards */ + (reg_01.entries != 0x1f) && /* dual Xeon boards */ + (reg_01.entries != 0x3F) /* bigger Xeon boards */ ) UNEXPECTED_IO_APIC(); if (reg_01.entries == 0x0f) @@ -754,7 +774,7 @@ static void __init init_sym_mode(void) { - int i, pin; + int i; for (i = 0; i < PIN_MAP_SIZE; i++) { irq_2_pin[i].pin = -1; @@ -784,8 +804,7 @@ /* * Do not trust the IO-APIC being empty at bootup */ - for (pin = 0; pin < nr_ioapic_registers; pin++) - clear_IO_APIC_pin(pin); + clear_IO_APIC(); } /* @@ -793,6 +812,15 @@ */ void init_pic_mode(void) { + /* + * Clear the IO-APIC before rebooting: + */ + clear_IO_APIC(); + + /* + * Put it back into PIC mode (has an effect only on + * certain boards) + */ printk("disabling symmetric IO mode... "); outb_p(0x70, 0x22); outb_p(0x00, 0x23); @@ -885,6 +913,8 @@ static void __init construct_default_ISA_mptable(void) { int i, pos = 0; + const int bus_type = (mpc_default_type == 2 || mpc_default_type == 3 || + mpc_default_type == 6) ? MP_BUS_EISA : MP_BUS_ISA; for (i = 0; i < 16; i++) { if (!IO_APIC_IRQ(i)) @@ -892,14 +922,14 @@ mp_irqs[pos].mpc_irqtype = mp_INT; mp_irqs[pos].mpc_irqflag = 0; /* default */ - mp_irqs[pos].mpc_srcbus = MP_BUS_ISA; + mp_irqs[pos].mpc_srcbus = 0; mp_irqs[pos].mpc_srcbusirq = i; mp_irqs[pos].mpc_dstapic = 0; mp_irqs[pos].mpc_dstirq = i; pos++; } mp_irq_entries = pos; - mp_bus_id_to_type[0] = MP_BUS_ISA; + mp_bus_id_to_type[0] = bus_type; /* * MP specification 1.4 defines some extra rules for default @@ -1019,7 +1049,7 @@ * and do not need to be masked. */ ack_APIC_irq(); - status = desc->status & ~IRQ_REPLAY; + status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING); status |= IRQ_PENDING; /* @@ -1030,8 +1060,9 @@ if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) { action = desc->action; status &= ~IRQ_PENDING; + status |= IRQ_INPROGRESS; } - desc->status = status | IRQ_INPROGRESS; + desc->status = status; spin_unlock(&irq_controller_lock); /* @@ -1073,7 +1104,7 @@ * So this all has to be within the spinlock. */ mask_IO_APIC_irq(irq); - status = desc->status & ~IRQ_REPLAY; + status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING); /* * If the IRQ is disabled for whatever reason, we must @@ -1082,8 +1113,9 @@ action = NULL; if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) { action = desc->action; + status |= IRQ_INPROGRESS; } - desc->status = status | IRQ_INPROGRESS; + desc->status = status; ack_APIC_irq(); spin_unlock(&irq_controller_lock); @@ -1143,7 +1175,7 @@ * 0x80, because int 0x80 is hm, kind of importantish. ;) */ for (i = 0; i < NR_IRQS ; i++) { - if (IO_APIC_IRQ(i)) { + if (IO_APIC_VECTOR(i) > 0) { if (IO_APIC_irq_trigger(i)) irq_desc[i].handler = &ioapic_level_irq_type; else @@ -1153,8 +1185,25 @@ */ if (i < 16) disable_8259A_irq(i); + } else { + if (!IO_APIC_IRQ(i)) + continue; + + /* + * Hmm.. We don't have an entry for this, + * so default to an old-fashioned 8259 + * interrupt if we can.. + */ + if (i < 16) { + make_8259A_irq(i); + continue; + } + + /* Strange. Oh, well.. */ + irq_desc[i].handler = &no_irq_type; } } + init_IRQ_SMP(); } /* @@ -1178,7 +1227,7 @@ if (pin2 != -1) { printk(".. (found pin %d) ...", pin2); - setup_ExtINT_pin(pin2); + setup_ExtINT_pin(pin2, 0); make_8259A_irq(0); } @@ -1258,14 +1307,12 @@ construct_default_ISA_mptable(); } - init_IO_APIC_traps(); - /* * Set up the IO-APIC IRQ routing table by parsing the MP-BIOS * mptable: */ setup_IO_APIC_irqs(); - init_IRQ_SMP(); + init_IO_APIC_traps(); check_timer(); print_IO_APIC(); diff -ur --new-file old/linux/arch/i386/kernel/irq.c new/linux/arch/i386/kernel/irq.c --- old/linux/arch/i386/kernel/irq.c Wed Jan 20 22:00:17 1999 +++ new/linux/arch/i386/kernel/irq.c Mon May 10 19:32:45 1999 @@ -70,11 +70,34 @@ */ spinlock_t irq_controller_lock; - /* * Dummy controller type for unused interrupts */ -static void do_none(unsigned int irq, struct pt_regs * regs) { } +static void do_none(unsigned int irq, struct pt_regs * regs) +{ + /* + * we are careful. While for ISA irqs it's common to happen + * outside of any driver (think autodetection), this is not + * at all nice for PCI interrupts. So we are stricter and + * print a warning when such spurious interrupts happen. + * Spurious interrupts can confuse other drivers if the PCI + * IRQ line is shared. + * + * Such spurious interrupts are either driver bugs, or + * sometimes hw (chipset) bugs. + */ + printk("unexpected IRQ vector %d on CPU#%d!\n",irq, smp_processor_id()); + +#ifdef __SMP__ + /* + * [currently unexpected vectors happen only on SMP and APIC. + * if we want to have non-APIC and non-8259A controllers + * in the future with unexpected vectors, this ack should + * probably be made controller-specific.] + */ + ack_APIC_irq(); +#endif +} static void enable_none(unsigned int irq) { } static void disable_none(unsigned int irq) { } @@ -82,7 +105,7 @@ #define startup_none enable_none #define shutdown_none disable_none -static struct hw_interrupt_type no_irq_type = { +struct hw_interrupt_type no_irq_type = { "none", startup_none, shutdown_none, @@ -128,10 +151,7 @@ */ 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 __byte(x,y) (((unsigned char *)&(y))[x]) #define cached_21 (__byte(0,cached_irq_mask)) #define cached_A1 (__byte(1,cached_irq_mask)) @@ -141,10 +161,10 @@ * fed to the CPU IRQ line directly. * * Any '1' bit in this mask means the IRQ is routed through the IO-APIC. - * this 'mixed mode' IRQ handling costs us one more branch in do_IRQ, - * but we have _much_ higher compatibility and robustness this way. + * this 'mixed mode' IRQ handling costs nothing because it's only used + * at IRQ setup time. */ -unsigned long long io_apic_irqs = 0; +unsigned long io_apic_irqs = 0; /* * These have to be protected by the irq controller spinlock @@ -183,8 +203,8 @@ void make_8259A_irq(unsigned int irq) { - disable_irq(irq); - __long(0,io_apic_irqs) &= ~(1<status & ~IRQ_REPLAY; + status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING); action = NULL; - if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) + if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) { action = desc->action; - desc->status = status | IRQ_INPROGRESS; + status |= IRQ_INPROGRESS; + } + desc->status = status; } spin_unlock(&irq_controller_lock); @@ -254,32 +276,43 @@ BUILD_COMMON_IRQ() + +#define BI(x,y) \ + BUILD_IRQ(##x##y) + +#define BUILD_16_IRQS(x) \ + BI(x,0) BI(x,1) BI(x,2) BI(x,3) \ + BI(x,4) BI(x,5) BI(x,6) BI(x,7) \ + BI(x,8) BI(x,9) BI(x,a) BI(x,b) \ + BI(x,c) BI(x,d) BI(x,e) BI(x,f) + /* * ISA PIC or low IO-APIC triggered (INTA-cycle or APIC) interrupts: + * (these are usually mapped to vectors 0x20-0x30) */ -BUILD_IRQ(0) BUILD_IRQ(1) BUILD_IRQ(2) BUILD_IRQ(3) -BUILD_IRQ(4) BUILD_IRQ(5) BUILD_IRQ(6) BUILD_IRQ(7) -BUILD_IRQ(8) BUILD_IRQ(9) BUILD_IRQ(10) BUILD_IRQ(11) -BUILD_IRQ(12) BUILD_IRQ(13) BUILD_IRQ(14) BUILD_IRQ(15) +BUILD_16_IRQS(0x0) #ifdef CONFIG_X86_IO_APIC /* - * The IO-APIC gives us many more interrupt sources.. + * The IO-APIC gives us many more interrupt sources. Most of these + * are unused but an SMP system is supposed to have enough memory ... + * sometimes (mostly wrt. hw bugs) we get corrupted vectors all + * across the spectrum, so we really want to be prepared to get all + * of these. Plus, more powerful systems might have more than 64 + * IO-APIC registers. + * + * (these are usually mapped into the 0x30-0xff vector range) */ -BUILD_IRQ(16) BUILD_IRQ(17) BUILD_IRQ(18) BUILD_IRQ(19) -BUILD_IRQ(20) BUILD_IRQ(21) BUILD_IRQ(22) BUILD_IRQ(23) -BUILD_IRQ(24) BUILD_IRQ(25) BUILD_IRQ(26) BUILD_IRQ(27) -BUILD_IRQ(28) BUILD_IRQ(29) BUILD_IRQ(30) BUILD_IRQ(31) -BUILD_IRQ(32) BUILD_IRQ(33) BUILD_IRQ(34) BUILD_IRQ(35) -BUILD_IRQ(36) BUILD_IRQ(37) BUILD_IRQ(38) BUILD_IRQ(39) -BUILD_IRQ(40) BUILD_IRQ(41) BUILD_IRQ(42) BUILD_IRQ(43) -BUILD_IRQ(44) BUILD_IRQ(45) BUILD_IRQ(46) BUILD_IRQ(47) -BUILD_IRQ(48) BUILD_IRQ(49) BUILD_IRQ(50) BUILD_IRQ(51) -BUILD_IRQ(52) BUILD_IRQ(53) BUILD_IRQ(54) BUILD_IRQ(55) -BUILD_IRQ(56) BUILD_IRQ(57) BUILD_IRQ(58) BUILD_IRQ(59) -BUILD_IRQ(60) BUILD_IRQ(61) BUILD_IRQ(62) BUILD_IRQ(63) + BUILD_16_IRQS(0x1) BUILD_16_IRQS(0x2) BUILD_16_IRQS(0x3) +BUILD_16_IRQS(0x4) BUILD_16_IRQS(0x5) BUILD_16_IRQS(0x6) BUILD_16_IRQS(0x7) +BUILD_16_IRQS(0x8) BUILD_16_IRQS(0x9) BUILD_16_IRQS(0xa) BUILD_16_IRQS(0xb) +BUILD_16_IRQS(0xc) BUILD_16_IRQS(0xd) #endif +#undef BUILD_16_IRQS +#undef BI + + #ifdef __SMP__ /* * The following vectors are part of the Linux architecture, there @@ -289,7 +322,7 @@ BUILD_SMP_INTERRUPT(reschedule_interrupt) BUILD_SMP_INTERRUPT(invalidate_interrupt) BUILD_SMP_INTERRUPT(stop_cpu_interrupt) -BUILD_SMP_INTERRUPT(mtrr_interrupt) +BUILD_SMP_INTERRUPT(call_function_interrupt) BUILD_SMP_INTERRUPT(spurious_interrupt) /* @@ -303,37 +336,35 @@ #endif +#define IRQ(x,y) \ + IRQ##x##y##_interrupt + +#define IRQLIST_16(x) \ + IRQ(x,0), IRQ(x,1), IRQ(x,2), IRQ(x,3), \ + IRQ(x,4), IRQ(x,5), IRQ(x,6), IRQ(x,7), \ + IRQ(x,8), IRQ(x,9), IRQ(x,a), IRQ(x,b), \ + IRQ(x,c), IRQ(x,d), IRQ(x,e), IRQ(x,f) + static void (*interrupt[NR_IRQS])(void) = { - IRQ0_interrupt, IRQ1_interrupt, IRQ2_interrupt, IRQ3_interrupt, - IRQ4_interrupt, IRQ5_interrupt, IRQ6_interrupt, IRQ7_interrupt, - IRQ8_interrupt, IRQ9_interrupt, IRQ10_interrupt, IRQ11_interrupt, - IRQ12_interrupt, IRQ13_interrupt, IRQ14_interrupt, IRQ15_interrupt + IRQLIST_16(0x0), + #ifdef CONFIG_X86_IO_APIC - ,IRQ16_interrupt, IRQ17_interrupt, IRQ18_interrupt, IRQ19_interrupt, - IRQ20_interrupt, IRQ21_interrupt, IRQ22_interrupt, IRQ23_interrupt, - IRQ24_interrupt, IRQ25_interrupt, IRQ26_interrupt, IRQ27_interrupt, - IRQ28_interrupt, IRQ29_interrupt, - IRQ30_interrupt, IRQ31_interrupt, IRQ32_interrupt, IRQ33_interrupt, - IRQ34_interrupt, IRQ35_interrupt, IRQ36_interrupt, IRQ37_interrupt, - IRQ38_interrupt, IRQ39_interrupt, - IRQ40_interrupt, IRQ41_interrupt, IRQ42_interrupt, IRQ43_interrupt, - IRQ44_interrupt, IRQ45_interrupt, IRQ46_interrupt, IRQ47_interrupt, - IRQ48_interrupt, IRQ49_interrupt, - IRQ50_interrupt, IRQ51_interrupt, IRQ52_interrupt, IRQ53_interrupt, - IRQ54_interrupt, IRQ55_interrupt, IRQ56_interrupt, IRQ57_interrupt, - IRQ58_interrupt, IRQ59_interrupt, - IRQ60_interrupt, IRQ61_interrupt, IRQ62_interrupt, IRQ63_interrupt + IRQLIST_16(0x1), IRQLIST_16(0x2), IRQLIST_16(0x3), + IRQLIST_16(0x4), IRQLIST_16(0x5), IRQLIST_16(0x6), IRQLIST_16(0x7), + IRQLIST_16(0x8), IRQLIST_16(0x9), IRQLIST_16(0xa), IRQLIST_16(0xb), + IRQLIST_16(0xc), IRQLIST_16(0xd) #endif }; +#undef IRQ +#undef IRQLIST_16 + /* - * Initial irq handlers. + * Special irq handlers. */ -void no_action(int cpl, void *dev_id, struct pt_regs *regs) -{ -} +void no_action(int cpl, void *dev_id, struct pt_regs *regs) { } #ifndef CONFIG_VISWS /* @@ -718,7 +749,7 @@ * hardware disable after having gotten the irq * controller lock. */ -void disable_irq(unsigned int irq) +void disable_irq_nosync(unsigned int irq) { unsigned long flags; @@ -728,9 +759,21 @@ irq_desc[irq].handler->disable(irq); } spin_unlock_irqrestore(&irq_controller_lock, flags); +} - if (irq_desc[irq].status & IRQ_INPROGRESS) - synchronize_irq(); +/* + * Synchronous version of the above, making sure the IRQ is + * no longer running on any other IRQ.. + */ +void disable_irq(unsigned int irq) +{ + disable_irq_nosync(irq); + + if (!local_irq_count[smp_processor_id()]) { + do { + barrier(); + } while (irq_desc[irq].status & IRQ_INPROGRESS); + } } void enable_irq(unsigned int irq) @@ -740,7 +783,7 @@ spin_lock_irqsave(&irq_controller_lock, flags); switch (irq_desc[irq].depth) { case 1: - irq_desc[irq].status &= ~(IRQ_DISABLED | IRQ_INPROGRESS); + irq_desc[irq].status &= ~IRQ_DISABLED; irq_desc[irq].handler->enable(irq); /* fall throught */ default: @@ -770,7 +813,7 @@ * 0 return value means that this irq is already being * handled by some other CPU. (or is disabled) */ - unsigned int irq = regs.orig_eax & 0xff; + int irq = regs.orig_eax & 0xff; /* subtle, see irq.h */ int cpu = smp_processor_id(); kstat.irqs[cpu][irq]++; @@ -835,7 +878,7 @@ if (!shared) { irq_desc[irq].depth = 0; - irq_desc[irq].status &= ~(IRQ_DISABLED | IRQ_INPROGRESS); + irq_desc[irq].status &= ~IRQ_DISABLED; irq_desc[irq].handler->startup(irq); } spin_unlock_irqrestore(&irq_controller_lock,flags); @@ -907,7 +950,7 @@ * * This depends on the fact that any interrupt that * comes in on to an unassigned handler will get stuck - * with "IRQ_INPROGRESS" asserted and the interrupt + * with "IRQ_WAITING" cleared and the interrupt * disabled. */ unsigned long probe_irq_on(void) @@ -921,8 +964,7 @@ spin_lock_irq(&irq_controller_lock); for (i = NR_IRQS-1; i > 0; i--) { if (!irq_desc[i].action) { - unsigned int status = irq_desc[i].status | IRQ_AUTODETECT; - irq_desc[i].status = status & ~IRQ_INPROGRESS; + irq_desc[i].status |= IRQ_AUTODETECT | IRQ_WAITING; irq_desc[i].handler->startup(i); } } @@ -945,7 +987,7 @@ continue; /* It triggered already - consider it spurious. */ - if (status & IRQ_INPROGRESS) { + if (!(status & IRQ_WAITING)) { irq_desc[i].status = status & ~IRQ_AUTODETECT; irq_desc[i].handler->shutdown(i); } @@ -971,7 +1013,7 @@ if (!(status & IRQ_AUTODETECT)) continue; - if (status & IRQ_INPROGRESS) { + if (!(status & IRQ_WAITING)) { if (!nr_irqs) irq_found = i; nr_irqs++; @@ -986,42 +1028,6 @@ return irq_found; } -/* - * Silly, horrible hack - */ -static char uglybuffer[10*256]; - -__asm__("\n" __ALIGN_STR"\n" - "common_unexpected:\n\t" - SAVE_ALL - "pushl $ret_from_intr\n\t" - "jmp strange_interrupt"); - -void strange_interrupt(int irqnum) -{ - printk("Unexpected interrupt %d\n", irqnum & 255); - for (;;); -} - -extern int common_unexpected; -__initfunc(void init_unexpected_irq(void)) -{ - int i; - for (i = 0; i < 256; i++) { - char *code = uglybuffer + 10*i; - unsigned long jumpto = (unsigned long) &common_unexpected; - - jumpto -= (unsigned long)(code+10); - code[0] = 0x68; /* pushl */ - *(int *)(code+1) = i - 512; - code[5] = 0xe9; /* jmp */ - *(int *)(code+6) = jumpto; - - set_intr_gate(i,code); - } -} - - void init_ISA_irqs (void) { int i; @@ -1033,7 +1039,7 @@ if (i < 16) { /* - * 16 old-style INTA-cycle interrupt gates: + * 16 old-style INTA-cycle interrupts: */ irq_desc[i].handler = &i8259A_irq_type; } else { @@ -1054,9 +1060,16 @@ #else init_VISWS_APIC_irqs(); #endif - - for (i = 0; i < 16; i++) - set_intr_gate(0x20+i,interrupt[i]); + /* + * Cover the whole vector space, no vector can escape + * us. (some of these will be overridden and become + * 'special' SMP interrupts) + */ + for (i = 0; i < NR_IRQS; i++) { + int vector = FIRST_EXTERNAL_VECTOR + i; + if (vector != SYSCALL_VECTOR) + set_intr_gate(vector, interrupt[i]); + } #ifdef __SMP__ @@ -1067,13 +1080,9 @@ set_intr_gate(IRQ0_TRAP_VECTOR, interrupt[0]); /* - * The reschedule interrupt slowly changes it's functionality, - * while so far it was a kind of broadcasted timer interrupt, - * in the future it should become a CPU-to-CPU rescheduling IPI, - * driven by schedule() ? + * The reschedule interrupt is a CPU-to-CPU reschedule-helper + * IPI, driven by wakeup. */ - - /* IPI for rescheduling */ set_intr_gate(RESCHEDULE_VECTOR, reschedule_interrupt); /* IPI for invalidation */ @@ -1085,8 +1094,8 @@ /* self generated IPI for local APIC timer */ set_intr_gate(LOCAL_TIMER_VECTOR, apic_timer_interrupt); - /* IPI for MTRR control */ - set_intr_gate(MTRR_CHANGE_VECTOR, mtrr_interrupt); + /* IPI for generic function call */ + set_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt); /* IPI vector for APIC spurious interrupts */ set_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt); diff -ur --new-file old/linux/arch/i386/kernel/irq.h new/linux/arch/i386/kernel/irq.h --- old/linux/arch/i386/kernel/irq.h Thu Jan 28 21:42:35 1999 +++ new/linux/arch/i386/kernel/irq.h Tue May 11 19:37:06 1999 @@ -16,6 +16,7 @@ void (*disable)(unsigned int irq); }; +extern struct hw_interrupt_type no_irq_type; /* * IRQ line status. @@ -25,6 +26,7 @@ #define IRQ_PENDING 4 /* IRQ pending - replay on enable */ #define IRQ_REPLAY 8 /* IRQ has been replayed but not acked yet */ #define IRQ_AUTODETECT 16 /* IRQ is being autodetected */ +#define IRQ_WAITING 32 /* IRQ not yet seen - for autodetection */ /* * This is the "IRQ descriptor", which contains various information @@ -41,6 +43,18 @@ } irq_desc_t; /* + * IDT vectors usable for external interrupt sources start + * at 0x20: + */ +#define FIRST_EXTERNAL_VECTOR 0x20 + +#define SYSCALL_VECTOR 0x80 + +/* + * Vectors 0x20-0x2f are used for ISA interrupts. + */ + +/* * Special IRQ vectors used by the SMP architecture: * * (some of the following vectors are 'rare', they might be merged @@ -51,10 +65,10 @@ #define INVALIDATE_TLB_VECTOR 0x31 #define STOP_CPU_VECTOR 0x40 #define LOCAL_TIMER_VECTOR 0x41 -#define MTRR_CHANGE_VECTOR 0x50 +#define CALL_FUNCTION_VECTOR 0x50 /* - * First vector available to drivers: (vectors 0x51-0xfe) + * First APIC vector available to drivers: (vectors 0x51-0xfe) */ #define IRQ0_TRAP_VECTOR 0x51 @@ -85,7 +99,6 @@ extern int i8259A_irq_pending(unsigned int irq); extern void ack_APIC_irq(void); extern void FASTCALL(send_IPI_self(int vector)); -extern void smp_send_mtrr(void); extern void init_VISWS_APIC_irqs(void); extern void setup_IO_APIC(void); extern int IO_APIC_get_PCI_irq_vector(int bus, int slot, int fn); @@ -94,12 +107,15 @@ extern void init_pic_mode(void); extern void print_IO_APIC(void); -extern unsigned long long io_apic_irqs; +extern unsigned long io_apic_irqs; + +extern char _stext, _etext; #define MAX_IRQ_SOURCES 128 #define MAX_MP_BUSSES 32 enum mp_bustype { MP_BUS_ISA, + MP_BUS_EISA, MP_BUS_PCI }; extern int mp_bus_id_to_type [MAX_MP_BUSSES]; @@ -126,7 +142,7 @@ hardirq_exit(cpu); } -#define IO_APIC_IRQ(x) ((1<= 16) || ((1<<(x)) & io_apic_irqs)) #else @@ -201,6 +217,13 @@ "pushl $ret_from_intr\n\t" \ "jmp "SYMBOL_NAME_STR(do_IRQ)); +/* + * subtle. orig_eax is used by the signal code to distinct between + * system calls and interrupted 'random user-space'. Thus we have + * to put a negative value into orig_eax here. (the problem is that + * both system calls and IRQs want to have small integer numbers in + * orig_eax, and the syscall code has won the optimization conflict ;) + */ #define BUILD_IRQ(nr) \ asmlinkage void IRQ_NAME(nr); \ __asm__( \ @@ -216,7 +239,6 @@ static inline void x86_do_profile (unsigned long eip) { if (prof_buffer && current->pid) { - extern int _stext; eip -= (unsigned long) &_stext; eip >>= prof_shift; /* diff -ur --new-file old/linux/arch/i386/kernel/mca.c new/linux/arch/i386/kernel/mca.c --- old/linux/arch/i386/kernel/mca.c Sun Oct 18 00:33:45 1998 +++ new/linux/arch/i386/kernel/mca.c Mon May 10 22:00:10 1999 @@ -26,6 +26,9 @@ * - Added the 'driver_loaded' flag in MCA_adapter * - Added an alternative implemention of ZP Gu's mca_find_unused_adapter * + * David Weinehall March 24th, 1999 + * - Fixed the output of 'Driver Installed' in /proc/mca/pos + * - Made the Integrated Video & SCSI show up even if they have id 0000 */ #include @@ -49,12 +52,12 @@ * Other miscellaneous information follows. */ -typedef enum { - MCA_ADAPTER_NORMAL = 0, - MCA_ADAPTER_NONE = 1, - MCA_ADAPTER_DISABLED = 2, - MCA_ADAPTER_ERROR = 3 -} MCA_AdapterStatus; +typedef enum { + MCA_ADAPTER_NORMAL = 0, + MCA_ADAPTER_NONE = 1, + MCA_ADAPTER_DISABLED = 2, + MCA_ADAPTER_ERROR = 3 +} MCA_AdapterStatus; struct MCA_adapter { MCA_AdapterStatus status; /* is there a valid adapter? */ @@ -69,16 +72,17 @@ }; struct MCA_info { -/* one for each of the 8 possible slots, plus one for integrated SCSI - and one for integrated video. */ + /* one for each of the 8 possible slots, plus one for integrated SCSI + * and one for integrated video. + */ struct MCA_adapter slot[MCA_NUMADAPTERS]; -/* two potential addresses for integrated SCSI adapter - this will - * track which one we think it is - */ + /* two potential addresses for integrated SCSI adapter - this will + * track which one we think it is. + */ - unsigned char which_scsi; + unsigned char which_scsi; }; /* The mca_info structure pointer. If MCA bus is present, the function @@ -88,7 +92,7 @@ * is set to zero. */ -static struct MCA_info* mca_info = 0; +static struct MCA_info* mca_info = NULL; /* MCA registers */ @@ -102,10 +106,10 @@ #ifdef CONFIG_PROC_FS -static void mca_do_proc_init( void ); -static int mca_default_procfn( char* buf, int slot ); +static void mca_do_proc_init(void); +static int mca_default_procfn(char* buf, int slot); -static ssize_t proc_mca_read( struct file*, char*, size_t, loff_t *); +static ssize_t proc_mca_read(struct file*, char*, size_t, loff_t *); static struct file_operations proc_mca_operations = { NULL, /* array_lseek */ @@ -146,23 +150,26 @@ /* Build the status info for the adapter */ -static void mca_configure_adapter_status( int slot ) { +static void mca_configure_adapter_status(int slot) { mca_info->slot[slot].status = MCA_ADAPTER_NONE; mca_info->slot[slot].id = mca_info->slot[slot].pos[0] + (mca_info->slot[slot].pos[1] << 8); - if( !mca_info->slot[slot].id ) { + if(!mca_info->slot[slot].id && slot < MCA_MAX_SLOT_NR) { /* id = 0x0000 usually indicates hardware failure, * however, ZP Gu (zpg@castle.net> reports that his 9556 - * has 0x0000 as id and everything still works. + * has 0x0000 as id and everything still works. There + * also seem to be an adapter with id = 0x0000; the + * NCR Parallel Bus Memory Card. Until this is confirmed, + * however, this code will stay. */ mca_info->slot[slot].status = MCA_ADAPTER_ERROR; return; - } else if( mca_info->slot[slot].id != 0xffff ) { + } else if(mca_info->slot[slot].id != 0xffff) { /* 0xffff usually indicates that there's no adapter, * however, some integrated adapters may have 0xffff as @@ -174,21 +181,21 @@ mca_info->slot[slot].status = MCA_ADAPTER_NORMAL; } - if( (mca_info->slot[slot].id == 0xffff || - mca_info->slot[slot].id == 0x0000) && slot >= MCA_MAX_SLOT_NR ) { + if((mca_info->slot[slot].id == 0xffff || + mca_info->slot[slot].id == 0x0000) && slot >= MCA_MAX_SLOT_NR) { int j; - for( j = 2; j < 8; j++ ) { - if( mca_info->slot[slot].pos[j] != 0xff ) { + for(j = 2; j < 8; j++) { + if(mca_info->slot[slot].pos[j] != 0xff) { mca_info->slot[slot].status = MCA_ADAPTER_NORMAL; break; } } } - if( !(mca_info->slot[slot].pos[2] & MCA_ENABLED) ) { + if(!(mca_info->slot[slot].pos[2] & MCA_ENABLED)) { - /* enabled bit is in pos 2 */ + /* enabled bit is in POS 2 */ mca_info->slot[slot].status = MCA_ADAPTER_DISABLED; } @@ -198,94 +205,101 @@ __initfunc(void mca_init(void)) { - unsigned int i, j; + unsigned int i, j; unsigned long flags; /* WARNING: Be careful when making changes here. Putting an adapter - * and the motherboard simultaneously into setup mode may result in - * damage to chips (according to The Indispensible PC Hardware Book - * by Hans-Peter Messmer). Also, we disable system interrupts (so + * and the motherboard simultaneously into setup mode may result in + * damage to chips (according to The Indispensible PC Hardware Book + * by Hans-Peter Messmer). Also, we disable system interrupts (so * that we are not disturbed in the middle of this). */ /* Make sure the MCA bus is present */ - if (!MCA_bus) + if(!MCA_bus) return; - printk( "Micro Channel bus detected.\n" ); - save_flags( flags ); + printk("Micro Channel bus detected.\n"); + save_flags(flags); cli(); /* Allocate MCA_info structure (at address divisible by 8) */ - mca_info = kmalloc(sizeof(struct MCA_info), GFP_ATOMIC); + mca_info = kmalloc(sizeof(struct MCA_info), GFP_KERNEL); + + if(mca_info == NULL) { + printk("Failed to allocate memory for mca_info!"); + restore_flags(flags); + return; + } /* Make sure adapter setup is off */ outb_p(0, MCA_ADAPTER_SETUP_REG); /* Put motherboard into video setup mode, read integrated video - * pos registers, and turn motherboard setup off. + * POS registers, and turn motherboard setup off. */ outb_p(0xdf, MCA_MOTHERBOARD_SETUP_REG); mca_info->slot[MCA_INTEGVIDEO].name[0] = 0; - for (j=0; j<8; j++) { - mca_info->slot[MCA_INTEGVIDEO].pos[j] = inb_p(MCA_POS_REG(j)); + for(j=0; j<8; j++) { + mca_info->slot[MCA_INTEGVIDEO].pos[j] = inb_p(MCA_POS_REG(j)); } mca_configure_adapter_status(MCA_INTEGVIDEO); /* Put motherboard into scsi setup mode, read integrated scsi - * pos registers, and turn motherboard setup off. + * POS registers, and turn motherboard setup off. * - * It seems there are two possible SCSI registers. Martin says that + * It seems there are two possible SCSI registers. Martin says that * for the 56,57, 0xf7 is the one, but fails on the 76. * Alfredo (apena@vnet.ibm.com) says - * 0xfd works on his machine. We'll try both of them. I figure it's - * a good bet that only one could be valid at a time. This could + * 0xfd works on his machine. We'll try both of them. I figure it's + * a good bet that only one could be valid at a time. This could * screw up though if one is used for something else on the other * machine. */ outb_p(0xf7, MCA_MOTHERBOARD_SETUP_REG); mca_info->slot[MCA_INTEGSCSI].name[0] = 0; - for (j=0; j<8; j++) { - if( (mca_info->slot[MCA_INTEGSCSI].pos[j] = inb_p(MCA_POS_REG(j))) != 0xff ) + for(j=0; j<8; j++) { + if((mca_info->slot[MCA_INTEGSCSI].pos[j] = inb_p(MCA_POS_REG(j))) != 0xff) { - /* 0xff all across means no device. 0x00 means something's - * broken, but a device is probably there. However, if you get - * 0x00 from a motherboard register it won't matter what we - * find. For the record, on the 57SLC, the integrated SCSI - * adapter has 0xffff for the adapter ID, but nonzero for - * other registers. + /* 0xff all across means no device. 0x00 means + * something's broken, but a device is probably there. + * However, if you get 0x00 from a motherboard + * register it won't matter what we find. For the + * record, on the 57SLC, the integrated SCSI + * adapter has 0xffff for the adapter ID, but + * nonzero for other registers. */ mca_info->which_scsi = 0xf7; } } - if( !mca_info->which_scsi ) { + if(!mca_info->which_scsi) { /* Didn't find it at 0xf7, try somewhere else... */ mca_info->which_scsi = 0xfd; outb_p(0xfd, MCA_MOTHERBOARD_SETUP_REG); - for (j=0; j<8; j++) - mca_info->slot[MCA_INTEGSCSI].pos[j] = inb_p(MCA_POS_REG(j)); + for(j=0; j<8; j++) + mca_info->slot[MCA_INTEGSCSI].pos[j] = inb_p(MCA_POS_REG(j)); } mca_configure_adapter_status(MCA_INTEGSCSI); - /* turn off motherboard setup */ + /* Turn off motherboard setup */ outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG); /* Now loop over MCA slots: put each adapter into setup mode, and - * read its pos registers. Then put adapter setup off. + * read its POS registers. Then put adapter setup off. */ - for (i=0; islot[i].pos[j]=inb_p(MCA_POS_REG(j)); + for(j=0; j<8; j++) { + mca_info->slot[i].pos[j]=inb_p(MCA_POS_REG(j)); } mca_info->slot[i].name[0] = 0; mca_info->slot[i].driver_loaded = 0; @@ -295,7 +309,7 @@ /* Enable interrupts and return memory start */ - restore_flags( flags ); + restore_flags(flags); request_region(0x60,0x01,"system control port B (MCA)"); request_region(0x90,0x01,"arbitration (MCA)"); @@ -312,89 +326,90 @@ /*--------------------------------------------------------------------*/ -static void mca_handle_nmi_slot( int slot, int check_flag ) +static void mca_handle_nmi_slot(int slot, int check_flag) { - if( slot < MCA_MAX_SLOT_NR ) { - printk( "NMI: caused by MCA adapter in slot %d (%s)\n", slot+1, - mca_info->slot[slot].name ); - } else if( slot == MCA_INTEGSCSI ) { - printk( "NMI: caused by MCA integrated SCSI adapter (%s)\n", - mca_info->slot[slot].name ); - } else if( slot == MCA_INTEGVIDEO ) { - printk( "NMI: caused by MCA integrated video adapter (%s)\n", - mca_info->slot[slot].name ); - } - - /* more info available in pos 6 and 7? */ - - if( check_flag ) { - unsigned char pos6, pos7; - - pos6 = mca_read_pos( slot, 6 ); - pos7 = mca_read_pos( slot, 7 ); - - printk( "NMI: POS 6 = 0x%x, POS 7 = 0x%x\n", pos6, pos7 ); - } - -} /* mca_handle_nmi_slot */ - -/*--------------------------------------------------------------------*/ + if(slot < MCA_MAX_SLOT_NR) { + printk("NMI: caused by MCA adapter in slot %d (%s)\n", slot+1, + mca_info->slot[slot].name); + } else if(slot == MCA_INTEGSCSI) { + printk("NMI: caused by MCA integrated SCSI adapter (%s)\n", + mca_info->slot[slot].name); + } else if(slot == MCA_INTEGVIDEO) { + printk("NMI: caused by MCA integrated video adapter (%s)\n", + mca_info->slot[slot].name); + } + + /* More info available in POS 6 and 7? */ + + if(check_flag) { + unsigned char pos6, pos7; + + pos6 = mca_read_pos(slot, 6); + pos7 = mca_read_pos(slot, 7); -void mca_handle_nmi( void ) + printk("NMI: POS 6 = 0x%x, POS 7 = 0x%x\n", pos6, pos7); + } + +} /* mca_handle_nmi_slot */ + +/*--------------------------------------------------------------------*/ + +void mca_handle_nmi(void) { int i; - unsigned char pos5; - - /* First try - scan the various adapters and see if a specific - * adapter was responsible for the error - */ - - for( i = 0; i < MCA_NUMADAPTERS; i += 1 ) { - - /* bit 7 of POS 5 is reset when this adapter has a hardware - * error. bit 7 it reset if there's error information - * available in pos 6 and 7. */ - - pos5 = mca_read_pos( i, 5 ); - - if( !(pos5 & 0x80) ) { - mca_handle_nmi_slot( i, !(pos5 & 0x40) ); - return; - } - } - - /* if I recall correctly, there's a whole bunch of other things that - * we can do to check for NMI problems, but that's all I know about + unsigned char pos5; + + /* First try - scan the various adapters and see if a specific + * adapter was responsible for the error. + */ + + for(i = 0; i < MCA_NUMADAPTERS; i++) { + + /* Bit 7 of POS 5 is reset when this adapter has a hardware + * error. Bit 7 it reset if there's error information + * available in POS 6 and 7. + */ + + pos5 = mca_read_pos(i, 5); + + if(!(pos5 & 0x80)) { + mca_handle_nmi_slot(i, !(pos5 & 0x40)); + return; + } + } + + /* If I recall correctly, there's a whole bunch of other things that + * we can do to check for NMI problems, but that's all I know about * at the moment. - */ + */ - printk( "NMI generated from unknown source!\n" ); -} /* mca_handle_nmi */ + printk("NMI generated from unknown source!\n"); +} /* mca_handle_nmi */ /*--------------------------------------------------------------------*/ -int mca_find_adapter( int id, int start ) +int mca_find_adapter(int id, int start) { - if( mca_info == 0 || id == 0 || id == 0xffff ) { + if(mca_info == NULL || id == 0xffff) { return MCA_NOTFOUND; } - for( ; start >= 0 && start < MCA_NUMADAPTERS; start += 1 ) { + for(; start >= 0 && start < MCA_NUMADAPTERS; start++) { - /* not sure about this. There's no point in returning + /* Not sure about this. There's no point in returning * adapters that aren't enabled, since they can't actually - * be used. However, they might be needed for statistical + * be used. However, they might be needed for statistical * purposes or something... But if that is the case, the * user is free to write a routine that manually iterates * through the adapters. */ - if( mca_info->slot[start].status == MCA_ADAPTER_DISABLED ) { + if(mca_info->slot[start].status == MCA_ADAPTER_DISABLED) { continue; } - if( id == mca_info->slot[start].id ) { + if(id == mca_info->slot[start].id) { return start; } } @@ -404,28 +419,28 @@ /*--------------------------------------------------------------------*/ -int mca_find_unused_adapter( int id, int start ) +int mca_find_unused_adapter(int id, int start) { - if( mca_info == 0 || id == 0 || id == 0xffff ) { + if(mca_info == NULL || id == 0xffff) { return MCA_NOTFOUND; } - for( ; start >= 0 && start < MCA_NUMADAPTERS; start += 1 ) { + for(; start >= 0 && start < MCA_NUMADAPTERS; start++) { - /* not sure about this. There's no point in returning + /* not sure about this. There's no point in returning * adapters that aren't enabled, since they can't actually - * be used. However, they might be needed for statistical + * be used. However, they might be needed for statistical * purposes or something... But if that is the case, the * user is free to write a routine that manually iterates * through the adapters. */ - if( mca_info->slot[start].status == MCA_ADAPTER_DISABLED || - mca_info->slot[start].driver_loaded ) { + if(mca_info->slot[start].status == MCA_ADAPTER_DISABLED || + mca_info->slot[start].driver_loaded) { continue; } - if( id == mca_info->slot[start].id ) { + if(id == mca_info->slot[start].id) { return start; } } @@ -435,68 +450,68 @@ /*--------------------------------------------------------------------*/ -unsigned char mca_read_stored_pos( int slot, int reg ) +unsigned char mca_read_stored_pos(int slot, int reg) { - if( slot < 0 || slot >= MCA_NUMADAPTERS || mca_info == 0 ) return 0; - if( reg < 0 || reg >= 8 ) return 0; + if(slot < 0 || slot >= MCA_NUMADAPTERS || mca_info == NULL) return 0; + if(reg < 0 || reg >= 8) return 0; return mca_info->slot[slot].pos[reg]; } /* mca_read_stored_pos() */ /*--------------------------------------------------------------------*/ -unsigned char mca_read_pos( int slot, int reg ) +unsigned char mca_read_pos(int slot, int reg) { unsigned int byte = 0; unsigned long flags; - if( slot < 0 || slot >= MCA_NUMADAPTERS || mca_info == 0 ) return 0; - if( reg < 0 || reg >= 8 ) return 0; + if(slot < 0 || slot >= MCA_NUMADAPTERS || mca_info == NULL) return 0; + if(reg < 0 || reg >= 8) return 0; - save_flags( flags ); + save_flags(flags); cli(); - /* make sure motherboard setup is off */ + /* Make sure motherboard setup is off */ outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG); - /* read in the appropriate register */ + /* Read in the appropriate register */ - if( slot == MCA_INTEGSCSI && mca_info->which_scsi ) { + if(slot == MCA_INTEGSCSI && mca_info->which_scsi) { - /* disable adapter setup, enable motherboard setup */ + /* Disable adapter setup, enable motherboard setup */ outb_p(0, MCA_ADAPTER_SETUP_REG); outb_p(mca_info->which_scsi, MCA_MOTHERBOARD_SETUP_REG); byte = inb_p(MCA_POS_REG(reg)); outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG); - } else if( slot == MCA_INTEGVIDEO ) { + } else if(slot == MCA_INTEGVIDEO) { - /* disable adapter setup, enable motherboard setup */ + /* Disable adapter setup, enable motherboard setup */ outb_p(0, MCA_ADAPTER_SETUP_REG); outb_p(0xdf, MCA_MOTHERBOARD_SETUP_REG); byte = inb_p(MCA_POS_REG(reg)); outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG); - } else if( slot < MCA_MAX_SLOT_NR ) { + } else if(slot < MCA_MAX_SLOT_NR) { - /* make sure motherboard setup is off */ + /* Make sure motherboard setup is off */ outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG); - /* read the appropriate register */ + /* Read the appropriate register */ outb_p(0x8|(slot&0xf), MCA_ADAPTER_SETUP_REG); byte = inb_p(MCA_POS_REG(reg)); outb_p(0, MCA_ADAPTER_SETUP_REG); } - /* make sure the stored values are consistent, while we're here */ + /* Make sure the stored values are consistent, while we're here */ mca_info->slot[slot].pos[reg] = byte; - restore_flags( flags ); + restore_flags(flags); return byte; } /* mca_read_pos() */ @@ -513,44 +528,47 @@ * screws up. */ -void mca_write_pos( int slot, int reg, unsigned char byte ) +void mca_write_pos(int slot, int reg, unsigned char byte) { unsigned long flags; - if( slot < 0 || slot >= MCA_MAX_SLOT_NR ) return; - if( reg < 0 || reg >= 8 ) return; - if (mca_info == 0 ) return; + if(slot < 0 || slot >= MCA_MAX_SLOT_NR) + return; + if(reg < 0 || reg >= 8) + return; + if(mca_info == NULL) + return; - save_flags( flags ); + save_flags(flags); cli(); - /* make sure motherboard setup is off */ + /* Make sure motherboard setup is off */ outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG); - /* read in the appropriate register */ + /* Read in the appropriate register */ outb_p(0x8|(slot&0xf), MCA_ADAPTER_SETUP_REG); - outb_p( byte, MCA_POS_REG(reg) ); + outb_p(byte, MCA_POS_REG(reg)); outb_p(0, MCA_ADAPTER_SETUP_REG); - restore_flags( flags ); + restore_flags(flags); - /* update the global register list, while we have the byte */ + /* Update the global register list, while we have the byte */ mca_info->slot[slot].pos[reg] = byte; } /* mca_write_pos() */ /*--------------------------------------------------------------------*/ -void mca_set_adapter_name( int slot, char* name ) +void mca_set_adapter_name(int slot, char* name) { - if( mca_info == 0 ) return; + if(mca_info == NULL) return; - if( slot >= 0 && slot < MCA_NUMADAPTERS ) { - if( name != NULL ) { - strncpy( mca_info->slot[slot].name, name, - sizeof(mca_info->slot[slot].name)-1 ); + if(slot >= 0 && slot < MCA_NUMADAPTERS) { + if(name != NULL) { + strncpy(mca_info->slot[slot].name, name, + sizeof(mca_info->slot[slot].name)-1); mca_info->slot[slot].name[ sizeof(mca_info->slot[slot].name)-1] = 0; } else { @@ -559,61 +577,61 @@ } } -void mca_set_adapter_procfn( int slot, MCA_ProcFn procfn, void* dev) +void mca_set_adapter_procfn(int slot, MCA_ProcFn procfn, void* dev) { - if( mca_info == 0 ) return; + if(mca_info == NULL) return; - if( slot >= 0 && slot < MCA_NUMADAPTERS ) { + if(slot >= 0 && slot < MCA_NUMADAPTERS) { mca_info->slot[slot].procfn = procfn; mca_info->slot[slot].dev = dev; } } -int mca_is_adapter_used( int slot ) +int mca_is_adapter_used(int slot) { return mca_info->slot[slot].driver_loaded; } -int mca_mark_as_used( int slot ) +int mca_mark_as_used(int slot) { if(mca_info->slot[slot].driver_loaded) return 1; mca_info->slot[slot].driver_loaded = 1; return 0; } -void mca_mark_as_unused( int slot ) +void mca_mark_as_unused(int slot) { mca_info->slot[slot].driver_loaded = 0; } -char *mca_get_adapter_name( int slot ) +char *mca_get_adapter_name(int slot) { - if( mca_info == 0 ) return 0; + if(mca_info == NULL) return 0; - if( slot >= 0 && slot < MCA_NUMADAPTERS ) { + if(slot >= 0 && slot < MCA_NUMADAPTERS) { return mca_info->slot[slot].name; } return 0; } -int mca_isadapter( int slot ) +int mca_isadapter(int slot) { - if( mca_info == 0 ) return 0; + if(mca_info == NULL) return 0; - if( slot >= 0 && slot < MCA_NUMADAPTERS ) { - return (( mca_info->slot[slot].status == MCA_ADAPTER_NORMAL ) - || (mca_info->slot[slot].status == MCA_ADAPTER_DISABLED ) ); + if(slot >= 0 && slot < MCA_NUMADAPTERS) { + return ((mca_info->slot[slot].status == MCA_ADAPTER_NORMAL) + || (mca_info->slot[slot].status == MCA_ADAPTER_DISABLED)); } return 0; } -int mca_isenabled( int slot ) +int mca_isenabled(int slot) { - if( mca_info == 0 ) return 0; + if(mca_info == NULL) return 0; - if( slot >= 0 && slot < MCA_NUMADAPTERS ) { + if(slot >= 0 && slot < MCA_NUMADAPTERS) { return (mca_info->slot[slot].status == MCA_ADAPTER_NORMAL); } @@ -624,39 +642,37 @@ #ifdef CONFIG_PROC_FS -int get_mca_info(char *buf) +int get_mca_info(char *buf) { - int i, j, len = 0; + int i, j, len = 0; - if( MCA_bus && mca_info != 0 ) + if(MCA_bus && mca_info != NULL) { - /* Format pos registers of eight MCA slots */ + /* Format POS registers of eight MCA slots */ - for (i=0; islot[i].pos[j]); - len += sprintf( buf+len, " %s\n", mca_info->slot[i].name ); - } + len += sprintf(buf+len, " %s\n", mca_info->slot[i].name); + } - /* Format pos registers of integrated video subsystem */ + /* Format POS registers of integrated video subsystem */ len += sprintf(buf+len, "Video : "); - for (j=0; j<8; j++) + for(j=0; j<8; j++) len += sprintf(buf+len, "%02x ", mca_info->slot[MCA_INTEGVIDEO].pos[j]); - len += sprintf( buf+len, " %s\n", mca_info->slot[MCA_INTEGVIDEO].name ); + len += sprintf(buf+len, " %s\n", mca_info->slot[MCA_INTEGVIDEO].name); - /* Format pos registers of integrated SCSI subsystem */ + /* Format POS registers of integrated SCSI subsystem */ len += sprintf(buf+len, "SCSI : "); - for (j=0; j<8; j++) + for(j=0; j<8; j++) len += sprintf(buf+len, "%02x ", mca_info->slot[MCA_INTEGSCSI].pos[j]); - len += sprintf( buf+len, " %s\n", mca_info->slot[MCA_INTEGSCSI].name ); - } - else - { - /* Leave it empty if MCA not detected - this should *never* + len += sprintf(buf+len, " %s\n", mca_info->slot[MCA_INTEGSCSI].name); + } else { + /* Leave it empty if MCA not detected - this should *never* * happen! */ } @@ -667,119 +683,123 @@ /*--------------------------------------------------------------------*/ -__initfunc(void mca_do_proc_init( void )) +__initfunc(void mca_do_proc_init(void)) { - int i = 0; - struct proc_dir_entry* node = 0; + int i; + struct proc_dir_entry* node = NULL; - if( mca_info == 0 ) return; /* should never happen */ + if(mca_info == NULL) return; /* Should never happen */ - proc_register( &proc_mca, &(struct proc_dir_entry) { + proc_register(&proc_mca, &(struct proc_dir_entry) { PROC_MCA_REGISTERS, 3, "pos", S_IFREG|S_IRUGO, - 1, 0, 0, 0, &proc_mca_inode_operations,} ); + 1, 0, 0, 0, &proc_mca_inode_operations,}); - proc_register( &proc_mca, &(struct proc_dir_entry) { + proc_register(&proc_mca, &(struct proc_dir_entry) { PROC_MCA_MACHINE, 7, "machine", S_IFREG|S_IRUGO, - 1, 0, 0, 0, &proc_mca_inode_operations,} ); + 1, 0, 0, 0, &proc_mca_inode_operations,}); - /* initialize /proc/mca entries for existing adapters */ + /* Initialize /proc/mca entries for existing adapters */ - for( i = 0; i < MCA_NUMADAPTERS; i += 1 ) { + for(i = 0; i < MCA_NUMADAPTERS; i++) { mca_info->slot[i].procfn = 0; mca_info->slot[i].dev = 0; - if( ! mca_isadapter( i ) ) continue; - node = kmalloc(sizeof(struct proc_dir_entry), GFP_ATOMIC); + if(!mca_isadapter(i)) continue; + node = kmalloc(sizeof(struct proc_dir_entry), GFP_KERNEL); - if( i < MCA_MAX_SLOT_NR ) { + if(node == NULL) { + printk("Failed to allocate memory for MCA proc-entries!"); + return; + } + if(i < MCA_MAX_SLOT_NR) { node->low_ino = PROC_MCA_SLOT + i; - node->namelen = sprintf( mca_info->slot[i].procname, - "slot%d", i+1 ); - } else if( i == MCA_INTEGVIDEO ) { + node->namelen = sprintf(mca_info->slot[i].procname, + "slot%d", i+1); + } else if(i == MCA_INTEGVIDEO) { node->low_ino = PROC_MCA_VIDEO; - node->namelen = sprintf( mca_info->slot[i].procname, - "video" ); - } else if( i == MCA_INTEGSCSI ) { + node->namelen = sprintf(mca_info->slot[i].procname, + "video"); + } else if(i == MCA_INTEGSCSI) { node->low_ino = PROC_MCA_SCSI; - node->namelen = sprintf( mca_info->slot[i].procname, - "scsi" ); + node->namelen = sprintf(mca_info->slot[i].procname, + "scsi"); } node->name = mca_info->slot[i].procname; node->mode = S_IFREG | S_IRUGO; node->ops = &proc_mca_inode_operations; - proc_register( &proc_mca, node ); + proc_register(&proc_mca, node); } } /* mca_do_proc_init() */ /*--------------------------------------------------------------------*/ -int mca_default_procfn( char* buf, int slot ) +int mca_default_procfn(char* buf, int slot) { int len = 0, i; - /* this really shouldn't happen... */ + /* This really shouldn't happen... */ - if( mca_info == 0 ) { + if(mca_info == NULL) { *buf = 0; return 0; } - /* print out the basic information */ + /* Print out the basic information */ - if( slot < MCA_MAX_SLOT_NR ) { - len += sprintf( buf+len, "Slot: %d\n", slot+1 ); - } else if( slot == MCA_INTEGSCSI ) { - len += sprintf( buf+len, "Integrated SCSI Adapter\n" ); - } else if( slot == MCA_INTEGVIDEO ) { - len += sprintf( buf+len, "Integrated Video Adapter\n" ); + if(slot < MCA_MAX_SLOT_NR) { + len += sprintf(buf+len, "Slot: %d\n", slot+1); + } else if(slot == MCA_INTEGSCSI) { + len += sprintf(buf+len, "Integrated SCSI Adapter\n"); + } else if(slot == MCA_INTEGVIDEO) { + len += sprintf(buf+len, "Integrated Video Adapter\n"); } - if( mca_info->slot[slot].name[0] ) { + if(mca_info->slot[slot].name[0]) { - /* drivers might register a name without /proc handler... */ + /* Drivers might register a name without /proc handler... */ - len += sprintf( buf+len, "Adapter Name: %s\n", - mca_info->slot[slot].name ); + len += sprintf(buf+len, "Adapter Name: %s\n", + mca_info->slot[slot].name); } else { - len += sprintf( buf+len, "Adapter Name: Unknown\n" ); + len += sprintf(buf+len, "Adapter Name: Unknown\n"); } - len += sprintf( buf+len, "Id: %02x%02x\n", - mca_info->slot[slot].pos[1], mca_info->slot[slot].pos[0] ); - len += sprintf( buf+len, "Enabled: %s\nPOS: ", - mca_isenabled(slot) ? "Yes" : "No" ); - len += sprintf( buf+len, "Driver Installed: %s\n", - mca_is_adapter_used(slot) ? "Yes" : "No" ); - for (i=0; i<8; i++) { + len += sprintf(buf+len, "Id: %02x%02x\n", + mca_info->slot[slot].pos[1], mca_info->slot[slot].pos[0]); + len += sprintf(buf+len, "Enabled: %s\nPOS: ", + mca_isenabled(slot) ? "Yes" : "No"); + for(i=0; i<8; i++) { len += sprintf(buf+len, "%02x ", mca_info->slot[slot].pos[i]); } + len += sprintf(buf+len, "\nDriver Installed: %s", + mca_is_adapter_used(slot) ? "Yes" : "No"); buf[len++] = '\n'; buf[len] = 0; return len; } /* mca_default_procfn() */ -static int get_mca_machine_info( char* buf ) +static int get_mca_machine_info(char* buf) { int len = 0; - len += sprintf( buf+len, "Model Id: 0x%x\n", machine_id ); - len += sprintf( buf+len, "Submodel Id: 0x%x\n", machine_submodel_id ); - len += sprintf( buf+len, "BIOS Revision: 0x%x\n", BIOS_revision ); + len += sprintf(buf+len, "Model Id: 0x%x\n", machine_id); + len += sprintf(buf+len, "Submodel Id: 0x%x\n", machine_submodel_id); + len += sprintf(buf+len, "BIOS Revision: 0x%x\n", BIOS_revision); return len; } -static int mca_fill( char* page, int pid, int type, char** start, +static int mca_fill(char* page, int pid, int type, char** start, loff_t *offset, int length) { int len = 0; int slot = 0; - switch( type ) { + switch(type) { case PROC_MCA_REGISTERS: - return get_mca_info( page ); + return get_mca_info(page); case PROC_MCA_MACHINE: - return get_mca_machine_info( page ); + return get_mca_machine_info(page); case PROC_MCA_VIDEO: slot = MCA_INTEGVIDEO; break; @@ -787,24 +807,24 @@ slot = MCA_INTEGSCSI; break; default: - if( type < PROC_MCA_SLOT || type >= PROC_MCA_LAST ) { + if(type < PROC_MCA_SLOT || type >= PROC_MCA_LAST) { return -EBADF; } slot = type - PROC_MCA_SLOT; break; } - /* if we made it here, we better have a valid slot */ + /* If we made it here, we better have a valid slot */ - /* get the standard info */ + /* Get the standard info */ - len = mca_default_procfn( page, slot ); + len = mca_default_procfn(page, slot); - /* do any device-specific processing, if there is any */ + /* Do any device-specific processing, if there is any */ - if( mca_info->slot[slot].procfn ) { - len += mca_info->slot[slot].procfn( page+len, slot, - mca_info->slot[slot].dev ); + if(mca_info->slot[slot].procfn) { + len += mca_info->slot[slot].procfn(page+len, slot, + mca_info->slot[slot].dev); } return len; @@ -814,7 +834,7 @@ #define PROC_BLOCK_SIZE (3*1024) -static ssize_t proc_mca_read( struct file* file, +static ssize_t proc_mca_read(struct file* file, char* buf, size_t count, loff_t *ppos) { unsigned long page; @@ -825,11 +845,11 @@ struct proc_dir_entry *dp; struct inode *inode = file->f_dentry->d_inode; - if (count < 0) + if(count < 0) return -EINVAL; - if (count > PROC_BLOCK_SIZE) + if(count > PROC_BLOCK_SIZE) count = PROC_BLOCK_SIZE; - if (!(page = __get_free_page(GFP_KERNEL))) + if(!(page = __get_free_page(GFP_KERNEL))) return -ENOMEM; type = inode->i_ino; pid = type >> 16; @@ -837,12 +857,12 @@ start = 0; dp = (struct proc_dir_entry *) inode->u.generic_ip; length = mca_fill((char *) page, pid, type, - &start, ppos, count); - if (length < 0) { + &start, ppos, count); + if(length < 0) { free_page(page); return length; } - if (start != 0) { + if(start != 0) { /* We have had block-adjusting processing! */ copy_to_user(buf, start, length); @@ -851,11 +871,11 @@ } else { /* Static 4kB (or whatever) block capacity */ - if (*ppos >= length) { + if(*ppos >= length) { free_page(page); return 0; } - if (count + *ppos > length) + if(count + *ppos > length) count = length - *ppos; end = count + *ppos; copy_to_user(buf, (char *) page + *ppos, count); diff -ur --new-file old/linux/arch/i386/kernel/mtrr.c new/linux/arch/i386/kernel/mtrr.c --- old/linux/arch/i386/kernel/mtrr.c Mon Dec 28 07:45:13 1998 +++ new/linux/arch/i386/kernel/mtrr.c Mon May 10 19:32:45 1999 @@ -132,6 +132,70 @@ Fixed harmless compiler warning in include/asm-i386/mtrr.h Fixed version numbering and history for v1.23 -> v1.24. v1.26 + 19990118 Richard Gooch + PLACEHOLDER. + v1.27 + 19990123 Richard Gooch + Changed locking to spin with reschedule. + Made use of new . + v1.28 + 19990201 Zoltan Boszormenyi + Extended the driver to be able to use Cyrix style ARRs. + 19990204 Richard Gooch + Restructured Cyrix support. + v1.29 + 19990204 Zoltan Boszormenyi + Refined ARR support: enable MAPEN in set_mtrr_prepare() + and disable MAPEN in set_mtrr_done(). + 19990205 Richard Gooch + Minor cleanups. + v1.30 + 19990208 Zoltan Boszormenyi + Protect plain 6x86s (and other processors without the + Page Global Enable feature) against accessing CR4 in + set_mtrr_prepare() and set_mtrr_done(). + 19990210 Richard Gooch + Turned and into function pointers. + v1.31 + 19990212 Zoltan Boszormenyi + Major rewrite of cyrix_arr_init(): do not touch ARRs, + leave them as the BIOS have set them up. + Enable usage of all 8 ARRs. + Avoid multiplications by 3 everywhere and other + code clean ups/speed ups. + 19990213 Zoltan Boszormenyi + Set up other Cyrix processors identical to the boot cpu. + Since Cyrix don't support Intel APIC, this is l'art pour l'art. + Weigh ARRs by size: + If size <= 32M is given, set up ARR# we were given. + If size > 32M is given, set up ARR7 only if it is free, + fail otherwise. + 19990214 Zoltan Boszormenyi + Also check for size >= 256K if we are to set up ARR7, + mtrr_add() returns the value it gets from set_mtrr() + 19990218 Zoltan Boszormenyi + Remove Cyrix "coma bug" workaround from here. + Moved to linux/arch/i386/kernel/setup.c and + linux/include/asm-i386/bugs.h + 19990228 Richard Gooch + Added #ifdef CONFIG_DEVFS_FS + Added MTRRIOC_KILL_ENTRY ioctl(2) + Trap for counter underflow in . + Trap for 4 MiB aligned regions for PPro, stepping <= 7. + 19990301 Richard Gooch + Created hook. + 19990305 Richard Gooch + Temporarily disable AMD support now MTRR capability flag is set. + v1.32 + 19990308 Zoltan Boszormenyi + Adjust my changes (19990212-19990218) to Richard Gooch's + latest changes. (19990228-19990305) + v1.33 + 19990309 Richard Gooch + Fixed typo in message. + 19990310 Richard Gooch + Support K6-II/III based on Alan Cox's patches. + v1.34 */ #include #include @@ -163,11 +227,12 @@ #include #include #include +#include #include #include "irq.h" -#define MTRR_VERSION "1.26 (19981001)" +#define MTRR_VERSION "1.34 (19990310)" #define TRUE 1 #define FALSE 0 @@ -197,7 +262,7 @@ # define MTRR_CHANGE_MASK_DEFTYPE 0x04 #endif -/* In the processor's MTRR interface, the MTRR type is always held in +/* In the Intel processor's MTRR interface, the MTRR type is always held in an 8 bit field: */ typedef u8 mtrr_type; @@ -207,9 +272,12 @@ #ifdef __SMP__ # define set_mtrr(reg,base,size,type) set_mtrr_smp (reg, base, size, type) #else -# define set_mtrr(reg,base,size,type) set_mtrr_up (reg, base, size, type,TRUE) +# define set_mtrr(reg,base,size,type) (*set_mtrr_up) (reg, base, size, type, \ + TRUE) #endif +#define spin_lock_reschedule(lock) while (!spin_trylock(lock)) schedule (); + #ifndef CONFIG_PROC_FS # define compute_ascii() while (0) #endif @@ -233,49 +301,30 @@ unsigned long deftype_lo; unsigned long deftype_hi; unsigned long cr4val; + unsigned long ccr3; }; -/* - * Access to machine-specific registers (available on 586 and better only) - * Note: the rd* operations modify the parameters directly (without using - * pointer indirection), this allows gcc to optimize better - */ -#define rdmsr(msr,val1,val2) \ - __asm__ __volatile__("rdmsr" \ - : "=a" (val1), "=d" (val2) \ - : "c" (msr)) - -#define wrmsr(msr,val1,val2) \ - __asm__ __volatile__("wrmsr" \ - : /* no outputs */ \ - : "c" (msr), "a" (val1), "d" (val2)) - -#define rdtsc(low,high) \ - __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high)) - -#define rdpmc(counter,low,high) \ - __asm__ __volatile__("rdpmc" \ - : "=a" (low), "=d" (high) \ - : "c" (counter)) - -/* Put the processor into a state where MTRRs can be safely set. */ -static void set_mtrr_prepare(struct set_mtrr_context *ctxt) +/* Put the processor into a state where MTRRs can be safely set */ +static void set_mtrr_prepare (struct set_mtrr_context *ctxt) { unsigned long tmp; - /* disable interrupts locally */ + /* Disable interrupts locally */ __save_flags (ctxt->flags); __cli (); - /* save value of CR4 and clear Page Global Enable (bit 7) */ - asm volatile ("movl %%cr4, %0\n\t" - "movl %0, %1\n\t" - "andb $0x7f, %b1\n\t" - "movl %1, %%cr4\n\t" - : "=r" (ctxt->cr4val), "=q" (tmp) : : "memory"); + if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) return; - /* disable and flush caches. Note that wbinvd flushes the TLBs as - a side-effect. */ + /* Save value of CR4 and clear Page Global Enable (bit 7) */ + if (boot_cpu_data.x86_capability & X86_FEATURE_PGE) + asm volatile ("movl %%cr4, %0\n\t" + "movl %0, %1\n\t" + "andb $0x7f, %b1\n\t" + "movl %1, %%cr4\n\t" + : "=r" (ctxt->cr4val), "=q" (tmp) : : "memory"); + + /* Disable and flush caches. Note that wbinvd flushes the TLBs as + a side-effect */ asm volatile ("movl %%cr0, %0\n\t" "orl $0x40000000, %0\n\t" "wbinvd\n\t" @@ -283,64 +332,108 @@ "wbinvd\n\t" : "=r" (tmp) : : "memory"); - /* disable MTRRs, and set the default type to uncached. */ - rdmsr(MTRRdefType_MSR, ctxt->deftype_lo, ctxt->deftype_hi); - wrmsr(MTRRdefType_MSR, ctxt->deftype_lo & 0xf300UL, ctxt->deftype_hi); + switch (boot_cpu_data.x86_vendor) + { + case X86_VENDOR_INTEL: + /* Disable MTRRs, and set the default type to uncached */ + rdmsr (MTRRdefType_MSR, ctxt->deftype_lo, ctxt->deftype_hi); + wrmsr (MTRRdefType_MSR, ctxt->deftype_lo & 0xf300UL, ctxt->deftype_hi); + break; + case X86_VENDOR_CYRIX: + tmp = getCx86 (CX86_CCR3); + setCx86 (CX86_CCR3, (tmp & 0x0f) | 0x10); + ctxt->ccr3 = tmp; + break; + } } /* End Function set_mtrr_prepare */ - -/* Restore the processor after a set_mtrr_prepare */ -static void set_mtrr_done(struct set_mtrr_context *ctxt) +/* Restore the processor after a set_mtrr_prepare */ +static void set_mtrr_done (struct set_mtrr_context *ctxt) { unsigned long tmp; - /* flush caches and TLBs */ + if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) + { + __restore_flags (ctxt->flags); + return; + } + + /* Flush caches and TLBs */ asm volatile ("wbinvd" : : : "memory" ); - /* restore MTRRdefType */ - wrmsr(MTRRdefType_MSR, ctxt->deftype_lo, ctxt->deftype_hi); + /* Restore MTRRdefType */ + switch (boot_cpu_data.x86_vendor) + { + case X86_VENDOR_INTEL: + wrmsr (MTRRdefType_MSR, ctxt->deftype_lo, ctxt->deftype_hi); + break; + case X86_VENDOR_CYRIX: + setCx86 (CX86_CCR3, ctxt->ccr3); + break; + } - /* enable caches */ + /* Enable caches */ asm volatile ("movl %%cr0, %0\n\t" "andl $0xbfffffff, %0\n\t" "movl %0, %%cr0\n\t" : "=r" (tmp) : : "memory"); - /* restore value of CR4 */ - asm volatile ("movl %0, %%cr4" - : : "r" (ctxt->cr4val) : "memory"); + /* Restore value of CR4 */ + if (boot_cpu_data.x86_capability & X86_FEATURE_PGE) + asm volatile ("movl %0, %%cr4" + : : "r" (ctxt->cr4val) : "memory"); - /* re-enable interrupts locally (if enabled previously) */ + /* Re-enable interrupts locally (if enabled previously) */ __restore_flags (ctxt->flags); } /* End Function set_mtrr_done */ - -/* this function returns the number of variable MTRRs */ +/* This function returns the number of variable MTRRs */ static unsigned int get_num_var_ranges (void) { unsigned long config, dummy; - rdmsr(MTRRcap_MSR, config, dummy); - return (config & 0xff); + switch (boot_cpu_data.x86_vendor) + { + case X86_VENDOR_INTEL: + rdmsr (MTRRcap_MSR, config, dummy); + return (config & 0xff); + /*break;*/ + case X86_VENDOR_CYRIX: + /* Cyrix have 8 ARRs */ + return 8; + /*break;*/ + case X86_VENDOR_AMD: + return 2; + /*break;*/ + } + return 0; } /* End Function get_num_var_ranges */ - -/* non-zero if we have the write-combining memory type. */ +/* Returns non-zero if we have the write-combining memory type */ static int have_wrcomb (void) { unsigned long config, dummy; - rdmsr(MTRRcap_MSR, config, dummy); - return (config & (1<<10)); -} - + switch (boot_cpu_data.x86_vendor) + { + case X86_VENDOR_INTEL: + rdmsr (MTRRcap_MSR, config, dummy); + return (config & (1<<10)); + /*break;*/ + case X86_VENDOR_CYRIX: + case X86_VENDOR_AMD: + return 1; + /*break;*/ + } + return 0; +} /* End Function have_wrcomb */ -static void get_mtrr (unsigned int reg, unsigned long *base, - unsigned long *size, mtrr_type *type) +static void intel_get_mtrr (unsigned int reg, unsigned long *base, + unsigned long *size, mtrr_type *type) { unsigned long dummy, mask_lo, base_lo; - rdmsr(MTRRphysMask_MSR(reg), mask_lo, dummy); + rdmsr (MTRRphysMask_MSR(reg), mask_lo, dummy); if ((mask_lo & 0x800) == 0) { /* Invalid (i.e. free) range. */ *base = 0; @@ -364,11 +457,104 @@ *base = (base_lo & 0xfffff000UL); *type = (base_lo & 0xff); -} /* End Function get_mtrr */ +} /* End Function intel_get_mtrr */ + +static void cyrix_get_arr (unsigned int reg, unsigned long *base, + unsigned long *size, mtrr_type *type) +{ + unsigned long flags; + unsigned char arr, ccr3, rcr, shift; + + arr = CX86_ARR_BASE + (reg << 1) + reg; /* avoid multiplication by 3 */ + /* Save flags and disable interrupts */ + __save_flags (flags); __cli (); -static void set_mtrr_up (unsigned int reg, unsigned long base, - unsigned long size, mtrr_type type, int do_safe) + ccr3 = getCx86 (CX86_CCR3); + setCx86 (CX86_CCR3, (ccr3 & 0x0f) | 0x10); /* enable MAPEN */ + ((unsigned char *) base)[3] = getCx86 (arr); + ((unsigned char *) base)[2] = getCx86 (arr+1); + ((unsigned char *) base)[1] = getCx86 (arr+2); + rcr = getCx86(CX86_RCR_BASE + reg); + setCx86 (CX86_CCR3, ccr3); /* disable MAPEN */ + + /* Enable interrupts if it was enabled previously */ + __restore_flags (flags); + + shift = ((unsigned char *) base)[1] & 0x0f; + *base &= 0xfffff000UL; + + /* Power of two, at least 4K on ARR0-ARR6, 256K on ARR7 + * Note: shift==0xf means 4G, this is unsupported. + */ + if (shift) + *size = (reg < 7 ? 0x800UL : 0x20000UL) << shift; + else + *size = 0; + + /* Bit 0 is Cache Enable on ARR7, Cache Disable on ARR0-ARR6 */ + if (reg < 7) { + switch (rcr) { + case 1: *type = MTRR_TYPE_UNCACHABLE; break; + case 8: *type = MTRR_TYPE_WRBACK; break; + case 9: *type = MTRR_TYPE_WRCOMB; break; + case 24: + default: *type = MTRR_TYPE_WRTHROUGH; break; + } + } else { + switch (rcr) { + case 0: *type = MTRR_TYPE_UNCACHABLE; break; + case 8: *type = MTRR_TYPE_WRCOMB; break; + case 9: *type = MTRR_TYPE_WRBACK; break; + case 25: + default: *type = MTRR_TYPE_WRTHROUGH; break; + } + } +} /* End Function cyrix_get_arr */ + +static void amd_get_mtrr (unsigned int reg, unsigned long *base, + unsigned long *size, mtrr_type *type) +{ + unsigned long low, high; + + rdmsr (0xC0000085, low, high); + /* Upper dword is region 1, lower is region 0 */ + if (reg == 1) low = high; + /* The base masks off on the right alignment */ + *base = low & 0xFFFE0000; + *type = 0; + if (low & 1) *type = MTRR_TYPE_UNCACHABLE; + if (low & 2) *type = MTRR_TYPE_WRCOMB; + if ( !(low & 3) ) + { + *size = 0; + return; + } + /* + * This needs a little explaining. The size is stored as an + * inverted mask of bits of 128K granularity 15 bits long offset + * 2 bits + * + * So to get a size we do invert the mask and add 1 to the lowest + * mask bit (4 as its 2 bits in). This gives us a size we then shift + * to turn into 128K blocks + * + * eg 111 1111 1111 1100 is 512K + * + * invert 000 0000 0000 0011 + * +1 000 0000 0000 0100 + * *128K ... + */ + low = (~low) & 0x1FFFC; + *size = (low + 4) << 15; + return; +} /* End Function amd_get_mtrr */ + +static void (*get_mtrr) (unsigned int reg, unsigned long *base, + unsigned long *size, mtrr_type *type) = NULL; + +static void intel_set_mtrr_up (unsigned int reg, unsigned long base, + unsigned long size, mtrr_type type, int do_safe) /* [SUMMARY] Set variable MTRR register on the local CPU. The register to set. The base address of the region. @@ -376,6 +562,7 @@ The type of the region. If TRUE, do the change safely. If FALSE, safety measures should be done externally. + [RETURNS] Nothing. */ { struct set_mtrr_context ctxt; @@ -393,8 +580,92 @@ wrmsr (MTRRphysMask_MSR (reg), ~(size - 1) | 0x800, 0); } if (do_safe) set_mtrr_done (&ctxt); -} /* End Function set_mtrr_up */ +} /* End Function intel_set_mtrr_up */ + +static void cyrix_set_arr_up (unsigned int reg, unsigned long base, + unsigned long size, mtrr_type type, int do_safe) +{ + struct set_mtrr_context ctxt; + unsigned char arr, arr_type, arr_size; + + arr = CX86_ARR_BASE + (reg << 1) + reg; /* avoid multiplication by 3 */ + + /* count down from 32M (ARR0-ARR6) or from 2G (ARR7) */ + size >>= (reg < 7 ? 12 : 18); + size &= 0x7fff; /* make sure arr_size <= 14 */ + for(arr_size = 0; size; arr_size++, size >>= 1); + + if (reg<7) { + switch (type) { + case MTRR_TYPE_UNCACHABLE: arr_type = 1; break; + case MTRR_TYPE_WRCOMB: arr_type = 9; break; + case MTRR_TYPE_WRTHROUGH: arr_type = 24; break; + default: arr_type = 8; break; + } + } else { + switch (type) { + case MTRR_TYPE_UNCACHABLE: arr_type = 0; break; + case MTRR_TYPE_WRCOMB: arr_type = 8; break; + case MTRR_TYPE_WRTHROUGH: arr_type = 25; break; + default: arr_type = 9; break; + } + } + + if (do_safe) set_mtrr_prepare (&ctxt); + setCx86(arr, ((unsigned char *) &base)[3]); + setCx86(arr+1, ((unsigned char *) &base)[2]); + setCx86(arr+2, (((unsigned char *) &base)[1]) | arr_size); + setCx86(CX86_RCR_BASE + reg, arr_type); + if (do_safe) set_mtrr_done (&ctxt); +} /* End Function cyrix_set_arr_up */ + +static void amd_set_mtrr_up (unsigned int reg, unsigned long base, + unsigned long size, mtrr_type type, int do_safe) +/* [SUMMARY] Set variable MTRR register on the local CPU. + The register to set. + The base address of the region. + The size of the region. If this is 0 the region is disabled. + The type of the region. + If TRUE, do the change safely. If FALSE, safety measures should + be done externally. + [RETURNS] Nothing. +*/ +{ + u32 low, high; + struct set_mtrr_context ctxt; + + if (do_safe) set_mtrr_prepare (&ctxt); + /* + * Low is MTRR0 , High MTRR 1 + */ + rdmsr (0xC0000085, low, high); + /* + * Blank to disable + */ + if (size == 0) + *(reg ? &high : &low) = 0; + else + /* Set the register to the base (already shifted for us), the + type (off by one) and an inverted bitmask of the size + + The size is the only odd bit. We are fed say 512K + We invert this and we get 111 1111 1111 1011 but + if you subtract one and invert you get the desired + 111 1111 1111 1100 mask + */ + *(reg ? &high : &low)=(((~(size-1))>>15)&0x0001FFFC)|base|(type+1); + /* + * The writeback rule is quite specific. See the manual. Its + * disable local interrupts, write back the cache, set the mtrr + */ + __asm__ __volatile__ ("wbinvd" : : : "memory"); + wrmsr (0xC0000085, low, high); + if (do_safe) set_mtrr_done (&ctxt); +} /* End Function amd_set_mtrr_up */ +static void (*set_mtrr_up) (unsigned int reg, unsigned long base, + unsigned long size, mtrr_type type, + int do_safe) = NULL; #ifdef __SMP__ @@ -407,7 +678,7 @@ }; -/* Get the MSR pair relating to a var range. */ +/* Get the MSR pair relating to a var range */ __initfunc(static void get_mtrr_var_range (unsigned int index, struct mtrr_var_range *vr)) { @@ -416,8 +687,8 @@ } /* End Function get_mtrr_var_range */ -/* Set the MSR pair relating to a var range. Returns TRUE if - changes are made. */ +/* Set the MSR pair relating to a var range. Returns TRUE if + changes are made */ __initfunc(static int set_mtrr_var_range_testing (unsigned int index, struct mtrr_var_range *vr)) { @@ -441,8 +712,7 @@ } return changed; -} - +} /* End Function set_mtrr_var_range_testing */ __initfunc(static void get_fixed_ranges(mtrr_type *frs)) { @@ -456,8 +726,7 @@ for (i = 0; i < 8; i++) rdmsr(MTRRfix4K_C0000_MSR + i, p[6 + i*2], p[7 + i*2]); -} - +} /* End Function get_fixed_ranges */ __initfunc(static int set_fixed_ranges_testing(mtrr_type *frs)) { @@ -487,10 +756,8 @@ changed = TRUE; } } - return changed; -} - +} /* End Function set_fixed_ranges_testing */ struct mtrr_state { @@ -502,7 +769,7 @@ }; -/* Grab all of the MTRR state for this CPU into *state. */ +/* Grab all of the MTRR state for this CPU into *state */ __initfunc(static void get_mtrr_state(struct mtrr_state *state)) { unsigned int nvrs, i; @@ -511,22 +778,22 @@ nvrs = state->num_var_ranges = get_num_var_ranges(); vrs = state->var_ranges - = kmalloc(nvrs * sizeof(struct mtrr_var_range), GFP_KERNEL); + = kmalloc (nvrs * sizeof (struct mtrr_var_range), GFP_KERNEL); if (vrs == NULL) nvrs = state->num_var_ranges = 0; for (i = 0; i < nvrs; i++) - get_mtrr_var_range(i, &vrs[i]); + get_mtrr_var_range (i, &vrs[i]); - get_fixed_ranges(state->fixed_ranges); + get_fixed_ranges (state->fixed_ranges); - rdmsr(MTRRdefType_MSR, lo, dummy); + rdmsr (MTRRdefType_MSR, lo, dummy); state->def_type = (lo & 0xff); state->enabled = (lo & 0xc00) >> 10; } /* End Function get_mtrr_state */ -/* Free resources associated with a struct mtrr_state */ +/* Free resources associated with a struct mtrr_state */ __initfunc(static void finalize_mtrr_state(struct mtrr_state *state)) { if (state->var_ranges) kfree (state->var_ranges); @@ -546,14 +813,14 @@ unsigned long change_mask = 0; for (i = 0; i < state->num_var_ranges; i++) - if (set_mtrr_var_range_testing(i, &state->var_ranges[i])) + if ( set_mtrr_var_range_testing (i, &state->var_ranges[i]) ) change_mask |= MTRR_CHANGE_MASK_VARIABLE; - if (set_fixed_ranges_testing(state->fixed_ranges)) + if ( set_fixed_ranges_testing(state->fixed_ranges) ) change_mask |= MTRR_CHANGE_MASK_FIXED; - /* set_mtrr_restore restores the old value of MTRRdefType, - so to set it we fiddle with the saved value. */ + /* Set_mtrr_restore restores the old value of MTRRdefType, + so to set it we fiddle with the saved value */ if ((ctxt->deftype_lo & 0xff) != state->def_type || ((ctxt->deftype_lo & 0xc00) >> 10) != state->enabled) { @@ -566,76 +833,63 @@ static atomic_t undone_count; -static void (*handler_func) (struct set_mtrr_context *ctxt, void *info); -static void *handler_info; static volatile int wait_barrier_execute = FALSE; static volatile int wait_barrier_cache_enable = FALSE; -static void sync_handler (void) +struct set_mtrr_data +{ + unsigned long smp_base; + unsigned long smp_size; + unsigned int smp_reg; + mtrr_type smp_type; +}; + +static void ipi_handler (void *info) /* [SUMMARY] Synchronisation handler. Executed by "other" CPUs. [RETURNS] Nothing. */ { + struct set_mtrr_data *data = info; struct set_mtrr_context ctxt; set_mtrr_prepare (&ctxt); - /* Notify master CPU that I'm at the barrier and then wait */ + /* Notify master that I've flushed and disabled my cache */ atomic_dec (&undone_count); while (wait_barrier_execute) barrier (); /* The master has cleared me to execute */ - (*handler_func) (&ctxt, handler_info); + (*set_mtrr_up) (data->smp_reg, data->smp_base, data->smp_size, + data->smp_type, FALSE); /* Notify master CPU that I've executed the function */ atomic_dec (&undone_count); /* Wait for master to clear me to enable cache and return */ while (wait_barrier_cache_enable) barrier (); set_mtrr_done (&ctxt); -} /* End Function sync_handler */ +} /* End Function ipi_handler */ -static void do_all_cpus (void (*handler) (struct set_mtrr_context *ctxt, - void *info), - void *info, int local) -/* [SUMMARY] Execute a function on all CPUs, with caches flushed and disabled. - [PURPOSE] This function will synchronise all CPUs, flush and disable caches - on all CPUs, then call a specified function. When the specified function - finishes on all CPUs, caches are enabled on all CPUs. - The function to execute. - An arbitrary information pointer which is passed to <>. - If TRUE <> is executed locally. - [RETURNS] Nothing. -*/ +static void set_mtrr_smp (unsigned int reg, unsigned long base, + unsigned long size, mtrr_type type) { - unsigned long timeout; + struct set_mtrr_data data; struct set_mtrr_context ctxt; - mtrr_hook = sync_handler; - handler_func = handler; - handler_info = info; + data.smp_reg = reg; + data.smp_base = base; + data.smp_size = size; + data.smp_type = type; wait_barrier_execute = TRUE; wait_barrier_cache_enable = TRUE; - /* Send a message to all other CPUs and wait for them to enter the - barrier */ atomic_set (&undone_count, smp_num_cpus - 1); - smp_send_mtrr(); - /* Wait for it to be done */ - timeout = jiffies + JIFFIE_TIMEOUT; - while ( (atomic_read (&undone_count) > 0) && - time_before(jiffies, timeout) ) - barrier (); - if (atomic_read (&undone_count) > 0) - { + /* Flush and disable the local CPU's cache and start the ball rolling on + other CPUs */ + set_mtrr_prepare (&ctxt); + if (smp_call_function (ipi_handler, &data, 1, 0) != 0) panic ("mtrr: timed out waiting for other CPUs\n"); - } - mtrr_hook = NULL; - /* All other CPUs should be waiting for the barrier, with their caches - already flushed and disabled. Prepare for function completion - notification */ + /* Wait for all other CPUs to flush and disable their caches */ + while (atomic_read (&undone_count) > 0) barrier (); + /* Set up for completion wait and then release other CPUs to change MTRRs*/ atomic_set (&undone_count, smp_num_cpus - 1); - /* Flush and disable the local CPU's cache and release the barier, which - should cause the other CPUs to execute the function. Also execute it - locally if required */ - set_mtrr_prepare (&ctxt); wait_barrier_execute = FALSE; - if (local) (*handler) (&ctxt, info); + (*set_mtrr_up) (reg, base, size, type, FALSE); /* Now wait for other CPUs to complete the function */ while (atomic_read (&undone_count) > 0) barrier (); /* Now all CPUs should have finished the function. Release the barrier to @@ -643,41 +897,10 @@ then enable the local cache and return */ wait_barrier_cache_enable = FALSE; set_mtrr_done (&ctxt); - handler_func = NULL; - handler_info = NULL; -} /* End Function do_all_cpus */ - - -struct set_mtrr_data -{ - unsigned long smp_base; - unsigned long smp_size; - unsigned int smp_reg; - mtrr_type smp_type; -}; - -static void set_mtrr_handler (struct set_mtrr_context *ctxt, void *info) -{ - struct set_mtrr_data *data = info; - - set_mtrr_up (data->smp_reg, data->smp_base, data->smp_size, data->smp_type, - FALSE); -} /* End Function set_mtrr_handler */ - -static void set_mtrr_smp (unsigned int reg, unsigned long base, - unsigned long size, mtrr_type type) -{ - struct set_mtrr_data data; - - data.smp_reg = reg; - data.smp_base = base; - data.smp_size = size; - data.smp_type = type; - do_all_cpus (set_mtrr_handler, &data, TRUE); } /* End Function set_mtrr_smp */ -/* Some BIOS's are fucked and don't set all MTRRs the same! */ +/* Some BIOS's are fucked and don't set all MTRRs the same! */ __initfunc(static void mtrr_state_warn (unsigned long mask)) { if (!mask) return; @@ -720,6 +943,58 @@ #endif } /* End Function init_table */ +static int generic_get_free_region (unsigned long base, unsigned long size) +/* [SUMMARY] Get a free MTRR. + The starting (base) address of the region. + The size (in bytes) of the region. + [RETURNS] The index of the region on success, else -1 on error. +*/ +{ + int i, max; + mtrr_type ltype; + unsigned long lbase, lsize; + + max = get_num_var_ranges (); + for (i = 0; i < max; ++i) + { + (*get_mtrr) (i, &lbase, &lsize, <ype); + if (lsize < 1) return i; + } + return -ENOSPC; +} /* End Function generic_get_free_region */ + +static int cyrix_get_free_region (unsigned long base, unsigned long size) +/* [SUMMARY] Get a free ARR. + The starting (base) address of the region. + The size (in bytes) of the region. + [RETURNS] The index of the region on success, else -1 on error. +*/ +{ + int i; + mtrr_type ltype; + unsigned long lbase, lsize; + + /* If we are to set up a region >32M then look at ARR7 immediately */ + if (size > 0x2000000UL) { + cyrix_get_arr (7, &lbase, &lsize, <ype); + if (lsize < 1) return 7; + /* else try ARR0-ARR6 first */ + } else { + for (i = 0; i < 7; i++) + { + cyrix_get_arr (i, &lbase, &lsize, <ype); + if (lsize < 1) return i; + } + /* ARR0-ARR6 isn't free, try ARR7 but its size must be at least 256K */ + cyrix_get_arr (i, &lbase, &lsize, <ype); + if ((lsize < 1) && (size >= 0x40000)) return i; + } + return -ENOSPC; +} /* End Function cyrix_get_free_region */ + +static int (*get_free_region) (unsigned long base, + unsigned long size) = generic_get_free_region; + int mtrr_add (unsigned long base, unsigned long size, unsigned int type, char increment) /* [SUMMARY] Add an MTRR entry. @@ -738,28 +1013,57 @@ unsigned long lbase, lsize, last; if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return -ENODEV; - if ( (base & 0xfff) || (size & 0xfff) ) - { - printk ("mtrr: size and base must be multiples of 4kB\n"); - printk ("mtrr: size: %lx base: %lx\n", size, base); - return -EINVAL; - } - if (base + size < 0x100000) - { - printk ("mtrr: cannot set region below 1 MByte (0x%lx,0x%lx)\n", - base, size); - return -EINVAL; - } - /* Check upper bits of base and last are equal and lower bits are 0 for - base and 1 for last */ - last = base + size - 1; - for (lbase = base; !(lbase & 1) && (last & 1); - lbase = lbase >> 1, last = last >> 1); - if (lbase != last) + switch (boot_cpu_data.x86_vendor) { - printk ("mtrr: base(0x%lx) is not aligned on a size(0x%lx) boundary\n", - base, size); + case X86_VENDOR_INTEL: + /* For Intel PPro stepping <= 7, must be 4 MiB aligned */ + if ( (boot_cpu_data.x86 == 6) && (boot_cpu_data.x86_model == 1) && + (boot_cpu_data.x86_mask <= 7) && ( base & ( (1 << 22) - 1 ) ) ) + { + printk ("mtrr: base(0x%lx) is not 4 MiB aligned\n", base); + return -EINVAL; + } + /* Fall through */ + case X86_VENDOR_CYRIX: + if ( (base & 0xfff) || (size & 0xfff) ) + { + printk ("mtrr: size and base must be multiples of 4 kiB\n"); + printk ("mtrr: size: %lx base: %lx\n", size, base); + return -EINVAL; + } + if (base + size < 0x100000) + { + printk ("mtrr: cannot set region below 1 MiB (0x%lx,0x%lx)\n", + base, size); + return -EINVAL; + } + /* Check upper bits of base and last are equal and lower bits are 0 + for base and 1 for last */ + last = base + size - 1; + for (lbase = base; !(lbase & 1) && (last & 1); + lbase = lbase >> 1, last = last >> 1); + if (lbase != last) + { + printk ("mtrr: base(0x%lx) is not aligned on a size(0x%lx) boundary\n", + base, size); + return -EINVAL; + } + break; + case X86_VENDOR_AMD: + /* Apply the K6 block alignment and size rules + In order + o Uncached or gathering only + o 128K or bigger block + o Power of 2 block + o base suitably aligned to the power + */ + if (type > MTRR_TYPE_WRCOMB || size < (1 << 17) || + (size & ~(size-1))-size || (base & (size-1))) + return -EINVAL; + break; + default: return -EINVAL; + /*break;*/ } if (type >= MTRR_NUM_TYPES) { @@ -775,10 +1079,10 @@ increment = increment ? 1 : 0; max = get_num_var_ranges (); /* Search for existing MTRR */ - spin_lock (&main_lock); + spin_lock_reschedule (&main_lock); for (i = 0; i < max; ++i) { - get_mtrr (i, &lbase, &lsize, <ype); + (*get_mtrr) (i, &lbase, &lsize, <ype); if (base >= lbase + lsize) continue; if ( (base < lbase) && (base + size <= lbase) ) continue; /* At this point we know there is some kind of overlap/enclosure */ @@ -804,19 +1108,18 @@ return i; } /* Search for an empty MTRR */ - for (i = 0; i < max; ++i) + i = (*get_free_region) (base, size); + if (i < 0) { - get_mtrr (i, &lbase, &lsize, <ype); - if (lsize > 0) continue; - set_mtrr (i, base, size, type); - usage_table[i] = 1; - compute_ascii (); spin_unlock (&main_lock); + printk ("mtrr: no more MTRRs available\n"); return i; } + set_mtrr (i, base, size, type); + usage_table[i] = 1; + compute_ascii (); spin_unlock (&main_lock); - printk ("mtrr: no more MTRRs available\n"); - return -ENOSPC; + return i; } /* End Function mtrr_add */ int mtrr_del (int reg, unsigned long base, unsigned long size) @@ -836,13 +1139,13 @@ if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return -ENODEV; max = get_num_var_ranges (); - spin_lock (&main_lock); + spin_lock_reschedule (&main_lock); if (reg < 0) { /* Search for existing MTRR */ for (i = 0; i < max; ++i) { - get_mtrr (i, &lbase, &lsize, <ype); + (*get_mtrr) (i, &lbase, &lsize, <ype); if ( (lbase == base) && (lsize == size) ) { reg = i; @@ -862,7 +1165,7 @@ printk ("mtrr: register: %d too big\n", reg); return -EINVAL; } - get_mtrr (reg, &lbase, &lsize, <ype); + (*get_mtrr) (reg, &lbase, &lsize, <ype); if (lsize < 1) { spin_unlock (&main_lock); @@ -913,7 +1216,9 @@ reg = mtrr_del (-1, base, size); if (reg < 0) return reg; - if (fcount != NULL) --fcount[reg]; + if (fcount == NULL) return reg; + if (fcount[reg] < 1) return -EINVAL; + --fcount[reg]; return reg; } /* End Function mtrr_file_del */ @@ -1019,11 +1324,18 @@ err = mtrr_file_del (sentry.base, sentry.size, file); if (err < 0) return err; break; + case MTRRIOC_KILL_ENTRY: + if ( !suser () ) return -EPERM; + if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) ) + return -EFAULT; + err = mtrr_del (-1, sentry.base, sentry.size); + if (err < 0) return err; + break; case MTRRIOC_GET_ENTRY: if ( copy_from_user (&gentry, (void *) arg, sizeof gentry) ) return -EFAULT; if ( gentry.regnum >= get_num_var_ranges () ) return -EINVAL; - get_mtrr (gentry.regnum, &gentry.base, &gentry.size, &type); + (*get_mtrr) (gentry.regnum, &gentry.base, &gentry.size, &type); gentry.type = type; if ( copy_to_user ( (void *) arg, &gentry, sizeof gentry) ) return -EFAULT; @@ -1115,7 +1427,7 @@ max = get_num_var_ranges (); for (i = 0; i < max; i++) { - get_mtrr (i, &base, &size, &type); + (*get_mtrr) (i, &base, &size, &type); if (size < 1) usage_table[i] = 0; else { @@ -1148,23 +1460,165 @@ #ifdef __SMP__ +typedef struct { + unsigned long base; + unsigned long size; + mtrr_type type; +} arr_state_t; + +arr_state_t arr_state[8] __initdata = { + {0UL,0UL,0UL}, {0UL,0UL,0UL}, {0UL,0UL,0UL}, {0UL,0UL,0UL}, + {0UL,0UL,0UL}, {0UL,0UL,0UL}, {0UL,0UL,0UL}, {0UL,0UL,0UL} +}; + +unsigned char ccr_state[7] __initdata = { 0, 0, 0, 0, 0, 0, 0 }; + +__initfunc(static void cyrix_arr_init_secondary(void)) +{ + struct set_mtrr_context ctxt; + int i; + + set_mtrr_prepare (&ctxt); /* flush cache and enable MAPEN */ + + /* the CCRs are not contiguous */ + for(i=0; i<4; i++) setCx86(CX86_CCR0 + i, ccr_state[i]); + for( ; i<7; i++) setCx86(CX86_CCR4 + i, ccr_state[i]); + for(i=0; i<8; i++) + cyrix_set_arr_up(i, + arr_state[i].base, arr_state[i].size, arr_state[i].type, FALSE); + + set_mtrr_done (&ctxt); /* flush cache and disable MAPEN */ +} /* End Function cyrix_arr_init_secondary */ + +#endif + +/* + * On Cyrix 6x86(MX) and M II the ARR3 is special: it has connection + * with the SMM (System Management Mode) mode. So we need the following: + * Check whether SMI_LOCK (CCR3 bit 0) is set + * if it is set, write a warning message: ARR3 cannot be changed! + * (it cannot be changed until the next processor reset) + * if it is reset, then we can change it, set all the needed bits: + * - disable access to SMM memory through ARR3 range (CCR1 bit 7 reset) + * - disable access to SMM memory (CCR1 bit 2 reset) + * - disable SMM mode (CCR1 bit 1 reset) + * - disable write protection of ARR3 (CCR6 bit 1 reset) + * - (maybe) disable ARR3 + * Just to be sure, we enable ARR usage by the processor (CCR5 bit 5 set) + */ +__initfunc(static void cyrix_arr_init(void)) +{ + struct set_mtrr_context ctxt; + unsigned char ccr[7]; + int ccrc[7] = { 0, 0, 0, 0, 0, 0, 0 }; +#ifdef __SMP__ + int i; +#endif + + set_mtrr_prepare (&ctxt); /* flush cache and enable MAPEN */ + + /* Save all CCRs locally */ + ccr[0] = getCx86 (CX86_CCR0); + ccr[1] = getCx86 (CX86_CCR1); + ccr[2] = getCx86 (CX86_CCR2); + ccr[3] = ctxt.ccr3; + ccr[4] = getCx86 (CX86_CCR4); + ccr[5] = getCx86 (CX86_CCR5); + ccr[6] = getCx86 (CX86_CCR6); + + if (ccr[3] & 1) + ccrc[3] = 1; + else { + /* Disable SMM mode (bit 1), access to SMM memory (bit 2) and + * access to SMM memory through ARR3 (bit 7). + */ +/* + if (ccr[1] & 0x80) { ccr[1] &= 0x7f; ccrc[1] |= 0x80; } + if (ccr[1] & 0x04) { ccr[1] &= 0xfb; ccrc[1] |= 0x04; } + if (ccr[1] & 0x02) { ccr[1] &= 0xfd; ccrc[1] |= 0x02; } +*/ + if (ccr[6] & 0x02) { + ccr[6] &= 0xfd; ccrc[6] = 1; /* Disable write protection of ARR3. */ + setCx86 (CX86_CCR6, ccr[6]); + } + /* Disable ARR3. */ + /* cyrix_set_arr_up (3, 0, 0, 0, FALSE); */ + } + /* If we changed CCR1 in memory, change it in the processor, too. */ + if (ccrc[1]) setCx86 (CX86_CCR1, ccr[1]); + + /* Enable ARR usage by the processor */ + if (!(ccr[5] & 0x20)) { + ccr[5] |= 0x20; ccrc[5] = 1; + setCx86 (CX86_CCR5, ccr[5]); + } + +#ifdef __SMP__ + for(i=0; i<7; i++) ccr_state[i] = ccr[i]; + for(i=0; i<8; i++) + cyrix_get_arr(i, + &arr_state[i].base, &arr_state[i].size, &arr_state[i].type); +#endif + + set_mtrr_done (&ctxt); /* flush cache and disable MAPEN */ + + if ( ccrc[5] ) printk ("mtrr: ARR usage was not enabled, enabled manually\n"); + if ( ccrc[3] ) printk ("mtrr: ARR3 cannot be changed\n"); +/* + if ( ccrc[1] & 0x80) printk ("mtrr: SMM memory access through ARR3 disabled\n"); + if ( ccrc[1] & 0x04) printk ("mtrr: SMM memory access disabled\n"); + if ( ccrc[1] & 0x02) printk ("mtrr: SMM mode disabled\n"); +*/ + if ( ccrc[6] ) printk ("mtrr: ARR3 was write protected, unprotected\n"); +} /* End Function cyrix_arr_init */ + +__initfunc(static void mtrr_setup (void)) +{ + printk ("mtrr: v%s Richard Gooch (rgooch@atnf.csiro.au)\n", MTRR_VERSION); + switch (boot_cpu_data.x86_vendor) + { + case X86_VENDOR_INTEL: + get_mtrr = intel_get_mtrr; + set_mtrr_up = intel_set_mtrr_up; + break; + case X86_VENDOR_CYRIX: + printk ("mtrr: Using Cyrix style ARRs\n"); + get_mtrr = cyrix_get_arr; + set_mtrr_up = cyrix_set_arr_up; + get_free_region = cyrix_get_free_region; + break; + case X86_VENDOR_AMD: + get_mtrr = amd_get_mtrr; + set_mtrr_up = amd_set_mtrr_up; + break; + } +} /* End Function mtrr_setup */ + +#ifdef __SMP__ + static volatile unsigned long smp_changes_mask __initdata = 0; static struct mtrr_state smp_mtrr_state __initdata = {0, 0}; __initfunc(void mtrr_init_boot_cpu (void)) { if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return; - printk("mtrr: v%s Richard Gooch (rgooch@atnf.csiro.au)\n", MTRR_VERSION); - - get_mtrr_state (&smp_mtrr_state); + mtrr_setup (); + switch (boot_cpu_data.x86_vendor) + { + case X86_VENDOR_INTEL: + get_mtrr_state (&smp_mtrr_state); + break; + case X86_VENDOR_CYRIX: + cyrix_arr_init (); + break; + } } /* End Function mtrr_init_boot_cpu */ -__initfunc(void mtrr_init_secondary_cpu (void)) +__initfunc(static void intel_mtrr_init_secondary_cpu (void)) { unsigned long mask, count; struct set_mtrr_context ctxt; - if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return; /* Note that this is not ideal, since the cache is only flushed/disabled for this CPU while the MTRRs are changed, but changing this requires more invasive changes to the way the kernel boots */ @@ -1177,21 +1631,52 @@ if (mask & 0x01) set_bit (count, &smp_changes_mask); mask >>= 1; } -} /* End Function mtrr_init_secondary_cpu */ +} /* End Function intel_mtrr_init_secondary_cpu */ +__initfunc(void mtrr_init_secondary_cpu (void)) +{ + if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return; + switch (boot_cpu_data.x86_vendor) + { + case X86_VENDOR_INTEL: + intel_mtrr_init_secondary_cpu (); + break; + case X86_VENDOR_CYRIX: + /* This is _completely theoretical_! + * I assume here that one day Cyrix will support Intel APIC. + * In reality on non-Intel CPUs we won't even get to this routine. + * Hopefully no one will plug two Cyrix processors in a dual P5 board. + * :-) + */ + cyrix_arr_init_secondary (); + break; + default: + printk ("mtrr: SMP support incomplete for this vendor\n"); + break; + } +} /* End Function mtrr_init_secondary_cpu */ #endif /* __SMP__ */ __initfunc(int mtrr_init(void)) { if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return 0; -# ifndef __SMP__ - printk("mtrr: v%s Richard Gooch (rgooch@atnf.csiro.au)\n", MTRR_VERSION); -# endif - # ifdef __SMP__ - finalize_mtrr_state (&smp_mtrr_state); - mtrr_state_warn (smp_changes_mask); -# endif /* __SMP__ */ + switch (boot_cpu_data.x86_vendor) + { + case X86_VENDOR_INTEL: + finalize_mtrr_state (&smp_mtrr_state); + mtrr_state_warn (smp_changes_mask); + break; + } +# else /* __SMP__ */ + mtrr_setup (); + switch (boot_cpu_data.x86_vendor) + { + case X86_VENDOR_CYRIX: + cyrix_arr_init (); + break; + } +# endif /* !__SMP__ */ # ifdef CONFIG_PROC_FS proc_register (&proc_root, &proc_root_mtrr); diff -ur --new-file old/linux/arch/i386/kernel/process.c new/linux/arch/i386/kernel/process.c --- old/linux/arch/i386/kernel/process.c Wed Jan 20 20:08:24 1999 +++ new/linux/arch/i386/kernel/process.c Fri Apr 30 17:13:37 1999 @@ -111,6 +111,8 @@ /* endless idle loop with no priority at all */ current->priority = 0; current->counter = -100; + init_idle(); + for (;;) { if (work) start_idle = jiffies; @@ -139,6 +141,8 @@ /* endless idle loop with no priority at all */ current->priority = 0; current->counter = -100; + init_idle(); + while(1) { if (current_cpu_data.hlt_works_ok && !hlt_counter && !current->need_resched) @@ -316,7 +320,7 @@ /* Make sure the first page is mapped to the start of physical memory. It is normally not mapped, to trap kernel NULL pointer dereferences. */ - pg0[0] = 7; + pg0[0] = _PAGE_RW | _PAGE_PRESENT; /* * Use `swapper_pg_dir' as our page directory. We bother with diff -ur --new-file old/linux/arch/i386/kernel/ptrace.c new/linux/arch/i386/kernel/ptrace.c --- old/linux/arch/i386/kernel/ptrace.c Tue Jan 12 21:03:53 1999 +++ new/linux/arch/i386/kernel/ptrace.c Wed Mar 24 22:18:46 1999 @@ -354,6 +354,7 @@ { struct task_struct *child; struct user * dummy = NULL; + unsigned long flags; int i, ret; lock_kernel(); @@ -385,21 +386,22 @@ (current->uid != child->uid) || (current->gid != child->egid) || (current->gid != child->sgid) || + (!cap_issubset(child->cap_permitted, current->cap_permitted)) || (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE)) goto out; /* the same process cannot be attached many times */ if (child->flags & PF_PTRACED) goto out; child->flags |= PF_PTRACED; - if (child->p_pptr != current) { - unsigned long flags; - write_lock_irqsave(&tasklist_lock, flags); + 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); } + write_unlock_irqrestore(&tasklist_lock, flags); + send_sig(SIGSTOP, child, 1); ret = 0; goto out; @@ -559,7 +561,6 @@ } case PTRACE_DETACH: { /* detach a process that was attached. */ - unsigned long flags; long tmp; ret = -EIO; diff -ur --new-file old/linux/arch/i386/kernel/setup.c new/linux/arch/i386/kernel/setup.c --- old/linux/arch/i386/kernel/setup.c Thu Jan 21 20:28:40 1999 +++ new/linux/arch/i386/kernel/setup.c Mon May 10 19:32:45 1999 @@ -5,6 +5,10 @@ * * Enhanced CPU type detection by Mike Jagdis, Patrick St. Jean * and Martin Mares, November 1997. + * + * Force Cyrix 6x86(MX) and M II processors to report MTRR capability + * and fix against Cyrix "coma bug" by + * Zoltan Boszormenyi February 1999. */ /* @@ -39,6 +43,7 @@ #include #include #include +#include /* * Machine setup.. @@ -57,6 +62,7 @@ unsigned int machine_id = 0; unsigned int machine_submodel_id = 0; unsigned int BIOS_revision = 0; +unsigned int mca_pentium_flag = 0; /* * Setup options @@ -244,11 +250,6 @@ unsigned long memory_start, memory_end; char c = ' ', *to = command_line, *from = COMMAND_LINE; int len = 0; - static unsigned char smptrap=0; - - if (smptrap) - return; - smptrap=1; #ifdef CONFIG_VISWS visws_get_board_type_and_rev(); @@ -381,7 +382,7 @@ } -__initfunc(static int amd_model(struct cpuinfo_x86 *c)) +__initfunc(static int get_model_name(struct cpuinfo_x86 *c)) { unsigned int n, dummy, *v; @@ -398,9 +399,87 @@ cpuid(0x80000003, &v[4], &v[5], &v[6], &v[7]); cpuid(0x80000004, &v[8], &v[9], &v[10], &v[11]); c->x86_model_id[48] = 0; + /* Set MTRR capability flag if appropriate */ + if(boot_cpu_data.x86 !=5) + return 1; + if((boot_cpu_data.x86_model == 9) || + ((boot_cpu_data.x86_model == 8) && + (boot_cpu_data.x86_mask >= 8))) + c->x86_capability |= X86_FEATURE_MTRR; + return 1; } +__initfunc(static int amd_model(struct cpuinfo_x86 *c)) +{ + u32 l, h; + unsigned long flags; + int mbytes = max_mapnr >> (20-PAGE_SHIFT); + + int r=get_model_name(c); + + /* + * Now do the cache operations. + */ + + switch(c->x86) + { + case 5: + if( c->x86_model < 6 ) + { + /* Anyone with a K5 want to fill this in */ + break; + } + + /* K6 with old style WHCR */ + if( c->x86_model < 8 || + (c->x86_model== 8 && c->x86_mask < 8)) + { + /* We can only write allocate on the low 508Mb */ + if(mbytes>508) + mbytes=508; + + rdmsr(0xC0000082, l, h); + if((l&0x0000FFFF)==0) + { + l=(1<<0)|(mbytes/4); + save_flags(flags); + __cli(); + __asm__ __volatile__ ("wbinvd": : :"memory"); + wrmsr(0xC0000082, l, h); + restore_flags(flags); + printk(KERN_INFO "Enabling old style K6 write allocation for %d Mb\n", + mbytes); + + } + break; + } + if (c->x86_model == 8 || c->x86_model == 9) + { + /* The more serious chips .. */ + + if(mbytes>4092) + mbytes=4092; + rdmsr(0xC0000082, l, h); + if((l&0xFFFF0000)==0) + { + l=((mbytes>>2)<<22)|(1<<16); + save_flags(flags); + __cli(); + __asm__ __volatile__ ("wbinvd": : :"memory"); + wrmsr(0xC0000082, l, h); + restore_flags(flags); + printk(KERN_INFO "Enabling new style K6 write allocation for %d Mb\n", + mbytes); + } + break; + } + break; + } + return r; +} + + /* * Read Cyrix DEVID registers (DIR) to get more detailed info. about the CPU */ @@ -507,6 +586,10 @@ (c->x86_model)++; } else /* 686 */ p = Cx86_cb+1; + /* Emulate MTRRs using Cyrix's ARRs. */ + c->x86_capability |= X86_FEATURE_MTRR; + /* 6x86's contain this bug */ + c->coma_bug = 1; break; case 4: /* MediaGX/GXm */ @@ -517,7 +600,7 @@ /* GXm supports extended cpuid levels 'ala' AMD */ if (c->cpuid_level == 2) { - amd_model(c); /* get CPU marketing name */ + get_model_name(c); /* get CPU marketing name */ c->x86_capability&=~X86_FEATURE_TSC; return; } @@ -531,11 +614,14 @@ case 5: /* 6x86MX/M II */ if (dir1 > 7) dir0_msn++; /* M II */ + else c->coma_bug = 1; /* 6x86MX, it has the bug. */ tmp = (!(dir0_lsn & 7) || dir0_lsn & 1) ? 2 : 0; Cx86_cb[tmp] = cyrix_model_mult2[dir0_lsn & 7]; p = Cx86_cb+tmp; if (((dir1 & 0x0f) > 4) || ((dir1 & 0xf0) == 0x20)) (c->x86_model)++; + /* Emulate MTRRs using Cyrix's ARRs. */ + c->x86_capability |= X86_FEATURE_MTRR; break; case 0xf: /* Cyrix 486 without DEVID registers */ @@ -642,6 +728,20 @@ if (c->x86_vendor == X86_VENDOR_AMD && amd_model(c)) return; + + if (c->cpuid_level > 0 && c->x86_vendor == X86_VENDOR_INTEL) + { + if(c->x86_capability&(1<<18)) + { + /* Disable processor serial number on Intel Pentium III + from code by Phil Karn */ + unsigned long lo,hi; + rdmsr(0x119,lo,hi); + lo |= 0x200000; + wrmsr(0x119,lo,hi); + printk(KERN_INFO "Pentium-III serial number disabled.\n"); + } + } for (i = 0; i < sizeof(cpu_models)/sizeof(struct cpu_model_info); i++) { if (c->cpuid_level > 1) { @@ -726,15 +826,6 @@ } -#define rdmsr(msr,val1,val2) \ - __asm__ __volatile__("rdmsr" \ - : "=a" (val1), "=d" (val2) \ - : "c" (msr)) - -#define wrmsr(msr,val1,val2) \ - __asm__ __volatile__("wrmsr" \ - : /* no outputs */ \ - : "c" (msr), "a" (val1), "d" (val2)) static char *cpu_vendor_names[] __initdata = { "Intel", "Cyrix", "AMD", "UMC", "NexGen", "Centaur" }; @@ -784,9 +875,9 @@ int sep_bug; static char *x86_cap_flags[] = { "fpu", "vme", "de", "pse", "tsc", "msr", "6", "mce", - "cx8", "9", "10", "sep", "12", "pge", "14", "cmov", - "16", "17", "18", "19", "20", "21", "22", "mmx", - "24", "25", "26", "27", "28", "29", "30", "31" + "cx8", "9", "10", "sep", "mtrr", "pge", "14", "cmov", + "16", "17", "psn", "19", "20", "21", "22", "mmx", + "24", "kni", "26", "27", "28", "29", "30", "31" }; struct cpuinfo_x86 *c = cpu_data; int i, n; @@ -807,7 +898,7 @@ c->x86_model, c->x86_model_id[0] ? c->x86_model_id : "unknown"); - if (c->x86_mask) + if (c->x86_mask || c->cpuid_level >= 0) p += sprintf(p, "stepping\t: %d\n", c->x86_mask); else p += sprintf(p, "stepping\t: unknown\n"); @@ -832,10 +923,10 @@ } else if (c->x86_vendor == X86_VENDOR_INTEL) { x86_cap_flags[6] = "pae"; x86_cap_flags[9] = "apic"; - x86_cap_flags[12] = "mtrr"; x86_cap_flags[14] = "mca"; x86_cap_flags[16] = "pat"; x86_cap_flags[17] = "pse36"; + x86_cap_flags[18] = "psn"; x86_cap_flags[24] = "osfxsr"; } @@ -850,6 +941,7 @@ "hlt_bug\t\t: %s\n" "sep_bug\t\t: %s\n" "f00f_bug\t: %s\n" + "coma_bug\t: %s\n" "fpu\t\t: %s\n" "fpu_exception\t: %s\n" "cpuid level\t: %d\n" @@ -859,6 +951,7 @@ c->hlt_works_ok ? "no" : "yes", sep_bug ? "yes" : "no", c->f00f_bug ? "yes" : "no", + c->coma_bug ? "yes" : "no", c->hard_math ? "yes" : "no", (c->hard_math && ignore_irq13) ? "yes" : "no", c->cpuid_level, diff -ur --new-file old/linux/arch/i386/kernel/smp.c new/linux/arch/i386/kernel/smp.c --- old/linux/arch/i386/kernel/smp.c Thu Jan 21 20:28:40 1999 +++ new/linux/arch/i386/kernel/smp.c Mon May 10 19:32:45 1999 @@ -29,6 +29,7 @@ * from Jose Renau * Alan Cox : Added EBDA scanning * Ingo Molnar : various cleanups and rewrites + * Tigran Aivazian : fixed "0.00 in /proc/uptime on SMP" bug. */ #include @@ -39,10 +40,12 @@ #include #include #include +#include #include "irq.h" -extern unsigned long start_kernel, _etext; +#define JIFFIE_TIMEOUT 100 + extern void update_one_process( struct task_struct *p, unsigned long ticks, unsigned long user, unsigned long system, int cpu); @@ -146,6 +149,8 @@ */ #define APIC_DEFAULT_PHYS_BASE 0xfee00000 +#define CLEAR_TSC wrmsr(0x10, 0x00001000, 0x00001000) + /* * Setup routine for controlling SMP activation * @@ -308,8 +313,17 @@ printk("Processor #%d unused. (Max %d processors).\n",m->mpc_apicid, NR_CPUS); else { + int ver = m->mpc_apicver; + cpu_present_map|=(1<mpc_apicid); - apic_version[m->mpc_apicid]=m->mpc_apicver; + /* + * Validate version + */ + if (ver == 0x0) { + printk("BIOS bug, APIC version is 0 for CPU#%d! fixing up to 0x10. (tell your hw vendor)\n", m->mpc_apicid); + ver = 0x10; + } + apic_version[m->mpc_apicid] = ver; } } mpt+=sizeof(*m); @@ -325,11 +339,13 @@ SMP_PRINTK(("Bus #%d is %s\n", m->mpc_busid, str)); - if ((strncmp(m->mpc_bustype,"ISA",3) == 0) || - (strncmp(m->mpc_bustype,"EISA",4) == 0)) + if (strncmp(m->mpc_bustype,"ISA",3) == 0) mp_bus_id_to_type[m->mpc_busid] = MP_BUS_ISA; else + if (strncmp(m->mpc_bustype,"EISA",4) == 0) + mp_bus_id_to_type[m->mpc_busid] = + MP_BUS_EISA; if (strncmp(m->mpc_bustype,"PCI",3) == 0) { mp_bus_id_to_type[m->mpc_busid] = MP_BUS_PCI; @@ -454,7 +470,7 @@ */ cfg=pg0[0]; - pg0[0] = (mp_lapic_addr | 7); + pg0[0] = (mp_lapic_addr | _PAGE_RW | _PAGE_PRESENT); local_flush_tlb(); boot_cpu_id = GET_APIC_ID(*((volatile unsigned long *) APIC_ID)); @@ -710,24 +726,19 @@ value |= 0xff; /* Set spurious IRQ vector to 0xff */ apic_write(APIC_SPIV,value); - value = apic_read(APIC_TASKPRI); - value &= ~APIC_TPRI_MASK; /* Set Task Priority to 'accept all' */ - apic_write(APIC_TASKPRI,value); - /* - * Set arbitrarion priority to 0 + * Set Task Priority to 'accept all' */ - value = apic_read(APIC_ARBPRI); - value &= ~APIC_ARBPRI_MASK; - apic_write(APIC_ARBPRI, value); + value = apic_read(APIC_TASKPRI); + value &= ~APIC_TPRI_MASK; + apic_write(APIC_TASKPRI,value); /* - * Set the logical destination ID to 'all', just to be safe. + * Clear the logical destination ID, just to be safe. * also, put the APIC into flat delivery mode. */ value = apic_read(APIC_LDR); value &= ~APIC_LDR_MASK; - value |= SET_APIC_LOGICAL_ID(0xff); apic_write(APIC_LDR,value); value = apic_read(APIC_DFR); @@ -735,8 +746,6 @@ apic_write(APIC_DFR, value); udelay(100); /* B safe */ - ack_APIC_irq(); - udelay(100); } unsigned long __init init_smp_mappings(unsigned long memory_start) @@ -883,6 +892,7 @@ * Everything has been set up for the secondary * CPUs - they just need to reload everything * from the task structure + * This function must not return. */ void __init initialize_secondary(void) { @@ -924,7 +934,6 @@ /* * We need an idle process for each processor. */ - kernel_thread(start_secondary, NULL, CLONE_PID); cpucount++; @@ -935,6 +944,8 @@ idle->processor = i; __cpu_logical_map[cpucount] = i; cpu_number_map[i] = cpucount; + idle->has_cpu = 1; /* we schedule the first task manually */ + idle->tss.eip = (unsigned long) start_secondary; /* start_eip had better be page-aligned! */ start_eip = setup_trampoline(); @@ -1167,6 +1178,7 @@ /* Must be done before other processors booted */ mtrr_init_boot_cpu (); #endif + init_idle(); /* * Initialize the logical to physical CPU number mapping * and the per-CPU profiling counter/multiplier @@ -1316,7 +1328,7 @@ * Install writable page 0 entry. */ cfg = pg0[0]; - pg0[0] = 3; /* writeable, present, addr 0 */ + pg0[0] = _PAGE_RW | _PAGE_PRESENT; /* writeable, present, addr 0 */ local_flush_tlb(); /* @@ -1641,15 +1653,84 @@ send_IPI_allbutself(STOP_CPU_VECTOR); } -/* - * this function sends an 'reload MTRR state' IPI to all other CPUs - * in the system. it goes straight through, completion processing - * is done on the mttr.c level. +/* Structure and data for smp_call_function(). This is designed to minimise + * static memory requirements. It also looks cleaner. */ - -void smp_send_mtrr(void) +struct smp_call_function_struct { + void (*func) (void *info); + void *info; + atomic_t unstarted_count; + atomic_t unfinished_count; + int wait; +}; +static volatile struct smp_call_function_struct *smp_call_function_data = NULL; + +/* + * this function sends a 'generic call function' IPI to all other CPUs + * in the system. + */ + +int smp_call_function (void (*func) (void *info), void *info, int retry, + int wait) +/* [SUMMARY] Run a function on all other CPUs. + The function to run. This must be fast and non-blocking. + An arbitrary pointer to pass to the function. + If true, keep retrying until ready. + If true, wait until function has completed on other CPUs. + [RETURNS] 0 on success, else a negative status code. Does not return until + remote CPUs are nearly ready to execute <> or are or have executed. +*/ { - send_IPI_allbutself(MTRR_CHANGE_VECTOR); + unsigned long timeout; + struct smp_call_function_struct data; + static spinlock_t lock = SPIN_LOCK_UNLOCKED; + + if (retry) { + while (1) { + if (smp_call_function_data) { + schedule (); /* Give a mate a go */ + continue; + } + spin_lock (&lock); + if (smp_call_function_data) { + spin_unlock (&lock); /* Bad luck */ + continue; + } + /* Mine, all mine! */ + break; + } + } + else { + if (smp_call_function_data) return -EBUSY; + spin_lock (&lock); + if (smp_call_function_data) { + spin_unlock (&lock); + return -EBUSY; + } + } + smp_call_function_data = &data; + spin_unlock (&lock); + data.func = func; + data.info = info; + atomic_set (&data.unstarted_count, smp_num_cpus - 1); + data.wait = wait; + if (wait) atomic_set (&data.unfinished_count, smp_num_cpus - 1); + /* Send a message to all other CPUs and wait for them to respond */ + send_IPI_allbutself (CALL_FUNCTION_VECTOR); + /* Wait for response */ + timeout = jiffies + JIFFIE_TIMEOUT; + while ( (atomic_read (&data.unstarted_count) > 0) && + time_before (jiffies, timeout) ) + barrier (); + if (atomic_read (&data.unstarted_count) > 0) { + smp_call_function_data = NULL; + return -ETIMEDOUT; + } + if (wait) + while (atomic_read (&data.unfinished_count) > 0) + barrier (); + smp_call_function_data = NULL; + return 0; } /* @@ -1692,9 +1773,8 @@ system=1; irq_enter(cpu, 0); + update_one_process(p, 1, user, system, cpu); if (p->pid) { - update_one_process(p, 1, user, system, cpu); - p->counter -= 1; if (p->counter < 0) { p->counter = 0; @@ -1707,7 +1787,6 @@ kstat.cpu_user += user; kstat.per_cpu_user[cpu] += user; } - kstat.cpu_system += system; kstat.per_cpu_system[cpu] += system; @@ -1767,6 +1846,7 @@ local_flush_tlb(); ack_APIC_irq(); + } static void stop_this_cpu (void) @@ -1789,12 +1869,19 @@ stop_this_cpu(); } -void (*mtrr_hook) (void) = NULL; - -asmlinkage void smp_mtrr_interrupt(void) +asmlinkage void smp_call_function_interrupt(void) { - ack_APIC_irq(); - if (mtrr_hook) (*mtrr_hook)(); + void (*func) (void *info) = smp_call_function_data->func; + void *info = smp_call_function_data->info; + int wait = smp_call_function_data->wait; + + ack_APIC_irq (); + /* Notify initiating CPU that I've grabbed the data and am about to + execute the function */ + atomic_dec (&smp_call_function_data->unstarted_count); + /* At this point the structure may be out of scope unless wait==1 */ + (*func) (info); + if (wait) atomic_dec (&smp_call_function_data->unfinished_count); } /* @@ -1802,8 +1889,10 @@ */ asmlinkage void smp_spurious_interrupt(void) { - /* ack_APIC_irq(); see sw-dev-man vol 3, chapter 7.4.13.5 */ - printk("spurious APIC interrupt, ayiee, should never happen.\n"); + ack_APIC_irq(); + /* see sw-dev-man vol 3, chapter 7.4.13.5 */ + printk("spurious APIC interrupt on CPU#%d, should never happen.\n", + smp_processor_id()); } /* @@ -1815,10 +1904,6 @@ * closely follows bus clocks. */ -#define RDTSC(x) __asm__ __volatile__ ( "rdtsc" \ - :"=a" (((unsigned long*)&x)[0]), \ - "=d" (((unsigned long*)&x)[1])) - /* * The timer chip is already set up at HZ interrupts per second here, * but we do not accept timer interrupts yet. We only allow the BP @@ -1937,7 +2022,7 @@ /* * We wrapped around just now. Let's start: */ - RDTSC(t1); + rdtscll(t1); tt1=apic_read(APIC_TMCCT); #define LOOPS (HZ/10) @@ -1948,7 +2033,7 @@ wait_8254_wraparound (); tt2=apic_read(APIC_TMCCT); - RDTSC(t2); + rdtscll(t2); /* * The APIC bus clock counter is 32 bits only, it @@ -2058,3 +2143,4 @@ } #undef APIC_DIVISOR + diff -ur --new-file old/linux/arch/i386/kernel/time.c new/linux/arch/i386/kernel/time.c --- old/linux/arch/i386/kernel/time.c Wed Jan 20 19:18:53 1999 +++ new/linux/arch/i386/kernel/time.c Thu Apr 29 20:53:41 1999 @@ -30,19 +30,6 @@ * serialize accesses to xtime/lost_ticks). */ -/* What about the "updated NTP code" stuff in 2.0 time.c? It's not in - * 2.1, perhaps it should be ported, too. - * - * What about the BUGGY_NEPTUN_TIMER stuff in do_slow_gettimeoffset()? - * Whatever it fixes, is it also fixed in the new code from the Jumbo - * patch, so that that code can be used instead? - * - * The CPU Hz should probably be displayed in check_bugs() together - * with the CPU vendor and type. Perhaps even only in MHz, though that - * takes away some of the fun of the new code :) - * - * - Michael Krause */ - #include #include #include @@ -60,6 +47,7 @@ #include #include #include +#include #include #include @@ -96,8 +84,8 @@ register unsigned long edx asm("dx"); /* Read the Time Stamp Counter */ - __asm__("rdtsc" - :"=a" (eax), "=d" (edx)); + + rdtsc(eax,edx); /* .. relative to previous jiffy (32 bits is enough) */ eax -= last_tsc_low; /* tsc_low delta */ @@ -292,7 +280,6 @@ xtime = *tv; time_adjust = 0; /* stop active adjtime() */ time_status |= STA_UNSYNC; - time_state = TIME_ERROR; /* p. 24, (a) */ time_maxerror = NTP_PHASE_LIMIT; time_esterror = NTP_PHASE_LIMIT; write_unlock_irq(&xtime_lock); @@ -457,7 +444,8 @@ */ /* read Pentium cycle counter */ - __asm__("rdtsc" : "=a" (last_tsc_low) : : "edx"); + + rdtscl(last_tsc_low); outb_p(0x00, 0x43); /* latch the count ASAP */ @@ -556,70 +544,72 @@ * device. */ +#define CALIBRATE_LATCH (5 * LATCH) +#define CALIBRATE_TIME (5 * 1000020/HZ) + __initfunc(static unsigned long calibrate_tsc(void)) { - unsigned long retval; + /* Set the Gate high, disable speaker */ + outb((inb(0x61) & ~0x02) | 0x01, 0x61); - __asm__( /* set the Gate high, program CTC channel 2 for mode 0 - * (interrupt on terminal count mode), binary count, - * load 5 * LATCH count, (LSB and MSB) - * to begin countdown, read the TSC and busy wait. - * BTW LATCH is calculated in timex.h from the HZ value - */ + /* + * Now let's take care of CTC channel 2 + * + * Set the Gate high, program CTC channel 2 for mode 0, + * (interrupt on terminal count mode), binary count, + * load 5 * LATCH count, (LSB and MSB) to begin countdown. + */ + outb(0xb0, 0x43); /* binary, mode 0, LSB/MSB, Ch 2 */ + outb(CALIBRATE_LATCH & 0xff, 0x42); /* LSB of count */ + outb(CALIBRATE_LATCH >> 8, 0x42); /* MSB of count */ + + { + unsigned long startlow, starthigh; + unsigned long endlow, endhigh; + unsigned long count; + + rdtsc(startlow,starthigh); + count = 0; + do { + count++; + } while ((inb(0x61) & 0x20) == 0); + rdtsc(endlow,endhigh); + + last_tsc_low = endlow; + + /* Error: ECTCNEVERSET */ + if (count <= 1) + goto bad_ctc; + + /* 64-bit subtract - gcc just messes up with long longs */ + __asm__("subl %2,%0\n\t" + "sbbl %3,%1" + :"=a" (endlow), "=d" (endhigh) + :"g" (startlow), "g" (starthigh), + "0" (endlow), "1" (endhigh)); + + /* Error: ECPUTOOFAST */ + if (endhigh) + goto bad_ctc; + + /* Error: ECPUTOOSLOW */ + if (endlow <= CALIBRATE_TIME) + goto bad_ctc; + + __asm__("divl %2" + :"=a" (endlow), "=d" (endhigh) + :"r" (endlow), "0" (0), "1" (CALIBRATE_TIME)); + + return endlow; + } - /* Set the Gate high, disable speaker */ - "inb $0x61, %%al\n\t" /* Read port */ - "andb $0xfd, %%al\n\t" /* Turn off speaker Data */ - "orb $0x01, %%al\n\t" /* Set Gate high */ - "outb %%al, $0x61\n\t" /* Write port */ - - /* Now let's take care of CTC channel 2 */ - "movb $0xb0, %%al\n\t" /* binary, mode 0, LSB/MSB, ch 2*/ - "outb %%al, $0x43\n\t" /* Write to CTC command port */ - "movl %1, %%eax\n\t" - "outb %%al, $0x42\n\t" /* LSB of count */ - "shrl $8, %%eax\n\t" - "outb %%al, $0x42\n\t" /* MSB of count */ - - /* Read the TSC; counting has just started */ - "rdtsc\n\t" - /* Move the value for safe-keeping. */ - "movl %%eax, %%ebx\n\t" - "movl %%edx, %%ecx\n\t" - - /* Busy wait. Only 50 ms wasted at boot time. */ - "0: inb $0x61, %%al\n\t" /* Read Speaker Output Port */ - "testb $0x20, %%al\n\t" /* Check CTC channel 2 output (bit 5) */ - "jz 0b\n\t" - - /* And read the TSC. 5 jiffies (50.00077ms) have elapsed. */ - "rdtsc\n\t" - - /* Great. So far so good. Store last TSC reading in - * last_tsc_low (only 32 lsb bits needed) */ - "movl %%eax, last_tsc_low\n\t" - /* And now calculate the difference between the readings. */ - "subl %%ebx, %%eax\n\t" - "sbbl %%ecx, %%edx\n\t" /* 64-bit subtract */ - /* but probably edx = 0 at this point (see below). */ - /* Now we have 5 * (TSC counts per jiffy) in eax. We want - * to calculate TSC->microsecond conversion factor. */ - - /* Note that edx (high 32-bits of difference) will now be - * zero iff CPU clock speed is less than 85 GHz. Moore's - * law says that this is likely to be true for the next - * 12 years or so. You will have to change this code to - * do a real 64-by-64 divide before that time's up. */ - "movl %%eax, %%ecx\n\t" - "xorl %%eax, %%eax\n\t" - "movl %2, %%edx\n\t" - "divl %%ecx\n\t" /* eax= 2^32 / (1 * TSC counts per microsecond) */ - /* Return eax for the use of fast_gettimeoffset */ - "movl %%eax, %0\n\t" - : "=r" (retval) - : "r" (5 * LATCH), "r" (5 * 1000020/HZ) - : /* we clobber: */ "ax", "bx", "cx", "dx", "cc", "memory"); - return retval; + /* + * The CTC wasn't reliable: we got a hit on the very first read, + * or the CPU was so fast/slow that the quotient wouldn't fit in + * 32 bits.. + */ +bad_ctc: + return 0; } __initfunc(void time_init(void)) @@ -655,23 +645,26 @@ dodgy_tsc(); if (boot_cpu_data.x86_capability & X86_FEATURE_TSC) { + unsigned long tsc_quotient = calibrate_tsc(); + if (tsc_quotient) { + fast_gettimeoffset_quotient = tsc_quotient; + use_tsc = 1; #ifndef do_gettimeoffset - do_gettimeoffset = do_fast_gettimeoffset; + do_gettimeoffset = do_fast_gettimeoffset; #endif - do_get_fast_time = do_gettimeofday; - use_tsc = 1; - fast_gettimeoffset_quotient = calibrate_tsc(); - - /* report CPU clock rate in Hz. - * The formula is (10^6 * 2^32) / (2^32 * 1 / (clocks/us)) = - * clock/second. Our precision is about 100 ppm. - */ - { unsigned long eax=0, edx=1000000; - __asm__("divl %2" - :"=a" (cpu_hz), "=d" (edx) - :"r" (fast_gettimeoffset_quotient), - "0" (eax), "1" (edx)); - printk("Detected %ld Hz processor.\n", cpu_hz); + do_get_fast_time = do_gettimeofday; + + /* report CPU clock rate in Hz. + * The formula is (10^6 * 2^32) / (2^32 * 1 / (clocks/us)) = + * clock/second. Our precision is about 100 ppm. + */ + { unsigned long eax=0, edx=1000000; + __asm__("divl %2" + :"=a" (cpu_hz), "=d" (edx) + :"r" (tsc_quotient), + "0" (eax), "1" (edx)); + printk("Detected %ld Hz processor.\n", cpu_hz); + } } } diff -ur --new-file old/linux/arch/i386/kernel/traps.c new/linux/arch/i386/kernel/traps.c --- old/linux/arch/i386/kernel/traps.c Thu Jan 28 20:44:15 1999 +++ new/linux/arch/i386/kernel/traps.c Tue Feb 16 23:20:05 1999 @@ -42,6 +42,8 @@ #include #endif +#include "irq.h" + asmlinkage int system_call(void); asmlinkage void lcall7(void); @@ -125,7 +127,6 @@ unsigned long esp; unsigned short ss; unsigned long *stack, addr, module_start, module_end; - extern char _stext, _etext; esp = (unsigned long) (1+regs); ss = __KERNEL_DS; @@ -669,9 +670,6 @@ #endif void __init trap_init(void) { - /* Initially up all of the IDT to jump to unexpected */ - init_unexpected_irq(); - if (readl(0x0FFFD9) == 'E' + ('I'<<8) + ('S'<<16) + ('A'<<24)) EISA_bus = 1; set_call_gate(&default_ldt,lcall7); @@ -693,7 +691,7 @@ set_trap_gate(15,&spurious_interrupt_bug); set_trap_gate(16,&coprocessor_error); set_trap_gate(17,&alignment_check); - set_system_gate(0x80,&system_call); + set_system_gate(SYSCALL_VECTOR,&system_call); /* set up GDT task & ldt entries */ set_tss_desc(0, &init_task.tss); diff -ur --new-file old/linux/arch/i386/kernel/visws_apic.c new/linux/arch/i386/kernel/visws_apic.c --- old/linux/arch/i386/kernel/visws_apic.c Wed Jan 20 19:18:53 1999 +++ new/linux/arch/i386/kernel/visws_apic.c Fri May 7 01:12:23 1999 @@ -201,11 +201,13 @@ { unsigned int status; /* XXX APIC EOI? */ - status = desc->status & ~IRQ_REPLAY; + status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING); action = NULL; - if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) + if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) { action = desc->action; - desc->status = status | IRQ_INPROGRESS; + status |= IRQ_INPROGRESS; + } + desc->status = status; } spin_unlock(&irq_controller_lock); diff -ur --new-file old/linux/arch/i386/lib/semaphore.S new/linux/arch/i386/lib/semaphore.S --- old/linux/arch/i386/lib/semaphore.S Wed Oct 15 03:24:09 1997 +++ new/linux/arch/i386/lib/semaphore.S Wed Feb 17 18:34:13 1999 @@ -31,6 +31,15 @@ popl %edx /* restore %edx */ ret +/* Don't save/restore %eax, because that will be our return value */ +ENTRY(__down_failed_trylock) + pushl %edx /* save %edx */ + pushl %ecx /* save %ecx (and argument) */ + call SYMBOL_NAME(__down_trylock) + popl %ecx /* restore %ecx (count on __down_trylock not changing it) */ + popl %edx /* restore %edx */ + ret + ENTRY(__up_wakeup) pushl %eax /* save %eax */ pushl %edx /* save %edx */ diff -ur --new-file old/linux/arch/m68k/Makefile new/linux/arch/m68k/Makefile --- old/linux/arch/m68k/Makefile Tue Jan 19 19:58:26 1999 +++ new/linux/arch/m68k/Makefile Tue May 11 18:57:14 1999 @@ -56,6 +56,11 @@ CORE_FILES := arch/m68k/kernel/kernel.o arch/m68k/mm/mm.o $(CORE_FILES) LIBS += arch/m68k/lib/lib.a +ifdef CONFIG_Q40 +CORE_FILES := $(CORE_FILES) arch/m68k/q40/q40.o +SUBDIRS := $(SUBDIRS) arch/m68k/q40 +endif + ifdef CONFIG_AMIGA CORE_FILES := $(CORE_FILES) arch/m68k/amiga/amiga.o SUBDIRS := $(SUBDIRS) arch/m68k/amiga @@ -81,6 +86,11 @@ SUBDIRS := $(SUBDIRS) arch/m68k/apollo endif +ifdef CONFIG_MVME147 +CORE_FILES := $(CORE_FILES) arch/m68k/mvme147/mvme147.o +SUBDIRS := $(SUBDIRS) arch/m68k/mvme147 +endif + ifdef CONFIG_MVME16x CORE_FILES := $(CORE_FILES) arch/m68k/mvme16x/mvme16x.o SUBDIRS := $(SUBDIRS) arch/m68k/mvme16x @@ -89,6 +99,11 @@ ifdef CONFIG_BVME6000 CORE_FILES := $(CORE_FILES) arch/m68k/bvme6000/bvme6000.o SUBDIRS := $(SUBDIRS) arch/m68k/bvme6000 +endif + +ifdef CONFIG_SUN3X +CORE_FILES := $(CORE_FILES) arch/m68k/sun3x/sun3x.o +SUBDIRS := $(SUBDIRS) arch/m68k/sun3x endif ifdef CONFIG_M68040 diff -ur --new-file old/linux/arch/m68k/atari/atakeyb.c new/linux/arch/m68k/atari/atakeyb.c --- old/linux/arch/m68k/atari/atakeyb.c Tue Jan 19 19:58:26 1999 +++ new/linux/arch/m68k/atari/atakeyb.c Mon Apr 26 22:35:34 1999 @@ -291,7 +291,7 @@ atakeyb_rep_timer.prev = atakeyb_rep_timer.next = NULL; add_timer( &atakeyb_rep_timer ); - handle_scancode(rep_scancode); + handle_scancode(rep_scancode, 1); } atari_enable_irq( IRQ_MFP_ACIA ); @@ -448,7 +448,7 @@ add_timer( &atakeyb_rep_timer ); } - handle_scancode(break_flag | scancode); + handle_scancode(scancode, !break_flag); break; } break; diff -ur --new-file old/linux/arch/m68k/bvme6000/config.c new/linux/arch/m68k/bvme6000/config.c --- old/linux/arch/m68k/bvme6000/config.c Thu Dec 17 18:06:29 1998 +++ new/linux/arch/m68k/bvme6000/config.c Tue May 11 18:57:14 1999 @@ -417,10 +417,10 @@ static void scc_delay (void) { int n; - char i; + volatile int trash; for (n = 0; n < 20; n++) - i = *(volatile char *)0; + trash = n; } static void scc_write (char ch) diff -ur --new-file old/linux/arch/m68k/config.in new/linux/arch/m68k/config.in --- old/linux/arch/m68k/config.in Tue Jan 19 19:58:26 1999 +++ new/linux/arch/m68k/config.in Tue May 11 18:57:14 1999 @@ -37,6 +37,7 @@ bool 'Apollo support' CONFIG_APOLLO bool 'VME (Motorola and BVM) support' CONFIG_VME if [ "$CONFIG_VME" = "y" ]; then + bool 'MVME147 support' CONFIG_MVME147 bool 'MVME162, 166 and 167 support' CONFIG_MVME16x bool 'BVME4000 and BVME6000 support' CONFIG_BVME6000 fi @@ -44,10 +45,13 @@ if [ "$CONFIG_HP300" = "y" ]; then bool 'DIO bus support' CONFIG_DIO fi +bool 'Sun3x support' CONFIG_SUN3X + define_bool CONFIG_SUN3 n if [ "$CONFIG_PCI" = "y" ]; then bool 'Backward-compatible /proc/pci' CONFIG_PCI_OLD_PROC fi +bool 'Q40/Q60 support' CONFIG_Q40 comment 'Processor type' bool '68020 support' CONFIG_M68020 @@ -94,6 +98,29 @@ fi fi bool '/proc/hardware support' CONFIG_PROC_HARDWARE + +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate 'Parallel port support (EXPERIMENTAL, disables old lp driver!)' CONFIG_PARPORT + if [ "$CONFIG_PARPORT" != "n" ]; then + if [ "$CONFIG_AMIGA" != "n" ]; then + dep_tristate ' Amiga builtin port' CONFIG_PARPORT_AMIGA $CONFIG_PARPORT + if [ "$CONFIG_ZORRO" != "n" ]; then + dep_tristate ' Multiface III parallel port' CONFIG_PARPORT_MFC3 $CONFIG_PARPORT + fi + fi + if [ "$CONFIG_Q40" != "n" ]; then + tristate ' Q40 Parallel port' CONFIG_PARPORT + if [ "$CONFIG_PARPORT" != "n" ]; then + define_bool CONFIG_PARPORT_PC y + fi + fi + fi + if [ "$CONFIG_ATARI" == "y" ]; then + dep_tristate ' Atari builtin port' CONFIG_PARPORT_ATARI $CONFIG_PARPORT + fi +fi + + endmenu source drivers/block/Config.in @@ -147,6 +174,7 @@ bool 'A4091 SCSI support' CONFIG_A4091_SCSI bool 'WarpEngine SCSI support' CONFIG_WARPENGINE_SCSI bool 'Blizzard PowerUP 603e+ SCSI' CONFIG_BLZ603EPLUS_SCSI + dep_tristate 'BSC Oktagon SCSI support' CONFIG_OKTAGON_SCSI $CONFIG_SCSI bool 'Cyberstorm Mk III SCSI support' CONFIG_CYBERSTORMIII_SCSI # bool 'GVP Turbo 040/060 SCSI support' CONFIG_GVP_TURBO_SCSI fi @@ -167,6 +195,10 @@ fi #dep_tristate 'SCSI debugging host adapter' CONFIG_SCSI_DEBUG $CONFIG_SCSI +if [ "$CONFIG_VME" = "y" -a "$CONFIG_MVME147" = "y" ]; then + bool 'WD33C93 SCSI driver for MVME147' CONFIG_MVME147_SCSI +fi + if [ "$CONFIG_VME" = "y" -a "$CONFIG_MVME16x" = "y" ]; then bool 'NCR53C710 SCSI driver for MVME16x' CONFIG_MVME16x_SCSI fi @@ -175,6 +207,10 @@ bool 'NCR53C710 SCSI driver for BVME6000' CONFIG_BVME6000_SCSI fi +if [ "$CONFIG_SUN3X" = "y" ]; then + bool 'ESP SCSI driver' CONFIG_SUN3X_ESP +fi + endmenu fi @@ -219,6 +255,9 @@ # bool 'Macintosh (AV) onboard MACE ethernet' CONFIG_MACMACE bool 'Macintosh (Quadra) onboard SONIC ethernet' CONFIG_MACSONIC fi +if [ "$CONFIG_VME" = "y" -a "$CONFIG_MVME147" = "y" ]; then + tristate 'MVME147 (Lance) Ethernet support' CONFIG_MVME147_NET +fi if [ "$CONFIG_VME" = "y" -a "$CONFIG_MVME16x" = "y" ]; then tristate 'MVME16x Ethernet support' CONFIG_MVME16x_NET fi @@ -232,9 +271,17 @@ tristate 'PAMsNet support' CONFIG_ATARI_PAMSNET fi fi +if [ "$CONFIG_SUN3X" = "y" ]; then + bool 'Sun3x Lance support' CONFIG_SUNLANCE +fi if [ "$CONFIG_HP300" = "y" ]; then bool 'HP on-board LANCE support' CONFIG_HPLANCE fi +if [ "$CONFIG_Q40" = "y" ]; then + if [ ! "$CONFIG_PARPORT" = "n" ]; then + dep_tristate 'PLIP (parallel port) support' CONFIG_PLIP $CONFIG_PARPORT + fi +fi fi endmenu @@ -243,6 +290,23 @@ mainmenu_option next_comment comment 'Character devices' +if [ "$CONFIG_Q40" = "y" ]; then + tristate 'Q40 Standard/generic serial support' CONFIG_SERIAL +fi + +if [ "$CONFIG_SERIAL" = "y" ]; then + bool ' Support for console on serial port' CONFIG_SERIAL_CONSOLE + bool 'Extended dumb serial driver options' CONFIG_SERIAL_EXTENDED +fi + +if [ "$CONFIG_SERIAL_EXTENDED" = "y" ]; then + bool ' Support more than 4 serial ports' CONFIG_SERIAL_MANY_PORTS + bool ' Support for sharing serial interrupts' CONFIG_SERIAL_SHARE_IRQ +# bool ' Autodetect IRQ - do not yet enable !!' CONFIG_SERIAL_DETECT_IRQ + bool ' Support special multiport boards' CONFIG_SERIAL_MULTIPORT + bool ' Support the Bell Technologies HUB6 card' CONFIG_HUB6 +fi + if [ "$CONFIG_VME" = "n" ]; then define_bool CONFIG_VT y if [ "$CONFIG_VT" = "y" ]; then @@ -254,10 +318,17 @@ define_bool CONFIG_NVRAM y fi -tristate 'Parallel printer support' CONFIG_M68K_PRINTER -if [ "$CONFIG_ZORRO" = "y" ]; then - dep_tristate 'Multiface Card III parallel support' CONFIG_MULTIFACE_III_LP $CONFIG_M68K_PRINTER -fi +if [ "$CONFIG_PARPORT" = "n" ]; then + tristate 'Parallel printer support' CONFIG_M68K_PRINTER + if [ "$CONFIG_ZORRO" = "y" ]; then + dep_tristate 'Multiface Card III parallel support' CONFIG_MULTIFACE_III_LP $CONFIG_M68K_PRINTER + fi +else + dep_tristate 'Parallel printer support' CONFIG_PRINTER $CONFIG_PARPORT + if [ "$CONFIG_PRINTER" != "n" ]; then + bool ' Support IEEE1284 status readback' CONFIG_PRINTER_READBACK + fi +fi if [ "$CONFIG_AMIGA" = "y" ]; then tristate 'Amiga mouse support' CONFIG_AMIGAMOUSE fi @@ -280,13 +351,17 @@ fi if [ "$CONFIG_AMIGA" = "y" ]; then tristate 'Amiga builtin serial support' CONFIG_AMIGA_BUILTIN_SERIAL - bool 'Hisoft Whippet PCMCIA serial support' CONFIG_WHIPPET + if [ "$CONFIG_AMIGA_PCMCIA" = "y" ]; then + tristate 'Hisoft Whippet PCMCIA serial support' CONFIG_WHIPPET_SERIAL + fi fi -if [ "$CONFIG_ZORRO" = "y" ]; then - tristate 'GVP IO-Extender support' CONFIG_GVPIOEXT - dep_tristate 'GVP IO-Extender parallel printer support' CONFIG_GVPIOEXT_LP $CONFIG_GVPIOEXT - dep_tristate 'GVP IO-Extender PLIP support' CONFIG_GVPIOEXT_PLIP $CONFIG_GVPIOEXT - tristate 'Multiface Card III serial support' CONFIG_MULTIFACE_III_TTY +if [ "$CONFIG_PARPORT" = "n" ]; then + if [ "$CONFIG_ZORRO" = "y" ]; then + tristate 'GVP IO-Extender support' CONFIG_GVPIOEXT + dep_tristate 'GVP IO-Extender parallel printer support' CONFIG_GVPIOEXT_LP $CONFIG_GVPIOEXT + dep_tristate 'GVP IO-Extender PLIP support' CONFIG_GVPIOEXT_PLIP $CONFIG_GVPIOEXT + tristate 'Multiface Card III serial support' CONFIG_MULTIFACE_III_TTY + fi fi if [ "$CONFIG_MAC" = "y" ]; then bool 'Mac SCC serial support' CONFIG_MAC_SCC @@ -294,18 +369,32 @@ if [ "$CONFIG_HP300" = "y" -a "$CONFIG_DIO" = "y" ]; then tristate 'HP DCA serial support' CONFIG_HPDCA fi +if [ "$CONFIG_SUN3X" = "y" ]; then + bool 'Sun3x builtin serial support' CONFIG_SUN3X_ZS + if [ "$CONFIG_SUN3X_ZS" = "y" ]; then + bool 'Sun keyboard support' CONFIG_SUN_KEYBOARD + bool 'Sun mouse support' CONFIG_SUN_MOUSE + define_bool CONFIG_SBUS y + define_bool CONFIG_SBUSCHAR y + define_bool CONFIG_SUN_SERIAL y + fi +fi if [ "$CONFIG_AMIGA" = "y" -o "$CONFIG_ATARI" = "y" -o \ - "$CONFIG_MAC" = "y" -o "$CONFIG_HP300" = "y" ]; then + "$CONFIG_MAC" = "y" -o "$CONFIG_HP300" = "y" -o \ + "$CONFIG_SUN3X" = "y" ]; then if [ "$CONFIG_ATARI_MFPSER" = "y" -o "$CONFIG_ATARI_SCC" = "y" -o \ "$CONFIG_ATARI_MIDI" = "y" -o "$CONFIG_MAC_SCC" = "y" -o \ "$CONFIG_AMIGA_BUILTIN_SERIAL" = "y" -o \ "$CONFIG_GVPIOEXT" = "y" -o "$CONFIG_MULTIFACE_III_TTY" = "y" -o \ - "$CONFIG_HPDCA" = "y" ]; then + "$CONFIG_HPDCA" = "y" -o "$CONFIG_SUN3X_ZS" = "y" ]; then bool 'Support for serial port console' CONFIG_SERIAL_CONSOLE fi fi if [ "$CONFIG_VME" = "y" ]; then define_bool CONFIG_SERIAL_CONSOLE y + if [ "$CONFIG_MVME147" = "y" ]; then + bool 'SCC support for MVME147 serial ports' CONFIG_MVME147_SCC + fi if [ "$CONFIG_MVME16x" = "y" ]; then bool 'CD2401 support for MVME166/7 serial ports' CONFIG_SERIAL167 bool 'SCC support for MVME162 serial ports' CONFIG_MVME162_SCC @@ -346,13 +435,13 @@ source fs/Config.in if [ "$CONFIG_VME" = "n" ]; then + mainmenu_option next_comment + comment 'Console drivers' if [ "$CONFIG_HP300" = "y" ]; then bool 'Frame buffer support' CONFIG_FB else define_bool CONFIG_FB y fi - mainmenu_option next_comment - comment 'Console drivers' source drivers/video/Config.in endmenu fi diff -ur --new-file old/linux/arch/m68k/defconfig new/linux/arch/m68k/defconfig --- old/linux/arch/m68k/defconfig Tue Jan 19 19:58:26 1999 +++ new/linux/arch/m68k/defconfig Thu Feb 25 19:46:46 1999 @@ -78,7 +78,6 @@ CONFIG_PACKET=y # CONFIG_NETLINK is not set # CONFIG_FIREWALL is not set -# CONFIG_NET_ALIAS is not set # CONFIG_FILTER is not set CONFIG_UNIX=y CONFIG_INET=y diff -ur --new-file old/linux/arch/m68k/hp300/hil.c new/linux/arch/m68k/hp300/hil.c --- old/linux/arch/m68k/hp300/hil.c Wed Sep 2 18:39:18 1998 +++ new/linux/arch/m68k/hp300/hil.c Mon Apr 26 22:37:14 1999 @@ -223,12 +223,13 @@ { case 0x40: { - unsigned char scode = (poll.data[1] >> 1) | ((poll.data[1] & 1)?0x80:0); + int down = (poll.data[1] & 1) == 0; + unsigned char scode = poll.data[1] >> 1; #if 0 - if (scode & 0x80) - printk("[%02x]", scode & 0x7f); + if (down) + printk("[%02x]", scode); #endif - handle_scancode(scode); + handle_scancode(scode, down); } break; } diff -ur --new-file old/linux/arch/m68k/kernel/entry.S new/linux/arch/m68k/kernel/entry.S --- old/linux/arch/m68k/kernel/entry.S Tue Jan 19 19:58:26 1999 +++ new/linux/arch/m68k/kernel/entry.S Tue May 11 18:57:14 1999 @@ -164,8 +164,17 @@ movel %sp,%sp@- movel %d0,%sp@- | put vector # on stack +#if defined(MACH_Q40_ONLY) && defined(CONFIG_BLK_DEV_FD) + btstb #4,0xff000000 | Q40 floppy needs very special treatment ... + jbeq 1f + btstb #3,0xff000004 + jbeq 1f + jbsr SYMBOL_NAME(floppy_hardint) + jbra 3f +1: +#endif jbsr SYMBOL_NAME(process_int)| process the IRQ - addql #8,%sp | pop parameters off stack +3: addql #8,%sp | pop parameters off stack SYMBOL_NAME_LABEL(ret_from_interrupt) subql #1,SYMBOL_NAME(local_irq_count) @@ -295,6 +304,8 @@ 2: fmovemx %fp0-%fp7,%a0@(TASK_TSS+TSS_FPREG) fmoveml %fpcr/%fpsr/%fpiar,%a0@(TASK_TSS+TSS_FPCNTL) 3: + /* Return previous task in %d1 */ + movel %curptr,%d1 /* switch to new task (a1 contains new task) */ movel %a1,%curptr @@ -320,7 +331,14 @@ movec %d0,%cacr /* switch the root pointer */ +#ifdef CPU_M68030_ONLY + .chip 68030 + pmovefd %a1@(TASK_TSS+TSS_CRP),%crp + .chip 68k + pflush #0,#4 +#else pmove %a1@(TASK_TSS+TSS_CRP),%crp +#endif #endif #if defined(CPU_M68020_OR_M68030) && defined(CPU_M68040_OR_M68060) diff -ur --new-file old/linux/arch/m68k/kernel/head.S new/linux/arch/m68k/kernel/head.S --- old/linux/arch/m68k/kernel/head.S Tue Jan 19 19:58:26 1999 +++ new/linux/arch/m68k/kernel/head.S Tue May 11 18:57:14 1999 @@ -23,6 +23,7 @@ ** 98/04/25 Phil Blundell: added HP300 support ** 1998/08/30 David Kilzer: Added support for fbcon_font_desc structures ** for linux-2.1.115 +** 9/02/11 Richard Zidlicky: added Q40 support (initial vesion 99/01/01) ** ** This file is subject to the terms and conditions of the GNU General Public ** License. See the file README.legal in the main directory of this archive @@ -303,6 +304,12 @@ .globl SYMBOL_NAME(availmem) .globl SYMBOL_NAME(m68k_pgtable_cachemode) .globl SYMBOL_NAME(m68k_supervisor_cachemode) +#ifdef CONFIG_MVME16x +.globl SYMBOL_NAME(mvme_bdid_ptr) +#endif +#ifdef CONFIG_Q40 +.globl SYMBOL_NAME(q40_mem_cptr) +#endif CPUTYPE_040 = 1 /* indicates an 040 */ CPUTYPE_060 = 2 /* indicates an 060 */ @@ -512,13 +519,15 @@ #endif .endm - #define is_not_amiga(lab) cmpl &MACH_AMIGA,%pc@(m68k_machtype); jne lab #define is_not_atari(lab) cmpl &MACH_ATARI,%pc@(m68k_machtype); jne lab #define is_not_mac(lab) cmpl &MACH_MAC,%pc@(m68k_machtype); jne lab +#define is_not_mvme147(lab) cmpl &MACH_MVME147,%pc@(m68k_machtype); jne lab #define is_not_mvme16x(lab) cmpl &MACH_MVME16x,%pc@(m68k_machtype); jne lab #define is_not_bvme6000(lab) cmpl &MACH_BVME6000,%pc@(m68k_machtype); jne lab #define is_not_hp300(lab) cmpl &MACH_HP300,%pc@(m68k_machtype); jne lab +#define is_not_q40(lab) cmpl &MACH_Q40,%pc@(m68k_machtype); jne lab +#define is_not_sun3x(lab) cmpl &MACH_SUN3X,%pc@(m68k_machtype); jne lab #define is_040_or_060(lab) btst &CPUTYPE_0460,%pc@(L(cputype)+3); jne lab #define is_not_040_or_060(lab) btst &CPUTYPE_0460,%pc@(L(cputype)+3); jeq lab @@ -552,9 +561,11 @@ .long BOOTINFOV_MAGIC .long MACH_AMIGA, AMIGA_BOOTI_VERSION .long MACH_ATARI, ATARI_BOOTI_VERSION + .long MACH_MVME147, MVME147_BOOTI_VERSION .long MACH_MVME16x, MVME16x_BOOTI_VERSION .long MACH_BVME6000, BVME6000_BOOTI_VERSION .long MACH_MAC, MAC_BOOTI_VERSION + .long MACH_Q40, Q40_BOOTI_VERSION .long 0 1: jra SYMBOL_NAME(__start) @@ -859,7 +870,12 @@ /* * 040: Map the 16Meg range physical 0x0 upto logical 0x8000.0000 */ - mmu_map #0x80000000,#0,#0x01000000,#_PAGE_NOCACHE_S + mmu_map #0x80000000,#0,#0x01000000,#_PAGE_NOCACHE_S + /* + * Map the Zorro III I/O space with transparent translation + * for frame buffer memory etc. + */ + mmu_map_tt #1,#0x40000000,#0x20000000,#_PAGE_NOCACHE_S jbra L(mmu_init_done) @@ -867,7 +883,8 @@ /* * 030: Map the 32Meg range physical 0x0 upto logical 0x8000.0000 */ - mmu_map #0x80000000,#0,#0x02000000,#_PAGE_NOCACHE030 + mmu_map #0x80000000,#0,#0x02000000,#_PAGE_NOCACHE030 + mmu_map_tt #1,#0x40000000,#0x20000000,#_PAGE_NOCACHE030 jbra L(mmu_init_done) @@ -926,6 +943,25 @@ L(mmu_init_not_atari): #endif +#ifdef CONFIG_Q40 + is_not_q40(L(notq40)) + /* + * add transparent mapping for 0xff00 0000 - 0xffff ffff + * non-cached serialized etc.. + * this includes master chip, DAC, RTC and ISA ports + * 0xfe000000-0xfeffffff is for screen and ROM + */ + + putc 'Q' + + mmu_map_tt #0,#0xfe000000,#0x01000000,#_PAGE_CACHE040W + mmu_map_tt #1,#0xff000000,#0x01000000,#_PAGE_NOCACHE_S + + jbra L(mmu_init_done) + +L(notq40): +#endif + #ifdef CONFIG_HP300 is_not_hp300(L(nothp300)) @@ -940,6 +976,24 @@ #endif +#ifdef CONFIG_MVME147 + + is_not_mvme147(L(not147)) + + /* + * On MVME147 we have already created kernel page tables for + * 4MB of RAM at address 0, so now need to do a transparent + * mapping of the top of memory space. Make it 0.5GByte for now, + * so we can access on-board i/o areas. + */ + + mmu_map_tt #1,#0xe0000000,#0x20000000,#_PAGE_NOCACHE030 + + jbra L(mmu_init_done) + +L(not147): +#endif /* CONFIG_MVME147 */ + #ifdef CONFIG_MVME16x is_not_mvme16x(L(not16x)) @@ -965,7 +1019,7 @@ * 0xffe00000->0xffe1ffff. */ - mmu_map_tt 1,#0xe0000000,#0x20000000,#_PAGE_NOCACHE_S + mmu_map_tt #1,#0xe0000000,#0x20000000,#_PAGE_NOCACHE_S jbra L(mmu_init_done) @@ -985,7 +1039,7 @@ * clash with User code virtual address space. */ - mmu_map_tt 1,#0xe0000000,#0x20000000,#_PAGE_NOCACHE_S + mmu_map_tt #1,#0xe0000000,#0x20000000,#_PAGE_NOCACHE_S jbra L(mmu_init_done) @@ -1052,13 +1106,23 @@ mmu_map_eq #0x50000000,#0x02000000,%d3 mmu_map_eq #0x60000000,#0x00400000,%d3 mmu_map_eq #0x9c000000,#0x00400000,%d3 - mmu_map_tt 1,#0xf8000000,#0x08000000,%d3 + mmu_map_tt #1,#0xf8000000,#0x08000000,%d3 jbra L(mmu_init_done) L(mmu_init_not_mac): #endif +#ifdef CONFIG_SUN3X + is_not_sun3x(L(notsun3x)) + + /* setup tt1 for I/O */ + mmu_map_tt #1,#0x40000000,#0x40000000,#_PAGE_NOCACHE_S + +L(notsun3x): + jbra L(mmu_init_done) +#endif + L(mmu_init_done): putc 'G' @@ -1214,6 +1278,14 @@ 1: #endif +#ifdef CONFIG_SUN3X + is_not_sun3x(1f) + + /* enable copro */ + oriw #0x4000,0x61000000 +1: +#endif + /* * Fixup the addresses for the kernel pointer table and availmem. * Convert them from physical addresses to virtual addresses. @@ -1780,7 +1852,7 @@ /* Extract the highest bit set */ bfffo ARG3{#0,#32},%d1 - cmpw #8,%d0 + cmpw #8,%d1 jcc L(do_map) /* And get the mask @@ -2155,7 +2227,9 @@ /* Temporary allocate a page table and insert it into the ptr table */ movel %a1@,%d0 - addl #PTR_TABLE_SIZE*4,%a1@ + /* The 512 should be PAGE_TABLE_SIZE*4, but that violates the + alignment restriction for pointer tables on the '0[46]0. */ + addl #512,%a1@ orw #_PAGE_TABLE+_PAGE_ACCESSED,%d0 movel %d0,%a0@ dputs " (new)" @@ -2703,6 +2777,31 @@ L(serial_init_not_mac): #endif /* CONFIG_MAC */ +#ifdef CONFIG_Q40 + is_not_q40(2f) +/* debug output goes into SRAM, so we don't do it unless requested + - check for '%LX$' signature in SRAM */ + lea %pc@(SYMBOL_NAME(q40_mem_cptr)),%a1 + move.l #0xff020010,%a1@ /* must be inited - also used by debug=mem */ + move.l #0xff020000,%a1 + cmp.b #'%',%a1@ + bne 2f /*nodbg*/ + addq.w #4,%a1 + cmp.b #'L',%a1@ + bne 2f /*nodbg*/ + addq.w #4,%a1 + cmp.b #'X',%a1@ + bne 2f /*nodbg*/ + addq.w #4,%a1 + cmp.b #'$',%a1@ + bne 2f /*nodbg*/ + /* signature OK */ + lea %pc@(L(q40_do_debug)),%a1 + tas %a1@ +/*nodbg: q40_do_debug is 0 by default*/ +2: +#endif + L(serial_init_done): func_return serial_init @@ -2792,6 +2891,15 @@ 4: #endif /* CONFIG_ATARI */ +#ifdef CONFIG_MVME147 + is_not_mvme147(2f) +1: btst #2,M147_SCC_CTRL_A + jeq 1b + moveb %d0,M147_SCC_DATA_A + jbra L(serial_putc_done) +2: +#endif + #ifdef CONFIG_MVME16x is_not_mvme16x(2f) /* @@ -2805,7 +2913,7 @@ moveml %sp@+,%d0-%d7/%a2-%a6 jbra L(serial_putc_done) 2: -#endif CONFIG_MVME162 | CONFIG_MVME167 +#endif CONFIG_MVME16x #ifdef CONFIG_BVME6000 is_not_bvme6000(2f) @@ -2819,6 +2927,18 @@ 2: #endif +#ifdef CONFIG_Q40 + is_not_q40(2f) + tst.l %pc@(L(q40_do_debug)) /* only debug if requested */ + beq 2f + lea %pc@(SYMBOL_NAME(q40_mem_cptr)),%a1 + move.l %a1@,%a0 + move.b %d0,%a0@ + addq.l #4,%a0 + move.l %a0,%a1@ +2: +#endif + L(serial_putc_done): func_return serial_putc @@ -3472,6 +3592,10 @@ L(temp_mmap_mem): .long 0 +#if defined (CONFIG_MVME147) +M147_SCC_CTRL_A = 0xfffe3002 +M147_SCC_DATA_A = 0xfffe3003 +#endif #if defined (CONFIG_BVME6000) BVME_SCC_CTRL_A = 0xffb0000b @@ -3508,4 +3632,10 @@ #if defined(CONFIG_MVME16x) SYMBOL_NAME_LABEL(mvme_bdid_ptr) .long 0 +#endif +#if defined(CONFIG_Q40) +SYMBOL_NAME_LABEL(q40_mem_cptr) + .long 0 +L(q40_do_debug): + .long 0 #endif diff -ur --new-file old/linux/arch/m68k/kernel/ints.c new/linux/arch/m68k/kernel/ints.c --- old/linux/arch/m68k/kernel/ints.c Sat Jun 13 22:14:32 1998 +++ new/linux/arch/m68k/kernel/ints.c Wed May 12 17:50:08 1999 @@ -25,6 +25,7 @@ * which must be served /Roman Zippel */ +#include #include #include #include @@ -38,6 +39,10 @@ #include #include +#ifdef CONFIG_Q40 +#include +#endif + /* table for system interrupt handlers */ static irq_handler_t irq_list[SYS_IRQS]; @@ -177,14 +182,24 @@ /* * Do we need these probe functions on the m68k? + * + * ... may be usefull with ISA devices */ unsigned long probe_irq_on (void) { +#ifdef CONFIG_Q40 + if (MACH_IS_Q40) + return q40_probe_irq_on(); +#endif return 0; } int probe_irq_off (unsigned long irqs) { +#ifdef CONFIG_Q40 + if (MACH_IS_Q40) + return q40_probe_irq_off(irqs); +#endif return 0; } diff -ur --new-file old/linux/arch/m68k/kernel/m68k_defs.h new/linux/arch/m68k/kernel/m68k_defs.h --- old/linux/arch/m68k/kernel/m68k_defs.h Tue Jan 5 20:20:43 1999 +++ new/linux/arch/m68k/kernel/m68k_defs.h Tue May 11 18:57:14 1999 @@ -3,6 +3,47 @@ */ #define TS_MAGICKEY 0x5a5a5a5a -#define TS_TSS 482 -#define TS_ESP0 502 -#define TS_FPU 506 +#define TASK_STATE 0 +#define TASK_FLAGS 4 +#define TASK_SIGPENDING 8 +#define TASK_NEEDRESCHED 20 +#define TASK_TSS 470 +#define TASK_MM 622 +#define TSS_KSP 0 +#define TSS_USP 4 +#define TSS_SR 8 +#define TSS_FS 10 +#define TSS_CRP 12 +#define TSS_ESP0 20 +#define TSS_FPREG 24 +#define TSS_FPCNTL 120 +#define TSS_FPSTATE 132 +#define PT_D0 32 +#define PT_ORIG_D0 36 +#define PT_SR 44 +#define PT_VECTOR 50 +#define IRQ_HANDLER 0 +#define IRQ_DEVID 8 +#define IRQ_NEXT 16 +#define STAT_IRQ 120 +#define BIR_TAG 0 +#define BIR_SIZE 2 +#define BIR_DATA 4 +#define FBCON_FONT_DESC_IDX 0 +#define FBCON_FONT_DESC_NAME 4 +#define FBCON_FONT_DESC_WIDTH 8 +#define FBCON_FONT_DESC_HEIGHT 12 +#define FBCON_FONT_DESC_DATA 16 +#define FBCON_FONT_DESC_PREF 20 +#define CUSTOMBASE -2132807680 +#define C_INTENAR 28 +#define C_INTREQR 30 +#define C_INTENA 154 +#define C_INTREQ 156 +#define C_SERDATR 24 +#define C_SERDAT 48 +#define C_SERPER 50 +#define CIAABASE -2134908927 +#define CIABBASE -2134913024 +#define C_PRA 0 +#define ZTWOBASE -2147483648 diff -ur --new-file old/linux/arch/m68k/kernel/m68k_ksyms.c new/linux/arch/m68k/kernel/m68k_ksyms.c --- old/linux/arch/m68k/kernel/m68k_ksyms.c Tue Jan 19 19:58:34 1999 +++ new/linux/arch/m68k/kernel/m68k_ksyms.c Tue May 11 18:57:14 1999 @@ -18,6 +18,7 @@ #include #include #include +#include asmlinkage long long __ashrdi3 (long long, int); extern char m68k_debug_device[]; @@ -54,6 +55,8 @@ EXPORT_SYMBOL(disable_irq); EXPORT_SYMBOL(kernel_set_cachemode); EXPORT_SYMBOL(kernel_thread); +EXPORT_SYMBOL(register_serial); +EXPORT_SYMBOL(unregister_serial); /* Networking helper routines. */ EXPORT_SYMBOL(csum_partial_copy); @@ -69,4 +72,5 @@ EXPORT_SYMBOL_NOVERS(__down_failed); EXPORT_SYMBOL_NOVERS(__down_failed_interruptible); +EXPORT_SYMBOL_NOVERS(__down_failed_trylock); EXPORT_SYMBOL_NOVERS(__up_wakeup); diff -ur --new-file old/linux/arch/m68k/kernel/process.c new/linux/arch/m68k/kernel/process.c --- old/linux/arch/m68k/kernel/process.c Tue Jan 19 19:58:34 1999 +++ new/linux/arch/m68k/kernel/process.c Tue May 11 18:57:14 1999 @@ -169,15 +169,7 @@ asmlinkage int m68k_vfork(struct pt_regs *regs) { - int child; - struct semaphore sem = MUTEX_LOCKED; - - child = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs); - - if (child > 0) - down(&sem); - - return child; + return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs); } asmlinkage int m68k_clone(struct pt_regs *regs) @@ -190,7 +182,7 @@ newsp = regs->d2; if (!newsp) newsp = rdusp(); - return do_fork(clone_flags & ~CLONE_VFORK, newsp, regs); + return do_fork(clone_flags, newsp, regs); } int copy_thread(int nr, unsigned long clone_flags, unsigned long usp, diff -ur --new-file old/linux/arch/m68k/kernel/ptrace.c new/linux/arch/m68k/kernel/ptrace.c --- old/linux/arch/m68k/kernel/ptrace.c Tue Jan 19 19:58:34 1999 +++ new/linux/arch/m68k/kernel/ptrace.c Tue May 11 18:57:14 1999 @@ -312,6 +312,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) { struct task_struct *child; + unsigned long flags; int ret; lock_kernel(); @@ -343,21 +344,22 @@ (current->uid != child->uid) || (current->gid != child->egid) || (current->gid != child->sgid) || + (!cap_issubset(child->cap_permitted, current->cap_permitted)) || (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE)) goto out; /* the same process cannot be attached many times */ if (child->flags & PF_PTRACED) goto out; child->flags |= PF_PTRACED; - if (child->p_pptr != current) { - unsigned long flags; - write_lock_irqsave(&tasklist_lock, flags); + 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); } + write_unlock_irqrestore(&tasklist_lock, flags); + send_sig(SIGSTOP, child, 1); ret = 0; goto out; @@ -502,7 +504,6 @@ } case PTRACE_DETACH: { /* detach a process that was attached. */ - unsigned long flags; long tmp; ret = -EIO; diff -ur --new-file old/linux/arch/m68k/kernel/setup.c new/linux/arch/m68k/kernel/setup.c --- old/linux/arch/m68k/kernel/setup.c Tue Jan 19 19:58:34 1999 +++ new/linux/arch/m68k/kernel/setup.c Tue May 11 18:57:14 1999 @@ -77,10 +77,26 @@ int (*mach_set_clock_mmss) (unsigned long) = NULL; void (*mach_reset)( void ); long mach_max_dma_address = 0x00ffffff; /* default set to the lower 16MB */ -#if defined(CONFIG_AMIGA_FLOPPY) || defined(CONFIG_ATARI_FLOPPY) +#if defined(CONFIG_AMIGA_FLOPPY) || defined(CONFIG_ATARI_FLOPPY) || defined(CONFIG_BLK_DEV_FD) void (*mach_floppy_setup) (char *, int *) __initdata = NULL; void (*mach_floppy_eject) (void) = NULL; #endif +struct serial_struct; +#ifdef CONFIG_SERIAL +long serial_rs_init(void); +int serial_register_serial(struct serial_struct *); +void serial_unregister_serial(int); +long ser_console_init(long, long ); +#endif +#if defined(CONFIG_USERIAL)||defined(CONFIG_BVME6000_SCC)||defined(CONFIG_MVME162_SCC)||defined(CONFIG_HPDCA)||defined(CONFIG_WHIPPET_SERIAL)||defined(CONFIG_MULTIFACE_III_TTY)||defined(CONFIG_GVPIOEXT)||defined(CONFIG_AMIGA_BUILTIN_SERIAL)||defined(CONFIG_MAC_SCC)||defined(CONFIG_ATARI_MIDI)||defined(CONFIG_ATARI_SCC)||defined(CONFIG_ATARI_MFPSER) +#define M68K_SERIAL +#endif +#ifdef M68K_SERIAL +long m68k_rs_init(void); +int m68k_register_serial(struct serial_struct *); +void m68k_unregister_serial(int); +long m68k_serial_console_init(long, long ); +#endif #ifdef CONFIG_HEARTBEAT void (*mach_heartbeat) (int) = NULL; #endif @@ -97,15 +113,19 @@ extern int amiga_parse_bootinfo(const struct bi_record *); extern int atari_parse_bootinfo(const struct bi_record *); extern int mac_parse_bootinfo(const struct bi_record *); +extern int q40_parse_bootinfo(const struct bi_record *); extern void config_amiga(void); extern void config_atari(void); extern void config_mac(void); extern void config_sun3(void); extern void config_apollo(void); +extern void config_mvme147(void); extern void config_mvme16x(void); extern void config_bvme6000(void); extern void config_hp300(void); +extern void config_q40(void); +extern void config_sun3x(void); #define MASK_256K 0xfffc0000 @@ -149,6 +169,8 @@ unknown = atari_parse_bootinfo(record); else if (MACH_IS_MAC) unknown = mac_parse_bootinfo(record); + else if (MACH_IS_Q40) + unknown = q40_parse_bootinfo(record); else unknown = 1; } @@ -258,6 +280,11 @@ config_apollo(); break; #endif +#ifdef CONFIG_MVME147 + case MACH_MVME147: + config_mvme147(); + break; +#endif #ifdef CONFIG_MVME16x case MACH_MVME16x: config_mvme16x(); @@ -273,6 +300,16 @@ config_hp300(); break; #endif +#ifdef CONFIG_Q40 + case MACH_Q40: + config_q40(); + break; +#endif +#ifdef CONFIG_SUN3X + case MACH_SUN3X: + config_sun3x(); + break; +#endif default: panic ("No configuration setup"); } @@ -384,7 +421,52 @@ return(len); } -#if defined(CONFIG_AMIGA_FLOPPY) || defined(CONFIG_ATARI_FLOPPY) +#if defined(CONFIG_SERIAL) || defined(M68K_SERIAL) +int rs_init(void) +{ +#ifdef CONFIG_SERIAL + if (MACH_IS_Q40) + return serial_rs_init(); +#endif +#ifdef M68K_SERIAL + return m68k_rs_init(); +#endif +} +int register_serial(struct serial_struct *p) +{ +#ifdef CONFIG_SERIAL + if (MACH_IS_Q40) + return serial_register_serial(p); +#endif +#ifdef M68K_SERIAL + return m68k_register_serial(p); +#endif +} +void unregister_serial(int i) +{ +#ifdef CONFIG_SERIAL + if (MACH_IS_Q40) + serial_unregister_serial(i); +#endif +#ifdef M68K_SERIAL + m68k_unregister_serial(i); +#endif +} +#ifdef CONFIG_SERIAL_CONSOLE +long serial_console_init(long kmem_start, long kmem_end) +{ +#ifdef CONFIG_SERIAL + if (MACH_IS_Q40) + return ser_console_init(kmem_start, kmem_end); +#endif +#if defined(M68K_SERIAL) && defined(CONFIG_SERIAL_CONSOLE) + return m68k_serial_console_init(kmem_start, kmem_end); +#endif +} +#endif +#endif + +#if defined(CONFIG_AMIGA_FLOPPY) || defined(CONFIG_ATARI_FLOPPY) || defined(CONFIG_BLK_DEV_FD) __initfunc(void floppy_setup(char *str, int *ints)) { if (mach_floppy_setup) @@ -399,7 +481,7 @@ #endif /* for "kbd-reset" cmdline param */ -void __init kbd_reset_setup(char *str, int *ints) +__initfunc(void kbd_reset_setup(char *str, int *ints)) { } diff -ur --new-file old/linux/arch/m68k/kernel/time.c new/linux/arch/m68k/kernel/time.c --- old/linux/arch/m68k/kernel/time.c Tue Jan 19 19:58:34 1999 +++ new/linux/arch/m68k/kernel/time.c Tue May 11 18:57:14 1999 @@ -198,8 +198,7 @@ xtime = *tv; time_adjust = 0; /* stop active adjtime() */ time_status |= STA_UNSYNC; - time_state = TIME_ERROR; /* p. 24, (a) */ time_maxerror = NTP_PHASE_LIMIT; time_esterror = NTP_PHASE_LIMIT; - sti(); + write_unlock_irq(&xtime_lock); } diff -ur --new-file old/linux/arch/m68k/lib/semaphore.S new/linux/arch/m68k/lib/semaphore.S --- old/linux/arch/m68k/lib/semaphore.S Sat May 24 18:10:22 1997 +++ new/linux/arch/m68k/lib/semaphore.S Tue May 11 18:57:14 1999 @@ -32,6 +32,16 @@ movel (%sp)+,%a0 rts +ENTRY(__down_failed_trylock) + movel %a0,-(%sp) + movel %d1,-(%sp) + movel %a1,-(%sp) + jbsr SYMBOL_NAME(__down_trylock) + movel (%sp)+,%a1 + movel (%sp)+,%d1 + movel (%sp)+,%a0 + rts + ENTRY(__up_wakeup) moveml %a0/%d0/%d1,-(%sp) movel %a1,-(%sp) diff -ur --new-file old/linux/arch/m68k/mac/mackeyb.c new/linux/arch/m68k/mac/mackeyb.c --- old/linux/arch/m68k/mac/mackeyb.c Tue Jan 19 19:58:34 1999 +++ new/linux/arch/m68k/mac/mackeyb.c Mon Apr 26 22:38:03 1999 @@ -60,7 +60,7 @@ extern struct kbd_struct kbd_table[]; extern void adb_bus_init(void); -extern void handle_scancode(unsigned char); +extern void handle_scancode(unsigned char, int); extern void put_queue(int); /* keyb */ @@ -387,7 +387,7 @@ */ switch (keycode) { case 0x39: - handle_scancode(keycode); /* down */ + handle_scancode(keycode, 1); /* down */ up_flag = 0x80; /* see below ... */ mark_bh(KEYBOARD_BH); break; @@ -397,7 +397,7 @@ } } - handle_scancode(keycode + up_flag); + handle_scancode(keycode, !up_flag); } static void diff -ur --new-file old/linux/arch/m68k/mm/init.c new/linux/arch/m68k/mm/init.c --- old/linux/arch/m68k/mm/init.c Tue Jan 19 19:58:34 1999 +++ new/linux/arch/m68k/mm/init.c Tue May 11 18:57:14 1999 @@ -123,7 +123,7 @@ unsigned long mm_cachebits = 0; #endif -static pte_t *__init kernel_page_table(unsigned long *memavailp) +__initfunc(static pte_t * kernel_page_table(unsigned long *memavailp)) { pte_t *ptablep; @@ -140,15 +140,19 @@ static pmd_t *last_pgtable __initdata = NULL; -static pmd_t *__init kernel_ptr_table(unsigned long *memavailp) +__initfunc(static pmd_t * kernel_ptr_table(unsigned long *memavailp)) { if (!last_pgtable) { unsigned long pmd, last; int i; + /* Find the last ptr table that was used in head.S and + * reuse the remaining space in that page for further + * ptr tables. + */ last = (unsigned long)kernel_pg_dir; for (i = 0; i < PTRS_PER_PGD; i++) { - if (!pgd_val(kernel_pg_dir[i])) + if (!pgd_present(kernel_pg_dir[i])) continue; pmd = pgd_page(kernel_pg_dir[i]); if (pmd > last) @@ -175,8 +179,8 @@ return last_pgtable; } -static unsigned long __init -map_chunk (unsigned long addr, long size, unsigned long *memavailp) +__initfunc(static unsigned long +map_chunk (unsigned long addr, long size, unsigned long *memavailp)) { #define PTRTREESIZE (256*1024) #define ROOTTREESIZE (32*1024*1024) @@ -282,8 +286,8 @@ * paging_init() continues the virtual memory environment setup which * was begun by the code in arch/head.S. */ -unsigned long __init paging_init(unsigned long start_mem, - unsigned long end_mem) +__initfunc(unsigned long paging_init(unsigned long start_mem, + unsigned long end_mem)) { int chunk; unsigned long mem_avail = 0; @@ -392,7 +396,7 @@ return PAGE_ALIGN(free_area_init(start_mem, end_mem)); } -void __init mem_init(unsigned long start_mem, unsigned long end_mem) +__initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem)) { int codepages = 0; int datapages = 0; @@ -443,7 +447,7 @@ /* insert pointer tables allocated so far into the tablelist */ init_pointer_table((unsigned long)kernel_pg_dir); for (i = 0; i < PTRS_PER_PGD; i++) { - if (pgd_val(kernel_pg_dir[i])) + if (pgd_present(kernel_pg_dir[i])) init_pointer_table(pgd_page(kernel_pg_dir[i])); } diff -ur --new-file old/linux/arch/m68k/mm/kmap.c new/linux/arch/m68k/mm/kmap.c --- old/linux/arch/m68k/mm/kmap.c Tue Jan 19 19:58:34 1999 +++ new/linux/arch/m68k/mm/kmap.c Wed May 12 17:50:08 1999 @@ -7,6 +7,7 @@ * used by other architectures /Roman Zippel */ +#include #include #include #include @@ -116,6 +117,14 @@ if (!size || size > physaddr + size) return NULL; +#ifdef CONFIG_AMIGA + if (MACH_IS_AMIGA) { + if ((physaddr >= 0x40000000) && (physaddr + size < 0x60000000) + && (cacheflag == IOMAP_NOCACHE_SER)) + return (void *)physaddr; + } +#endif + #ifdef DEBUG printk("ioremap: 0x%lx,0x%lx(%d) - ", physaddr, size, cacheflag); #endif @@ -174,7 +183,7 @@ } } - while (size > 0) { + while ((long)size > 0) { #ifdef DEBUG if (!(virtaddr & (PTRTREESIZE-1))) printk ("\npa=%#lx va=%#lx ", physaddr, virtaddr); @@ -187,7 +196,7 @@ } if (CPU_IS_020_OR_030) { - pmd_dir->pmd[(virtaddr/PTRTREESIZE)&-16] = physaddr; + pmd_dir->pmd[(virtaddr/PTRTREESIZE) & 15] = physaddr; physaddr += PTRTREESIZE; virtaddr += PTRTREESIZE; size -= PTRTREESIZE; @@ -217,7 +226,14 @@ */ void iounmap(void *addr) { +#ifdef CONFIG_AMIGA + if ((!MACH_IS_AMIGA) || + (((unsigned long)addr < 0x40000000) || + ((unsigned long)addr > 0x60000000))) + free_io_area(addr); +#else free_io_area(addr); +#endif } /* @@ -232,7 +248,7 @@ pmd_t *pmd_dir; pte_t *pte_dir; - while (size > 0) { + while ((long)size > 0) { pgd_dir = pgd_offset_k(virtaddr); if (pgd_bad(*pgd_dir)) { printk("iounmap: bad pgd(%08lx)\n", pgd_val(*pgd_dir)); @@ -242,7 +258,7 @@ pmd_dir = pmd_offset(pgd_dir, virtaddr); if (CPU_IS_020_OR_030) { - int pmd_off = (virtaddr/PTRTREESIZE) & -16; + int pmd_off = (virtaddr/PTRTREESIZE) & 15; if ((pmd_dir->pmd[pmd_off] & _DESCTYPE_MASK) == _PAGE_PRESENT) { pmd_dir->pmd[pmd_off] = 0; @@ -308,7 +324,7 @@ } } - while (size > 0) { + while ((long)size > 0) { pgd_dir = pgd_offset_k(virtaddr); if (pgd_bad(*pgd_dir)) { printk("iocachemode: bad pgd(%08lx)\n", pgd_val(*pgd_dir)); @@ -318,7 +334,7 @@ pmd_dir = pmd_offset(pgd_dir, virtaddr); if (CPU_IS_020_OR_030) { - int pmd_off = (virtaddr/PTRTREESIZE) & -16; + int pmd_off = (virtaddr/PTRTREESIZE) & 15; if ((pmd_dir->pmd[pmd_off] & _DESCTYPE_MASK) == _PAGE_PRESENT) { pmd_dir->pmd[pmd_off] = (pmd_dir->pmd[pmd_off] & diff -ur --new-file old/linux/arch/m68k/mm/memory.c new/linux/arch/m68k/mm/memory.c --- old/linux/arch/m68k/mm/memory.c Tue Jan 19 19:58:34 1999 +++ new/linux/arch/m68k/mm/memory.c Tue May 11 18:57:14 1999 @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -93,12 +94,11 @@ static ptable_desc ptable_list = { &ptable_list, &ptable_list }; #define PD_MARKBITS(dp) (*(unsigned char *)&(dp)->offset) -#define PD_PAGE(dp) (PAGE_OFFSET + ((dp)->map_nr << PAGE_SHIFT)) #define PAGE_PD(page) ((ptable_desc *)&mem_map[MAP_NR(page)]) #define PTABLE_SIZE (PTRS_PER_PMD * sizeof(pmd_t)) -void __init init_pointer_table(unsigned long ptable) +__initfunc(void init_pointer_table(unsigned long ptable)) { ptable_desc *dp; unsigned long page = ptable & PAGE_MASK; @@ -166,7 +166,7 @@ (dp->next = last->next)->prev = dp; (dp->prev = last)->next = dp; } - return (pmd_t *) (PD_PAGE(dp) + off); + return (pmd_t *) (page_address(dp) + off); } int free_pointer_table (pmd_t *ptable) @@ -215,8 +215,8 @@ /* function code match? */ base = (regval >> 4) & 7; mask = ~(regval & 7); - if ((SUPER_DATA & mask) != (base & mask)) - return( 0 ); + if (((SUPER_DATA ^ base) & mask) != 0) + return 0; } else { /* must not be user-only */ @@ -226,8 +226,8 @@ /* address match? */ base = regval & 0xff000000; - mask = ~((regval << 8) & 0xff000000); - return( (vaddr & mask) == (base & mask) ); + mask = ~(regval << 8) & 0xff000000; + return ((vaddr ^ base) & mask) == 0; } #ifndef CONFIG_SINGLE_MEMORY_CHUNK diff -ur --new-file old/linux/arch/m68k/mvme147/147ints.c new/linux/arch/m68k/mvme147/147ints.c --- old/linux/arch/m68k/mvme147/147ints.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/m68k/mvme147/147ints.c Tue May 11 18:57:14 1999 @@ -0,0 +1,142 @@ +/* + * arch/m68k/mvme147/147ints.c + * + * Copyright (C) 1997 Richard Hirst [richard@sleepie.demon.co.uk] + * + * based on amiints.c -- Amiga Linux interrupt handling code + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file README.legal in the main directory of this archive + * for more details. + * + */ + +#include +#include +#include + +#include +#include +#include +#include + +static void mvme147_defhand (int irq, void *dev_id, struct pt_regs *fp); + +/* + * This should ideally be 4 elements only, for speed. + */ + +static struct { + void (*handler)(int, void *, struct pt_regs *); + unsigned long flags; + void *dev_id; + const char *devname; + unsigned count; +} irq_tab[256]; + +/* + * void mvme147_init_IRQ (void) + * + * Parameters: None + * + * Returns: Nothing + * + * This function is called during kernel startup to initialize + * the mvme147 IRQ handling routines. + */ + +void mvme147_init_IRQ (void) +{ + int i; + + for (i = 0; i < 256; i++) { + irq_tab[i].handler = mvme147_defhand; + irq_tab[i].flags = IRQ_FLG_STD; + irq_tab[i].dev_id = NULL; + irq_tab[i].devname = NULL; + irq_tab[i].count = 0; + } +} + +int mvme147_request_irq(unsigned int irq, + void (*handler)(int, void *, struct pt_regs *), + unsigned long flags, const char *devname, void *dev_id) +{ + if (irq > 255) { + printk("%s: Incorrect IRQ %d from %s\n", __FUNCTION__, irq, devname); + return -ENXIO; + } + if (!(irq_tab[irq].flags & IRQ_FLG_STD)) { + if (irq_tab[irq].flags & IRQ_FLG_LOCK) { + printk("%s: IRQ %d from %s is not replaceable\n", + __FUNCTION__, irq, irq_tab[irq].devname); + return -EBUSY; + } + if (flags & IRQ_FLG_REPLACE) { + printk("%s: %s can't replace IRQ %d from %s\n", + __FUNCTION__, devname, irq, irq_tab[irq].devname); + return -EBUSY; + } + } + irq_tab[irq].handler = handler; + irq_tab[irq].flags = flags; + irq_tab[irq].dev_id = dev_id; + irq_tab[irq].devname = devname; + return 0; +} + +void mvme147_free_irq(unsigned int irq, void *dev_id) +{ + if (irq > 255) { + printk("%s: Incorrect IRQ %d\n", __FUNCTION__, irq); + return; + } + if (irq_tab[irq].dev_id != dev_id) + printk("%s: Removing probably wrong IRQ %d from %s\n", + __FUNCTION__, irq, irq_tab[irq].devname); + + irq_tab[irq].handler = mvme147_defhand; + irq_tab[irq].flags = IRQ_FLG_STD; + irq_tab[irq].dev_id = NULL; + irq_tab[irq].devname = NULL; +} + +void mvme147_process_int (unsigned long vec, struct pt_regs *fp) +{ + if (vec > 255) + printk ("mvme147_process_int: Illegal vector %ld\n", vec); + else + { + irq_tab[vec].count++; + irq_tab[vec].handler(vec, irq_tab[vec].dev_id, fp); + } +} + +int mvme147_get_irq_list (char *buf) +{ + int i, len = 0; + + for (i = 0; i < 256; i++) { + if (irq_tab[i].count) + len += sprintf (buf+len, "Vec 0x%02x: %8d %s\n", + i, irq_tab[i].count, + irq_tab[i].devname ? irq_tab[i].devname : "free"); + } + return len; +} + + +static void mvme147_defhand (int irq, void *dev_id, struct pt_regs *fp) +{ + printk ("Unknown interrupt 0x%02x\n", irq); +} + +void mvme147_enable_irq (unsigned int irq) +{ +} + + +void mvme147_disable_irq (unsigned int irq) +{ +} + diff -ur --new-file old/linux/arch/m68k/mvme147/Makefile new/linux/arch/m68k/mvme147/Makefile --- old/linux/arch/m68k/mvme147/Makefile Thu Jan 1 01:00:00 1970 +++ new/linux/arch/m68k/mvme147/Makefile Tue May 11 18:57:14 1999 @@ -0,0 +1,14 @@ +# +# Makefile for Linux arch/m68k/mvme147 source directory +# +# 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). +# + +O_TARGET := mvme147.o +O_OBJS := config.o 147ints.o + + +include $(TOPDIR)/Rules.make + diff -ur --new-file old/linux/arch/m68k/mvme147/config.c new/linux/arch/m68k/mvme147/config.c --- old/linux/arch/m68k/mvme147/config.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/m68k/mvme147/config.c Wed May 12 17:50:08 1999 @@ -0,0 +1,239 @@ +/* + * arch/m68k/mvme147/config.c + * + * Copyright (C) 1996 Dave Frascone [chaos@mindspring.com] + * Cloned from Richard Hirst [richard@sleepie.demon.co.uk] + * + * Based on: + * + * Copyright (C) 1993 Hamish Macdonald + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file README.legal in the main directory of this archive + * for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + + +extern void mvme147_process_int (int level, struct pt_regs *regs); +extern void mvme147_init_IRQ (void); +extern void mvme147_free_irq (unsigned int, void *); +extern int mvme147_get_irq_list (char *); +extern void mvme147_enable_irq (unsigned int); +extern void mvme147_disable_irq (unsigned int); +static void mvme147_get_model(char *model); +static int mvme147_get_hardware_list(char *buffer); +extern int mvme147_request_irq (unsigned int irq, void (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *devname, void *dev_id); +extern void mvme147_sched_init(void (*handler)(int, void *, struct pt_regs *)); +extern int mvme147_keyb_init(void); +extern int mvme147_kbdrate (struct kbd_repeat *); +extern unsigned long mvme147_gettimeoffset (void); +extern void mvme147_gettod (int *year, int *mon, int *day, int *hour, + int *min, int *sec); +extern int mvme147_hwclk (int, struct hwclk_time *); +extern int mvme147_set_clock_mmss (unsigned long); +extern void mvme147_check_partition (struct gendisk *hd, unsigned int dev); +extern void mvme147_reset (void); +extern void mvme147_waitbut(void); + + +static int bcd2int (unsigned char b); + +/* Save tick handler routine pointer, will point to do_timer() in + * kernel/sched.c, called via mvme147_process_int() */ + +void (*tick_handler)(int, void *, struct pt_regs *); + + +int mvme147_kbdrate (struct kbd_repeat *k) +{ + return 0; +} + +void mvme147_reset() +{ + printk ("\r\n\nCalled mvme147_reset\r\n"); + m147_pcc->watchdog = 0x0a; /* Clear timer */ + m147_pcc->watchdog = 0xa5; /* Enable watchdog - 100ms to reset */ + while (1) + ; +} + +static void mvme147_get_model(char *model) +{ + sprintf(model, "Motorola MVME147"); +} + + +static int mvme147_get_hardware_list(char *buffer) +{ + *buffer = '\0'; + + return 0; +} + + +__initfunc(void config_mvme147(void)) +{ + mach_sched_init = mvme147_sched_init; + mach_keyb_init = mvme147_keyb_init; + mach_kbdrate = mvme147_kbdrate; + mach_init_IRQ = mvme147_init_IRQ; + mach_gettimeoffset = mvme147_gettimeoffset; + mach_gettod = mvme147_gettod; + mach_hwclk = mvme147_hwclk; + mach_set_clock_mmss = mvme147_set_clock_mmss; + mach_reset = mvme147_reset; + mach_free_irq = mvme147_free_irq; + mach_process_int = mvme147_process_int; + mach_get_irq_list = mvme147_get_irq_list; + mach_request_irq = mvme147_request_irq; + enable_irq = mvme147_enable_irq; + disable_irq = mvme147_disable_irq; + mach_get_model = mvme147_get_model; + mach_get_hardware_list = mvme147_get_hardware_list; +} + + +/* Using pcc tick timer 1 */ + +static void mvme147_timer_int (int irq, void *dev_id, struct pt_regs *fp) +{ + m147_pcc->t1_int_cntrl = PCC_TIMER_INT_CLR; + m147_pcc->t1_int_cntrl = PCC_INT_ENAB|PCC_LEVEL_TIMER1; + tick_handler(irq, dev_id, fp); +} + + +void mvme147_sched_init (void (*timer_routine)(int, void *, struct pt_regs *)) +{ + tick_handler = timer_routine; + request_irq (PCC_IRQ_TIMER1, mvme147_timer_int, + IRQ_FLG_REPLACE, "timer 1", NULL); + + /* Init the clock with a value */ + /* our clock goes off every 6.25us */ + m147_pcc->t1_preload = PCC_TIMER_PRELOAD; + m147_pcc->t1_cntrl = 0x0; /* clear timer */ + m147_pcc->t1_cntrl = 0x3; /* start timer */ + m147_pcc->t1_int_cntrl = PCC_TIMER_INT_CLR; /* clear pending ints */ + m147_pcc->t1_int_cntrl = PCC_INT_ENAB|PCC_LEVEL_TIMER1; +} + +/* This is always executed with interrupts disabled. */ +/* XXX There are race hazards in this code XXX */ +unsigned long mvme147_gettimeoffset (void) +{ + volatile unsigned short *cp = (volatile unsigned short *)0xfffe1012; + unsigned short n; + + n = *cp; + while (n != *cp) + n = *cp; + + n -= PCC_TIMER_PRELOAD; + return (unsigned long)n * 25 / 4; +} + +extern void mvme147_gettod (int *year, int *mon, int *day, int *hour, + int *min, int *sec) +{ + m147_rtc->ctrl = RTC_READ; + *year = bcd2int (m147_rtc->bcd_year); + *mon = bcd2int (m147_rtc->bcd_mth); + *day = bcd2int (m147_rtc->bcd_dom); + *hour = bcd2int (m147_rtc->bcd_hr); + *min = bcd2int (m147_rtc->bcd_min); + *sec = bcd2int (m147_rtc->bcd_sec); + m147_rtc->ctrl = 0; +} + +static int bcd2int (unsigned char b) +{ + return ((b>>4)*10 + (b&15)); +} + +int mvme147_hwclk(int op, struct hwclk_time *t) +{ + return 0; +} + +int mvme147_set_clock_mmss (unsigned long nowtime) +{ + return 0; +} + +int mvme147_keyb_init (void) +{ + return 0; +} + +/*------------------- Serial console stuff ------------------------*/ + +void m147_scc_write(struct console *co, const char *str, unsigned cnt); + + +void mvme147_init_console_port (struct console *co, int cflag) +{ + co->write = m147_scc_write; +} + + +static void scc_delay (void) +{ + int n; + volatile int trash; + + for (n = 0; n < 20; n++) + trash = n; +} + +static void scc_write (char ch) +{ + volatile char *p = (volatile char *)M147_SCC_A_ADDR; + + do { + scc_delay(); + } + while (!(*p & 4)); + scc_delay(); + *p = 8; + scc_delay(); + *p = ch; +} + + +void m147_scc_write (struct console *co, const char *str, unsigned count) +{ + unsigned long flags; + + save_flags(flags); + cli(); + + while (count--) + { + if (*str == '\n') + scc_write ('\r'); + scc_write (*str++); + } + restore_flags(flags); +} + diff -ur --new-file old/linux/arch/m68k/mvme16x/config.c new/linux/arch/m68k/mvme16x/config.c --- old/linux/arch/m68k/mvme16x/config.c Sat Jun 13 22:14:33 1998 +++ new/linux/arch/m68k/mvme16x/config.c Tue May 11 18:57:14 1999 @@ -335,10 +335,10 @@ static void scc_delay (void) { int n; - char i; + volatile int trash; for (n = 0; n < 20; n++) - i = *(volatile char *)0; + trash = n; } static void scc_write (char ch) diff -ur --new-file old/linux/arch/m68k/q40/Makefile new/linux/arch/m68k/q40/Makefile --- old/linux/arch/m68k/q40/Makefile Thu Jan 1 01:00:00 1970 +++ new/linux/arch/m68k/q40/Makefile Tue May 11 18:57:14 1999 @@ -0,0 +1,14 @@ +# +# Makefile for Linux arch/m68k/q40 source directory +# +# 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 := q40.o +O_OBJS := config.o q40ints.o + + +include $(TOPDIR)/Rules.make diff -ur --new-file old/linux/arch/m68k/q40/README new/linux/arch/m68k/q40/README --- old/linux/arch/m68k/q40/README Thu Jan 1 01:00:00 1970 +++ new/linux/arch/m68k/q40/README Tue May 11 18:57:14 1999 @@ -0,0 +1,121 @@ +Linux for the Q40 +================= + +You may try http://www.geocities.com/SiliconValley/Bay/2602/ for +some up to date information. Booter and other tools will be also +available from this place and ftp.uni-erlangen.de/linux/680x0/q40/ +and mirrors. + +Hints to documentation usually refer to the linux source tree in +/usr/src/linux unless URL given. + +It seems IRQ unmasking can't be safely done on a Q40. Autoprobing is +not yet implemented - do not try it! (See below) + +For a list of kernel commandline options read the documentation for the +particular device drivers. + +The floppy imposes a very high interrupt load on the CPU, approx 30K/s. +When something blocks interrupts (HD) it will loose some of them, so far +this is not known to have caused any data loss. On hihgly loaded systems +it can make the floppy very slow. Other Q40 OS' simply poll the floppy +for this reason - something that can't be done in Linux. +Only possible cure is getting a 82072 contoler with fifo instead of +the 8272A + +drivers used by the Q40, appart from the very obvious (console etc.): + drivers/char/q40_keyb.c # use PC keymaps for national keyboards + serial.c # normal PC driver - any speed + lp.c # printer driver + char/joystick/* # most of this should work + block/q40ide.c # startup for ide + ide* # see Documentation/ide.txt + floppy.c # normal PC driver, DMA emu in asm/floppy.h + # and arch/m68k/kernel/entry.S + # see drivers/block/README.fd + video/q40fb.c + misc/parport_pc.c + +Various other PC drivers can be enabled simply by adding them to +arch/m68k/config.in, especially 8 bit devices should be without any +problems. For cards using 16bit io/mem more care is required, like +checking byteorder issues, hacking memcpy_*_io etc. + + +Debugging +========= + +Upon startup the kernel will usually output "ABCQGHIJ" into the SRAM, +preceded by the booter signature. This is a trace just in case something +went wrong during earliest setup stages. +*Changed* to preserve SRAM contents by default, this is only done when +requested - SRAM must start with '%LX$' signature to do this. '-d' option +to 'lxx' loader enables this. + +SRAM can also be used as additional console device, use debug=mem. +This will save kernel startup msgs into SRAM, the screen will display +only the penguin - and shell prompt if it gets that far.. + +Serial console works and can also be used for debugging, provided serial +initialisation works. + +Most problems seem to be caused by fawlty or badly configured io-cards or +harddrives anyway..there are so many things that can go wrong here. +Make sure to configure the parallel port as SPP for first testing..the +Q40 may have trouble with parallel interrupts. + + +Q40 Hardware Description +======================== + +This is just an overview, see asm-m68k/* for details ask if you have any +questions. + +The Q40 consists of a 68040@40 MHz, 1MB video RAM, up to 32MB RAM, AT-style +keyboard interface, 1 Programmable LED, 2 8bit DACs and up to 1MB ROM, 1MB +shadow ROM. + +Most interfacing like floppy, hd, serial, parallel ports is done via ISA +slots. The ISA io and mem range is mapped (sparse&byteswapped!) into separate +regions of the memory. +The main interrupt register IIRQ_REG will indicate whether an IRQ was internal +or from some ISA devices, EIRQ_REG can distinguish up to 8 ISA IRQs. + +The Q40 custom chip is programmable to provide 2 periodic timers: + - 50 or 200 Hz - level 2, !!THIS CANT BE DISABLED!! + - 10 or 20 KHz - level 4 (and possibly 6 - hardware decoding..) + +Linux uses the 200 Hz interrupt for timer and beep by default. + + +Interrupts +========== + +q40 master chip handles only level triggered interrupts :-(( +further limitation is no disabling etc. Unless someone finds +some ingenious clue this means autoprobing will never work. +Parallel port interrupts cause most trouble.. + +IRQ sharing is not yet implemented. + + +Keyboard +======== + +q40 receives AT make/break codes from the keyboard, these are translated to +the PC scancodes x86 Linux uses. So by theory every national keyboard should +work just by loading the apropriate x86 keytable - see any national-HOWTO. + +Unfortunately the AT->PC translation isn't quite trivial and even worse, my +documentation of it is absolutely minimal - thus some exotic keys may not +behave exactly as expected. + +There is still hope that it can be fixed completely though. If you encounter +problems, email me idealy this: + - exact keypress/release sequence + - 'showkey -s' run on q40, non-X session + - 'showkey -s' run on a PC, non-X session + - AT codes as displayed by the q40 debuging ROM +btw if the showkey output from PC and Q40 doesn't differ then you have some +classic configuration problem - don't send me anything in this case + diff -ur --new-file old/linux/arch/m68k/q40/config.c new/linux/arch/m68k/q40/config.c --- old/linux/arch/m68k/q40/config.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/m68k/q40/config.c Wed May 12 17:50:08 1999 @@ -0,0 +1,426 @@ +/* + * arch/m68k/q40/config.c + * + * originally based on: + * + * linux/bvme/config.c + * + * Copyright (C) 1993 Hamish Macdonald + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file README.legal in the main directory of this archive + * for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern void fd_floppy_eject(void); +extern void fd_floppy_setup(char *str, int *ints); + +extern void q40_process_int (int level, struct pt_regs *regs); +extern void (*q40_sys_default_handler[]) (int, void *, struct pt_regs *); /* added just for debugging */ +extern void q40_init_IRQ (void); +extern void q40_free_irq (unsigned int, void *); +extern int q40_get_irq_list (char *); +extern void q40_enable_irq (unsigned int); +extern void q40_disable_irq (unsigned int); +static void q40_get_model(char *model); +static int q40_get_hardware_list(char *buffer); +extern int q40_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *devname, void *dev_id); +extern void q40_sched_init(void (*handler)(int, void *, struct pt_regs *)); +extern int q40_keyb_init(void); +extern int q40_kbdrate (struct kbd_repeat *); +extern unsigned long q40_gettimeoffset (void); +extern void q40_gettod (int *year, int *mon, int *day, int *hour, + int *min, int *sec); +extern int q40_hwclk (int, struct hwclk_time *); +extern int q40_set_clock_mmss (unsigned long); +extern void q40_reset (void); +extern void q40_waitbut(void); +void q40_set_vectors (void); +extern void (*kd_mksound)(unsigned int, unsigned int); +void q40_mksound(unsigned int /*freq*/, unsigned int /*ticks*/ ); + +extern char *saved_command_line; +extern char m68k_debug_device[]; +static void q40_mem_console_write(struct console *co, const char *b, + unsigned int count); + +static int ql_ticks=0; +static int sound_ticks=0; + +static unsigned char bcd2bin (unsigned char b); +static unsigned char bin2bcd (unsigned char b); + +static int q40_wait_key(struct console *co){return 0;} +static struct console q40_console_driver = { + "debug", + NULL, /* write */ + NULL, /* read */ + NULL, /* device */ + q40_wait_key, /* wait_key */ + NULL, /* unblank */ + NULL, /* setup */ + CON_PRINTBUFFER, + -1, + 0, + NULL +}; + + +/* Save tick handler routine pointer, will point to do_timer() in + * kernel/sched.c */ + +/* static void (*tick_handler)(int, void *, struct pt_regs *); */ + + +/* early debugging function:*/ +extern char *q40_mem_cptr; /*=(char *)0xff020000;*/ +static int _cpleft; + +static void q40_mem_console_write(struct console *co, const char *s, + unsigned int count) +{ + char *p=(char *)s; + + if (count<_cpleft) + while (count-- >0){ + *q40_mem_cptr=*p++; + q40_mem_cptr+=4; + _cpleft--; + } +} +#if 0 +void printq40(char *str) +{ + int l=strlen(str); + char *p=q40_mem_cptr; + + while (l-- >0 && _cpleft-- >0) + { + *p=*str++; + p+=4; + } + q40_mem_cptr=p; +} +#endif + +#if 0 +int q40_kbdrate (struct kbd_repeat *k) +{ + return 0; +} +#endif + +void q40_reset() +{ + + printk ("\n\n*******************************************\n" + "Called q40_reset : press the RESET button!! \n"); + printk( "*******************************************\n"); + + while(1) + ; +} + +static void q40_get_model(char *model) +{ + sprintf(model, "Q40"); +} + + +/* No hardware options on Q40? */ + +static int q40_get_hardware_list(char *buffer) +{ + *buffer = '\0'; + return 0; +} + + +__initfunc(void config_q40(void)) +{ + mach_sched_init = q40_sched_init; /* ok */ + /*mach_kbdrate = q40_kbdrate;*/ /* unneeded ?*/ + mach_keyb_init = q40_keyb_init; /* OK */ + mach_init_IRQ = q40_init_IRQ; + mach_gettimeoffset = q40_gettimeoffset; + mach_gettod = q40_gettod; + mach_hwclk = q40_hwclk; + mach_set_clock_mmss = q40_set_clock_mmss; +/* mach_mksound = q40_mksound; */ + mach_reset = q40_reset; /* use reset button instead !*/ + mach_free_irq = q40_free_irq; + mach_process_int = q40_process_int; + mach_get_irq_list = q40_get_irq_list; + mach_request_irq = q40_request_irq; + enable_irq = q40_enable_irq; + disable_irq = q40_disable_irq; + mach_default_handler = &q40_sys_default_handler; + mach_get_model = q40_get_model; /* no use..*/ + mach_get_hardware_list = q40_get_hardware_list; /* no use */ + kd_mksound = q40_mksound; + /*mach_kbd_leds = q40kbd_leds;*/ +#ifdef CONFIG_MAGIC_SYSRQ + mach_sysrq_key = 0x54; +#endif + conswitchp = &dummy_con; +#ifdef CONFIG_BLK_DEV_FD + mach_floppy_setup = fd_floppy_setup; + mach_floppy_eject = fd_floppy_eject; + /**/ +#endif + + mach_max_dma_address = 0; /* no DMA at all */ + + +/* userfull for early debuging stages writes kernel messages into SRAM */ + + if (!strncmp( m68k_debug_device,"mem",3 )) + { + /*printk("using NVRAM debug, q40_mem_cptr=%p\n",q40_mem_cptr);*/ + _cpleft=2000-((long)q40_mem_cptr-0xff020000)/4; + q40_console_driver.write = q40_mem_console_write; + register_console(&q40_console_driver); + } +} + + +int q40_parse_bootinfo(const struct bi_record *rec) +{ + return 1; /* unknown */ +} + +#define DAC_LEFT ((unsigned char *)0xff008000) +#define DAC_RIGHT ((unsigned char *)0xff008004) +void q40_mksound(unsigned int hz, unsigned int ticks) +{ + /* for now ignore hz, except that hz==0 switches off sound */ + /* simply alternate the ampl 0-255-0-.. at 200Hz */ + if (hz==0) + { + if (sound_ticks) + sound_ticks=1; /* atomic - no irq spinlock used */ + + *DAC_LEFT=0; + *DAC_RIGHT=0; + + return; + } + /* sound itself is done in q40_timer_int */ + if (sound_ticks == 0) sound_ticks=1000; /* pretty long beep */ + sound_ticks=ticks<<1; +} + +static void (*q40_timer_routine)(int, void *, struct pt_regs *); + +static void q40_timer_int (int irq, void *dev_id, struct pt_regs *fp) +{ +#if (HZ==10000) + master_outb(-1,SAMPLE_CLEAR_REG); +#else /* must be 50 or 100 */ + master_outb(-1,FRAME_CLEAR_REG); +#endif + +#if (HZ==100) + ql_ticks = ql_ticks ? 0 : 1; + if (sound_ticks) + { + unsigned char sval=(sound_ticks & 1) ? 0 : 255; + sound_ticks--; + *DAC_LEFT=sval; + *DAC_RIGHT=sval; + } + if (ql_ticks) return; +#endif + q40_timer_routine(irq, dev_id, fp); +} + + +void q40_sched_init (void (*timer_routine)(int, void *, struct pt_regs *)) +{ + int timer_irq; + + q40_timer_routine = timer_routine; + +#if (HZ==10000) + timer_irq=Q40_IRQ_TIMER; +#else + timer_irq=Q40_IRQ_FRAME; +#endif + + /*printk("registering sched/timer IRQ %d\n", timer_irq);*/ + + if (request_irq(timer_irq, q40_timer_int, 0, + "timer", q40_timer_int)) + panic ("Couldn't register timer int"); + +#if (HZ==10000) + master_outb(SAMPLE_LOW,SAMPLE_RATE_REG); + master_outb(-1,SAMPLE_CLEAR_REG); + master_outb(1,SAMPLE_ENABLE_REG); +#else + master_outb(-1,FRAME_CLEAR_REG); /* not necessary ? */ +#if (HZ==100) + master_outb( 1,FRAME_RATE_REG); +#endif +#endif +} + + +unsigned long q40_gettimeoffset (void) +{ +#if (HZ==100) + return 5000*(ql_ticks!=0); +#else + return 0; +#endif +} + +extern void q40_gettod (int *year, int *mon, int *day, int *hour, + int *min, int *sec) +{ + RTC_CTRL |= RTC_READ; + *year = bcd2bin (RTC_YEAR); + *mon = bcd2bin (RTC_MNTH)-1; + *day = bcd2bin (RTC_DATE); + *hour = bcd2bin (RTC_HOUR); + *min = bcd2bin (RTC_MINS); + *sec = bcd2bin (RTC_SECS); + RTC_CTRL &= ~(RTC_READ); + +} + +static unsigned char bcd2bin (unsigned char b) +{ + return ((b>>4)*10 + (b&15)); +} + +static unsigned char bin2bcd (unsigned char b) +{ + return (((b/10)*16) + (b%10)); +} + + +/* + * Looks like op is non-zero for setting the clock, and zero for + * reading the clock. + * + * struct hwclk_time { + * unsigned sec; 0..59 + * unsigned min; 0..59 + * unsigned hour; 0..23 + * unsigned day; 1..31 + * unsigned mon; 0..11 + * unsigned year; 00... + * int wday; 0..6, 0 is Sunday, -1 means unknown/don't set + * }; + */ + +int q40_hwclk(int op, struct hwclk_time *t) +{ + if (op) + { /* Write.... */ + RTC_CTRL |= RTC_WRITE; + + RTC_SECS = bin2bcd(t->sec); + RTC_MINS = bin2bcd(t->min); + RTC_HOUR = bin2bcd(t->hour); + RTC_DATE = bin2bcd(t->day); + RTC_MNTH = bin2bcd(t->mon + 1); + RTC_YEAR = bin2bcd(t->year%100); + if (t->wday >= 0) + RTC_DOW = bin2bcd(t->wday+1); + + RTC_CTRL &= ~(RTC_WRITE); + } + else + { /* Read.... */ + RTC_CTRL |= RTC_READ; + + t->year = bcd2bin (RTC_YEAR); + t->mon = bcd2bin (RTC_MNTH)-1; + t->day = bcd2bin (RTC_DATE); + t->hour = bcd2bin (RTC_HOUR); + t->min = bcd2bin (RTC_MINS); + t->sec = bcd2bin (RTC_SECS); + + RTC_CTRL &= ~(RTC_READ); + + if (t->year < 70) + t->year += 100; + t->wday = bcd2bin(RTC_DOW)-1; + + } + + return 0; +} + +/* + * Set the minutes and seconds from seconds value 'nowtime'. Fail if + * clock is out by > 30 minutes. Logic lifted from atari code. + * Algorithm is to wait for the 10ms register to change, and then to + * wait a short while, and then set it. + */ + +int q40_set_clock_mmss (unsigned long nowtime) +{ + int retval = 0; + short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60; + + int rtc_minutes; + + + rtc_minutes = bcd2bin (RTC_MINS); + + if ((rtc_minutes < real_minutes + ? real_minutes - rtc_minutes + : rtc_minutes - real_minutes) < 30) + { + RTC_CTRL |= RTC_WRITE; + RTC_MINS = bin2bcd(real_minutes); + RTC_SECS = bin2bcd(real_seconds); + RTC_CTRL &= ~(RTC_WRITE); + } + else + retval = -1; + + + return retval; +} + +extern void q40kbd_init_hw(void); + +int q40_keyb_init (void) +{ + q40kbd_init_hw(); + return 0; +} + +#if 0 +/* dummy to cause */ +void q40_slow_io() +{ + return; +} +#endif diff -ur --new-file old/linux/arch/m68k/q40/q40ints.c new/linux/arch/m68k/q40/q40ints.c --- old/linux/arch/m68k/q40/q40ints.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/m68k/q40/q40ints.c Tue May 11 18:57:14 1999 @@ -0,0 +1,347 @@ +/* + * arch/m68k/q40/q40ints.c + * + * Copyright (C) 1999 Richard Zidlicky + * + * 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. + * + * losely based on bvme6000ints.c + * + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +/* + * Q40 IRQs are defined as follows: + * 3,4,5,6,7,10,11,14,15 : ISA dev IRQs + * 16-31: reserved + * 32 : keyboard int + * 33 : frame int (50 Hz periodic timer) + * 34 : sample int (10/20 KHz periodic timer) + * +*/ + +extern int ints_inited; + + +void q40_irq2_handler (int, void *, struct pt_regs *fp); + + +extern void (*q40_sys_default_handler[]) (int, void *, struct pt_regs *); /* added just for debugging */ + +static void q40_defhand (int irq, void *dev_id, struct pt_regs *fp); +static void sys_default_handler(int lev, void *dev_id, struct pt_regs *regs); + +/* + * This should ideally be 4 elements only, for speed. + */ + +#define DEVNAME_SIZE 24 + +static struct { + void (*handler)(int, void *, struct pt_regs *); + unsigned long flags; + void *dev_id; + char devname[DEVNAME_SIZE]; + unsigned count; +} irq_tab[Q40_IRQ_MAX+1]; + +/* + * void q40_init_IRQ (void) + * + * Parameters: None + * + * Returns: Nothing + * + * This function is called during kernel startup to initialize + * the q40 IRQ handling routines. + */ + +void q40_init_IRQ (void) +{ + int i; + + for (i = 0; i <= Q40_IRQ_MAX; i++) { + irq_tab[i].handler = q40_defhand; + irq_tab[i].flags = IRQ_FLG_STD; + irq_tab[i].dev_id = NULL; + irq_tab[i].devname[0] = 0; + irq_tab[i].count = 0; + } + + /* setup handler for ISA ints */ + sys_request_irq(IRQ2,q40_irq2_handler, IRQ_FLG_LOCK, "q40 ISA and master chip", NULL); + + /* now enable some ints.. */ + +#if 0 /* has been abandoned */ + master_outb(1,SER_ENABLE_REG); +#endif + master_outb(1,EXT_ENABLE_REG); + + /* would be spurious ints by now, q40kbd_init_hw() does that */ + master_outb(0,KEY_IRQ_ENABLE_REG); +} + +int q40_request_irq(unsigned int irq, + void (*handler)(int, void *, struct pt_regs *), + unsigned long flags, const char *devname, void *dev_id) +{ + /*printk("q40_request_irq %d, %s\n",irq,devname);*/ + + if (irq > Q40_IRQ_MAX || (irq>15 && irq<32)) { + printk("%s: Incorrect IRQ %d from %s\n", __FUNCTION__, irq, devname); + return -ENXIO; + } + + /* test for ISA ints not implemented by HW */ + if (irq<15) + { + switch (irq){ + case 1: case 2: case 8: case 9: + case 12: case 13: + printk("%s: ISA IRQ %d from %s not implemented by HW\n", __FUNCTION__, irq, devname); + return -ENXIO; + default: + } + } + + if (irq Q40_IRQ_MAX || (irq>15 && irq<32)) { + printk("%s: Incorrect IRQ %d, dev_id %x \n", __FUNCTION__, irq, (unsigned)dev_id); + return; + } + + /* test for ISA ints not implemented by HW */ + if (irq<15) { + switch (irq){ + case 1: case 2: case 8: case 9: + case 12: case 13: + printk("%s: ISA IRQ %d from %x illegal\n", __FUNCTION__, irq, (unsigned)dev_id); + return; + default: + } + } + + if (irq0) + printk("ISA interrupt from unknown source? EIRQ_REG = %x\n",mer),ccleirq--; + } + else + { + /* internal */ + + for (i=0; iirqs[i].mask; i++) + { + if (mir&(iirqs[i].mask)) + { + irq=iirqs[i].irq; + irq_tab[irq].count++; + if (irq_tab[irq].handler == q40_defhand ) + continue; /* ignore uninited INTs :-( */ + + irq_tab[irq].handler(irq,irq_tab[irq].dev_id,fp); + return; + } + } + if (cclirq>0) + printk("internal level 2 interrupt from unknown source ? IIRQ_REG=%x\n",mir),cclirq--; + } +} + +int q40_get_irq_list (char *buf) +{ + int i, len = 0; + + for (i = 0; i <= Q40_IRQ_MAX; i++) { + if (irq_tab[i].count) + len += sprintf (buf+len, "Vec 0x%02x: %8d %s%s\n", + i, irq_tab[i].count, + irq_tab[i].devname[0] ? irq_tab[i].devname : "?", + irq_tab[i].handler == q40_defhand ? + " (now unassigned)" : ""); + } + return len; +} + + +static void q40_defhand (int irq, void *dev_id, struct pt_regs *fp) +{ +#if 0 + printk ("Unknown q40 interrupt 0x%02x\n", irq); +#endif +} +static void sys_default_handler(int lev, void *dev_id, struct pt_regs *regs) +{ +#if 0 + if (ints_inited) +#endif + printk ("Uninitialised interrupt level %d\n", lev); +#if 0 + else + printk ("Interrupt before interrupt initialisation\n"); +#endif +} + + void (*q40_sys_default_handler[SYS_IRQS]) (int, void *, struct pt_regs *) = { + sys_default_handler,sys_default_handler,sys_default_handler,sys_default_handler, + sys_default_handler,sys_default_handler,sys_default_handler,sys_default_handler + }; + +void q40_enable_irq (unsigned int irq) +{ +} + + +void q40_disable_irq (unsigned int irq) +{ +} + +unsigned long q40_probe_irq_on (void) +{ + printk("sorry, irq probing not yet implemented - reconfigure the driver to avoid this\n"); + return 0; +} +int q40_probe_irq_off (unsigned long irqs) +{ + return -1; +} diff -ur --new-file old/linux/arch/m68k/sun3x/Makefile new/linux/arch/m68k/sun3x/Makefile --- old/linux/arch/m68k/sun3x/Makefile Thu Jan 1 01:00:00 1970 +++ new/linux/arch/m68k/sun3x/Makefile Tue May 11 18:57:14 1999 @@ -0,0 +1,14 @@ +# +# Makefile for Linux arch/m68k/sun3x source directory +# +# 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 := sun3x.o +O_OBJS := config.o time.o dvma.o sbus.o +OX_OBJS := + +include $(TOPDIR)/Rules.make diff -ur --new-file old/linux/arch/m68k/sun3x/config.c new/linux/arch/m68k/sun3x/config.c --- old/linux/arch/m68k/sun3x/config.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/m68k/sun3x/config.c Tue May 11 18:57:14 1999 @@ -0,0 +1,128 @@ +/* + * Setup kernel for a Sun3x machine + * + * (C) 1999 Thomas Bogendoerfer (tsbogend@alpha.franken.de) + * + * based on code from Oliver Jowett + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "time.h" + +static volatile unsigned char *sun3x_intreg = (unsigned char *)SUN3X_INTREG; +extern int serial_console; + +void sun3x_halt(void) +{ + /* Disable interrupts */ + cli(); + + /* we can't drop back to PROM, so we loop here */ + for (;;); +} + +void sun3x_reboot(void) +{ + /* This never returns, don't bother saving things */ + cli(); + + /* no idea, whether this works */ + asm ("reset"); +} + +__initfunc(int sun3x_keyb_init(void)) +{ + return 0; +} + +int sun3x_kbdrate(struct kbd_repeat *r) +{ + return 0; +} + +void sun3x_kbd_leds(unsigned int i) +{ + +} + +static void sun3x_badint (int irq, void *dev_id, struct pt_regs *fp) +{ + printk ("received spurious interrupt %d\n",irq); + num_spurious += 1; +} + +void (*sun3x_default_handler[SYS_IRQS])(int, void *, struct pt_regs *) = { + sun3x_badint, sun3x_badint, sun3x_badint, sun3x_badint, + sun3x_badint, sun3x_badint, sun3x_badint, sun3x_badint +}; + +void sun3x_enable_irq(unsigned int irq) +{ + *sun3x_intreg |= (1 << irq); +} + +void sun3x_disable_irq(unsigned int irq) +{ + *sun3x_intreg &= ~(1 << irq); +} + +__initfunc(void sun3x_init_IRQ(void)) +{ + /* disable all interrupts initially */ + *sun3x_intreg = 1; /* master enable only */ +} + +int sun3x_get_irq_list(char *buf) +{ + return 0; +} + +/* + * Setup the sun3x configuration info + */ +__initfunc(void config_sun3x(void)) +{ + mach_get_irq_list = sun3x_get_irq_list; + mach_max_dma_address = 0xffffffff; /* we can DMA anywhere, whee */ + + mach_keyb_init = sun3x_keyb_init; + mach_kbdrate = sun3x_kbdrate; + mach_kbd_leds = sun3x_kbd_leds; + + mach_sched_init = sun3x_sched_init; + mach_init_IRQ = sun3x_init_IRQ; + enable_irq = sun3x_enable_irq; + disable_irq = sun3x_disable_irq; + mach_request_irq = sys_request_irq; + mach_free_irq = sys_free_irq; + mach_default_handler = &sun3x_default_handler; + mach_gettimeoffset = sun3x_gettimeoffset; + mach_reset = sun3x_reboot; + + mach_gettod = sun3x_gettod; + + switch (*(unsigned char *)SUN3X_EEPROM_CONS) { + case 0x10: + serial_console = 1; + conswitchp = NULL; + break; + case 0x11: + serial_console = 2; + conswitchp = NULL; + break; + default: + serial_console = 0; + conswitchp = &dummy_con; + break; + } + +} diff -ur --new-file old/linux/arch/m68k/sun3x/dvma.c new/linux/arch/m68k/sun3x/dvma.c --- old/linux/arch/m68k/sun3x/dvma.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/m68k/sun3x/dvma.c Tue May 11 18:57:14 1999 @@ -0,0 +1,162 @@ +/* + * Virtual DMA allocation + * + * (C) 1999 Thomas Bogendoerfer (tsbogend@alpha.franken.de) + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +/* IOMMU support */ + +#define IOMMU_ENTRIES 2048 +#define IOMMU_ADDR_MASK 0x03ffe000 +#define IOMMU_CACHE_INHIBIT 0x00000040 +#define IOMMU_FULL_BLOCK 0x00000020 +#define IOMMU_MODIFIED 0x00000010 +#define IOMMU_USED 0x00000008 +#define IOMMU_WRITE_PROTECT 0x00000004 +#define IOMMU_DT_MASK 0x00000003 +#define IOMMU_DT_INVALID 0x00000000 +#define IOMMU_DT_VALID 0x00000001 +#define IOMMU_DT_BAD 0x00000002 + +#define DVMA_PAGE_SHIFT 13 +#define DVMA_PAGE_SIZE (1UL << DVMA_PAGE_SHIFT) +#define DVMA_PAGE_MASK (~(DVMA_PAGE_SIZE-1)) + + +static volatile unsigned long *iommu_pte = (unsigned long *)SUN3X_IOMMU; +static unsigned long iommu_use[IOMMU_ENTRIES]; +static unsigned long iommu_bitmap[IOMMU_ENTRIES/32]; + + +#define dvma_entry_paddr(index) (iommu_pte[index] & IOMMU_ADDR_MASK) +#define dvma_entry_vaddr(index,paddr) ((index << DVMA_PAGE_SHIFT) | \ + (paddr & (DVMA_PAGE_SIZE-1))) +#define dvma_entry_set(index,addr) (iommu_pte[index] = \ + (addr & IOMMU_ADDR_MASK) | \ + IOMMU_DT_VALID) +#define dvma_entry_clr(index) (iommu_pte[index] = IOMMU_DT_INVALID) +#define dvma_entry_use(index) (iommu_use[index]) +#define dvma_entry_inc(index) (iommu_use[index]++) +#define dvma_entry_dec(index) (iommu_use[index]--) +#define dvma_entry_hash(addr) ((addr >> DVMA_PAGE_SHIFT) ^ \ + ((addr & 0x03c00000) >> \ + (DVMA_PAGE_SHIFT+4))) +#define dvma_map iommu_bitmap +#define dvma_map_size (IOMMU_ENTRIES/2) +#define dvma_slow_offset (IOMMU_ENTRIES/2) +#define dvma_is_slow(addr) ((addr) & \ + (dvma_slow_offset << DVMA_PAGE_SHIFT)) + +static int fixed_dvma; + +void __init dvma_init(void) +{ + unsigned long tmp; + + if ((unsigned long)high_memory < (IOMMU_ENTRIES << DVMA_PAGE_SHIFT)) { + printk ("Sun3x fixed DVMA mapping\n"); + fixed_dvma = 1; + for (tmp = 0; tmp < (unsigned long)high_memory; tmp += DVMA_PAGE_SIZE) + dvma_entry_set (tmp >> DVMA_PAGE_SHIFT, virt_to_phys((void *)tmp)); + fixed_dvma = 1; + } else { + printk ("Sun3x variable DVMA mapping\n"); + for (tmp = 0; tmp < IOMMU_ENTRIES; tmp++) + dvma_entry_clr (tmp); + fixed_dvma = 0; + } +} + +unsigned long dvma_slow_alloc (unsigned long paddr, int npages) +{ + int scan, base; + + scan = 0; + for (;;) { + scan = find_next_zero_bit(dvma_map, dvma_map_size, scan); + if ((base = scan) + npages > dvma_map_size) { + printk ("dvma_slow_alloc failed for %d pages\n",npages); + return 0; + } + for (;;) { + if (scan >= base + npages) goto found; + if (test_bit(scan, dvma_map)) break; + scan++; + } + } + +found: + for (scan = base; scan < base+npages; scan++) { + dvma_entry_set(scan+dvma_slow_offset, paddr); + paddr += DVMA_PAGE_SIZE; + set_bit(scan, dvma_map); + } + return (dvma_entry_vaddr((base+dvma_slow_offset),paddr)); +} + +unsigned long dvma_alloc (unsigned long paddr, unsigned long size) +{ + int index; + int pages = ((paddr & ~DVMA_PAGE_MASK) + size + (DVMA_PAGE_SIZE-1)) >> + DVMA_PAGE_SHIFT; + + if (fixed_dvma) + return ((unsigned long)phys_to_virt (paddr)); + + if (pages > 1) /* multi page, allocate from slow pool */ + return dvma_slow_alloc (paddr, pages); + + index = dvma_entry_hash (paddr); + + if (dvma_entry_use(index)) { + if (dvma_entry_paddr(index) == (paddr & DVMA_PAGE_MASK)) { + dvma_entry_inc(index); + return dvma_entry_vaddr(index,paddr); + } + /* collision, allocate from slow pool */ + return dvma_slow_alloc (paddr, pages); + } + + dvma_entry_set(index,paddr); + dvma_entry_inc(index); + return dvma_entry_vaddr(index,paddr); +} + +void dvma_free (unsigned long dvma_addr, unsigned long size) +{ + int npages; + int index; + + if (fixed_dvma) + return; + + if (!dvma_is_slow(dvma_addr)) { + index = (dvma_addr >> DVMA_PAGE_SHIFT); + if (dvma_entry_use(index) == 0) { + printk ("dvma_free: %lx entry already free\n",dvma_addr); + return; + } + dvma_entry_dec(index); + if (dvma_entry_use(index) == 0) + dvma_entry_clr(index); + return; + } + + /* free in slow pool */ + npages = ((dvma_addr & ~DVMA_PAGE_MASK) + size + (DVMA_PAGE_SIZE-1)) >> + DVMA_PAGE_SHIFT; + for (index = (dvma_addr >> DVMA_PAGE_SHIFT); npages--; index++) { + dvma_entry_clr(index); + clear_bit (index,dvma_map); + } +} diff -ur --new-file old/linux/arch/m68k/sun3x/sbus.c new/linux/arch/m68k/sun3x/sbus.c --- old/linux/arch/m68k/sun3x/sbus.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/m68k/sun3x/sbus.c Tue May 11 18:57:14 1999 @@ -0,0 +1,44 @@ +/* + * SBus helper functions + * + * Sun3x don't have a sbus, but many of the used devices are also + * used on Sparc machines with sbus. To avoid having a lot of + * duplicate code, we provide necessary glue stuff to make using + * of the sbus driver code possible. + * + * (C) 1999 Thomas Bogendoerfer (tsbogend@alpha.franken.de) + */ + +#include +#include + +__initfunc(void sbus_init(void)) +{ + +} + +void *sparc_alloc_io (u32 address, void *virtual, int len, char *name, + u32 bus_type, int rdonly) +{ + return (void *)address; +} + +int prom_getintdefault(int node, char *property, int deflt) +{ + return deflt; +} + +int prom_getbool (int node, char *prop) +{ + return 1; +} + +void prom_printf(char *fmt, ...) +{ + +} + +void prom_halt (void) +{ + +} diff -ur --new-file old/linux/arch/m68k/sun3x/time.c new/linux/arch/m68k/sun3x/time.c --- old/linux/arch/m68k/sun3x/time.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/m68k/sun3x/time.c Wed May 12 17:50:08 1999 @@ -0,0 +1,82 @@ +/* + * linux/arch/m68k/sun3x/time.c + * + * Sun3x-specific time handling + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "time.h" + +#define M_CONTROL 0xf8 +#define M_SEC 0xf9 +#define M_MIN 0xfa +#define M_HOUR 0xfb +#define M_DAY 0xfc +#define M_DATE 0xfd +#define M_MONTH 0xfe +#define M_YEAR 0xff + +#define C_WRITE 0x80 +#define C_READ 0x40 +#define C_SIGN 0x20 +#define C_CALIB 0x1f + +#define BCD_TO_BIN(val) (((val)&15) + ((val)>>4)*10) + +/* Read the Mostek */ +void sun3x_gettod (int *yearp, int *monp, int *dayp, + int *hourp, int *minp, int *secp) +{ + volatile unsigned char *eeprom = (unsigned char *)SUN3X_EEPROM; + + /* Stop updates */ + *(eeprom + M_CONTROL) |= C_READ; + + /* Read values */ + *yearp = BCD_TO_BIN(*(eeprom + M_YEAR)); + *monp = BCD_TO_BIN(*(eeprom + M_MONTH)); + *dayp = BCD_TO_BIN(*(eeprom + M_DATE)); + *hourp = BCD_TO_BIN(*(eeprom + M_HOUR)); + *minp = BCD_TO_BIN(*(eeprom + M_MIN)); + *secp = BCD_TO_BIN(*(eeprom + M_SEC)); + + /* Restart updates */ + *(eeprom + M_CONTROL) &= ~C_READ; +} + +/* Not much we can do here */ +unsigned long sun3x_gettimeoffset (void) +{ + return 0L; +} + +static void sun3x_timer_tick(int irq, void *dev_id, struct pt_regs *regs) +{ + void (*vector)(int, void *, struct pt_regs *) = dev_id; + + /* Clear the pending interrupt - pulse the enable line low */ + disable_irq(5); + enable_irq(5); + + vector(irq, NULL, regs); +} + +__initfunc(void sun3x_sched_init(void (*vector)(int, void *, struct pt_regs *))) +{ + sys_request_irq(5, sun3x_timer_tick, IRQ_FLG_STD, "timer tick", vector); + + /* Pulse enable low to get the clock started */ + disable_irq(5); + enable_irq(5); +} diff -ur --new-file old/linux/arch/m68k/sun3x/time.h new/linux/arch/m68k/sun3x/time.h --- old/linux/arch/m68k/sun3x/time.h Thu Jan 1 01:00:00 1970 +++ new/linux/arch/m68k/sun3x/time.h Tue May 11 18:57:14 1999 @@ -0,0 +1,9 @@ +#ifndef SUN3X_TIME_H +#define SUN3X_TIME_H + +void sun3x_gettod (int *yearp, int *monp, int *dayp, + int *hourp, int *minp, int *secp); +unsigned long sun3x_gettimeoffset (void); +void sun3x_sched_init(void (*vector)(int, void *, struct pt_regs *)); + +#endif diff -ur --new-file old/linux/arch/mips/config.in new/linux/arch/mips/config.in --- old/linux/arch/mips/config.in Thu Jan 14 19:29:28 1999 +++ new/linux/arch/mips/config.in Mon Feb 1 21:03:20 1999 @@ -179,7 +179,7 @@ endmenu mainmenu_option next_comment - comment 'CD-ROM drivers (not for SCSI or IDE/ATAPI drives)' + 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 diff -ur --new-file old/linux/arch/mips/defconfig new/linux/arch/mips/defconfig --- old/linux/arch/mips/defconfig Tue Oct 20 22:52:54 1998 +++ new/linux/arch/mips/defconfig Thu Feb 25 19:46:47 1999 @@ -90,7 +90,6 @@ # CONFIG_PACKET is not set # CONFIG_NETLINK is not set # CONFIG_FIREWALL is not set -# CONFIG_NET_ALIAS is not set # CONFIG_FILTER is not set CONFIG_UNIX=y CONFIG_INET=y diff -ur --new-file old/linux/arch/mips/kernel/irixioctl.c new/linux/arch/mips/kernel/irixioctl.c --- old/linux/arch/mips/kernel/irixioctl.c Tue Oct 20 22:52:54 1998 +++ new/linux/arch/mips/kernel/irixioctl.c Sat May 8 20:14:01 1999 @@ -33,13 +33,15 @@ { struct file *filp; - if(fd >= NR_OPEN || !(filp = current->files->fd[fd])) + file = fcheck(fd); + if(!file) 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 -ur --new-file old/linux/arch/mips/kernel/sysirix.c new/linux/arch/mips/kernel/sysirix.c --- old/linux/arch/mips/kernel/sysirix.c Thu Nov 5 18:58:29 1998 +++ new/linux/arch/mips/kernel/sysirix.c Sat May 8 20:14:01 1999 @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -627,7 +628,6 @@ cli(); xtime.tv_sec = value; xtime.tv_usec = 0; - time_state = TIME_ERROR; time_maxerror = MAXPHASE; time_esterror = MAXPHASE; sti(); @@ -735,6 +735,7 @@ int error, i; /* We don't support this feature yet. */ + lock_kernel(); if(fs_type) { error = -EINVAL; goto out; @@ -777,7 +778,6 @@ asmlinkage int irix_fstatfs(unsigned int fd, struct irix_statfs *buf) { - struct dentry *dentry; struct inode *inode; struct statfs kbuf; mm_segment_t old_fs; @@ -788,25 +788,22 @@ error = verify_area(VERIFY_WRITE, buf, sizeof(struct irix_statfs)); if (error) goto out; - if (fd >= NR_OPEN || !(file = current->files->fd[fd])) { + if (!(file = fget(fd))) { error = -EBADF; goto out; } - if (!(dentry = file->f_dentry)) { + + if (!(inode = file->f_dentry->d_inode)) { error = -ENOENT; - goto out; - } - if (!(inode = dentry->d_inode)) { - error = -ENOENT; - goto out; + goto out_f; } if (!inode->i_sb) { error = -ENODEV; - goto out; + goto out_f; } if (!inode->i_sb->s_op->statfs) { error = -ENOSYS; - goto out; + goto out_f; } old_fs = get_fs(); set_fs(get_ds()); @@ -814,7 +811,7 @@ sizeof(struct statfs)); set_fs(old_fs); if (error) - goto out; + goto out_f; __put_user(kbuf.f_type, &buf->f_type); __put_user(kbuf.f_bsize, &buf->f_bsize); @@ -827,9 +824,9 @@ __put_user(0, &buf->f_fname[i]); __put_user(0, &buf->f_fpack[i]); } - error = 0; - dput(dentry); +out_f: + fput(file); out: unlock_kernel(); return error; @@ -1111,7 +1108,7 @@ lock_kernel(); if(!(flags & MAP_ANONYMOUS)) { - if(fd >= NR_OPEN || !(file = current->files->fd[fd])) { + if(!(file = fget(fd))) { retval = -EBADF; goto out; } @@ -1131,6 +1128,8 @@ flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); retval = do_mmap(file, addr, len, prot, flags, offset); + if (file) + fput(file); out: unlock_kernel(); @@ -1569,7 +1568,6 @@ asmlinkage int irix_fstatvfs(int fd, struct irix_statvfs *buf) { - struct dentry *dentry; struct inode *inode; mm_segment_t old_fs; struct statfs kbuf; @@ -1583,21 +1581,21 @@ error = verify_area(VERIFY_WRITE, buf, sizeof(struct irix_statvfs)); if (error) goto out; - if (fd >= NR_OPEN || !(file = current->files->fd[fd])) { + if (!(file = fget(fd))) { error = -EBADF; goto out; } - if (!(dentry = file->f_dentry)) { + if (!(inode = file->f_dentry->d_inode)) { error = -ENOENT; - goto out; + goto out_f; } - if (!(inode = dentry->d_inode)) { - error = -ENOENT; - goto out; + if (!inode->i_sb) { + error = -ENODEV; + goto out_f; } if (!inode->i_sb->s_op->statfs) { error = -ENOSYS; - goto out; + goto out_f; } old_fs = get_fs(); set_fs(get_ds()); @@ -1605,7 +1603,7 @@ sizeof(struct statfs)); set_fs(old_fs); if (error) - goto out; + goto out_f; __put_user(kbuf.f_bsize, &buf->f_bsize); __put_user(kbuf.f_frsize, &buf->f_frsize); @@ -1627,9 +1625,8 @@ for(i = 0; i < 32; i++) __put_user(0, &buf->f_fstr[i]); - error = 0; - - dput(dentry); +out_f: + fput(file); out: unlock_kernel(); return error; @@ -1727,7 +1724,7 @@ } if(!(flags & MAP_ANONYMOUS)) { - if(fd >= NR_OPEN || !(file = current->files->fd[fd])) { + if(!(file = fcheck(fd))) { error = -EBADF; goto out; } @@ -1813,6 +1810,7 @@ struct statfs kbuf; int error, i; + lock_kernel(); printk("[%s:%ld] Wheee.. irix_statvfs(%s,%p)\n", current->comm, current->pid, fname, buf); error = verify_area(VERIFY_WRITE, buf, sizeof(struct irix_statvfs)); @@ -1865,7 +1863,6 @@ asmlinkage int irix_fstatvfs64(int fd, struct irix_statvfs *buf) { - struct dentry *dentry; struct inode *inode; mm_segment_t old_fs; struct statfs kbuf; @@ -1879,21 +1876,21 @@ error = verify_area(VERIFY_WRITE, buf, sizeof(struct irix_statvfs)); if (error) goto out; - if (fd >= NR_OPEN || !(file = current->files->fd[fd])) { + if (!(file = fget(fd))) { error = -EBADF; goto out; } - if (!(dentry = file->f_dentry)) { + if (!(inode = file->f_dentry->d_inode)) { error = -ENOENT; - goto out; + goto out_f; } - if (!(inode = dentry->d_inode)) { - error = -ENOENT; - goto out; + if (!inode->i_sb) { + error = -ENODEV; + goto out_f; } if (!inode->i_sb->s_op->statfs) { error = -ENOSYS; - goto out; + goto out_f; } old_fs = get_fs(); set_fs(get_ds()); @@ -1901,7 +1898,7 @@ sizeof(struct statfs)); set_fs(old_fs); if (error) - goto out; + goto out_f; __put_user(kbuf.f_bsize, &buf->f_bsize); __put_user(kbuf.f_frsize, &buf->f_frsize); @@ -1922,10 +1919,8 @@ __put_user(kbuf.f_namelen, &buf->f_namemax); for(i = 0; i < 32; i++) __put_user(0, &buf->f_fstr[i]); - - error = 0; - - dput(dentry); +out_f: + fput(file); out: unlock_kernel(); return error; @@ -1995,7 +1990,6 @@ unsigned short reclen = ROUND_UP32(NAME_OFFSET32(dirent) + namlen + 1); int retval; - lock_kernel(); #ifdef DEBUG_GETDENTS printk("\nirix_filldir32[reclen<%d>namlen<%d>count<%d>]", reclen, namlen, buf->count); @@ -2021,14 +2015,12 @@ retval = 0; out: - unlock_kernel(); return retval; } asmlinkage int irix_ngetdents(unsigned int fd, void * dirent, unsigned int count, int *eob) { struct file *file; - struct dentry *dentry; struct inode *inode; struct irix_dirent32 *lastdirent; struct irix_dirent32_callback buf; @@ -2040,46 +2032,56 @@ current->pid, fd, dirent, count, eob); #endif error = -EBADF; - if (fd >= NR_OPEN || !(file = current->files->fd[fd])) + file = fget(fd); + if (!file) goto out; - dentry = file->f_dentry; - if (!dentry) - goto out; + inode = file->f_dentry->d_inode; + if (!inode) + goto out_putf; inode = dentry->d_inode; if (!inode) - goto out; + goto out_putf; - error = -ENOTDIR; - if (!file->f_op || !file->f_op->readdir) - goto out; - - error = -EFAULT; - if(!access_ok(VERIFY_WRITE, dirent, count) || - !access_ok(VERIFY_WRITE, eob, sizeof(*eob))) - goto out; - - __put_user(0, eob); buf.current_dir = (struct irix_dirent32 *) dirent; buf.previous = NULL; buf.count = count; buf.error = 0; + error = -ENOTDIR; + if (!file->f_op || !file->f_op->readdir) + goto out_putf; + + /* + * Get the inode's semaphore to prevent changes + * to the directory while we read it. + */ + down(&inode->i_sem); error = file->f_op->readdir(file, &buf, irix_filldir32); + up(&inode->i_sem); if (error < 0) - goto out; + goto out_putf; + error = buf.error; lastdirent = buf.previous; - if (!lastdirent) { - error = buf.error; - goto out; + if (lastdirent) { + put_user(file->f_pos, &lastdirent->d_off); + error = count - buf.count; } - lastdirent->d_off = (u32) file->f_pos; + + if (put_user(0, eob) < 0) { + error = EFAULT; + goto out_putf; + } + + #ifdef DEBUG_GETDENTS printk("eob=%d returning %d\n", *eob, count - buf.count); #endif error = count - buf.count; +out_putf: + fput(file); out: unlock_kernel(); return error; @@ -2111,7 +2113,6 @@ unsigned short reclen = ROUND_UP64(NAME_OFFSET64(dirent) + namlen + 1); int retval; - lock_kernel(); buf->error = -EINVAL; /* only used if we fail.. */ if (reclen > buf->count) { retval = -EINVAL; @@ -2132,14 +2133,12 @@ retval = 0; out: - unlock_kernel(); return retval; } asmlinkage int irix_getdents64(int fd, void *dirent, int cnt) { struct file *file; - struct dentry *dentry; struct inode *inode; struct irix_dirent64 *lastdirent; struct irix_dirent64_callback buf; @@ -2151,40 +2150,38 @@ current->pid, fd, dirent, cnt); #endif error = -EBADF; - if (fd >= NR_OPEN || !(file = current->files->fd[fd])) - goto out; - - dentry = file->f_dentry; - if (!dentry) + if (!(file = fget(fd))) goto out; - inode = dentry->d_inode; + inode = file->f_dentry->d_inode; if (!inode) - goto out; + goto out_f; error = -ENOTDIR; if (!file->f_op || !file->f_op->readdir) - goto out; + goto out_f; error = -EFAULT; if(!access_ok(VERIFY_WRITE, dirent, cnt)) - goto out; + goto out_f; error = -EINVAL; if(cnt < (sizeof(struct irix_dirent64) + 255)) - goto out; + goto out_f; buf.curr = (struct irix_dirent64 *) dirent; buf.previous = NULL; buf.count = cnt; buf.error = 0; + down(&inode->i_sem); error = file->f_op->readdir(file, &buf, irix_filldir64); + up(&inode->i_sem); if (error < 0) - goto out; + goto out_f; lastdirent = buf.previous; if (!lastdirent) { error = buf.error; - goto out; + goto out_f; } lastdirent->d_off = (u64) file->f_pos; #ifdef DEBUG_GETDENTS @@ -2192,6 +2189,8 @@ #endif error = cnt - buf.count; +out_f: + fput(file); out: unlock_kernel(); return error; @@ -2200,7 +2199,6 @@ asmlinkage int irix_ngetdents64(int fd, void *dirent, int cnt, int *eob) { struct file *file; - struct dentry *dentry; struct inode *inode; struct irix_dirent64 *lastdirent; struct irix_dirent64_callback buf; @@ -2212,42 +2210,40 @@ current->pid, fd, dirent, cnt); #endif error = -EBADF; - if (fd >= NR_OPEN || !(file = current->files->fd[fd])) - goto out; - - dentry = file->f_dentry; - if (!dentry) + if (!(file = fget(fd))) goto out; - inode = dentry->d_inode; + inode = file->f_dentry->d_inode; if (!inode) - goto out; + goto out_f; error = -ENOTDIR; if (!file->f_op || !file->f_op->readdir) - goto out; + goto out_f; error = -EFAULT; if(!access_ok(VERIFY_WRITE, dirent, cnt) || !access_ok(VERIFY_WRITE, eob, sizeof(*eob))) - goto out; + goto out_f; error = -EINVAL; if(cnt < (sizeof(struct irix_dirent64) + 255)) - goto out; + goto out_f; *eob = 0; buf.curr = (struct irix_dirent64 *) dirent; buf.previous = NULL; buf.count = cnt; buf.error = 0; + down(&inode->i_sem); error = file->f_op->readdir(file, &buf, irix_filldir64); + up(&inode->i_sem); if (error < 0) - goto out; + goto out_f; lastdirent = buf.previous; if (!lastdirent) { error = buf.error; - goto out; + goto out_f; } lastdirent->d_off = (u64) file->f_pos; #ifdef DEBUG_GETDENTS @@ -2255,6 +2251,8 @@ #endif error = cnt - buf.count; +out_f: + fput(file); out: unlock_kernel(); return error; diff -ur --new-file old/linux/arch/mips/kernel/time.c new/linux/arch/mips/kernel/time.c --- old/linux/arch/mips/kernel/time.c Tue Jan 19 19:19:48 1999 +++ new/linux/arch/mips/kernel/time.c Fri Mar 12 08:25:19 1999 @@ -260,7 +260,6 @@ xtime = *tv; time_adjust = 0; /* stop active adjtime() */ time_status |= STA_UNSYNC; - time_state = TIME_ERROR; /* p. 24, (a) */ time_maxerror = NTP_PHASE_LIMIT; time_esterror = NTP_PHASE_LIMIT; sti(); diff -ur --new-file old/linux/arch/mips/sgi/kernel/indy_timer.c new/linux/arch/mips/sgi/kernel/indy_timer.c --- old/linux/arch/mips/sgi/kernel/indy_timer.c Tue Oct 20 22:52:55 1998 +++ new/linux/arch/mips/sgi/kernel/indy_timer.c Fri Mar 12 08:25:24 1999 @@ -104,9 +104,10 @@ * absolutely sure we do this update within 500ms before the * next second starts, thus the following code. */ - 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 ((time_status & STA_UNSYNC) == 0 && + 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 diff -ur --new-file old/linux/arch/ppc/8xx_io/commproc.c new/linux/arch/ppc/8xx_io/commproc.c --- old/linux/arch/ppc/8xx_io/commproc.c Thu Oct 1 18:55:12 1998 +++ new/linux/arch/ppc/8xx_io/commproc.c Fri Mar 19 19:50:03 1999 @@ -111,7 +111,12 @@ */ ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cicr = (CICR_SCD_SCC4 | CICR_SCC_SCC3 | CICR_SCB_SCC2 | CICR_SCA_SCC1) | - ((CPM_INTERRUPT/2) << 13) | CICR_HP_MASK; + (((5)/2) << 13) | CICR_HP_MASK; + /* I hard coded the CPM interrupt to 5 above + * since the CPM_INTERRUPT define is relative to + * the linux irq structure not what the hardware + * belives. -- Cort + */ ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr = 0; /* Set our interrupt handler with the core CPU. */ diff -ur --new-file old/linux/arch/ppc/8xx_io/enet.c new/linux/arch/ppc/8xx_io/enet.c --- old/linux/arch/ppc/8xx_io/enet.c Mon Dec 21 17:37:20 1998 +++ new/linux/arch/ppc/8xx_io/enet.c Fri Apr 16 17:20:23 1999 @@ -1,5 +1,4 @@ /* - * $Id: enet.c,v 1.8 1998/11/15 19:58:07 cort Exp $ * Ethernet driver for Motorola MPC8xx. * Copyright (c) 1997 Dan Malek (dmalek@jlc.net) * @@ -22,6 +21,7 @@ * small packets. * */ +#include #include #include #include @@ -39,7 +39,7 @@ #include #include -#include +#include #include #include #include "commproc.h" @@ -49,7 +49,7 @@ * * The MPC8xx CPM performs the Ethernet processing on SCC1. It can use * an aribtrary number of buffers on byte boundaries, but must have at - * least two receive buffers to prevent constand overrun conditions. + * least two receive buffers to prevent constant overrun conditions. * * The buffer descriptors are allocated from the CPM dual port memory * with the data buffers allocated from host memory, just like all other @@ -94,6 +94,17 @@ * Port C, 15 - SCC1 Ethernet Tx Enable * Port C, 11 - SCC1 Ethernet Collision * Port C, 10 - SCC1 Ethernet Rx Enable + * + * The RPX-Lite (that I had :-), was the MPC850SAR. It has a control + * register to enable Ethernet functions in the 68160, and the Ethernet + * was controlled by SCC2. So, the pin I/O was like this: + * Port A, 13 - SCC2 Ethernet Rx + * Port A, 12 - SCC2 Ethernet Tx + * Port A, 6 (CLK2) - Ethernet Tx Clk + * Port A, 4 (CLK4) - Ethernet Rx Clk + * Port B, 18 (RTS2) - Ethernet Tx Enable + * Port C, 8 (CD2) - Ethernet Rx Enable + * Port C, 9 (CTS2) - SCC Ethernet Collision */ /* The number of Tx and Rx buffers. These are allocated from the page @@ -149,10 +160,26 @@ static struct net_device_stats *cpm_enet_get_stats(struct device *dev); static void set_multicast_list(struct device *dev); -/* GET THIS FROM THE VPD!!!! +/* Get this from various configuration locations (depends on board). */ /*static ushort my_enet_addr[] = { 0x0800, 0x3e26, 0x1559 };*/ +/* Right now, only the boards with an 860 use SCC1 for the Ethernet. + * All others use SCC2. We may need to make this board specific someday. + */ +#ifndef CONFIG_MPC860 +/*static ushort my_enet_addr[] = { 0x2700, 0x00ec, 0x1000 };*/ +#define CPM_CR_ENET CPM_CR_CH_SCC2 +#define PROFF_ENET PROFF_SCC2 +#define SCC_ENET 1 /* Index, not number! */ +#define CPMVEC_ENET CPMVEC_SCC2 +#else +#define CPM_CR_ENET CPM_CR_CH_SCC1 +#define PROFF_ENET PROFF_SCC1 +#define SCC_ENET 0 +#define CPMVEC_ENET CPMVEC_SCC1 +#endif + static int cpm_enet_open(struct device *dev) { @@ -178,7 +205,7 @@ /* Transmitter timeout, serious problems. */ if (dev->tbusy) { int tickssofar = jiffies - dev->trans_start; - if (tickssofar < 20) + if (tickssofar < 200) return 1; printk("%s: transmit timed out.\n", dev->name); cep->stats.tx_errors++; @@ -186,17 +213,17 @@ { int i; cbd_t *bdp; - printk(" Ring data dump: cur_tx %x%s cur_rx %x.\n", + printk(" Ring data dump: cur_tx %p%s cur_rx %p.\n", cep->cur_tx, cep->tx_full ? " (full)" : "", cep->cur_rx); bdp = cep->tx_bd_base; - for (i = 0 ; i < TX_RING_SIZE; i++) + for (i = 0 ; i < TX_RING_SIZE; i++, bdp++) printk("%04x %04x %08x\n", bdp->cbd_sc, bdp->cbd_datlen, bdp->cbd_bufaddr); bdp = cep->rx_bd_base; - for (i = 0 ; i < RX_RING_SIZE; i++) + for (i = 0 ; i < RX_RING_SIZE; i++, bdp++) printk("%04x %04x %08x\n", bdp->cbd_sc, bdp->cbd_datlen, @@ -263,7 +290,7 @@ /* Push the data cache so the CPM does not get stale memory * data. */ - /*flush_dcache_range(skb->data, skb->data + skb->len);*/ + flush_dcache_range(skb->data, skb->data + skb->len); /* Send it on its way. Tell CPM its ready, interrupt when done, * its the last BD of the frame, and to put the CRC on the end. @@ -300,7 +327,7 @@ cpm_enet_interrupt(void *dev_id) { struct device *dev = dev_id; - struct cpm_enet_private *cep; + volatile struct cpm_enet_private *cep; volatile cbd_t *bdp; ushort int_events; int must_restart; @@ -314,6 +341,7 @@ /* Get the interrupt events that caused us to be here. */ int_events = cep->sccp->scc_scce; + cep->sccp->scc_scce = int_events; must_restart = 0; /* Handle receive event in its own function. @@ -329,6 +357,7 @@ * I don't know if "normally" implies TXB is set when the buffer * descriptor is closed.....trial and error :-). */ +#if 0 if (int_events & SCCE_ENET_TXE) { /* Transmission errors. @@ -359,16 +388,46 @@ (BD_ENET_TX_LC | BD_ENET_TX_RL | BD_ENET_TX_UN)) must_restart = 1; } +#endif /* Transmit OK, or non-fatal error. Update the buffer descriptors. */ if (int_events & (SCCE_ENET_TXE | SCCE_ENET_TXB)) { +#if 1 + bdp = cep->dirty_tx; + while ((bdp->cbd_sc&BD_ENET_TX_READY)==0) { + if ((bdp==cep->cur_tx) && (cep->tx_full == 0)) + break; + + if (bdp->cbd_sc & BD_ENET_TX_HB) /* No heartbeat */ + cep->stats.tx_heartbeat_errors++; + if (bdp->cbd_sc & BD_ENET_TX_LC) /* Late collision */ + cep->stats.tx_window_errors++; + if (bdp->cbd_sc & BD_ENET_TX_RL) /* Retrans limit */ + cep->stats.tx_aborted_errors++; + if (bdp->cbd_sc & BD_ENET_TX_UN) /* Underrun */ + cep->stats.tx_fifo_errors++; + if (bdp->cbd_sc & BD_ENET_TX_CSL) /* Carrier lost */ + cep->stats.tx_carrier_errors++; + + + /* No heartbeat or Lost carrier are not really bad errors. + * The others require a restart transmit command. + */ + if (bdp->cbd_sc & + (BD_ENET_TX_LC | BD_ENET_TX_RL | BD_ENET_TX_UN)) { + must_restart = 1; + cep->stats.tx_errors++; + } + cep->stats.tx_packets++; +#else bdp = cep->dirty_tx; -#ifndef final_version +#if 1 if (bdp->cbd_sc & BD_ENET_TX_READY) printk("HEY! Enet xmit interrupt and TX_READY.\n"); #endif +#endif /* Deferred means some collisions occurred during transmit, * but we eventually sent the packet OK. */ @@ -406,9 +465,9 @@ } cep->dirty_tx = (cbd_t *)bdp; - } + } - if (must_restart) { + if (must_restart) { volatile cpm8xx_t *cp; /* Some transmit errors cause the transmitter to shut @@ -419,8 +478,9 @@ */ cp = cpmp; cp->cp_cpcr = - mk_cr_cmd(CPM_CR_CH_SCC1, CPM_CR_RESTART_TX) | CPM_CR_FLG; + mk_cr_cmd(CPM_CR_ENET, CPM_CR_RESTART_TX) | CPM_CR_FLG; while (cp->cp_cpcr & CPM_CR_FLG); + } } /* Check for receive busy, i.e. packets coming but no place to @@ -432,11 +492,6 @@ printk("CPM ENET: BSY can't happen.\n"); } - /* Write the SCC event register with the events we have handled - * to clear them. Maybe we should do this sooner? - */ - cep->sccp->scc_scce = int_events; - dev->interrupt = 0; return; @@ -576,7 +631,7 @@ int i, j; cep = (struct cpm_enet_private *)dev->priv; - /* Get pointer to SCC1 area in parameter RAM. + /* Get pointer to SCC area in parameter RAM. */ ep = (scc_enet_t *)dev->base_addr; @@ -627,7 +682,7 @@ /* Ask CPM to run CRC and set bit in * filter mask. */ - cpmp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SCC1, CPM_CR_SET_GADDR) | CPM_CR_FLG; + cpmp->cp_cpcr = mk_cr_cmd(CPM_CR_ENET, CPM_CR_SET_GADDR) | CPM_CR_FLG; /* this delay is necessary here -- Cort */ udelay(10); while (cpmp->cp_cpcr & CPM_CR_FLG); @@ -636,13 +691,15 @@ } } -/* Initialize the CPM Ethernet on SCC1. If EPPC-Bug loaded us, or performed +/* Initialize the CPM Ethernet on SCC. If EPPC-Bug loaded us, or performed * some other network I/O, a whole bunch of this has already been set up. * It is no big deal if we do it again, we just have to disable the * transmit and receive to make sure we don't catch the CPM with some * inconsistent control information. */ -__initfunc(int cpm_enet_init(void)) +/* until this gets cleared up -- Cort */ +int __init cpm_enet_init() { m8xx_enet_init(); } +int __init m8xx_enet_init(void) { struct device *dev; struct cpm_enet_private *cep; @@ -650,6 +707,7 @@ unsigned char *eap; unsigned long mem_addr; pte_t *pte; + bd_t *bd; volatile cbd_t *bdp; volatile cpm8xx_t *cp; volatile scc_t *sccp; @@ -660,6 +718,8 @@ immap = (immap_t *)IMAP_ADDR; /* and to internal registers */ + bd = (bd_t *)res; + /* Allocate some private information. */ cep = (struct cpm_enet_private *)kmalloc(sizeof(*cep), GFP_KERNEL); @@ -670,13 +730,13 @@ */ dev = init_etherdev(0, 0); - /* Get pointer to SCC1 area in parameter RAM. + /* Get pointer to SCC area in parameter RAM. */ - ep = (scc_enet_t *)(&cp->cp_dparam[PROFF_SCC1]); + ep = (scc_enet_t *)(&cp->cp_dparam[PROFF_ENET]); /* And another to the SCC register area. */ - sccp = (volatile scc_t *)(&cp->cp_scc[0]); + sccp = (volatile scc_t *)(&cp->cp_scc[SCC_ENET]); cep->sccp = (scc_t *)sccp; /* Keep the pointer handy */ /* Disable receive and transmit in case EPPC-Bug started it. @@ -686,6 +746,9 @@ /* Cookbook style from the MPC860 manual..... * Not all of this is necessary if EPPC-Bug has initialized * the network. + * So far we are lucky, all board configurations use the same + * pins, or at least the same I/O Port for these functions..... + * It can't last though...... */ /* Configure port A pins for Txd and Rxd. @@ -706,7 +769,7 @@ immap->im_ioport.iop_padir &= ~(PA_ENET_TCLK | PA_ENET_RCLK); /* Configure Serial Interface clock routing. - * First, clear all SCC1 bits to zero, then set the ones we want. + * First, clear all SCC bits to zero, then set the ones we want. */ cp->cp_sicr &= ~SICR_ENET_MASK; cp->cp_sicr |= SICR_ENET_CLKRT; @@ -731,13 +794,13 @@ cep->dirty_tx = cep->cur_tx = cep->tx_bd_base; cep->cur_rx = cep->rx_bd_base; - /* Issue init Rx BD command for SCC1. + /* Issue init Rx BD command for SCC. * Manual says to perform an Init Rx parameters here. We have * to perform both Rx and Tx because the SCC may have been * already running. * In addition, we have to do it later because we don't yet have * all of the BD control/status set properly. - cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SCC1, CPM_CR_INIT_RX) | CPM_CR_FLG; + cp->cp_cpcr = mk_cr_cmd(CPM_CR_ENET, CPM_CR_INIT_RX) | CPM_CR_FLG; while (cp->cp_cpcr & CPM_CR_FLG); */ @@ -781,20 +844,17 @@ ep->sen_iaddr3 = 0; ep->sen_iaddr4 = 0; - /* Set Ethernet station address. This must come from the - * Vital Product Data (VPD) EEPROM.....as soon as I get the - * I2C interface working..... + /* Set Ethernet station address. * - * Since we performed a diskless boot, the Ethernet controller + * If we performed a MBX diskless boot, the Ethernet controller * has been initialized and we copy the address out into our * own structure. */ -#ifdef notdef - ep->sen_paddrh = my_enet_addr[0]; - ep->sen_paddrm = my_enet_addr[1]; - ep->sen_paddrl = my_enet_addr[2]; -#else eap = (unsigned char *)&(ep->sen_paddrh); +#ifndef CONFIG_MBX + for (i=5; i>=0; i--) + *eap++ = dev->dev_addr[i] = bd->bi_enetaddr[i]; +#else for (i=5; i>=0; i--) dev->dev_addr[i] = *eap++; #endif @@ -854,7 +914,7 @@ * than the manual describes because we have just now finished * the BD initialization. */ - cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SCC1, CPM_CR_INIT_TRX) | CPM_CR_FLG; + cp->cp_cpcr = mk_cr_cmd(CPM_CR_ENET, CPM_CR_INIT_TRX) | CPM_CR_FLG; while (cp->cp_cpcr & CPM_CR_FLG); cep->skb_cur = cep->skb_dirty = 0; @@ -869,7 +929,7 @@ /* Install our interrupt handler. */ - cpm_install_handler(CPMVEC_SCC1, cpm_enet_interrupt, dev); + cpm_install_handler(CPMVEC_ENET, cpm_enet_interrupt, dev); /* Set GSMR_H to enable all normal operating modes. * Set GSMR_L to enable Ethernet to MC68160. @@ -884,12 +944,42 @@ /* Set processing mode. Use Ethernet CRC, catch broadcast, and * start frame search 22 bit times after RENA. */ - sccp->scc_pmsr = (SCC_PMSR_ENCRC | SCC_PMSR_BRO | SCC_PMSR_NIB22); + sccp->scc_pmsr = (SCC_PMSR_ENCRC | SCC_PMSR_NIB22); /* It is now OK to enable the Ethernet transmitter. - */ + * Unfortunately, there are board implementation differences here. + */ +#ifdef CONFIG_MBX immap->im_ioport.iop_pcpar |= PC_ENET_TENA; immap->im_ioport.iop_pcdir &= ~PC_ENET_TENA; +#endif + +#if defined(CONFIG_RPXLITE) || defined(CONFIG_RPXCLASSIC) + cp->cp_pbpar |= PB_ENET_TENA; + cp->cp_pbdir |= PB_ENET_TENA; + + /* And while we are here, set the configuration to enable ethernet. + */ + *((volatile uint *)RPX_CSR_ADDR) &= ~BCSR0_ETHLPBK; + *((volatile uint *)RPX_CSR_ADDR) |= + (BCSR0_ETHEN | BCSR0_COLTESTDIS | BCSR0_FULLDPLXDIS); +#endif + +#ifdef CONFIG_BSEIP + cp->cp_pbpar |= PB_ENET_TENA; + cp->cp_pbdir |= PB_ENET_TENA; + + /* BSE uses port B and C for PHY control. + */ + cp->cp_pbpar &= ~(PB_BSE_POWERUP | PB_BSE_FDXDIS); + cp->cp_pbdir |= (PB_BSE_POWERUP | PB_BSE_FDXDIS); + cp->cp_pbdat |= (PB_BSE_POWERUP | PB_BSE_FDXDIS); + + immap->im_ioport.iop_pcpar &= ~PC_BSE_LOOPBACK; + immap->im_ioport.iop_pcdir |= PC_BSE_LOOPBACK; + immap->im_ioport.iop_pcso &= ~PC_BSE_LOOPBACK; + immap->im_ioport.iop_pcdat &= ~PC_BSE_LOOPBACK; +#endif dev->base_addr = (unsigned long)ep; dev->priv = cep; @@ -913,3 +1003,4 @@ return 0; } + diff -ur --new-file old/linux/arch/ppc/Makefile new/linux/arch/ppc/Makefile --- old/linux/arch/ppc/Makefile Mon Dec 21 17:37:20 1998 +++ new/linux/arch/ppc/Makefile Fri Mar 19 19:50:03 1999 @@ -45,6 +45,7 @@ MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot MAKECOFFBOOT = $(MAKE) -C arch/$(ARCH)/coffboot MAKECHRPBOOT = $(MAKE) -C arch/$(ARCH)/chrpboot +MAKEMBXBOOT = $(MAKE) -C arch/$(ARCH)/mbxboot ifdef CONFIG_8xx SUBDIRS += arch/ppc/8xx_io @@ -63,10 +64,16 @@ BOOT_TARGETS = netboot znetboot zImage floppy install \ vmlinux.coff znetboot.initrd zImage.initrd vmlinux.coff.initrd +ifdef CONFIG_MBX +$(BOOT_TARGETS): $(CHECKS) vmlinux + @$(MAKECOFFBOOT) $@ + @$(MAKEMBXBOOT) $@ +else $(BOOT_TARGETS): $(CHECKS) vmlinux @$(MAKECOFFBOOT) $@ @$(MAKEBOOT) $@ @$(MAKECHRPBOOT) $@ +endif pmac_config: rm -f .config arch/ppc/defconfig @@ -100,10 +107,10 @@ @$(MAKECOFFBOOT) clean @$(MAKEBOOT) clean @$(MAKECHRPBOOT) clean + @$(MAKEMBXBOOT) clean archmrproper: archdep: $(MAKEBOOT) fastdep $(MAKECHRPBOOT) fastdep - diff -ur --new-file old/linux/arch/ppc/apus_defconfig new/linux/arch/ppc/apus_defconfig --- old/linux/arch/ppc/apus_defconfig Wed Dec 23 16:34:11 1998 +++ new/linux/arch/ppc/apus_defconfig Thu Feb 25 19:46:47 1999 @@ -100,7 +100,6 @@ # CONFIG_RTNETLINK is not set # CONFIG_NETLINK_DEV is not set # CONFIG_FIREWALL is not set -CONFIG_NET_ALIAS=y # CONFIG_FILTER is not set CONFIG_UNIX=y CONFIG_INET=y diff -ur --new-file old/linux/arch/ppc/boot/Makefile new/linux/arch/ppc/boot/Makefile --- old/linux/arch/ppc/boot/Makefile Mon Dec 21 17:37:20 1998 +++ new/linux/arch/ppc/boot/Makefile Thu Apr 29 21:39:01 1999 @@ -14,7 +14,7 @@ .s.o: $(AS) -o $*.o $< .c.o: - $(CC) $(CFLAGS) -DINITRD_OFFSET=$(IOFF) -DINITRD_SIZE=$(ISZ) -DZIMAGE_OFFSET=$(ZOFF) -DZIMAGE_SIZE=$(ZSZ) -DKERNELBASE=$(KERNELBASE) -c -o $*.o $< + $(CC) $(CFLAGS) -DINITRD_OFFSET=$(IOFF) -DINITRD_SIZE=$(ISZ) -DZIMAGE_OFFSET=$(ZOFF) -DZIMAGE_SIZE=$(ZSZ) -c -o $*.o $< .S.s: $(CC) -D__ASSEMBLY__ -traditional -E -o $*.o $< .S.o: @@ -25,17 +25,14 @@ IOFF = 0 ISZ = 0 -ifeq ($(CONFIG_ALL_PPC),y) -# yes, we want to build prep stuff -CONFIG_PREP = y -endif - -ifeq ($(CONFIG_MBX),y) -ZLINKFLAGS = -T ../vmlinux.lds -Ttext 0x00100000 +ifeq ($(CONFIG_SMP),y) +TFTPIMAGE=/tftpboot/zImage.prep.smp else -ZLINKFLAGS = -T ../vmlinux.lds -Ttext 0x00600000 +TFTPIMAGE=/tftpboot/zImage.prep endif +ZLINKFLAGS = -T ../vmlinux.lds -Ttext 0x00800000 + GZIP_FLAGS = -v9 OBJECTS := head.o misc.o ../coffboot/zlib.o @@ -43,19 +40,13 @@ OBJCOPY = $(CROSS_COMPILE)objcopy OBJCOPY_ARGS = -O elf32-powerpc -ifeq ($(CONFIG_MBX),y) -OBJECTS += mbxtty.o -CFLAGS += -DCONFIG_MBX -else -OBJECTS += vreset.o kbd.o +OBJECTS += vreset.o kbd.o of1275.o ifeq ($(CONFIG_SERIAL_CONSOLE),y) OBJECTS += ns16550.o endif -endif all: zImage -ifeq ($(CONFIG_PREP),y) zvmlinux.initrd: zvmlinux $(LD) $(ZLINKFLAGS) -o zvmlinux.initrd.tmp $(OBJECTS) $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \ @@ -66,54 +57,19 @@ -DINITRD_SIZE=`sh size $(OBJDUMP) zvmlinux.initrd initrd` \ -DZIMAGE_OFFSET=`sh offset $(OBJDUMP) zvmlinux.initrd image` \ -DZIMAGE_SIZE=`sh size $(OBJDUMP) zvmlinux.initrd image` \ - -DKERNELBASE=$(KERNELBASE) -c -o misc.o misc.c - $(LD) $(ZLINKFLAGS) -o zvmlinux.initrd.tmp $(OBJECTS) - $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \ - --add-section=initrd=ramdisk.image.gz \ - --add-section=image=../coffboot/vmlinux.gz \ - zvmlinux.initrd.tmp $@ - rm zvmlinux.initrd.tmp -endif -ifeq ($(CONFIG_MBX),y) -zvmlinux.initrd: zvmlinux - $(LD) $(ZLINKFLAGS) -o zvmlinux.initrd.tmp $(OBJECTS) - $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \ - --add-section=initrd=ramdisk.image.gz \ - --add-section=image=../coffboot/vmlinux.gz \ - zvmlinux.initrd.tmp zvmlinux.initrd - $(CC) $(CFLAGS) -DINITRD_OFFSET=`sh offset $(OBJDUMP) zvmlinux.initrd initrd` \ - -DINITRD_SIZE=`sh size $(OBJDUMP) zvmlinux.initrd initrd` \ - -DZIMAGE_OFFSET=`sh offset $(OBJDUMP) zvmlinux.initrd image` \ - -DZIMAGE_SIZE=`sh size $(OBJDUMP) zvmlinux.initrd image` \ - -DKERNELBASE=$(KERNELBASE) -c -o misc.o misc.c + -c -o misc.o misc.c $(LD) $(ZLINKFLAGS) -o zvmlinux.initrd.tmp $(OBJECTS) $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \ --add-section=initrd=ramdisk.image.gz \ --add-section=image=../coffboot/vmlinux.gz \ zvmlinux.initrd.tmp $@ rm zvmlinux.initrd.tmp -endif -ifeq ($(CONFIG_PREP),y) zImage: zvmlinux mkprep ./mkprep -pbp zvmlinux zImage -else -ifeq ($(CONFIG_MBX),y) -zImage: zvmlinux - ln -sf zvmlinux zImage -else -zImage: -endif -endif -ifeq ($(CONFIG_PREP),y) zImage.initrd: zvmlinux.initrd mkprep ./mkprep -pbp zvmlinux.initrd zImage.initrd -endif -ifeq ($(CONFIG_MBX),y) -zImage.initrd: zvmlinux.initrd - ln -sf zvmlinux.initrd zImage.initrd -endif zvmlinux: $(OBJECTS) ../coffboot/vmlinux.gz # @@ -128,7 +84,7 @@ # $(CC) $(CFLAGS) -DINITRD_OFFSET=0 -DINITRD_SIZE=0 \ -DZIMAGE_OFFSET=`sh offset $(OBJDUMP) zvmlinux image` \ - -DZIMAGE_SIZE=`sh size $(OBJDUMP) zvmlinux image` -DKERNELBASE=$(KERNELBASE) \ + -DZIMAGE_SIZE=`sh size $(OBJDUMP) zvmlinux image` \ -c -o misc.o misc.c $(LD) $(ZLINKFLAGS) -o zvmlinux.tmp $(OBJECTS) $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment --add-section=image=../coffboot/vmlinux.gz \ @@ -136,34 +92,16 @@ rm zvmlinux.tmp floppy: $(TOPDIR)/vmlinux zImage -ifeq ($(CONFIG_PREP),y) dd if=zImage of=/dev/fd0H1440 bs=64b -endif -ifeq ($(CONFIG_PREP),y) mkprep : mkprep.c - $(HOSTCC) -DKERNELBASE=$(KERNELBASE) -o mkprep mkprep.c -endif + $(HOSTCC) -o mkprep mkprep.c -ifeq ($(CONFIG_PREP),y) znetboot : zImage - cp zImage /tftpboot/zImage.prep -else -ifeq ($(CONFIG_MBX),y) -znetboot : zImage - cp zImage /tftpboot/zImage.mbx -else -znetboot : -endif -endif + cp zImage $(TFTPIMAGE) znetboot.initrd : zImage.initrd -ifeq ($(CONFIG_PREP),y) - cp zImage.initrd /tftpboot/zImage.prep -endif -ifeq ($(CONFIG_MBX),y) - cp zImage.initrd /tftpboot/zImage.mbx -endif + cp zImage.initrd $(TFTPIMAGE) clean: rm -f vmlinux* zvmlinux* mkprep zImage* diff -ur --new-file old/linux/arch/ppc/boot/head.S new/linux/arch/ppc/boot/head.S --- old/linux/arch/ppc/boot/head.S Wed Sep 30 19:14:16 1998 +++ new/linux/arch/ppc/boot/head.S Thu Apr 29 21:39:01 1999 @@ -1,4 +1,3 @@ -#include #include "../kernel/ppc_defs.h" #include "../kernel/ppc_asm.tmpl" #include @@ -7,43 +6,24 @@ .text /* - * $Id: head.S,v 1.26 1998/09/19 01:21:20 cort Exp $ + * $Id: head.S,v 1.31 1999/04/22 06:32:00 davem Exp $ * - * This code is loaded by the ROM loader at some arbitrary location. - * Move it to high memory so that it can load the kernel at 0x0000. - * - * The MBX EPPC-Bug understands ELF, so it loads us into the location - * specified in the header. This is a two step process. First, EPPC-Bug - * loads the file into the intermediate buffer memory location specified - * by the environment parameters. When it discovers this is an ELF - * binary, it relocates to the link address for us. Unfortunately, the - * header does not move with the file, so we have to find the - * intermediate load location and read the header from there. From - * information provided by Motorola (thank you), we know this intermediate - * location can be found from the NVRAM environment. - * All of these addresses must be somewhat carefully chosen to make sure - * we don't overlap the regions. I chose to load the kernel at 0, the - * compressed image loads at 0x00100000, and the MBX intermediate buffer - * was set to 0x00200000. Provided the loaded kernel image never grows - * over one megabyte (which I am going to ensure never happens :-), these - * will work fine. When we get called from EPPC-Bug, registers are: - * R1 - Stack pointer at a high memory address. - * R3 - Pointer to Board Information Block. - * R4 - Pointer to argument string. - * Interrupts masked, cache and MMU disabled. + * Boot loader philosophy: + * ROM loads us to some arbitrary location + * Move the boot code to the link address (8M) + * Call decompress_kernel() + * Relocate the initrd, zimage and residual data to 8M + * Decompress the kernel to 0 + * Jump to the kernel entry + * -- Cort */ - .globl start start: bl start_ start_: mr r11,r3 /* Save pointer to residual/board data */ - -#ifndef CONFIG_MBX - mfmsr r3 /* Turn off interrupts */ - li r4,0 - ori r4,r4,MSR_EE - andc r3,r3,r4 + mr r25,r5 /* Save OFW pointer */ + li r3,MSR_IP /* Establish default MSR value */ mtmsr r3 /* check if we need to relocate ourselves to the link addr or were we @@ -68,25 +48,6 @@ mr r7,r5 b start_ldr 1010: -#if 0 -/* Copy relocation code down to location 0x0100 (where we hope it's safe!) */ - mflr r3 - addi r5,r3,start_ldr-start_ - addi r3,r3,relocate-start_ - li r4,0x0100 - mtctr r4 - subi r3,r3,4 - subi r4,r4,4 -00: lwzu r6,4(r3) - stwu r6,4(r4) - cmp 0,r3,r5 - bne 00b - mflr r21 - mfctr r22 - mtlr r21 - mtctr r22 - bctr /* Jump to code */ -#endif /* * no matter where we're loaded, move ourselves to -Ttext address */ @@ -96,13 +57,8 @@ mr r8,r3 lis r4,start@h ori r4,r4,start@l -#if 0 - lis r5,edata@h - ori r5,r5,edata@l -#else lis r5,end@h ori r5,r5,end@l -#endif addi r5,r5,3 /* Round up - just in case */ sub r5,r5,r4 /* Compute # longwords to move */ srwi r5,r5,2 @@ -120,7 +76,6 @@ mtlr r3 /* Easiest way to do an absolute jump */ blr start_ldr: -#endif /* ndef CONFIG_MBX */ /* Clear all of BSS */ lis r3,edata@h ori r3,r3,edata@l @@ -140,31 +95,11 @@ li r2,0x000F /* Mask pointer to 16-byte boundary */ andc r1,r1,r2 /* Run loader */ -#ifdef CONFIG_MBX - mr r3, r11 - mr r21, r11 - bl serial_init /* Init MBX serial port */ - - lis r8, 0xfa200000@h /* Disable Ethernet SCC */ - li r0, 0 - stw r0, 0x0a00(r8) - - mr r11, r21 - lis r8,start@h - ori r8,r8,start@l - li r9,end@h - ori r9,r9,end@l - sub r7,r8,r9 - srwi r7,r7,2 -#define ILAP_ADDRESS 0xfa000020 - lis r8, ILAP_ADDRESS@h - lwz r8, ILAP_ADDRESS@l(r8) - addis r8, r8, 1 /* Add 64K */ -#endif mr r3,r8 /* Load point */ mr r4,r7 /* Program length */ mr r5,r6 /* Checksum */ mr r6,r11 /* Residual data */ + mr r7,r25 /* OFW interfaces */ bl decompress_kernel /* changed to use r3 (as firmware does) for kernel @@ -193,12 +128,24 @@ li r9,0x0 lwz r9,0(r9) mtlr r9 -#ifndef CONFIG_MBX li r9,0 lis r10,0xdeadc0de@h ori r10,r10,0xdeadc0de@l stw r10,0(r9) -#endif +/* + * The Radstone firmware maps PCI memory at 0xc0000000 using BAT2 + * so disable BATs before setting this to avoid a clash + */ + li r8,0 + mtspr DBAT0U,r8 + mtspr DBAT1U,r8 + mtspr DBAT2U,r8 + mtspr DBAT3U,r8 + mtspr IBAT0U,r8 + mtspr IBAT1U,r8 + mtspr IBAT2U,r8 + mtspr IBAT3U,r8 + blr hang: b hang @@ -269,7 +216,6 @@ _GLOBAL(flush_instruction_cache) mflr r5 bl flush_data_cache -#ifndef CONFIG_MBX mfspr r3,HID0 /* Caches are controlled by this register */ li r4,0 ori r4,r4,(HID0_ICE|HID0_ICFI) @@ -278,18 +224,12 @@ andc r3,r3,r4 ori r3,r3,HID0_ICE /* Enable cache */ mtspr HID0,r3 -#endif mtlr r5 blr #define NUM_CACHE_LINES 128*8 #define CACHE_LINE_SIZE 32 -#if 0 -cache_flush_buffer: - .space NUM_CACHE_LINES*CACHE_LINE_SIZE /* CAUTION! these need to match hardware */ -#else #define cache_flush_buffer 0x1000 -#endif /* * Flush data cache @@ -300,11 +240,7 @@ ori r3,r3,cache_flush_buffer@l li r4,NUM_CACHE_LINES mtctr r4 -#if 0 -00: dcbz 0,r3 /* Flush cache line with minimal BUS traffic */ -#else 00: lwz r4,0(r3) -#endif addi r3,r3,CACHE_LINE_SIZE /* Next line, please */ bdnz 00b 10: blr diff -ur --new-file old/linux/arch/ppc/boot/kbd.c new/linux/arch/ppc/boot/kbd.c --- old/linux/arch/ppc/boot/kbd.c Tue Jan 13 00:18:13 1998 +++ new/linux/arch/ppc/boot/kbd.c Thu Apr 29 21:39:01 1999 @@ -1,7 +1,6 @@ - #include -#include <../drivers/char/defkeymap.c> /* yeah I know it's bad */ +#include <../drivers/char/defkeymap.c> /* yeah I know it's bad -- Cort */ unsigned char shfts, ctls, alts, caps; @@ -119,7 +118,7 @@ } break; } - if (brk) return (0); /* Ignore initial 'key up' codes */ + if (brk) return (-1); /* Ignore initial 'key up' codes */ goto loop; } @@ -128,6 +127,11 @@ unsigned char c; int i; + /* flush input queue */ + while ((inb(KBSTATP) & KBINRDY)) + { + (void)inb(KBDATAP); + } /* Send self-test */ while (inb(KBSTATP) & KBOUTRDY) ; outb(KBSTATP,0xAA); @@ -144,22 +148,63 @@ while (inb(KBSTATP) & KBOUTRDY) ; outb(KBDATAP,0x45); for (i = 0; i < 10000; i++) udelay(1); + + while (inb(KBSTATP) & KBOUTRDY) ; + outb(KBSTATP,0x20); + while ((inb(KBSTATP) & KBINRDY) == 0) ; /* wait input ready */ + if (! (inb(KBDATAP) & 0x40)) { + /* + * Quote from PS/2 System Reference Manual: + * + * "Address hex 0060 and address hex 0064 should be + * written only when the input-buffer-full bit and + * output-buffer-full bit in the Controller Status + * register are set 0." (KBINRDY and KBOUTRDY) + */ + + while (inb(KBSTATP) & (KBINRDY | KBOUTRDY)) ; + outb(KBDATAP,0xF0); + while (inb(KBSTATP) & (KBINRDY | KBOUTRDY)) ; + outb(KBDATAP,0x01); + } + while (inb(KBSTATP) & KBOUTRDY) ; outb(KBSTATP,0xAE); } +/* We have to actually read the keyboard when CRT_tstc is called, + * since the pending data might be a key release code, and therefore + * not valid data. In this case, kbd() will return -1, even though there's + * data to be read. Of course, we might actually read a valid key press, + * in which case it gets queued into key_pending for use by CRT_getc. + */ + static int kbd_reset = 0; +static int key_pending = -1; + int CRT_getc(void) { int c; if (!kbd_reset) {kbdreset(); kbd_reset++; } + + if (key_pending != -1) { + c = key_pending; + key_pending = -1; + return c; + } else { while ((c = kbd(0)) == 0) ; - return(c); + return c; + } } int CRT_tstc(void) { if (!kbd_reset) {kbdreset(); kbd_reset++; } - return ((inb(KBSTATP) & KBINRDY) != 0); + + while (key_pending == -1 && ((inb(KBSTATP) & KBINRDY) != 0)) { + key_pending = kbd(1); + } + + return (key_pending != -1); } diff -ur --new-file old/linux/arch/ppc/boot/mbxtty.c new/linux/arch/ppc/boot/mbxtty.c --- old/linux/arch/ppc/boot/mbxtty.c Thu Oct 1 18:55:13 1998 +++ new/linux/arch/ppc/boot/mbxtty.c Thu Jan 1 01:00:00 1970 @@ -1,201 +0,0 @@ - - -/* Minimal serial functions needed to send messages out the serial - * port on the MBX console. - * - * The MBX uxes SMC1 for the serial port. We reset the port and use - * only the first BD that EPPC-Bug set up as a character FIFO. - * - * Later versions (at least 1.4, maybe earlier) of the MBX EPPC-Bug - * use COM1 instead of SMC1 as the console port. This kinda sucks - * for the rest of the kernel, so here we force the use of SMC1 again. - * I f**ked around for a day trying to figure out how to make EPPC-Bug - * use SMC1, but gave up and decided to fix it here. - */ -#include -#include -#ifdef CONFIG_MBX -#include -#endif -#ifdef CONFIG_FADS -#include -#endif -#include "../8xx_io/commproc.h" - -#ifdef CONFIG_MBX -#define MBX_CSR1 ((volatile u_char *)0xfa100000) -#define CSR1_COMEN (u_char)0x02 -#endif - -static cpm8xx_t *cpmp = (cpm8xx_t *)&(((immap_t *)IMAP_ADDR)->im_cpm); - -void -serial_init(bd_t *bd) -{ - volatile smc_t *sp; - volatile smc_uart_t *up; - volatile cbd_t *tbdf, *rbdf; - volatile cpm8xx_t *cp; - uint dpaddr, memaddr; - - cp = cpmp; - sp = (smc_t*)&(cp->cp_smc[0]); - up = (smc_uart_t *)&cp->cp_dparam[PROFF_SMC1]; - - /* Disable transmitter/receiver. - */ - sp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN); - -#ifdef CONFIG_MBX - if (*MBX_CSR1 & CSR1_COMEN) { - /* COM1 is enabled. Initialize SMC1 and use it for - * the console port. - */ - - /* Enable SDMA. - */ - ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sdcr = 1; - - /* Use Port B for SMCs instead of other functions. - */ - cp->cp_pbpar |= 0x00000cc0; - cp->cp_pbdir &= ~0x00000cc0; - cp->cp_pbodr &= ~0x00000cc0; - - /* Allocate space for two buffer descriptors in the DP ram. - * For now, this address seems OK, but it may have to - * change with newer versions of the firmware. - */ - dpaddr = 0x0800; - - /* Grab a few bytes from the top of memory. EPPC-Bug isn't - * running any more, so we can do this. - */ - memaddr = (bd->bi_memsize - 32) & ~15; - - /* Set the physical address of the host memory buffers in - * the buffer descriptors. - */ - rbdf = (cbd_t *)&cp->cp_dpmem[dpaddr]; - rbdf->cbd_bufaddr = memaddr; - rbdf->cbd_sc = 0; - tbdf = rbdf + 1; - tbdf->cbd_bufaddr = memaddr+4; - tbdf->cbd_sc = 0; - - /* Set up the uart parameters in the parameter ram. - */ - up->smc_rbase = dpaddr; - up->smc_tbase = dpaddr+sizeof(cbd_t); - up->smc_rfcr = SMC_EB; - up->smc_tfcr = SMC_EB; - - /* Set UART mode, 8 bit, no parity, one stop. - * Enable receive and transmit. - */ - sp->smc_smcmr = smcr_mk_clen(9) | SMCMR_SM_UART; - - /* Mask all interrupts and remove anything pending. - */ - sp->smc_smcm = 0; - sp->smc_smce = 0xff; - - /* Set up the baud rate generator. - * See 8xx_io/commproc.c for details. - */ - cp->cp_simode = 0x10000000; - cp->cp_brgc1 = - ((((bd->bi_intfreq * 1000000)/16) / 9600) << 1) | CPM_BRG_EN; - - /* Enable SMC1 for console output. - */ - *MBX_CSR1 &= ~CSR1_COMEN; - } - else { -#endif - /* SMC1 is used as console port. - */ - tbdf = (cbd_t *)&cp->cp_dpmem[up->smc_tbase]; - rbdf = (cbd_t *)&cp->cp_dpmem[up->smc_rbase]; - - /* Issue a stop transmit, and wait for it. - */ - cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SMC1, - CPM_CR_STOP_TX) | CPM_CR_FLG; - while (cp->cp_cpcr & CPM_CR_FLG); -#ifdef CONFIG_MBX - } -#endif - - /* Make the first buffer the only buffer. - */ - tbdf->cbd_sc |= BD_SC_WRAP; - rbdf->cbd_sc |= BD_SC_EMPTY | BD_SC_WRAP; - - /* Single character receive. - */ - up->smc_mrblr = 1; - up->smc_maxidl = 0; - - /* Initialize Tx/Rx parameters. - */ - cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SMC1, CPM_CR_INIT_TRX) | CPM_CR_FLG; - while (cp->cp_cpcr & CPM_CR_FLG); - - /* Enable transmitter/receiver. - */ - sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN; -} - -void -serial_putchar(const char c) -{ - volatile cbd_t *tbdf; - volatile char *buf; - volatile smc_uart_t *up; - - up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_SMC1]; - tbdf = (cbd_t *)&cpmp->cp_dpmem[up->smc_tbase]; - - /* Wait for last character to go. - */ - buf = (char *)tbdf->cbd_bufaddr; - while (tbdf->cbd_sc & BD_SC_READY); - - *buf = c; - tbdf->cbd_datlen = 1; - tbdf->cbd_sc |= BD_SC_READY; -} - -char -serial_getc() -{ - volatile cbd_t *rbdf; - volatile char *buf; - volatile smc_uart_t *up; - char c; - - up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_SMC1]; - rbdf = (cbd_t *)&cpmp->cp_dpmem[up->smc_rbase]; - - /* Wait for character to show up. - */ - buf = (char *)rbdf->cbd_bufaddr; - while (rbdf->cbd_sc & BD_SC_EMPTY); - c = *buf; - rbdf->cbd_sc |= BD_SC_EMPTY; - - return(c); -} - -int -serial_tstc() -{ - volatile cbd_t *rbdf; - volatile smc_uart_t *up; - - up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_SMC1]; - rbdf = (cbd_t *)&cpmp->cp_dpmem[up->smc_rbase]; - - return(!(rbdf->cbd_sc & BD_SC_EMPTY)); -} diff -ur --new-file old/linux/arch/ppc/boot/misc.c new/linux/arch/ppc/boot/misc.c --- old/linux/arch/ppc/boot/misc.c Mon Dec 21 17:37:20 1998 +++ new/linux/arch/ppc/boot/misc.c Tue May 11 17:24:32 1999 @@ -1,7 +1,7 @@ /* * misc.c * - * $Id: misc.c,v 1.53 1998/12/15 17:40:15 cort Exp $ + * $Id: misc.c,v 1.64 1999/04/30 05:52:46 cort Exp $ * * Adapted for PowerPC by Gary Thomas * @@ -17,13 +17,7 @@ #include #include #include -#ifdef CONFIG_MBX -#include -#endif -#ifdef CONFIG_FADS -#include -#endif -#if defined(CONFIG_SERIAL_CONSOLE) && !defined(CONFIG_MBX) +#if defined(CONFIG_SERIAL_CONSOLE) #include "ns16550.h" struct NS16550 *com_port; #endif /* CONFIG_SERIAL_CONSOLE */ @@ -37,30 +31,18 @@ */ char *avail_ram; char *end_avail; +extern char _end[]; -/* Because of the limited amount of memory on the MBX, it presents - * loading problems. The biggest is that we load this boot program - * into a relatively low memory address, and the Linux kernel Bss often - * extends into this space when it get loaded. When the kernel starts - * and zeros the BSS space, it also writes over the information we - * save here and pass to the kernel (command line and board info). - * On the MBX we grab some known memory holes to hold this information. - */ -char cmd_preset[] = "console=tty0 console=ttyS0,9600n8"; -char cmd_buf[256]; -char *cmd_line = cmd_buf; - -#if defined(CONFIG_MBX) || defined(CONFIG_FADS) -char *root_string = "root=/dev/nfs"; -char *nfsaddrs_string = "nfsaddrs="; -char *nfsroot_string = "nfsroot="; -char *defroot_string = "/sys/mbxroot"; -int do_ipaddrs(char **cmd_cp, int echo); -void do_nfsroot(char **cmd_cp, char *dp); -int strncmp(const char * cs,const char * ct,size_t count); -char *strrchr(const char * s, int c); +#ifdef CONFIG_CMDLINE +#define CMDLINE CONFIG_CMDLINE +#else +#define CMDLINE ""; #endif +char cmd_preset[] = CMDLINE; +char cmd_buf[256]; +char *cmd_line = cmd_buf; +int keyb_present = 1; /* keyboard controller is present by default */ RESIDUAL hold_resid_buf; RESIDUAL *hold_residual = &hold_resid_buf; unsigned long initrd_start = 0, initrd_end = 0; @@ -78,6 +60,8 @@ void * memcpy(void * __dest, __const void * __src, int __n); void gunzip(void *, int, unsigned char *, int *); +static int _cvt(unsigned long val, char *buf, long radix, char *digits); +unsigned char inb(int); void pause() { @@ -90,7 +74,6 @@ while(1); } -#if !defined(CONFIG_MBX) && !defined(CONFIG_FADS) static void clear_screen() { int i, j; @@ -113,8 +96,11 @@ tstc(void) { -#if defined(CONFIG_SERIAL_CONSOLE) && !defined(CONFIG_MBX) - return (CRT_tstc() || NS16550_tstc(com_port)); +#if defined(CONFIG_SERIAL_CONSOLE) + if (keyb_present) + return (CRT_tstc() || NS16550_tstc(com_port)); + else + NS16550_tstc(com_port); #else return (CRT_tstc() ); #endif /* CONFIG_SERIAL_CONSOLE */ @@ -123,10 +109,11 @@ getc(void) { while (1) { -#if defined(CONFIG_SERIAL_CONSOLE) && !defined(CONFIG_MBX) +#if defined(CONFIG_SERIAL_CONSOLE) if (NS16550_tstc(com_port)) return (NS16550_getc(com_port)); #endif /* CONFIG_SERIAL_CONSOLE */ - if (CRT_tstc()) return (CRT_getc()); + if (keyb_present) + if (CRT_tstc()) return (CRT_getc()); } } @@ -135,7 +122,7 @@ { int x,y; -#if defined(CONFIG_SERIAL_CONSOLE) && !defined(CONFIG_MBX) +#if defined(CONFIG_SERIAL_CONSOLE) NS16550_putc(com_port, c); if ( c == '\n' ) NS16550_putc(com_port, '\r'); #endif /* CONFIG_SERIAL_CONSOLE */ @@ -149,6 +136,8 @@ scroll(); y--; } + } else if (c == '\r') { + x = 0; } else if (c == '\b') { if (x > 0) { x--; @@ -179,7 +168,7 @@ y = orig_y; while ( ( c = *s++ ) != '\0' ) { -#if defined(CONFIG_SERIAL_CONSOLE) && !defined(CONFIG_MBX) +#if defined(CONFIG_SERIAL_CONSOLE) NS16550_putc(com_port, c); if ( c == '\n' ) NS16550_putc(com_port, '\r'); #endif /* CONFIG_SERIAL_CONSOLE */ @@ -206,42 +195,11 @@ } } + cursor(x, y); + orig_x = x; orig_y = y; } -#else -/* The MBX is just the serial port. -*/ -tstc(void) -{ - return (serial_tstc()); -} - -getc(void) -{ - while (1) { - if (serial_tstc()) return (serial_getc()); - } -} - -void -putc(const char c) -{ - serial_putchar(c); -} - -void puts(const char *s) -{ - char c; - - while ( ( c = *s++ ) != '\0' ) { - serial_putchar(c); - if ( c == '\n' ) - serial_putchar('\r'); - } -} - -#endif /* CONFIG_MBX */ void * memcpy(void * __dest, __const void * __src, int __n) @@ -354,7 +312,8 @@ unsigned char sanity[0x2000]; unsigned long -decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, RESIDUAL *residual) +decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, + RESIDUAL *residual, void *OFW_interface) { int timer; extern unsigned long start; @@ -362,9 +321,13 @@ unsigned long i; BATU *u; BATL *l; -#if defined(CONFIG_MBX) || defined(CONFIG_KB) - char *dp; -#endif + unsigned long TotalMemory; + unsigned long orig_MSR; + int dev_handle; + int mem_info[2]; + int res, size; + unsigned char board_type; + unsigned char base_mod; lines = 25; cols = 80; @@ -372,7 +335,6 @@ orig_y = 24; -#if !defined(CONFIG_MBX) && !defined(CONFIG_FADS) /* * IBM's have the MMU on, so we have to disable it or * things get really unhappy in the kernel when @@ -381,42 +343,79 @@ */ flush_instruction_cache(); _put_HID0(_get_HID0() & ~0x0000C000); - _put_MSR(_get_MSR() & ~0x0030); - vga_init(0xC0000000); + _put_MSR((orig_MSR = _get_MSR()) & ~0x0030); -#if defined(CONFIG_SERIAL_CONSOLE) && !defined(CONFIG_MBX) +#if defined(CONFIG_SERIAL_CONSOLE) com_port = (struct NS16550 *)NS16550_init(0); #endif /* CONFIG_SERIAL_CONSOLE */ + vga_init(0xC0000000); if (residual) - memcpy(hold_residual,residual,sizeof(RESIDUAL)); -#else /* CONFIG_MBX */ - - /* Grab some space for the command line and board info. Since - * we no longer use the ELF header, but it was loaded, grab - * that space. - */ - cmd_line = (char *)(load_addr - 0x10000); - hold_residual = (RESIDUAL *)(cmd_line + sizeof(cmd_buf)); - /* copy board data */ - if (residual) - memcpy(hold_residual,residual,sizeof(bd_t)); -#endif /* CONFIG_MBX */ + { + /* Is this Motorola PPCBug? */ + if ((1 & residual->VitalProductData.FirmwareSupports) && + (1 == residual->VitalProductData.FirmwareSupplier)) { + board_type = inb(0x800) & 0xF0; - /* MBX/prep sometimes put the residual/board info at the end of mem - * assume 16M for now -- Cort - * To boot on standard MBX boards with 4M, we can't use initrd, - * and we have to assume less memory. -- Dan - */ - if ( INITRD_OFFSET ) - end_avail = (char *)0x01000000; - else - end_avail = (char *)0x00400000; + /* If this is genesis 2 board then check for no + * keyboard controller and more than one processor. + */ + if (board_type == 0xe0) { + base_mod = inb(0x803); + /* if a MVME2300/2400 or a Sitka then no keyboard */ + if((base_mod == 0x9) || (base_mod == 0xF9) || + (base_mod == 0xE1)) { + keyb_present = 0; /* no keyboard */ + } + } + } + memcpy(hold_residual,residual,sizeof(RESIDUAL)); + } else { + /* Assume 32M in the absence of more info... */ + TotalMemory = 0x02000000; + /* + * This is a 'best guess' check. We want to make sure + * we don't try this on a PReP box without OF + * -- Cort + */ + while (OFW_interface && ((unsigned long)OFW_interface < 0x10000000) ) + { + /* The MMU needs to be on when we call OFW */ + _put_MSR(orig_MSR); + of_init(OFW_interface); + + /* get handle to memory description */ + res = of_finddevice("/memory@0", + &dev_handle); + // puthex(res); puts("\n"); + if (res) break; + + /* get the info */ + // puts("get info = "); + res = of_getprop(dev_handle, + "reg", + mem_info, + sizeof(mem_info), + &size); + // puthex(res); puts(", info = "); puthex(mem_info[0]); + // puts(" "); puthex(mem_info[1]); puts("\n"); + if (res) break; + + TotalMemory = mem_info[1]; + break; + } + hold_residual->TotalMemory = TotalMemory; + residual = hold_residual; + /* Turn MMU back off */ + _put_MSR(orig_MSR & ~0x0030); + } - /* let residual data tell us it's higher */ - if ( (unsigned long)residual > 0x00800000 ) - end_avail = (char *)PAGE_ALIGN((unsigned long)residual); + /* assume the chunk below 8M is free */ + end_avail = (char *)0x00800000; + /* tell the user where we were loaded at and where we + * were relocated to for debugging this process + */ puts("loaded at: "); puthex(load_addr); puts(" "); puthex((unsigned long)(load_addr + (4*num_words))); puts("\n"); if ( (unsigned long)load_addr != (unsigned long)&start ) @@ -431,20 +430,12 @@ { puts("board data at: "); puthex((unsigned long)residual); puts(" "); -#if defined(CONFIG_MBX) || defined(CONFIG_FADS) - puthex((unsigned long)((unsigned long)residual + sizeof(bd_t))); -#else puthex((unsigned long)((unsigned long)residual + sizeof(RESIDUAL))); -#endif puts("\n"); puts("relocated to: "); puthex((unsigned long)hold_residual); puts(" "); -#if defined(CONFIG_MBX) || defined(CONFIG_FADS) - puthex((unsigned long)((unsigned long)hold_residual + sizeof(bd_t))); -#else puthex((unsigned long)((unsigned long)hold_residual + sizeof(RESIDUAL))); -#endif puts("\n"); } @@ -460,33 +451,16 @@ initrd_end = INITRD_SIZE + initrd_start; /* - * setup avail_ram - this is the first part of ram usable - * by the uncompress code. -- Cort + * Find a place to stick the zimage and initrd and + * relocate them if we have to. -- Cort */ - avail_ram = (char *)PAGE_ALIGN((unsigned long)zimage_start+zimage_size); - if ( ((load_addr+(num_words*4)) > (unsigned long) avail_ram) - && (load_addr <= 0x01000000) ) - avail_ram = (char *)(load_addr+(num_words*4)); - if ( (((unsigned long)&start+(num_words*4)) > (unsigned long) avail_ram) - && (load_addr <= 0x01000000) ) - avail_ram = (char *)((unsigned long)&start+(num_words*4)); - - /* relocate zimage */ + avail_ram = (char *)PAGE_ALIGN((unsigned long)_end); puts("zimage at: "); puthex((unsigned long)zimage_start); puts(" "); puthex((unsigned long)(zimage_size+zimage_start)); puts("\n"); - /* - * don't relocate the zimage if it was loaded above 16M since - * things get weird if we try to relocate -- Cort - * We don't relocate zimage on a base MBX board because of - * insufficient memory. In this case we don't have initrd either, - * so use that as an indicator. -- Dan - */ - if (( (unsigned long)zimage_start <= 0x01000000 ) && initrd_start) + if ( (unsigned long)zimage_start <= 0x00800000 ) { - memcpy ((void *)PAGE_ALIGN(-PAGE_SIZE+(unsigned long)end_avail-zimage_size), - (void *)zimage_start, zimage_size ); - zimage_start = (char *)PAGE_ALIGN(-PAGE_SIZE+(unsigned long)end_avail-zimage_size); - end_avail = (char *)zimage_start; + memcpy( (void *)avail_ram, (void *)zimage_start, zimage_size ); + zimage_start = (char *)avail_ram; puts("relocated to: "); puthex((unsigned long)zimage_start); puts(" "); puthex((unsigned long)zimage_size+(unsigned long)zimage_start); @@ -498,44 +472,24 @@ { puts("initrd at: "); puthex(initrd_start); puts(" "); puthex(initrd_end); puts("\n"); - /* - * Memory is really tight on the MBX (we can assume 4M) - * so put the initrd at the TOP of ram, and set end_avail - * to right after that. - * - * I should do something like this for prep, too and keep - * a variable end_of_DRAM to keep track of what we think the - * max ram is. - * -- Cort - */ -#if 0 - memcpy ((void *)PAGE_ALIGN(-PAGE_SIZE+(unsigned long)end_avail-INITRD_SIZE), - (void *)initrd_start, - INITRD_SIZE ); - initrd_start = PAGE_ALIGN(-PAGE_SIZE+(unsigned long)end_avail-INITRD_SIZE); +#ifdef OMIT + avail_ram = (char *)PAGE_ALIGN( + (unsigned long)zimage_size+(unsigned long)zimage_start); + memcpy ((void *)avail_ram, (void *)initrd_start, INITRD_SIZE ); + initrd_start = (unsigned long)avail_ram; initrd_end = initrd_start + INITRD_SIZE; - end_avail = (char *)initrd_start; puts("relocated to: "); puthex(initrd_start); puts(" "); puthex(initrd_end); puts("\n"); -#endif +#endif } -#ifndef CONFIG_MBX - /* this is safe, just use it */ - /* I don't know why it didn't work for me on the MBX with 20 MB - * memory. I guess something was saved up there, but I can't - * figure it out......we are running on luck. -- Dan. - */ avail_ram = (char *)0x00400000; - end_avail = (char *)0x00600000; -#endif + end_avail = (char *)0x00800000; puts("avail ram: "); puthex((unsigned long)avail_ram); puts(" "); puthex((unsigned long)end_avail); puts("\n"); - -#if !defined(CONFIG_MBX) && !defined(CONFIG_FADS) - CRT_tstc(); /* Forces keyboard to be initialized */ -#endif + if (keyb_present) + CRT_tstc(); /* Forces keyboard to be initialized */ puts("\nLinux/PPC load: "); timer = 0; @@ -550,13 +504,6 @@ cp--; puts("\b \b"); } -#ifdef CONFIG_MBX - } else if (ch == '?') { - if (!do_ipaddrs(&cp, 1)) { - *cp++ = ch; - putc(ch); - } -#endif } else { *cp++ = ch; putc(ch); @@ -567,32 +514,6 @@ udelay(1000); /* 1 msec */ } *cp = 0; -#ifdef CONFIG_MBX - /* The MBX does not currently have any default boot strategy. - * If the command line is not filled in, we will automatically - * create the default network boot. - */ - if (cmd_line[0] == 0) { - dp = root_string; - while (*dp != 0) - *cp++ = *dp++; - *cp++ = ' '; - - dp = nfsaddrs_string; - while (*dp != 0) - *cp++ = *dp++; - dp = cp; - do_ipaddrs(&cp, 0); - *cp++ = ' '; - - /* Add the server address to the root file system path. - */ - dp = strrchr(dp, ':'); - dp++; - do_nfsroot(&cp, dp); - *cp = 0; - } -#endif puts("\n"); /* mappings on early boot can only handle 16M */ @@ -611,150 +532,6 @@ return (unsigned long)hold_residual; } -#ifdef CONFIG_MBX -int -do_ipaddrs(char **cmd_cp, int echo) -{ - char *cp, *ip, ch; - unsigned char ipd; - int i, j, retval; - - /* We need to create the string: - * : - */ - cp = *cmd_cp; - retval = 0; - - if ((cp - 9) >= cmd_line) { - if (strncmp(cp - 9, "nfsaddrs=", 9) == 0) { - ip = (char *)0xfa000060; - retval = 1; - for (j=0; j<2; j++) { - for (i=0; i<4; i++) { - ipd = *ip++; - - ch = ipd/100; - if (ch) { - ch += '0'; - if (echo) - putc(ch); - *cp++ = ch; - ipd -= 100 * (ch - '0'); - } - - ch = ipd/10; - if (ch) { - ch += '0'; - if (echo) - putc(ch); - *cp++ = ch; - ipd -= 10 * (ch - '0'); - } - - ch = ipd + '0'; - if (echo) - putc(ch); - *cp++ = ch; - - ch = '.'; - if (echo) - putc(ch); - *cp++ = ch; - } - - /* At the end of the string, remove the - * '.' and replace it with a ':'. - */ - *(cp - 1) = ':'; - if (echo) { - putc('\b'); putc(':'); - } - } - - /* At the end of the second string, remove the - * '.' from both the command line and the - * screen. - */ - --cp; - putc('\b'); putc(' '); putc('\b'); - } - } - *cmd_cp = cp; - return(retval); -} - -void -do_nfsroot(char **cmd_cp, char *dp) -{ - char *cp, *rp, *ep; - - /* The boot argument (i.e /sys/mbxroot/zImage) is stored - * at offset 0x0078 in NVRAM. We use this path name to - * construct the root file system path. - */ - cp = *cmd_cp; - - /* build command string. - */ - rp = nfsroot_string; - while (*rp != 0) - *cp++ = *rp++; - - /* Add the server address to the path. - */ - while (*dp != ' ') - *cp++ = *dp++; - *cp++ = ':'; - - rp = (char *)0xfa000078; - ep = strrchr(rp, '/'); - - if (ep != 0) { - while (rp < ep) - *cp++ = *rp++; - } - else { - rp = defroot_string; - while (*rp != 0) - *cp++ = *rp++; - } - - *cmd_cp = cp; -} - -size_t strlen(const char * s) -{ - const char *sc; - - for (sc = s; *sc != '\0'; ++sc) - /* nothing */; - return sc - s; -} - -int strncmp(const char * cs,const char * ct,size_t count) -{ - register signed char __res = 0; - - while (count) { - if ((__res = *cs - *ct++) != 0 || !*cs++) - break; - count--; - } - - return __res; -} - -char * strrchr(const char * s, int c) -{ - const char *p = s + strlen(s); - do { - if (*p == (char)c) - return (char *)p; - } while (--p >= s); - return NULL; -} -#endif - void puthex(unsigned long val) { unsigned char buf[10]; @@ -801,4 +578,244 @@ _bcopy(char *src, char *dst, int len) { while (len--) *dst++ = *src++; +} + + +#define FALSE 0 +#define TRUE 1 +#include + +int +strlen(char *s) +{ + int len = 0; + while (*s++) len++; + return len; +} + +_printk(char const *fmt, ...) +{ + int ret; + va_list ap; + + va_start(ap, fmt); + ret = _vprintk(putc, fmt, ap); + va_end(ap); + return (ret); +} + +#define is_digit(c) ((c >= '0') && (c <= '9')) + +int +_vprintk(putc, fmt0, ap) +int (*putc)(); +const char *fmt0; +va_list ap; +{ + char c, sign, *cp; + int left_prec, right_prec, zero_fill, length, pad, pad_on_right; + char buf[32]; + long val; + while (c = *fmt0++) + { + if (c == '%') + { + c = *fmt0++; + left_prec = right_prec = pad_on_right = 0; + if (c == '-') + { + c = *fmt0++; + pad_on_right++; + } + if (c == '0') + { + zero_fill = TRUE; + c = *fmt0++; + } else + { + zero_fill = FALSE; + } + while (is_digit(c)) + { + left_prec = (left_prec * 10) + (c - '0'); + c = *fmt0++; + } + if (c == '.') + { + c = *fmt0++; + zero_fill++; + while (is_digit(c)) + { + right_prec = (right_prec * 10) + (c - '0'); + c = *fmt0++; + } + } else + { + right_prec = left_prec; + } + sign = '\0'; + switch (c) + { + case 'd': + case 'x': + case 'X': + val = va_arg(ap, long); + switch (c) + { + case 'd': + if (val < 0) + { + sign = '-'; + val = -val; + } + length = _cvt(val, buf, 10, "0123456789"); + break; + case 'x': + length = _cvt(val, buf, 16, "0123456789abcdef"); + break; + case 'X': + length = _cvt(val, buf, 16, "0123456789ABCDEF"); + break; + } + cp = buf; + break; + case 's': + cp = va_arg(ap, char *); + length = strlen(cp); + break; + case 'c': + c = va_arg(ap, long /*char*/); + (*putc)(c); + continue; + default: + (*putc)('?'); + } + pad = left_prec - length; + if (sign != '\0') + { + pad--; + } + if (zero_fill) + { + c = '0'; + if (sign != '\0') + { + (*putc)(sign); + sign = '\0'; + } + } else + { + c = ' '; + } + if (!pad_on_right) + { + while (pad-- > 0) + { + (*putc)(c); + } + } + if (sign != '\0') + { + (*putc)(sign); + } + while (length-- > 0) + { + (*putc)(c = *cp++); + if (c == '\n') + { + (*putc)('\r'); + } + } + if (pad_on_right) + { + while (pad-- > 0) + { + (*putc)(c); + } + } + } else + { + (*putc)(c); + if (c == '\n') + { + (*putc)('\r'); + } + } + } +} + +int _cvt(unsigned long val, char *buf, long radix, char *digits) +{ + char temp[80]; + char *cp = temp; + int length = 0; + if (val == 0) + { /* Special case */ + *cp++ = '0'; + } else + while (val) + { + *cp++ = digits[val % radix]; + val /= radix; + } + while (cp != temp) + { + *buf++ = *--cp; + length++; + } + *buf = '\0'; + return (length); +} + +_dump_buf_with_offset(unsigned char *p, int s, unsigned char *base) +{ + int i, c; + if ((unsigned int)s > (unsigned int)p) + { + s = (unsigned int)s - (unsigned int)p; + } + while (s > 0) + { + if (base) + { + _printk("%06X: ", (int)p - (int)base); + } else + { + _printk("%06X: ", p); + } + for (i = 0; i < 16; i++) + { + if (i < s) + { + _printk("%02X", p[i] & 0xFF); + } else + { + _printk(" "); + } + if ((i % 2) == 1) _printk(" "); + if ((i % 8) == 7) _printk(" "); + } + _printk(" |"); + for (i = 0; i < 16; i++) + { + if (i < s) + { + c = p[i] & 0xFF; + if ((c < 0x20) || (c >= 0x7F)) c = '.'; + } else + { + c = ' '; + } + _printk("%c", c); + } + _printk("|\n"); + s -= 16; + p += 16; + } +} + +_dump_buf(unsigned char *p, int s) +{ + _printk("\n"); + _dump_buf_with_offset(p, s, 0); } diff -ur --new-file old/linux/arch/ppc/boot/mkprep.c new/linux/arch/ppc/boot/mkprep.c --- old/linux/arch/ppc/boot/mkprep.c Wed Sep 30 19:14:16 1998 +++ new/linux/arch/ppc/boot/mkprep.c Thu Apr 29 21:39:01 1999 @@ -14,15 +14,8 @@ * Modified for x86 hosted builds by Matt Porter */ -#ifdef linux -#include -/*#include */ -/*#include */ /* the byte swap funcs don't work here -- Cort */ -#else #include -#endif #include - #include #include @@ -168,10 +161,10 @@ /* set entry point and boot image size skipping over elf header */ #ifdef __i386__ *entry = 0x400/*+65536*/; - *length = info.st_size+0x400; + *length = info.st_size-elfhdr_size+0x400; #else *entry = cpu_to_le32(0x400/*+65536*/); - *length = cpu_to_le32(info.st_size+0x400); + *length = cpu_to_le32(info.st_size-elfhdr_size+0x400); #endif /* __i386__ */ /* sets magic number for msdos partition (used by linux) */ diff -ur --new-file old/linux/arch/ppc/boot/of1275.c new/linux/arch/ppc/boot/of1275.c --- old/linux/arch/ppc/boot/of1275.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/ppc/boot/of1275.c Fri Mar 19 19:50:03 1999 @@ -0,0 +1,427 @@ +/* Open Firmware Client Interface */ + + +#include "of1275.h" + + +static int (*of_server)(void *) = (int(*)(void*))-1; + +void +of_init(void *handler) +{ + of_server = (int(*)(void*))handler; +} + + +/* 6.3.2.1 Client interface */ + + +int +of_test(const char *name, int *missing) +{ + int result; + static of_test_service s; + s.service = "test"; + s.n_args = 1; + s.n_returns = 1; + s.name = name; + result = of_server(&s); + *missing = s.missing; + return result; +} + + +/* 6.3.2.2 Device tree */ + + +int +of_peer(int phandle, int *sibling_phandle) +{ + int result; + static of_peer_service s; + s.service = "peer"; + s.n_args = 1; + s.n_returns = 1; + s.phandle = phandle; + result = of_server(&s); + *sibling_phandle = s.sibling_phandle; + return result; +} + +int +of_child(int phandle, int *child_phandle) +{ + int result; + static of_child_service s; + s.service = "child"; + s.n_args = 1; + s.n_returns = 1; + s.phandle = phandle; + result = of_server(&s); + *child_phandle = s.child_phandle; + return result; +} + +int +of_parent(int phandle, int *parent_phandle) +{ + int result; + static of_parent_service s; + s.service = "parent"; + s.n_args = 1; + s.n_returns = 1; + s.phandle = phandle; + result = of_server(&s); + *parent_phandle = s.parent_phandle; + return result; +} + +int +of_instance_to_package(int ihandle, int *phandle) +{ + int result; + static of_instance_to_package_service s; + s.service = "instance-to-package"; + s.n_args = 1; + s.n_returns = 1; + s.ihandle = ihandle; + result = of_server(&s); + *phandle = s.phandle; + return result; +} + +int +of_getproplen(int phandle, const char *name, int *proplen) +{ + int result; + static of_getproplen_service s; + s.service = "getproplen"; + s.n_args = 2; + s.n_returns = 1; + s.phandle = phandle; + s.name = name; + result = of_server(&s); + *proplen = s.proplen; + return result; +} + +int +of_getprop(int phandle, const char *name, void *buf, int buflen, int *size) +{ + int result; + static of_getprop_service s; + s.service = "getprop"; + s.n_args = 4; + s.n_returns = 1; + s.phandle = phandle; + s.name = name; + s.buf = buf; + s.buflen = buflen; + result = of_server(&s); + *size = s.size; + return result; +} + +int +of_nextprop(int phandle, const char *previous, void *buf, int *flag) +{ + int result; + static of_nextprop_service s; + s.service = "nextprop"; + s.n_args = 3; + s.n_returns = 1; + s.phandle = phandle; + s.previous = previous; + s.buf = buf; + result = of_server(&s); + *flag = s.flag; + return result; +} + +int +of_setprop(int phandle, const char *name, void *buf, int len, int *size) +{ + int result; + static of_setprop_service s; + s.service = "setprop"; + s.n_args = 4; + s.n_returns = 1; + s.phandle = phandle; + s.name = name; + s.buf = buf; + s.len = len; + result = of_server(&s); + *size = s.size; + return result; +} + +int +of_canon(const char *device_specifier, void *buf, int buflen, int *length) +{ + int result; + static of_canon_service s; + s.service = "canon"; + s.n_args = 3; + s.n_returns = 1; + s.device_specifier = device_specifier; + s.buf = buf; + s.buflen = buflen; + result = of_server(&s); + *length = s.length; + return result; +} + +int +of_finddevice(const char *device_specifier, int *phandle) +{ + int result; + static of_finddevice_service s; + s.service = "finddevice"; + s.n_args = 1; + s.n_returns = 1; + s.device_specifier = device_specifier; + result = of_server(&s); + *phandle = s.phandle; + return result; +} + +int +of_instance_to_path(int ihandle, void *buf, int buflen, int *length) +{ + int result; + static of_instance_to_path_service s; + s.service = "instance-to-path"; + s.n_args = 3; + s.n_returns = 1; + s.ihandle = ihandle; + s.buf = buf; + s.buflen = buflen; + result = of_server(&s); + *length = s.length; + return result; +} + +int +of_package_to_path(int phandle, void *buf, int buflen, int *length) +{ + int result; + static of_package_to_path_service s; + s.service = "package-to-path"; + s.n_args = 3; + s.n_returns = 1; + s.phandle = phandle; + s.buf = buf; + s.buflen = buflen; + result = of_server(&s); + *length = s.length; + return result; +} + +/* int of_call_method(const char *method, int ihandle, ...); */ + + +/* 6.3.2.3 Device I/O */ + + +int +of_open(const char *device_specifier, int *ihandle) +{ + int result; + static of_open_service s; + s.service = "open"; + s.n_args = 1; + s.n_returns = 1; + s.device_specifier = device_specifier; + result = of_server(&s); + *ihandle = s.ihandle; + return result; +} + +int +of_close(int ihandle) +{ + int result; + static of_close_service s; + s.service = "close"; + s.n_args = 1; + s.n_returns = 0; + s.ihandle = ihandle; + result = of_server(&s); + return result; +} + +int +of_read(int ihandle, void *addr, int len, int *actual) +{ + int result; + static of_read_service s; + s.service = "read"; + s.n_args = 3; + s.n_returns = 1; + s.ihandle = ihandle; + s.addr = addr; + s.len = len; + result = of_server(&s); + *actual = s.actual; + return result; +} + +int +of_write(int ihandle, void *addr, int len, int *actual) +{ + int result; + static of_write_service s; + s.service = "write"; + s.n_args = 3; + s.n_returns = 1; + s.ihandle = ihandle; + s.addr = addr; + s.len = len; + result = of_server(&s); + *actual = s.actual; + return result; +} + +int +of_seek(int ihandle, int pos_hi, int pos_lo, int *status) +{ + int result; + static of_seek_service s; + s.service = "seek"; + s.n_args = 3; + s.n_returns = 1; + s.ihandle = ihandle; + s.pos_hi = pos_hi; + s.pos_lo = pos_lo; + result = of_server(&s); + *status = s.status; + return result; +} + + +/* 6.3.2.4 Memory */ + + +int +of_claim(void *virt, int size, int align, void **baseaddr) +{ + int result; + static of_claim_service s; + s.service = "claim"; + s.n_args = 3; + s.n_returns = 1; + s.virt = virt; + s.size = size; + s.align = align; + result = of_server(&s); + *baseaddr = s.baseaddr; + return result; +} + +int +of_release(void *virt, int size) +{ + int result; + static of_release_service s; + s.service = "release"; + s.n_args = 2; + s.n_returns = 0; + s.virt = virt; + s.size = size; + result = of_server(&s); + return result; +} + + +/* 6.3.2.5 Control transfer */ + + +int +of_boot(const char *bootspec) +{ + int result; + static of_boot_service s; + s.service = "boot"; + s.n_args = 1; + s.n_returns = 0; + s.bootspec = bootspec; + result = of_server(&s); + return result; +} + +int +of_enter(void) +{ + int result; + static of_enter_service s; + s.service = "enter"; + s.n_args = 0; + s.n_returns = 0; + result = of_server(&s); + return result; +} + +int +of_exit(void) +{ + int result; + static of_exit_service s; + s.service = "exit"; + s.n_args = 0; + s.n_returns = 0; + result = of_server(&s); + return result; +} + +/* int of_chain(void *virt, int size, void *entry, void *args, int len); */ + + +/* 6.3.2.6 User interface */ + + +/* int of_interpret(const char *arg, ...); */ + +int +of_set_callback(void *newfunc, void **oldfunc) +{ + int result; + static of_set_callback_service s; + s.service = "set-callback"; + s.n_args = 1; + s.n_returns = 1; + s.newfunc = newfunc; + result = of_server(&s); + *oldfunc = s.oldfunc; + return result; +} + +int +of_set_symbol_lookup(void *sym_to_value, void *value_to_sym) +{ + int result; + static of_set_symbol_lookup_service s; + s.service = "set-symbol-lookup"; + s.n_args = 2; + s.n_returns = 0; + s.sym_to_value = sym_to_value; + s.value_to_sym = s.value_to_sym; + result = of_server(&s); + return result; +} + + +/* 6.3.2.7 Time */ + + +int +of_milliseconds(int *ms) +{ + int result; + static of_milliseconds_service s; + s.service = "milliseconds"; + s.n_args = 0; + s.n_returns = 1; + result = of_server(&s); + *ms = s.ms; + return result; +} diff -ur --new-file old/linux/arch/ppc/boot/of1275.h new/linux/arch/ppc/boot/of1275.h --- old/linux/arch/ppc/boot/of1275.h Thu Jan 1 01:00:00 1970 +++ new/linux/arch/ppc/boot/of1275.h Fri Mar 19 19:50:03 1999 @@ -0,0 +1,421 @@ +/* 6.3.2.1 Client interface */ + + +typedef struct _of_test_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + const char *name; + /*out*/ + int missing; +} of_test_service; + +int of_test(const char *name, int *missing); + + +/* 6.3.2.2 Device tree */ + + +typedef struct _of_peer_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + int phandle; + /*out*/ + int sibling_phandle; +} of_peer_service; + +int of_peer(int phandle, int *sibling_phandle); + + +typedef struct _of_child_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + int phandle; + /*out*/ + int child_phandle; +} of_child_service; + +int of_child(int phandle, int *child_phandle); + + +typedef struct _of_parent_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + int phandle; + /*out*/ + int parent_phandle; +} of_parent_service; + +int of_child(int phandle, int *parent_phandle); + + +typedef struct _of_instance_to_package_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + int ihandle; + /*out*/ + int phandle; +} of_instance_to_package_service; + +int of_instance_to_package(int ihandle, int *phandle); + + +typedef struct _of_getproplen_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + int phandle; + const char *name; + /*out*/ + int proplen; +} of_getproplen_service; + +int of_getproplen(int phandle, const char *name, int *proplen); + + +typedef struct _of_getprop_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + int phandle; + const char *name; + void *buf; + int buflen; + /*out*/ + int size; +} of_getprop_service; + +int of_getprop(int phandle, const char *name, void *buf, int buflen, + int *size); + + +typedef struct _of_nextprop_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + int phandle; + const char *previous; + void *buf; + /*out*/ + int flag; +} of_nextprop_service; + +int of_nextprop(int phandle, const char *previous, void *buf, int *flag); + + +typedef struct _of_setprop_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + int phandle; + const char *name; + void *buf; + int len; + /*out*/ + int size; +} of_setprop_service; + +int of_setprop(int phandle, const char *name, void *buf, int len, int *size); + + +typedef struct _of_canon_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + const char *device_specifier; + void *buf; + int buflen; + /*out*/ + int length; +} of_canon_service; + +int of_canon(const char *device_specifier, void *buf, int buflen, int *length); + + +typedef struct _of_finddevice_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + const char *device_specifier; + /*out*/ + int phandle; +} of_finddevice_service; + +int of_finddevice(const char *device_specifier, int *phandle); + + +typedef struct _of_instance_to_path_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + int ihandle; + void *buf; + int buflen; + /*out*/ + int length; +} of_instance_to_path_service; + +int of_instance_to_path(int ihandle, void *buf, int buflen, int *length); + + +typedef struct _of_package_to_path_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + int phandle; + void *buf; + int buflen; + /*out*/ + int length; +} of_package_to_path_service; + +int of_package_to_path(int phandle, void *buf, int buflen, int *length); + + +typedef struct _of_call_method_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + const char *method; + int ihandle; + /*...*/ + int args[0]; +} of_call_method_service; + +int of_call_method(const char *method, int ihandle, ...); + + +/* 6.3.2.3 Device I/O */ + + +typedef struct _of_open_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + const char *device_specifier; + /*out*/ + int ihandle; +} of_open_service; + +int of_open(const char *device_specifier, + int *ihandle); + + +typedef struct _of_close_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + int ihandle; + /*out*/ +} of_close_service; + +int of_close(int ihandle); + + +typedef struct _of_read_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + int ihandle; + void *addr; + int len; + /*out*/ + int actual; +} of_read_service; + +int of_read(int ihandle, void *addr, int len, int *actual); + + +typedef struct _of_write_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + int ihandle; + void *addr; + int len; + /*out*/ + int actual; +} of_write_service; + +int of_write(int ihandle, void *addr, int len, int *actual); + + +typedef struct _of_seek_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + int ihandle; + int pos_hi; + int pos_lo; + /*out*/ + int status; +} of_seek_service; + +int of_seek(int ihandle, int pos_hi, int pos_lo, int *status); + + +/* 6.3.2.4 Memory */ + + +typedef struct _of_claim_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + void *virt; + int size; + int align; + /*out*/ + void *baseaddr; +} of_claim_service; + +int of_claim(void *virt, int size, int align, void **baseaddr); + + +typedef struct _of_release_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + void *virt; + int size; + int align; + /*out*/ +} of_release_service; + +int of_release(void *virt, int size); + + +/* 6.3.2.5 Control transfer */ + + +typedef struct _of_boot_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + const char *bootspec; + /*out*/ +} of_boot_service; + +int of_boot(const char *bootspec); + + +typedef struct _of_enter_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + /*out*/ +} of_enter_service; + +int of_enter(void); + + +typedef struct _of_exit_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + /*out*/ +} of_exit_service; + +int of_exit(void); + + +typedef struct _of_chain_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + void *virt; + int size; + void *entry; + void *args; + int len; + /*out*/ +} of_chain_service; + +int of_chain(void *virt, int size, void *entry, void *args, int len); + + +/* 6.3.2.6 User interface */ + + +typedef struct _of_interpret_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + const char *cmd; + int args[0]; + /*...*/ + /*out*/ + /*...*/ +} of_interpret_service; + +int of_interpret(const char *arg, ...); + + +typedef struct _of_set_callback_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + void *newfunc; + /*out*/ + void *oldfunc; +} of_set_callback_service; + +int of_set_callback(void *newfunc, void **oldfunc); + + +typedef struct _of_set_symbol_lookup_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + void *sym_to_value; + void *value_to_sym; + /*out*/ +} of_set_symbol_lookup_service; + +int of_set_symbol_lookup(void *sym_to_value, void *value_to_sym); + + +/* 6.3.2.7 Time */ + + +typedef struct _of_milliseconds_service { + const char *service; + int n_args; + int n_returns; + /*in*/ + /*out*/ + int ms; +} of_milliseconds_service; + +int of_milliseconds(int *ms); diff -ur --new-file old/linux/arch/ppc/boot/piggyback.c new/linux/arch/ppc/boot/piggyback.c --- old/linux/arch/ppc/boot/piggyback.c Tue Jan 13 00:18:13 1998 +++ new/linux/arch/ppc/boot/piggyback.c Thu Jan 1 01:00:00 1970 @@ -1,64 +0,0 @@ -#include - -extern long ce_exec_config[]; - -main(int argc, char *argv[]) -{ - int i, cnt, pos, len; - unsigned int cksum, val; - unsigned char *lp; - unsigned char buf[8192]; - if (argc != 1) - { - fprintf(stderr, "usage: %s out-file\n", argv[0]); - exit(1); - } - fprintf(stdout, "#\n"); - fprintf(stdout, "# Miscellaneous data structures:\n"); - fprintf(stdout, "# WARNING - this file is automatically generated!\n"); - fprintf(stdout, "#\n"); - fprintf(stdout, "\n"); - fprintf(stdout, "\t.data\n"); - fprintf(stdout, "\t.globl input_data\n"); - fprintf(stdout, "input_data:\n"); - pos = 0; - cksum = 0; - while ((len = read(0, buf, sizeof(buf))) > 0) - { - cnt = 0; - lp = (unsigned char *)buf; - len = (len + 3) & ~3; /* Round up to longwords */ - for (i = 0; i < len; i += 4) - { - if (cnt == 0) - { - fprintf(stdout, "\t.long\t"); - } - fprintf(stdout, "0x%02X%02X%02X%02X", lp[0], lp[1], lp[2], lp[3]); - val = *(unsigned long *)lp; - cksum ^= val; - lp += 4; - if (++cnt == 4) - { - cnt = 0; - fprintf(stdout, " # %x \n", pos+i-12); - fflush(stdout); - } else - { - fprintf(stdout, ","); - } - } - if (cnt) - { - fprintf(stdout, "0\n"); - } - pos += len; - } - fprintf(stdout, "\t.globl input_len\n"); - fprintf(stdout, "input_len:\t.long\t0x%x\n", pos); - fflush(stdout); - fclose(stdout); - fprintf(stderr, "cksum = %x\n", cksum); - exit(0); -} - diff -ur --new-file old/linux/arch/ppc/chrp_defconfig new/linux/arch/ppc/chrp_defconfig --- old/linux/arch/ppc/chrp_defconfig Wed Dec 23 16:34:11 1998 +++ new/linux/arch/ppc/chrp_defconfig Thu Feb 25 19:46:47 1999 @@ -85,7 +85,6 @@ # CONFIG_PACKET is not set # CONFIG_NETLINK is not set # CONFIG_FIREWALL is not set -CONFIG_NET_ALIAS=y # CONFIG_FILTER is not set CONFIG_UNIX=y CONFIG_INET=y diff -ur --new-file old/linux/arch/ppc/chrpboot/Makefile new/linux/arch/ppc/chrpboot/Makefile --- old/linux/arch/ppc/chrpboot/Makefile Sun Nov 15 19:51:42 1998 +++ new/linux/arch/ppc/chrpboot/Makefile Fri Mar 19 19:50:03 1999 @@ -28,6 +28,12 @@ CONFIG_CHRP = y endif +ifeq ($(CONFIG_SMP),y) +TFTPIMAGE=/tftpboot/zImage.chrp.smp +else +TFTPIMAGE=/tftpboot/zImage.chrp +endif + all: $(TOPDIR)/zImage # @@ -36,10 +42,10 @@ # ifeq ($(CONFIG_CHRP),y) znetboot: zImage - cp zImage /tftpboot/zImage.chrp + cp zImage $(TFTPIMAGE) znetboot.initrd: zImage.initrd - cp zImage.initrd /tftpboot/zImage.chrp + cp zImage.initrd $(TFTPIMAGE) floppy: zImage mcopy zImage a:zImage diff -ur --new-file old/linux/arch/ppc/coffboot/Makefile new/linux/arch/ppc/coffboot/Makefile --- old/linux/arch/ppc/coffboot/Makefile Mon Dec 21 17:37:20 1998 +++ new/linux/arch/ppc/coffboot/Makefile Fri Mar 19 19:50:03 1999 @@ -23,6 +23,12 @@ CONFIG_PMAC = y endif +ifeq ($(CONFIG_SMP),y) +TFTPIMAGE=/tftpboot/zImage.pmac.smp +else +TFTPIMAGE=/tftpboot/zImage.pmac +endif + ifeq ($(CONFIG_PMAC),y) hack-coff: hack-coff.c $(HOSTCC) $(HOSTCFLAGS) -o hack-coff hack-coff.c @@ -33,10 +39,10 @@ # umount /mnt znetboot: vmlinux.coff - cp vmlinux.coff /tftpboot/zImage.pmac + cp vmlinux.coff $(TFTPIMAGE) znetboot.initrd: vmlinux.coff.initrd - cp vmlinux.coff.initrd /tftpboot/zImage.pmac + cp vmlinux.coff.initrd $(TFTPIMAGE) coffboot: $(OBJS) ld.script $(LD) -o coffboot $(LD_ARGS) $(OBJS) $(LIBS) diff -ur --new-file old/linux/arch/ppc/common_defconfig new/linux/arch/ppc/common_defconfig --- old/linux/arch/ppc/common_defconfig Thu Jan 7 21:06:57 1999 +++ new/linux/arch/ppc/common_defconfig Tue May 11 17:24:32 1999 @@ -1,5 +1,5 @@ # -# Automatically generated by make menuconfig: don't edit +# Automatically generated make config: don't edit # # @@ -21,7 +21,7 @@ # CONFIG_EXPERIMENTAL=y CONFIG_MODULES=y -CONFIG_MODVERSIONS=y +# CONFIG_MODVERSIONS is not set CONFIG_KMOD=y CONFIG_PCI=y # CONFIG_PCI_QUIRKS is not set @@ -32,23 +32,23 @@ # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_BINFMT_ELF=y CONFIG_KERNEL_ELF=y -# CONFIG_BINFMT_MISC is not set +CONFIG_BINFMT_MISC=m # CONFIG_BINFMT_JAVA is not set # CONFIG_PARPORT is not set -# CONFIG_VGA_CONSOLE is not set +CONFIG_VGA_CONSOLE=y CONFIG_FB=y CONFIG_FB_COMPAT_XPMAC=y CONFIG_PMAC_PBOOK=y CONFIG_MAC_KEYBOARD=y CONFIG_MAC_FLOPPY=y CONFIG_MAC_SERIAL=y +# CONFIG_SERIAL_CONSOLE is not set CONFIG_ADBMOUSE=y -CONFIG_BLK_DEV_IDE_PMAC=y CONFIG_PROC_DEVICETREE=y -# CONFIG_KGDB is not set -# CONFIG_XMON is not set # CONFIG_TOTALMP is not set CONFIG_BOOTX_TEXT=y +# CONFIG_MOTOROLA_HOTSWAP is not set +# CONFIG_CMDLINE_BOOL is not set # # Plug and Play support @@ -60,18 +60,28 @@ # # CONFIG_BLK_DEV_FD is not set CONFIG_BLK_DEV_IDE=y + +# +# 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_IDETAPE is not set -# CONFIG_BLK_DEV_IDEFLOPPY is not set +CONFIG_BLK_DEV_IDEFLOPPY=y # CONFIG_BLK_DEV_IDESCSI is not set # CONFIG_BLK_DEV_CMD640 is not set # CONFIG_BLK_DEV_RZ1000 is not set # CONFIG_BLK_DEV_IDEPCI is not set -CONFIG_BLK_DEV_SL82C105=y +# CONFIG_BLK_DEV_SL82C105 is not set +CONFIG_BLK_DEV_IDE_PMAC=y +# CONFIG_BLK_DEV_IDEDMA_PMAC is not set # CONFIG_IDE_CHIPSETS is not set -CONFIG_BLK_DEV_LOOP=m + +# +# Additional Block Devices +# +CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_NBD is not set # CONFIG_BLK_DEV_MD is not set CONFIG_BLK_DEV_RAM=y @@ -84,27 +94,36 @@ # # Networking options # -# CONFIG_PACKET is not set -# CONFIG_NETLINK is not set +CONFIG_PACKET=y +CONFIG_NETLINK=y +# CONFIG_RTNETLINK is not set +# CONFIG_NETLINK_DEV is not set # CONFIG_FIREWALL is not set -# CONFIG_NET_ALIAS is not set # CONFIG_FILTER is not set CONFIG_UNIX=y CONFIG_INET=y -# CONFIG_IP_MULTICAST is not set +CONFIG_IP_MULTICAST=y # CONFIG_IP_ADVANCED_ROUTER is not set # CONFIG_IP_PNP is not set # CONFIG_IP_ROUTER is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set -# CONFIG_IP_ALIAS is not set -CONFIG_SYN_COOKIES=y -# CONFIG_INET_RARP is not set -# CONFIG_IP_NOSR is not set +# CONFIG_IP_MROUTE is not set +CONFIG_IP_ALIAS=y +# CONFIG_SYN_COOKIES is not set + +# +# (it is safe to leave these untouched) +# +CONFIG_INET_RARP=y CONFIG_SKB_LARGE=y # CONFIG_IPV6 is not set + +# +# +# # CONFIG_IPX is not set -# CONFIG_ATALK is not set +CONFIG_ATALK=m # CONFIG_X25 is not set # CONFIG_LAPB is not set # CONFIG_BRIDGE is not set @@ -124,13 +143,21 @@ # SCSI support # CONFIG_SCSI=y + +# +# SCSI support type (disk, tape, CD-ROM) +# CONFIG_BLK_DEV_SD=y -CONFIG_CHR_DEV_ST=m +CONFIG_CHR_DEV_ST=y CONFIG_BLK_DEV_SR=y CONFIG_BLK_DEV_SR_VENDOR=y -# CONFIG_CHR_DEV_SG is not set -# CONFIG_SCSI_MULTI_LUN is not set -# CONFIG_SCSI_CONSTANTS is not set +CONFIG_CHR_DEV_SG=y + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +CONFIG_SCSI_MULTI_LUN=y +CONFIG_SCSI_CONSTANTS=y # CONFIG_SCSI_LOGGING is not set # @@ -141,7 +168,10 @@ # CONFIG_SCSI_AHA152X is not set # CONFIG_SCSI_AHA1542 is not set # CONFIG_SCSI_AHA1740 is not set -# CONFIG_SCSI_AIC7XXX is not set +CONFIG_SCSI_AIC7XXX=y +# CONFIG_OVERRIDE_CMDS is not set +CONFIG_AIC7XXX_PROC_STATS=y +CONFIG_AIC7XXX_RESET_DELAY=15 # CONFIG_SCSI_ADVANSYS is not set # CONFIG_SCSI_IN2000 is not set # CONFIG_SCSI_AM53C974 is not set @@ -154,15 +184,20 @@ # CONFIG_SCSI_FUTURE_DOMAIN is not set # CONFIG_SCSI_GDTH is not set # CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_G_NCR5380_PORT is not set +# CONFIG_SCSI_G_NCR5380_MEM 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=y +# CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set # CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set # CONFIG_SCSI_PAS16 is not set # CONFIG_SCSI_PCI2000 is not set @@ -170,6 +205,7 @@ # 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 @@ -187,6 +223,7 @@ # CONFIG_ARCNET is not set # CONFIG_DUMMY is not set # CONFIG_EQUALIZER is not set +# CONFIG_ETHERTAP is not set CONFIG_NET_ETHERNET=y CONFIG_MACE=y CONFIG_BMAC=y @@ -199,7 +236,7 @@ # CONFIG_ACENIC is not set # CONFIG_NET_ISA is not set CONFIG_NET_EISA=y -CONFIG_PCNET32=m +CONFIG_PCNET32=y # CONFIG_AC3200 is not set # CONFIG_APRICOT is not set # CONFIG_CS89x0 is not set @@ -219,16 +256,21 @@ # CONFIG_FDDI is not set # CONFIG_HIPPI is not set # CONFIG_DLCI is not set +# CONFIG_LTPC is not set +# CONFIG_COPS is not set +# CONFIG_IPDDP is not set CONFIG_PPP=y -CONFIG_SLIP=m -# CONFIG_SLIP_COMPRESSED is not set -# CONFIG_SLIP_SMART is not set -# CONFIG_SLIP_MODE_SLIP6 is not set + +# +# CCP compressors for PPP are only built as modules. +# +# CONFIG_SLIP is not set # CONFIG_NET_RADIO is not set # CONFIG_TR is not set # CONFIG_SHAPER is not set # CONFIG_HOSTESS_SV11 is not set # CONFIG_COSA is not set +# CONFIG_RCPCI is not set # # Amateur Radio support @@ -241,7 +283,7 @@ # CONFIG_ISDN is not set # -# CD-ROM drivers (not for SCSI or IDE/ATAPI drives) +# Old CD-ROM drivers (not SCSI, not IDE) # # CONFIG_CD_NO_IDESCSI is not set @@ -249,27 +291,42 @@ # Console drivers # CONFIG_DUMMY_CONSOLE=y +# CONFIG_FB_PM2 is not set CONFIG_FB_OF=y CONFIG_FB_CONTROL=y CONFIG_FB_PLATINUM=y CONFIG_FB_VALKYRIE=y -CONFIG_FB_ATY=y +# CONFIG_FB_ATY is not set CONFIG_FB_IMSTT=y CONFIG_FB_CT65550=y # CONFIG_FB_S3TRIO is not set -# CONFIG_FB_MATROX is not set -CONFIG_FB_ATY=y +CONFIG_FB_MATROX=y +CONFIG_FB_MATROX_MILLENIUM=y +CONFIG_FB_MATROX_MYSTIQUE=y +CONFIG_FB_MATROX_G100=y +# CONFIG_FB_MATROX_MULTIHEAD is not set +# CONFIG_FB_ATY is not set # CONFIG_FB_VIRTUAL is not set -# CONFIG_FBCON_ADVANCED is not set +CONFIG_FBCON_ADVANCED=y +# CONFIG_FBCON_MFB is not set +# CONFIG_FBCON_CFB2 is not set +# CONFIG_FBCON_CFB4 is not set CONFIG_FBCON_CFB8=y CONFIG_FBCON_CFB16=y CONFIG_FBCON_CFB24=y CONFIG_FBCON_CFB32=y +# CONFIG_FBCON_AFB is not set +# CONFIG_FBCON_ILBM is not set +# CONFIG_FBCON_IPLAN2P2 is not set +# CONFIG_FBCON_IPLAN2P4 is not set +# CONFIG_FBCON_IPLAN2P8 is not set +# CONFIG_FBCON_MAC is not set +# CONFIG_FBCON_VGA is not set # CONFIG_FBCON_FONTWIDTH8_ONLY is not set CONFIG_FBCON_FONTS=y -CONFIG_FONT_8x8=y +# CONFIG_FONT_8x8 is not set CONFIG_FONT_8x16=y -# CONFIG_FONT_SUN8x16 is not set +CONFIG_FONT_SUN8x16=y CONFIG_FONT_SUN12x22=y # CONFIG_FONT_6x11 is not set # CONFIG_FONT_PEARL_8x8 is not set @@ -283,7 +340,8 @@ CONFIG_SERIAL=m # CONFIG_SERIAL_EXTENDED is not set # CONFIG_SERIAL_NONSTANDARD is not set -# CONFIG_UNIX98_PTYS is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 CONFIG_MOUSE=y # @@ -309,30 +367,40 @@ # Joystick support # # CONFIG_JOYSTICK is not set +# CONFIG_DTLK is not set # # Ftape, the floppy tape device driver # # CONFIG_FTAPE is not set +# CONFIG_FT_NORMAL_DEBUG is not set +# CONFIG_FT_FULL_DEBUG is not set +# CONFIG_FT_NO_TRACE is not set +# CONFIG_FT_NO_TRACE_AT_ALL is not set +# CONFIG_FT_STD_FDC is not set +# CONFIG_FT_MACH2 is not set +# CONFIG_FT_PROBE_FC10 is not set +# CONFIG_FT_ALT_FDC is not set # # Filesystems # # CONFIG_QUOTA is not set -# CONFIG_AUTOFS_FS is not set +CONFIG_AUTOFS_FS=y # CONFIG_ADFS_FS is not set # CONFIG_AFFS_FS is not set CONFIG_HFS_FS=y CONFIG_FAT_FS=m CONFIG_MSDOS_FS=m # CONFIG_UMSDOS_FS is not set -# CONFIG_VFAT_FS is not set +CONFIG_VFAT_FS=m CONFIG_ISO9660_FS=y # CONFIG_JOLIET is not set # CONFIG_MINIX_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y +CONFIG_DEVPTS_FS=y # CONFIG_QNX4FS_FS is not set # CONFIG_ROMFS_FS is not set CONFIG_EXT2_FS=y @@ -344,7 +412,7 @@ # # CONFIG_CODA_FS is not set CONFIG_NFS_FS=y -CONFIG_NFSD=m +CONFIG_NFSD=y # CONFIG_NFSD_SUN is not set CONFIG_SUNRPC=y CONFIG_LOCKD=y @@ -364,7 +432,7 @@ # # Native Language Support # -# CONFIG_NLS_CODEPAGE_437 is not set +CONFIG_NLS_CODEPAGE_437=y # CONFIG_NLS_CODEPAGE_737 is not set # CONFIG_NLS_CODEPAGE_775 is not set # CONFIG_NLS_CODEPAGE_850 is not set @@ -402,30 +470,11 @@ # CONFIG_SOUND_SONICVIBES is not set # CONFIG_SOUND_MSNDCLAS is not set # CONFIG_SOUND_MSNDPIN is not set -CONFIG_SOUND_OSS=y -# CONFIG_SOUND_PAS is not set -# CONFIG_SOUND_SB is not set -# CONFIG_SOUND_ADLIB is not set -# CONFIG_SOUND_GUS is not set -# CONFIG_SOUND_MPU401 is not set -# CONFIG_SOUND_PSS is not set -# CONFIG_SOUND_MSS is not set -# CONFIG_SOUND_SSCAPE is not set -# CONFIG_SOUND_TRIX is not set -# CONFIG_SOUND_MAD16 is not set -# CONFIG_SOUND_WAVEFRONT is not set -# CONFIG_SOUND_CS4232 is not set -# CONFIG_SOUND_OPL3SA2 is not set -# CONFIG_SOUND_MAUI is not set -# CONFIG_SOUND_SGALAXY is not set -# CONFIG_SOUND_AD1816 is not set -# CONFIG_SOUND_OPL3SA1 is not set -# CONFIG_SOUND_SOFTOSS is not set -# CONFIG_SOUND_YM3812 is not set -# CONFIG_SOUND_VMIDI is not set -# CONFIG_SOUND_UART6850 is not set +# CONFIG_SOUND_OSS is not set # -# Additional low level sound drivers +# Kernel hacking # -# CONFIG_LOWLEVEL_SOUND is not set +CONFIG_MAGIC_SYSRQ=y +# CONFIG_KGDB is not set +# CONFIG_XMON is not set diff -ur --new-file old/linux/arch/ppc/config.in new/linux/arch/ppc/config.in --- old/linux/arch/ppc/config.in Thu Jan 14 19:29:28 1999 +++ new/linux/arch/ppc/config.in Tue May 11 17:24:32 1999 @@ -1,4 +1,4 @@ -# $Id: config.in,v 1.80 1998/11/11 03:54:56 paulus Exp $ +# $Id: config.in,v 1.92 1999/04/30 05:41:43 cort Exp $ # For a description of the syntax of this configuration file, # see the Configure script. # @@ -19,12 +19,10 @@ APUS CONFIG_APUS \ MBX CONFIG_MBX" PowerMac +bool 'Symmetric multi-processing support' CONFIG_SMP if [ "$CONFIG_ALL_PPC" != "y" ];then define_bool CONFIG_MACH_SPECIFIC y fi - -bool 'Symmetric multi-processing support' CONFIG_SMP - endmenu if [ "$CONFIG_MBX" = "y" ];then @@ -82,13 +80,20 @@ bool 'Support for PowerMac keyboard' CONFIG_MAC_KEYBOARD bool 'Support for PowerMac floppy' CONFIG_MAC_FLOPPY bool 'Support for PowerMac serial ports' CONFIG_MAC_SERIAL +if [ "$CONFIG_MAC_SERIAL" = "y" ]; then + bool ' Support for console on serial port' CONFIG_SERIAL_CONSOLE +fi bool 'Support for PowerMac ADB mouse' CONFIG_ADBMOUSE -bool 'Support for PowerMac IDE devices (must also enable IDE)' CONFIG_BLK_DEV_IDE_PMAC bool 'Support for Open Firmware device tree in /proc' CONFIG_PROC_DEVICETREE -bool 'Include kgdb kernel debugger' CONFIG_KGDB -bool 'Include xmon kernel debugger' CONFIG_XMON bool 'Support for TotalImpact TotalMP' CONFIG_TOTALMP bool 'Support for early boot text console (BootX only)' CONFIG_BOOTX_TEXT +bool 'Support for Motorola Hot Swap' CONFIG_MOTOROLA_HOTSWAP +if [ "$CONFIG_PREP" = "y" -o "$CONFIG_ALL_PPC" = "y" ]; then + bool 'PReP bootloader kernel arguments' CONFIG_CMDLINE_BOOL y + if [ "$CONFIG_CMDLINE_BOOL" = "y" ] ; then + string 'Initial kernel command string' CONFIG_CMDLINE console=ttyS0,9600 console=tty0 root=/dev/sda2 + fi +fi if [ "$CONFIG_APUS" = "y" ]; then define_bool CONFIG_FB_CONSOLE y @@ -152,7 +157,7 @@ endmenu mainmenu_option next_comment -comment 'CD-ROM drivers (not for SCSI or IDE/ATAPI drives)' +comment 'Old CD-ROM drivers (not SCSI, not IDE)' bool 'Support non-SCSI/IDE/ATAPI CDROM drives' CONFIG_CD_NO_IDESCSI if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then @@ -172,8 +177,16 @@ comment 'Sound' tristate 'Sound card support' CONFIG_SOUND if [ "$CONFIG_SOUND" != "n" ]; then - tristate 'Amiga or PowerMac DMA sound support' CONFIG_DMASOUND + dep_tristate 'Amiga or PowerMac DMA sound support' CONFIG_DMASOUND $CONFIG_SOUND source drivers/sound/Config.in fi +endmenu + +mainmenu_option next_comment +comment 'Kernel hacking' + +bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ +bool 'Include kgdb kernel debugger' CONFIG_KGDB +bool 'Include xmon kernel debugger' CONFIG_XMON endmenu diff -ur --new-file old/linux/arch/ppc/defconfig new/linux/arch/ppc/defconfig --- old/linux/arch/ppc/defconfig Tue Jan 5 00:32:42 1999 +++ new/linux/arch/ppc/defconfig Tue May 11 17:24:32 1999 @@ -8,13 +8,12 @@ CONFIG_PPC=y CONFIG_6xx=y # CONFIG_8xx is not set -CONFIG_PMAC=y +# CONFIG_PMAC is not set # CONFIG_PREP is not set # CONFIG_CHRP is not set -# CONFIG_ALL_PPC is not set +CONFIG_ALL_PPC=y # CONFIG_APUS is not set # CONFIG_MBX is not set -CONFIG_MACH_SPECIFIC=y # CONFIG_SMP is not set # @@ -36,20 +35,20 @@ CONFIG_BINFMT_MISC=m # CONFIG_BINFMT_JAVA is not set # CONFIG_PARPORT is not set -# CONFIG_VGA_CONSOLE is not set +CONFIG_VGA_CONSOLE=y CONFIG_FB=y CONFIG_FB_COMPAT_XPMAC=y CONFIG_PMAC_PBOOK=y CONFIG_MAC_KEYBOARD=y CONFIG_MAC_FLOPPY=y CONFIG_MAC_SERIAL=y +# CONFIG_SERIAL_CONSOLE is not set CONFIG_ADBMOUSE=y -CONFIG_BLK_DEV_IDE_PMAC=y CONFIG_PROC_DEVICETREE=y -# CONFIG_KGDB is not set -# CONFIG_XMON is not set # CONFIG_TOTALMP is not set CONFIG_BOOTX_TEXT=y +# CONFIG_MOTOROLA_HOTSWAP is not set +# CONFIG_CMDLINE_BOOL is not set # # Plug and Play support @@ -76,15 +75,13 @@ # CONFIG_BLK_DEV_IDEPCI is not set # CONFIG_BLK_DEV_SL82C105 is not set CONFIG_BLK_DEV_IDE_PMAC=y -CONFIG_BLK_DEV_IDEDMA_PMAC=y -CONFIG_BLK_DEV_IDEDMA=y -CONFIG_PMAC_IDEDMA_AUTO=y +# CONFIG_BLK_DEV_IDEDMA_PMAC is not set # CONFIG_IDE_CHIPSETS is not set # # Additional Block Devices # -# CONFIG_BLK_DEV_LOOP is not set +CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_NBD is not set # CONFIG_BLK_DEV_MD is not set CONFIG_BLK_DEV_RAM=y @@ -102,7 +99,6 @@ # CONFIG_RTNETLINK is not set # CONFIG_NETLINK_DEV is not set # CONFIG_FIREWALL is not set -CONFIG_NET_ALIAS=y # CONFIG_FILTER is not set CONFIG_UNIX=y CONFIG_INET=y @@ -120,7 +116,6 @@ # (it is safe to leave these untouched) # CONFIG_INET_RARP=y -CONFIG_IP_NOSR=y CONFIG_SKB_LARGE=y # CONFIG_IPV6 is not set @@ -156,12 +151,12 @@ CONFIG_CHR_DEV_ST=y CONFIG_BLK_DEV_SR=y CONFIG_BLK_DEV_SR_VENDOR=y -# CONFIG_CHR_DEV_SG is not set +CONFIG_CHR_DEV_SG=y # # Some SCSI devices (e.g. CD jukebox) support multiple LUNs # -# CONFIG_SCSI_MULTI_LUN is not set +CONFIG_SCSI_MULTI_LUN=y CONFIG_SCSI_CONSTANTS=y # CONFIG_SCSI_LOGGING is not set @@ -189,16 +184,28 @@ # CONFIG_SCSI_FUTURE_DOMAIN is not set # CONFIG_SCSI_GDTH is not set # CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_G_NCR5380_PORT is not set +# CONFIG_SCSI_G_NCR5380_MEM 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 is not set +CONFIG_SCSI_NCR53C8XX=y +# CONFIG_SCSI_SYM53C8XX is not set +CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8 +CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32 +CONFIG_SCSI_NCR53C8XX_SYNC=20 +# CONFIG_SCSI_NCR53C8XX_PROFILE is not set +# CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set +# CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set # CONFIG_SCSI_PAS16 is not set # CONFIG_SCSI_PCI2000 is not set # CONFIG_SCSI_PCI2220I is not set # CONFIG_SCSI_PSI240I is not set # CONFIG_SCSI_QLOGIC_FAS is not set # CONFIG_SCSI_QLOGIC_ISP is not set +# CONFIG_SCSI_QLOGIC_FC is not set # CONFIG_SCSI_SEAGATE is not set # CONFIG_SCSI_DC390T is not set # CONFIG_SCSI_T128 is not set @@ -229,7 +236,7 @@ # CONFIG_ACENIC is not set # CONFIG_NET_ISA is not set CONFIG_NET_EISA=y -# CONFIG_PCNET32 is not set +CONFIG_PCNET32=y # CONFIG_AC3200 is not set # CONFIG_APRICOT is not set # CONFIG_CS89x0 is not set @@ -263,6 +270,7 @@ # CONFIG_SHAPER is not set # CONFIG_HOSTESS_SV11 is not set # CONFIG_COSA is not set +# CONFIG_RCPCI is not set # # Amateur Radio support @@ -275,7 +283,7 @@ # CONFIG_ISDN is not set # -# CD-ROM drivers (not for SCSI or IDE/ATAPI drives) +# Old CD-ROM drivers (not SCSI, not IDE) # # CONFIG_CD_NO_IDESCSI is not set @@ -283,22 +291,37 @@ # Console drivers # CONFIG_DUMMY_CONSOLE=y +# CONFIG_FB_PM2 is not set CONFIG_FB_OF=y CONFIG_FB_CONTROL=y CONFIG_FB_PLATINUM=y CONFIG_FB_VALKYRIE=y -CONFIG_FB_ATY=y +# CONFIG_FB_ATY is not set CONFIG_FB_IMSTT=y CONFIG_FB_CT65550=y # CONFIG_FB_S3TRIO is not set -# CONFIG_FB_MATROX is not set -CONFIG_FB_ATY=y +CONFIG_FB_MATROX=y +CONFIG_FB_MATROX_MILLENIUM=y +CONFIG_FB_MATROX_MYSTIQUE=y +CONFIG_FB_MATROX_G100=y +# CONFIG_FB_MATROX_MULTIHEAD is not set +# CONFIG_FB_ATY is not set # CONFIG_FB_VIRTUAL is not set -# CONFIG_FBCON_ADVANCED is not set +CONFIG_FBCON_ADVANCED=y +# CONFIG_FBCON_MFB is not set +# CONFIG_FBCON_CFB2 is not set +# CONFIG_FBCON_CFB4 is not set CONFIG_FBCON_CFB8=y CONFIG_FBCON_CFB16=y CONFIG_FBCON_CFB24=y CONFIG_FBCON_CFB32=y +# CONFIG_FBCON_AFB is not set +# CONFIG_FBCON_ILBM is not set +# CONFIG_FBCON_IPLAN2P2 is not set +# CONFIG_FBCON_IPLAN2P4 is not set +# CONFIG_FBCON_IPLAN2P8 is not set +# CONFIG_FBCON_MAC is not set +# CONFIG_FBCON_VGA is not set # CONFIG_FBCON_FONTWIDTH8_ONLY is not set CONFIG_FBCON_FONTS=y # CONFIG_FONT_8x8 is not set @@ -314,15 +337,25 @@ # CONFIG_VT=y CONFIG_VT_CONSOLE=y -# CONFIG_SERIAL is not set +CONFIG_SERIAL=m # CONFIG_SERIAL_EXTENDED is not set # CONFIG_SERIAL_NONSTANDARD is not set CONFIG_UNIX98_PTYS=y CONFIG_UNIX98_PTY_COUNT=256 -# CONFIG_MOUSE is not set +CONFIG_MOUSE=y + +# +# Mice +# +# CONFIG_ATIXL_BUSMOUSE is not set +# CONFIG_BUSMOUSE is not set +# CONFIG_MS_BUSMOUSE is not set +CONFIG_PSMOUSE=y +# CONFIG_82C710_MOUSE is not set +# CONFIG_PC110_PAD is not set # CONFIG_QIC02_TAPE is not set # CONFIG_WATCHDOG is not set -CONFIG_NVRAM=y +# CONFIG_NVRAM is not set # CONFIG_RTC is not set # @@ -334,11 +367,20 @@ # Joystick support # # CONFIG_JOYSTICK is not set +# CONFIG_DTLK is not set # # Ftape, the floppy tape device driver # # CONFIG_FTAPE is not set +# CONFIG_FT_NORMAL_DEBUG is not set +# CONFIG_FT_FULL_DEBUG is not set +# CONFIG_FT_NO_TRACE is not set +# CONFIG_FT_NO_TRACE_AT_ALL is not set +# CONFIG_FT_STD_FDC is not set +# CONFIG_FT_MACH2 is not set +# CONFIG_FT_PROBE_FC10 is not set +# CONFIG_FT_ALT_FDC is not set # # Filesystems @@ -429,3 +471,10 @@ # CONFIG_SOUND_MSNDCLAS is not set # CONFIG_SOUND_MSNDPIN is not set # CONFIG_SOUND_OSS is not set + +# +# Kernel hacking +# +CONFIG_MAGIC_SYSRQ=y +# CONFIG_KGDB is not set +# CONFIG_XMON is not set diff -ur --new-file old/linux/arch/ppc/kernel/Makefile new/linux/arch/ppc/kernel/Makefile --- old/linux/arch/ppc/kernel/Makefile Wed Dec 23 16:34:11 1998 +++ new/linux/arch/ppc/kernel/Makefile Thu Apr 29 21:39:01 1999 @@ -27,7 +27,7 @@ endif ifeq ($(CONFIG_MBX),y) -O_OBJS += mbx_setup.o mbx_pci.o softemu8xx.o +O_OBJS += mbx_setup.o mbx_pci.o softemu8xx.o i8259.o ppc8xx_pic.o else ifeq ($(CONFIG_APUS),y) O_OBJS += apus_setup.o prom.o openpic.o @@ -36,7 +36,8 @@ O_OBJS += prep_time.o pmac_time.o chrp_time.o \ pmac_setup.o pmac_support.o \ prep_pci.o pmac_pci.o chrp_pci.o \ - residual.o prom.o openpic.o feature.o + residual.o prom.o openpic.o feature.o \ + prep_nvram.o open_pic.o i8259.o pmac_pic.o indirect_pci.o OX_OBJS += chrp_setup.o prep_setup.o endif endif diff -ur --new-file old/linux/arch/ppc/kernel/align.c new/linux/arch/ppc/kernel/align.c --- old/linux/arch/ppc/kernel/align.c Wed Sep 30 19:14:17 1998 +++ new/linux/arch/ppc/kernel/align.c Thu Apr 29 21:39:01 1999 @@ -194,13 +194,8 @@ return -EFAULT; /* bad address */ } -#ifdef __SMP__ - if ((flags & F) && (regs->msr & MSR_FP) ) - smp_giveup_fpu(current); -#else - if ((flags & F) && last_task_used_math == current) - giveup_fpu(); -#endif + if ((flags & F) && (regs->msr & MSR_FP)) + giveup_fpu(current); if (flags & M) return 0; /* too hard for now */ @@ -254,27 +249,16 @@ data.d = current->tss.fpr[reg]; break; /* these require some floating point conversions... */ - /* note that giveup_fpu enables the FPU for the kernel */ /* we'd like to use the assignment, but we have to compile * the kernel with -msoft-float so it doesn't use the * fp regs for copying 8-byte objects. */ case LD+F+S: -#ifdef __SMP__ - if (regs->msr & MSR_FP ) - smp_giveup_fpu(current); -#else - giveup_fpu(); -#endif + enable_kernel_fp(); cvt_fd(&data.f, ¤t->tss.fpr[reg], ¤t->tss.fpscr); /* current->tss.fpr[reg] = data.f; */ break; case ST+F+S: -#ifdef __SMP__ - if (regs->msr & MSR_FP ) - smp_giveup_fpu(current); -#else - giveup_fpu(); -#endif + enable_kernel_fp(); cvt_df(¤t->tss.fpr[reg], &data.f, ¤t->tss.fpscr); /* data.f = current->tss.fpr[reg]; */ break; diff -ur --new-file old/linux/arch/ppc/kernel/apus_setup.c new/linux/arch/ppc/kernel/apus_setup.c --- old/linux/arch/ppc/kernel/apus_setup.c Mon Dec 21 17:37:20 1998 +++ new/linux/arch/ppc/kernel/apus_setup.c Thu Apr 29 21:39:01 1999 @@ -14,12 +14,50 @@ #include #include #include +#include + +/* Get the IDE stuff from the 68k file */ +#define ide_init_hwif_ports m68k_ide_init_hwif_ports +#define ide_default_irq m68k_ide_default_irq +#define ide_default_io_base m68k_ide_default_io_base +#define ide_check_region m68k_ide_check_region +#define ide_request_region m68k_ide_request_region +#define ide_release_region m68k_ide_release_region +#define ide_fix_driveid m68k_ide_fix_driveid +#include +#undef ide_init_hwif_ports +#define ide_default_irq +#define ide_default_io_base +#define ide_check_region +#define ide_request_region +#define ide_release_region +#define ide_fix_driveid + #include #include #include #include #include +#include +#include + +#include "time.h" +#include "local_irq.h" + +unsigned long apus_get_rtc_time(void); +int apus_set_rtc_time(unsigned long nowtime); + +/* APUS defs */ +extern int parse_bootinfo(const struct bi_record *); +extern char _end[]; +#ifdef CONFIG_APUS +struct mem_info ramdisk; +unsigned long isa_io_base; +unsigned long isa_mem_base; +unsigned long pci_dram_offset; +#endif +/* END APUS defs */ unsigned long m68k_machtype; char debug_device[6] = ""; @@ -72,6 +110,8 @@ int i; char *p, *q; + m68k_machtype = MACH_AMIGA; + /* Parse the command line for arch-specific options. * For the m68k, this is currently only "debug=xxx" to enable printing * certain kernel messages to some machine-specific device. */ @@ -408,4 +448,195 @@ "icbi 0,%0 \n\t" "isync \n\t" : : "r" (addr)); +} + +void +apus_restart(char *cmd) +{ + cli(); + + APUS_WRITE(APUS_REG_LOCK, + REGLOCK_BLACKMAGICK1|REGLOCK_BLACKMAGICK2); + APUS_WRITE(APUS_REG_LOCK, + REGLOCK_BLACKMAGICK1|REGLOCK_BLACKMAGICK3); + APUS_WRITE(APUS_REG_LOCK, + REGLOCK_BLACKMAGICK2|REGLOCK_BLACKMAGICK3); + APUS_WRITE(APUS_REG_SHADOW, REGSHADOW_SELFRESET); + APUS_WRITE(APUS_REG_RESET, REGRESET_AMIGARESET); + for(;;); +} + +void +apus_power_off(void) +{ + for (;;); +} + +void +apus_halt(void) +{ + apus_restart(NULL); +} + +void +apus_do_IRQ(struct pt_regs *regs, + int cpu, + int isfake) +{ + int old_level, new_level; + + /* I don't think we need SMP code here - Corey */ + + old_level = ~(regs->mq) & IPLEMU_IPLMASK; + new_level = (~(regs->mq) >> 3) & IPLEMU_IPLMASK; + if (new_level != 0) + { + APUS_WRITE(APUS_IPL_EMU, IPLEMU_IPLMASK); + APUS_WRITE(APUS_IPL_EMU, (IPLEMU_SETRESET + | (~(new_level) & IPLEMU_IPLMASK))); + APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT); + + process_int (VEC_SPUR+new_level, regs); + APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET | IPLEMU_DISABLEINT); + APUS_WRITE(APUS_IPL_EMU, IPLEMU_IPLMASK); + APUS_WRITE(APUS_IPL_EMU, (IPLEMU_SETRESET + | (~(old_level) & IPLEMU_IPLMASK))); + } + APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT); +} + +#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) +/* + * IDE stuff. + */ +void +apus_ide_insw(ide_ioreg_t port, void *buf, int ns) +{ + ide_insw(port, buf, ns); +} + +void +apus_ide_outsw(ide_ioreg_t port, void *buf, int ns) +{ + ide_outsw(port, buf, ns); +} + +int +apus_ide_default_irq(ide_ioreg_t base) +{ + m68k_ide_default_irq(base); +} + +ide_ioreg_t +apus_ide_default_io_base(int index) +{ + m68k_ide_default_io_base(index); +} + +int +apus_ide_check_region(ide_ioreg_t from, unsigned int extent) +{ + return m68k_ide_check_region(from, extent); +} + +void +apus_ide_request_region(ide_ioreg_t from, + unsigned int extent, + const char *name) +{ + m68k_ide_request_region(from, extent, name); +} + +void +apus_ide_release_region(ide_ioreg_t from, + unsigned int extent) +{ + m68k_ide_release_region(from, extent); +} + +void +apus_ide_fix_driveid(struct hd_driveid *id) +{ + m68k_ide_fix_driveid(id); +} + +__initfunc(void +apus_ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq)) +{ + m68k_ide_init_hwif_ports(p, base, irq); +} +#endif + +__initfunc(void +apus_local_init_IRQ(void)) +{ + ppc_md.mask_irq = amiga_disable_irq; + ppc_md.unmask_irq = amiga_enable_irq; + apus_init_IRQ(); +} + +__initfunc(void +apus_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7)) +{ + /* Parse bootinfo. The bootinfo is located right after + the kernel bss */ + parse_bootinfo((const struct bi_record *)&_end); +#ifdef CONFIG_BLK_DEV_INITRD + /* Take care of initrd if we have one. Use data from + bootinfo to avoid the need to initialize PPC + registers when kernel is booted via a PPC reset. */ + if ( ramdisk.addr ) { + initrd_start = (unsigned long) __va(ramdisk.addr); + initrd_end = (unsigned long) + __va(ramdisk.size + ramdisk.addr); + } + /* Make sure code below is not executed. */ + r4 = 0; + r6 = 0; +#endif /* CONFIG_BLK_DEV_INITRD */ + + ISA_DMA_THRESHOLD = 0x00ffffff; + + ppc_md.setup_arch = apus_setup_arch; + ppc_md.setup_residual = NULL; + ppc_md.get_cpuinfo = apus_get_cpuinfo; + ppc_md.irq_cannonicalize = NULL; + ppc_md.init_IRQ = apus_init_IRQ; + ppc_md.do_IRQ = apus_do_IRQ; + ppc_md.get_irq_source = NULL; + ppc_md.init = NULL; + + ppc_md.restart = apus_restart; + ppc_md.power_off = apus_power_off; + ppc_md.halt = apus_halt; + + ppc_md.time_init = NULL; + ppc_md.set_rtc_time = apus_set_rtc_time; + ppc_md.get_rtc_time = apus_get_rtc_time; + ppc_md.calibrate_decr = apus_calibrate_decr; + + /* These should not be used for the APUS yet, since it uses + the M68K keyboard now. */ + ppc_md.kbd_setkeycode = NULL; + ppc_md.kbd_getkeycode = NULL; + ppc_md.kbd_translate = NULL; + ppc_md.kbd_unexpected_up = NULL; + ppc_md.kbd_leds = NULL; + ppc_md.kbd_init_hw = NULL; + ppc_md.kbd_sysrq_xlate = NULL; + +#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) + ppc_ide_md.insw = apus_ide_insw; + ppc_ide_md.outsw = apus_ide_outsw; + ppc_ide_md.default_irq = apus_ide_default_irq; + ppc_ide_md.default_io_base = apus_ide_default_io_base; + ppc_ide_md.check_region = apus_ide_check_region; + ppc_ide_md.request_region = apus_ide_request_region; + ppc_ide_md.release_region = apus_ide_release_region; + ppc_ide_md.fix_driveid = apus_ide_fix_driveid; + ppc_ide_md.ide_init_hwif = apus_ide_init_hwif_ports; + + ppc_ide_md.io_base = _IO_BASE; +#endif } diff -ur --new-file old/linux/arch/ppc/kernel/chrp_pci.c new/linux/arch/ppc/kernel/chrp_pci.c --- old/linux/arch/ppc/kernel/chrp_pci.c Wed Aug 5 01:06:36 1998 +++ new/linux/arch/ppc/kernel/chrp_pci.c Tue May 11 17:24:32 1999 @@ -15,10 +15,14 @@ #include #include #include +#include +#include + +#include "pci.h" /* LongTrail */ #define pci_config_addr(bus, dev, offset) \ - (GG2_PCI_CONFIG_BASE | ((bus)<<16) | ((dev)<<8) | (offset)) +(GG2_PCI_CONFIG_BASE | ((bus)<<16) | ((dev)<<8) | (offset)) volatile struct Hydra *Hydra = NULL; @@ -30,144 +34,136 @@ int gg2_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned char *val) { - if (bus > 7) { - *val = 0xff; - return PCIBIOS_DEVICE_NOT_FOUND; - } - *val = in_8((unsigned char *)pci_config_addr(bus, dev_fn, offset)); - return PCIBIOS_SUCCESSFUL; + if (bus > 7) { + *val = 0xff; + return PCIBIOS_DEVICE_NOT_FOUND; + } + *val = in_8((unsigned char *)pci_config_addr(bus, dev_fn, offset)); + return PCIBIOS_SUCCESSFUL; } int gg2_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned short *val) { - if (bus > 7) { - *val = 0xffff; - return PCIBIOS_DEVICE_NOT_FOUND; - } - *val = in_le16((unsigned short *)pci_config_addr(bus, dev_fn, offset)); - return PCIBIOS_SUCCESSFUL; + if (bus > 7) { + *val = 0xffff; + return PCIBIOS_DEVICE_NOT_FOUND; + } + *val = in_le16((unsigned short *)pci_config_addr(bus, dev_fn, offset)); + return PCIBIOS_SUCCESSFUL; } int gg2_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned int *val) { - if (bus > 7) { - *val = 0xffffffff; - return PCIBIOS_DEVICE_NOT_FOUND; - } - *val = in_le32((unsigned int *)pci_config_addr(bus, dev_fn, offset)); - return PCIBIOS_SUCCESSFUL; + if (bus > 7) { + *val = 0xffffffff; + return PCIBIOS_DEVICE_NOT_FOUND; + } + *val = in_le32((unsigned int *)pci_config_addr(bus, dev_fn, offset)); + return PCIBIOS_SUCCESSFUL; } int gg2_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned char val) { - if (bus > 7) - return PCIBIOS_DEVICE_NOT_FOUND; - out_8((unsigned char *)pci_config_addr(bus, dev_fn, offset), val); - return PCIBIOS_SUCCESSFUL; + if (bus > 7) + return PCIBIOS_DEVICE_NOT_FOUND; + out_8((unsigned char *)pci_config_addr(bus, dev_fn, offset), val); + return PCIBIOS_SUCCESSFUL; } int gg2_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned short val) { - if (bus > 7) - return PCIBIOS_DEVICE_NOT_FOUND; - out_le16((unsigned short *)pci_config_addr(bus, dev_fn, offset), val); - return PCIBIOS_SUCCESSFUL; + if (bus > 7) + return PCIBIOS_DEVICE_NOT_FOUND; + out_le16((unsigned short *)pci_config_addr(bus, dev_fn, offset), val); + return PCIBIOS_SUCCESSFUL; } int gg2_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned int val) { - if (bus > 7) - return PCIBIOS_DEVICE_NOT_FOUND; - out_le32((unsigned int *)pci_config_addr(bus, dev_fn, offset), val); - return PCIBIOS_SUCCESSFUL; -} - -extern volatile unsigned int *pci_config_address; -extern volatile unsigned char *pci_config_data; - -#define DEV_FN_MAX (31<<3) - -int raven_pcibios_read_config_byte(unsigned char bus, - unsigned char dev_fn, - unsigned char offset, - unsigned char *val) -{ - if (dev_fn >= DEV_FN_MAX) return PCIBIOS_DEVICE_NOT_FOUND; - out_be32(pci_config_address, - 0x80|(bus<<8)|(dev_fn<<16)|((offset&~3)<<24)); - *val = in_8(pci_config_data+(offset&3)); - return PCIBIOS_SUCCESSFUL; -} - -int raven_pcibios_read_config_word(unsigned char bus, - unsigned char dev_fn, - unsigned char offset, - unsigned short *val) -{ - if (dev_fn >= DEV_FN_MAX) return PCIBIOS_DEVICE_NOT_FOUND; - if (offset&1)return PCIBIOS_BAD_REGISTER_NUMBER; - out_be32(pci_config_address, - 0x80|(bus<<8)|(dev_fn<<16)|((offset&~3)<<24)); - *val = in_le16((volatile unsigned short *) - (pci_config_data+(offset&3))); - return PCIBIOS_SUCCESSFUL; -} - -int raven_pcibios_read_config_dword(unsigned char bus, - unsigned char dev_fn, - unsigned char offset, - unsigned int *val) -{ - if (dev_fn >= DEV_FN_MAX) return PCIBIOS_DEVICE_NOT_FOUND; - if (offset&3)return PCIBIOS_BAD_REGISTER_NUMBER; - out_be32(pci_config_address, - 0x80|(bus<<8)|(dev_fn<<16)|(offset<<24)); - *val = in_le32((volatile unsigned int *)(pci_config_data)); - return PCIBIOS_SUCCESSFUL; -} - -int raven_pcibios_write_config_byte(unsigned char bus, - unsigned char dev_fn, - unsigned char offset, - unsigned char val) -{ - if (dev_fn >= DEV_FN_MAX) return PCIBIOS_DEVICE_NOT_FOUND; - out_be32(pci_config_address, - 0x80|(bus<<8)|(dev_fn<<16)|((offset&~3)<<24)); - out_8(pci_config_data+(offset&3),val); - return PCIBIOS_SUCCESSFUL; -} - -int raven_pcibios_write_config_word(unsigned char bus, - unsigned char dev_fn, - unsigned char offset, - unsigned short val) -{ - if (dev_fn >= DEV_FN_MAX) return PCIBIOS_DEVICE_NOT_FOUND; - if (offset&1)return PCIBIOS_BAD_REGISTER_NUMBER; - out_be32(pci_config_address, - 0x80|(bus<<8)|(dev_fn<<16)|((offset&~3)<<24)); - out_le16((volatile unsigned short *)(pci_config_data+(offset&3)),val); - return PCIBIOS_SUCCESSFUL; -} - -int raven_pcibios_write_config_dword(unsigned char bus, - unsigned char dev_fn, - unsigned char offset, - unsigned int val) -{ - if (dev_fn >= DEV_FN_MAX) return PCIBIOS_DEVICE_NOT_FOUND; - if (offset&3)return PCIBIOS_BAD_REGISTER_NUMBER; - out_be32(pci_config_address, - 0x80|(bus<<8)|(dev_fn<<16)|(offset<<24)); - out_le32((volatile unsigned int *)pci_config_data,val); - return PCIBIOS_SUCCESSFUL; + if (bus > 7) + return PCIBIOS_DEVICE_NOT_FOUND; + out_le32((unsigned int *)pci_config_addr(bus, dev_fn, offset), val); + return PCIBIOS_SUCCESSFUL; +} + +#define python_config_address(bus) (unsigned *)((0xfef00000+0xf8000)-(bus*0x100000)) +#define python_config_data(bus) ((0xfef00000+0xf8010)-(bus*0x100000)) +#define PYTHON_CFA(b, d, o) (0x80 | ((b<<6) << 8) | ((d) << 16) \ + | (((o) & ~3) << 24)) +unsigned int python_busnr = 1; + +int python_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn, + unsigned char offset, unsigned char *val) +{ + if (bus > python_busnr) { + *val = 0xff; + return PCIBIOS_DEVICE_NOT_FOUND; + } + out_be32( python_config_address( bus ), PYTHON_CFA(bus,dev_fn,offset)); + *val = in_8((unsigned char *)python_config_data(bus) + (offset&3)); + return PCIBIOS_SUCCESSFUL; +} + +int python_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn, + unsigned char offset, unsigned short *val) +{ + if (bus > python_busnr) { + *val = 0xffff; + return PCIBIOS_DEVICE_NOT_FOUND; + } + out_be32( python_config_address( bus ), PYTHON_CFA(bus,dev_fn,offset)); + *val = in_le16((unsigned short *)(python_config_data(bus) + (offset&3))); + return PCIBIOS_SUCCESSFUL; +} + + +int python_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn, + unsigned char offset, unsigned int *val) +{ + if (bus > python_busnr) { + *val = 0xffffffff; + return PCIBIOS_DEVICE_NOT_FOUND; + } + out_be32( python_config_address( bus ), PYTHON_CFA(bus,dev_fn,offset)); + *val = in_le32((unsigned *)python_config_data(bus)); + return PCIBIOS_SUCCESSFUL; +} + +int python_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn, + unsigned char offset, unsigned char val) +{ + if (bus > python_busnr) + return PCIBIOS_DEVICE_NOT_FOUND; + out_be32( python_config_address( bus ), PYTHON_CFA(bus,dev_fn,offset)); + out_8((volatile unsigned char *)python_config_data(bus) + (offset&3), val); + return PCIBIOS_SUCCESSFUL; +} + +int python_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn, + unsigned char offset, unsigned short val) +{ + if (bus > python_busnr) + return PCIBIOS_DEVICE_NOT_FOUND; + out_be32( python_config_address( bus ), PYTHON_CFA(bus,dev_fn,offset)); + out_le16((volatile unsigned short *)python_config_data(bus) + (offset&3), + val); + return PCIBIOS_SUCCESSFUL; +} + +int python_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn, + unsigned char offset, unsigned int val) +{ + if (bus > python_busnr) + return PCIBIOS_DEVICE_NOT_FOUND; + out_be32( python_config_address( bus ), PYTHON_CFA(bus,dev_fn,offset)); + out_le32((unsigned *)python_config_data(bus) + (offset&3), val); + return PCIBIOS_SUCCESSFUL; } /* @@ -191,7 +187,8 @@ /* all others are 1 (= default) */ }; -__initfunc(int hydra_init(void)) +int __init +hydra_init(void) { struct device_node *np; @@ -216,75 +213,95 @@ return 1; } +void __init +chrp_pcibios_fixup(void) +{ + struct pci_dev *dev; + + /* some of IBM chrps have > 1 bus */ + if ( !strncmp("IBM", get_property(find_path_device("/"), + "name", NULL),3) ) + { + pci_scan_peer_bridge(1); + pci_scan_peer_bridge(2); + } + + /* PCI interrupts are controlled by the OpenPIC */ + for( dev=pci_devices ; dev; dev=dev->next ) + { + if ( dev->irq ) + dev->irq = openpic_to_irq( dev->irq ); + /* adjust the io_port for the NCR cards for busses other than 0 -- Cort */ + if ( (dev->bus->number > 0) && (dev->vendor == PCI_VENDOR_ID_NCR) ) + dev->base_address[0] += (dev->bus->number*0x08000000); + /* these need to be absolute addrs for OF and Matrox FB -- Cort */ + if ( dev->vendor == PCI_VENDOR_ID_MATROX ) + { + if ( dev->base_address[0] < isa_mem_base ) + dev->base_address[0] += isa_mem_base; + if ( dev->base_address[1] < isa_mem_base ) + dev->base_address[1] += isa_mem_base; + } + /* the F50 identifies the amd as a trident */ + if ( (dev->vendor == PCI_VENDOR_ID_TRIDENT) && + (dev->class == PCI_CLASS_NETWORK_ETHERNET) ) + { + dev->vendor = PCI_VENDOR_ID_AMD; + pcibios_write_config_word(dev->bus->number, dev->devfn, + PCI_VENDOR_ID, PCI_VENDOR_ID_AMD); + } + } +} -extern int chrp_ide_irq; +decl_config_access_method(grackle); +decl_config_access_method(indirect); -__initfunc(int w83c553f_init(void)) +void __init +chrp_setup_pci_ptrs(void) { - u_char bus, dev; -#if 0 - unsigned char t8; - unsigned short t16; -#endif - unsigned int t32; - struct pci_dev *pdev; - if ((pdev = pci_find_device(PCI_VENDOR_ID_WINBOND, - PCI_DEVICE_ID_WINBOND_83C553, NULL))) { - bus = pdev->bus->number; - dev = pdev->devfn + 1; - pcibios_read_config_dword(bus, dev, PCI_VENDOR_ID, &t32); - if (t32 == (PCI_DEVICE_ID_WINBOND_82C105<<16) + PCI_VENDOR_ID_WINBOND) { -#if 0 - printk("Enabling SL82C105 IDE on W83C553F\n"); - /* - * FIXME: this doesn't help :-( - */ - - /* I/O mapping */ - pcibios_read_config_word(bus, dev, PCI_COMMAND, &t16); - t16 |= PCI_COMMAND_IO; - pcibios_write_config_word(bus, dev, PCI_COMMAND, t16); - - /* Standard IDE registers */ - pcibios_write_config_dword(bus, dev, PCI_BASE_ADDRESS_0, - 0xffffffff); - pcibios_read_config_dword(bus, dev, PCI_BASE_ADDRESS_0, &t32); - pcibios_write_config_dword(bus, dev, PCI_BASE_ADDRESS_0, - 0x000001f0 | 1); - pcibios_write_config_dword(bus, dev, PCI_BASE_ADDRESS_1, - 0xffffffff); - pcibios_read_config_dword(bus, dev, PCI_BASE_ADDRESS_1, &t32); - pcibios_write_config_dword(bus, dev, PCI_BASE_ADDRESS_1, - 0x000003f4 | 1); - pcibios_write_config_dword(bus, dev, PCI_BASE_ADDRESS_2, - 0xffffffff); - pcibios_read_config_dword(bus, dev, PCI_BASE_ADDRESS_2, &t32); - pcibios_write_config_dword(bus, dev, PCI_BASE_ADDRESS_2, - 0x00000170 | 1); - pcibios_write_config_dword(bus, dev, PCI_BASE_ADDRESS_3, - 0xffffffff); - pcibios_read_config_dword(bus, dev, PCI_BASE_ADDRESS_3, &t32); - pcibios_write_config_dword(bus, dev, PCI_BASE_ADDRESS_3, - 0x00000374 | 1); - - /* IDE Bus Master Control */ - pcibios_write_config_dword(bus, dev, PCI_BASE_ADDRESS_4, - 0xffffffff); - pcibios_read_config_dword(bus, dev, PCI_BASE_ADDRESS_4, &t32); - pcibios_write_config_dword(bus, dev, PCI_BASE_ADDRESS_4, - 0x1000 | 1); - pcibios_write_config_dword(bus, dev, PCI_BASE_ADDRESS_5, - 0xffffffff); - pcibios_read_config_dword(bus, dev, PCI_BASE_ADDRESS_5, &t32); - pcibios_write_config_dword(bus, dev, PCI_BASE_ADDRESS_5, - 0x1010 | 1); - - /* IDE Interrupt */ - pcibios_read_config_byte(bus, dev, PCI_INTERRUPT_LINE, &t8); - chrp_ide_irq = t8; -#endif - return 1; - } - } - return 0; + struct device_node *py; + + if ( !strncmp("MOT", + get_property(find_path_device("/"), "model", NULL),3) ) + { + pci_dram_offset = 0; + isa_mem_base = 0xf7000000; + isa_io_base = 0xfe000000; + set_config_access_method(grackle); + } + else + { + if ( (py = find_compatible_devices( "pci", "IBM,python" )) ) + { + /* find out how many pythons */ + while ( (py = py->next) ) python_busnr++; + set_config_access_method(python); + /* + * We base these values on the machine type but should + * try to read them from the python controller itself. + * -- Cort + */ + if ( !strncmp("IBM,7025-F50", get_property(find_path_device("/"), "name", NULL),12) ) + { + pci_dram_offset = 0x80000000; + isa_mem_base = 0xa0000000; + isa_io_base = 0x88000000; + } else if ( !strncmp("IBM,7043-260", + get_property(find_path_device("/"), "name", NULL),12) ) + { + pci_dram_offset = 0x80000000; + isa_mem_base = 0xc0000000; + isa_io_base = 0xf8000000; + } + } + else + { + pci_dram_offset = 0; + isa_mem_base = 0xf7000000; + isa_io_base = 0xf8000000; + set_config_access_method(gg2); + } + } + + ppc_md.pcibios_fixup = chrp_pcibios_fixup; } diff -ur --new-file old/linux/arch/ppc/kernel/chrp_setup.c new/linux/arch/ppc/kernel/chrp_setup.c --- old/linux/arch/ppc/kernel/chrp_setup.c Sun Nov 15 19:51:43 1998 +++ new/linux/arch/ppc/kernel/chrp_setup.c Tue May 11 17:24:32 1999 @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -40,9 +41,50 @@ #include #include #include - -extern void hydra_init(void); -extern void w83c553f_init(void); +#include +#include +#include +#include +#include + +#include "time.h" +#include "local_irq.h" +#include "i8259.h" +#include "open_pic.h" + +/* Fixme - need to move these into their own .c and .h file */ +extern void i8259_mask_and_ack_irq(unsigned int irq_nr); +extern void i8259_set_irq_mask(unsigned int irq_nr); +extern void i8259_mask_irq(unsigned int irq_nr); +extern void i8259_unmask_irq(unsigned int irq_nr); +extern void i8259_init(void); + +/* Fixme - remove this when it is fixed. - Corey */ +extern volatile unsigned char *chrp_int_ack_special; + +unsigned long chrp_get_rtc_time(void); +int chrp_set_rtc_time(unsigned long nowtime); +void chrp_calibrate_decr(void); +void chrp_time_init(void); + +void chrp_setup_pci_ptrs(void); + +extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode); +extern int pckbd_getkeycode(unsigned int scancode); +extern int pckbd_translate(unsigned char scancode, unsigned char *keycode, + char raw_mode); +extern char pckbd_unexpected_up(unsigned char keycode); +extern void pckbd_leds(unsigned char leds); +extern void pckbd_init_hw(void); +extern unsigned char pckbd_sysrq_xlate[128]; +extern int mackbd_setkeycode(unsigned int scancode, unsigned int keycode); +extern int mackbd_getkeycode(unsigned int scancode); +extern int mackbd_translate(unsigned char scancode, unsigned char *keycode, + char raw_mode); +extern char mackbd_unexpected_up(unsigned char keycode); +extern void mackbd_leds(unsigned char leds); +extern void mackbd_init_hw(void); +extern unsigned char mackbd_sysrq_xlate[128]; /* for the mac fs */ kdev_t boot_dev; @@ -53,7 +95,6 @@ extern unsigned long loops_per_sec; unsigned long empty_zero_page[1024]; -extern unsigned char aux_device_present; #ifdef CONFIG_BLK_DEV_RAM extern int rd_doload; /* 1 = load ramdisk, 0 = don't load */ @@ -62,17 +103,17 @@ #endif static const char *gg2_memtypes[4] = { - "FPM", "SDRAM", "EDO", "BEDO" + "FPM", "SDRAM", "EDO", "BEDO" }; static const char *gg2_cachesizes[4] = { - "256 KB", "512 KB", "1 MB", "Reserved" + "256 KB", "512 KB", "1 MB", "Reserved" }; static const char *gg2_cachetypes[4] = { - "Asynchronous", "Reserved", "Flow-Through Synchronous", - "Pipelined Synchronous" + "Asynchronous", "Reserved", "Flow-Through Synchronous", + "Pipelined Synchronous" }; static const char *gg2_cachemodes[4] = { - "Disabled", "Write-Through", "Copy-Back", "Transparent Mode" + "Disabled", "Write-Through", "Copy-Back", "Transparent Mode" }; int @@ -85,53 +126,60 @@ root = find_path_device("/"); if (root) - model = get_property(root, "model", NULL); + model = get_property(root, "model", NULL); len = sprintf(buffer,"machine\t\t: CHRP %s\n", model); - /* VLSI VAS96011/12 `Golden Gate 2' */ - /* Memory banks */ - sdramen = (in_le32((unsigned *)(GG2_PCI_CONFIG_BASE+GG2_PCI_DRAM_CTRL)) - >>31) & 1; - for (i = 0; i < (sdramen ? 4 : 6); i++) { - t = in_le32((unsigned *)(GG2_PCI_CONFIG_BASE+GG2_PCI_DRAM_BANK0+ - i*4)); - if (!(t & 1)) - continue; - switch ((t>>8) & 0x1f) { - case 0x1f: - model = "4 MB"; - break; - case 0x1e: - model = "8 MB"; - break; - case 0x1c: - model = "16 MB"; - break; - case 0x18: - model = "32 MB"; - break; - case 0x10: - model = "64 MB"; - break; - case 0x00: - model = "128 MB"; - break; - default: - model = "Reserved"; - break; - } - len += sprintf(buffer+len, "memory bank %d\t: %s %s\n", i, model, - gg2_memtypes[sdramen ? 1 : ((t>>1) & 3)]); - } - /* L2 cache */ - t = in_le32((unsigned *)(GG2_PCI_CONFIG_BASE+GG2_PCI_CC_CTRL)); - len += sprintf(buffer+len, "board l2\t: %s %s (%s)\n", - gg2_cachesizes[(t>>7) & 3], gg2_cachetypes[(t>>2) & 3], - gg2_cachemodes[t & 3]); + /* longtrail (goldengate) stuff */ + if ( !strncmp( model, "IBM,LongTrail", 9 ) ) + { + /* VLSI VAS96011/12 `Golden Gate 2' */ + /* Memory banks */ + sdramen = (in_le32((unsigned *)(GG2_PCI_CONFIG_BASE+ + GG2_PCI_DRAM_CTRL)) + >>31) & 1; + for (i = 0; i < (sdramen ? 4 : 6); i++) { + t = in_le32((unsigned *)(GG2_PCI_CONFIG_BASE+ + GG2_PCI_DRAM_BANK0+ + i*4)); + if (!(t & 1)) + continue; + switch ((t>>8) & 0x1f) { + case 0x1f: + model = "4 MB"; + break; + case 0x1e: + model = "8 MB"; + break; + case 0x1c: + model = "16 MB"; + break; + case 0x18: + model = "32 MB"; + break; + case 0x10: + model = "64 MB"; + break; + case 0x00: + model = "128 MB"; + break; + default: + model = "Reserved"; + break; + } + len += sprintf(buffer+len, "memory bank %d\t: %s %s\n", i, model, + gg2_memtypes[sdramen ? 1 : ((t>>1) & 3)]); + } + /* L2 cache */ + t = in_le32((unsigned *)(GG2_PCI_CONFIG_BASE+GG2_PCI_CC_CTRL)); + len += sprintf(buffer+len, "board l2\t: %s %s (%s)\n", + gg2_cachesizes[(t>>7) & 3], + gg2_cachetypes[(t>>2) & 3], + gg2_cachemodes[t & 3]); + } return len; } - /* +/* * Fixes for the National Semiconductor PC78308VUL SuperI/O * * Some versions of Open Firmware incorrectly initialize the IRQ settings @@ -140,57 +188,55 @@ __initfunc(static inline void sio_write(u8 val, u8 index)) { - outb(index, 0x15c); - outb(val, 0x15d); + outb(index, 0x15c); + outb(val, 0x15d); } __initfunc(static inline u8 sio_read(u8 index)) { - outb(index, 0x15c); - return inb(0x15d); + outb(index, 0x15c); + return inb(0x15d); } __initfunc(static void sio_fixup_irq(const char *name, u8 device, u8 level, u8 type)) { - u8 level0, type0, active; + u8 level0, type0, active; - /* select logical device */ - sio_write(device, 0x07); - active = sio_read(0x30); - level0 = sio_read(0x70); - type0 = sio_read(0x71); - printk("sio: %s irq level %d, type %d, %sactive: ", name, level0, type0, - !active ? "in" : ""); - if (level0 == level && type0 == type && active) - printk("OK\n"); - else { - printk("remapping to level %d, type %d, active\n", level, type); - sio_write(0x01, 0x30); - sio_write(level, 0x70); - sio_write(type, 0x71); - } + /* select logical device */ + sio_write(device, 0x07); + active = sio_read(0x30); + level0 = sio_read(0x70); + type0 = sio_read(0x71); + printk("sio: %s irq level %d, type %d, %sactive: ", name, level0, type0, + !active ? "in" : ""); + if (level0 == level && type0 == type && active) + printk("OK\n"); + else { + printk("remapping to level %d, type %d, active\n", level, type); + sio_write(0x01, 0x30); + sio_write(level, 0x70); + sio_write(type, 0x71); + } } __initfunc(static void sio_init(void)) { - /* logical device 0 (KBC/Keyboard) */ - sio_fixup_irq("keyboard", 0, 1, 2); - /* select logical device 1 (KBC/Mouse) */ - sio_fixup_irq("mouse", 1, 12, 2); + /* logical device 0 (KBC/Keyboard) */ + sio_fixup_irq("keyboard", 0, 1, 2); + /* select logical device 1 (KBC/Mouse) */ + sio_fixup_irq("mouse", 1, 12, 2); } __initfunc(void -chrp_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p)) + chrp_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p)) { extern char cmd_line[]; /* init to some ~sane value until calibrate_delay() runs */ loops_per_sec = 50000000; - - aux_device_present = 0xaa; #ifdef CONFIG_BLK_DEV_INITRD /* this is fine for chrp */ @@ -219,8 +265,15 @@ * -- Geert */ hydra_init(); /* Mac I/O */ - w83c553f_init(); /* PCI-ISA bridge and IDE */ + /* Some IBM machines don't have the hydra -- Cort */ + if ( !OpenPIC ) + { + OpenPIC = (struct OpenPIC *)*(unsigned long *)get_property( + find_path_device("/"), "platform-open-pic", NULL); + OpenPIC = ioremap((unsigned long)OpenPIC, sizeof(struct OpenPIC)); + } + /* * Fix the Super I/O configuration */ @@ -232,27 +285,210 @@ if ( !strncmp("MOT", get_property(find_path_device("/"), "model", NULL),3) ) *memory_start_p = pmac_find_bridges(*memory_start_p, *memory_end_p); + /* + * The f50 has a lot of IO space - we need to map some in that + * isn't covered by the BAT mappings in MMU_init() -- Cort + */ + if ( !strncmp("F5", get_property(find_path_device("/"), + "ibm,model-class", NULL),2) ) + { +#if 0 + /* + * This ugly hack allows us to force ioremap() to + * create a 1-to-1 mapping for us, even though + * the address is < ioremap_base. This is necessary + * since we want our PCI IO space to have contiguous + * virtual addresses and I think it's worse to have + * calls to map_page() here. + * -- Cort + */ + unsigned long hold = ioremap_base; + ioremap_base = 0; + __ioremap(0x90000000, 0x10000000, _PAGE_NO_CACHE); + ioremap_base = hold; +#endif + } } -#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) +void +chrp_restart(char *cmd) +{ +#if 0 + extern unsigned int rtas_entry, rtas_data, rtas_size; + printk("RTAS system-reboot returned %d\n", + call_rtas("system-reboot", 0, 1, NULL)); + printk("rtas_entry: %08lx rtas_data: %08lx rtas_size: %08lx\n", + rtas_entry,rtas_data,rtas_size); + for (;;); +#else + printk("System Halted\n"); + while(1); +#endif +} -unsigned int chrp_ide_irq = 0; -int chrp_ide_ports_known = 0; -ide_ioreg_t chrp_ide_regbase[MAX_HWIFS]; -ide_ioreg_t chrp_idedma_regbase; +void +chrp_power_off(void) +{ + /* RTAS doesn't seem to work on Longtrail. + For now, do it the same way as the PReP. */ +#if 0 + extern unsigned int rtas_entry, rtas_data, rtas_size; + printk("RTAS power-off returned %d\n", + call_rtas("power-off", 2, 1, NULL, 0, 0)); + printk("rtas_entry: %08lx rtas_data: %08lx rtas_size: %08lx\n", + rtas_entry,rtas_data,rtas_size); + for (;;); +#else + chrp_restart(NULL); +#endif +} -void chrp_ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq) +void +chrp_halt(void) { - ide_ioreg_t port = base; - int i = 8; + chrp_restart(NULL); +} - while (i--) - *p++ = port++; - *p++ = port; - if (irq != NULL) - *irq = chrp_ide_irq; +u_int +chrp_irq_cannonicalize(u_int irq) +{ + if (irq == 2) + { + return 9; + } + else + { + return irq; + } +} + +void +chrp_do_IRQ(struct pt_regs *regs, + int cpu, + int isfake) +{ + int irq; + unsigned long bits = 0; + int openpic_eoi_done = 0; + +#ifdef __SMP__ + { + unsigned int loops = 1000000; + while (test_bit(0, &global_irq_lock)) { + if (smp_processor_id() == global_irq_holder) { + printk("uh oh, interrupt while we hold global irq lock!\n"); +#ifdef CONFIG_XMON + xmon(0); +#endif + break; + } + if (loops-- == 0) { + printk("do_IRQ waiting for irq lock (holder=%d)\n", global_irq_holder); +#ifdef CONFIG_XMON + xmon(0); +#endif + } + } + } +#endif /* __SMP__ */ + + irq = openpic_irq(0); + if (irq == IRQ_8259_CASCADE) + { + /* + * This magic address generates a PCI IACK cycle. + * + * This should go in the above mask/ack code soon. -- Cort + */ + if ( chrp_int_ack_special ) + irq = *chrp_int_ack_special; + else + irq = i8259_irq(0); + /* + * Acknowledge as soon as possible to allow i8259 + * interrupt nesting */ + openpic_eoi(0); + openpic_eoi_done = 1; + } + if (irq == OPENPIC_VEC_SPURIOUS) + { + /* + * Spurious interrupts should never be + * acknowledged + */ + ppc_spurious_interrupts++; + openpic_eoi_done = 1; + goto out; + } + bits = 1UL << irq; + + if (irq < 0) + { + printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n", + irq, regs->nip); + ppc_spurious_interrupts++; + } + else + { + ppc_irq_dispatch_handler( regs, irq ); + } +out: + if (!openpic_eoi_done) + openpic_eoi(0); } +__initfunc(void + chrp_init_IRQ(void)) +{ + struct device_node *np; + int i; + + if ( !(np = find_devices("pci") ) ) + printk("Cannot find pci to get ack address\n"); + else + { + chrp_int_ack_special = (volatile unsigned char *) + (*(unsigned long *)get_property(np, + "8259-interrupt-acknowledge", NULL)); + } + for ( i = 16 ; i < NR_IRQS ; i++ ) + irq_desc[i].ctl = &open_pic; + /* openpic knows that it's at irq 16 offset + * so we don't need to set it in the pic structure + * -- Cort + */ + openpic_init(1); + for ( i = 0 ; i < 16 ; i++ ) + irq_desc[i].ctl = &i8259_pic; + i8259_init(); +#ifdef CONFIG_XMON + request_irq(openpic_to_irq(HYDRA_INT_ADB_NMI), + xmon_irq, 0, "NMI", 0); +#endif /* CONFIG_XMON */ +#ifdef __SMP__ + request_irq(openpic_to_irq(OPENPIC_VEC_IPI), + openpic_ipi_action, 0, "IPI0", 0); +#endif /* __SMP__ */ +} + +__initfunc(void + chrp_init2(void)) +{ + adb_init(); + + /* Should this be here? - Corey */ + pmac_nvram_init(); +} + +#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) +/* + * IDE stuff. + */ +unsigned int chrp_ide_irq = 0; +int chrp_ide_ports_known = 0; +ide_ioreg_t chrp_ide_regbase[MAX_HWIFS]; +ide_ioreg_t chrp_idedma_regbase; + void chrp_ide_probe(void) { struct pci_dev *pdev = pci_find_device(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105, NULL); @@ -270,9 +506,167 @@ } } +void +chrp_ide_insw(ide_ioreg_t port, void *buf, int ns) +{ + ide_insw(port+_IO_BASE, buf, ns); +} + +void +chrp_ide_outsw(ide_ioreg_t port, void *buf, int ns) +{ + ide_outsw(port+_IO_BASE, buf, ns); +} + +int +chrp_ide_default_irq(ide_ioreg_t base) +{ + if (chrp_ide_ports_known == 0) + chrp_ide_probe(); + return chrp_ide_irq; +} + +ide_ioreg_t +chrp_ide_default_io_base(int index) +{ + if (chrp_ide_ports_known == 0) + chrp_ide_probe(); + return chrp_ide_regbase[index]; +} + +int +chrp_ide_check_region(ide_ioreg_t from, unsigned int extent) +{ + return check_region(from, extent); +} + +void +chrp_ide_request_region(ide_ioreg_t from, + unsigned int extent, + const char *name) +{ + request_region(from, extent, name); +} + +void +chrp_ide_release_region(ide_ioreg_t from, + unsigned int extent) +{ + release_region(from, extent); +} + +void +chrp_ide_fix_driveid(struct hd_driveid *id) +{ + ppc_generic_ide_fix_driveid(id); +} + +void chrp_ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq) +{ + ide_ioreg_t port = base; + int i = 8; + + while (i--) + *p++ = port++; + *p++ = port; + if (irq != NULL) + *irq = chrp_ide_irq; +} + EXPORT_SYMBOL(chrp_ide_irq); EXPORT_SYMBOL(chrp_ide_ports_known); EXPORT_SYMBOL(chrp_ide_regbase); EXPORT_SYMBOL(chrp_ide_probe); #endif + +__initfunc(void + chrp_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7)) +{ + chrp_setup_pci_ptrs(); +#ifdef CONFIG_BLK_DEV_INITRD + /* take care of initrd if we have one */ + if ( r3 ) + { + initrd_start = r3 + KERNELBASE; + initrd_end = r3 + r4 + KERNELBASE; + } +#endif /* CONFIG_BLK_DEV_INITRD */ + + /* pci_dram_offset/isa_io_base/isa_mem_base set by setup_pci_ptrs() */ + ISA_DMA_THRESHOLD = ~0L; + DMA_MODE_READ = 0x44; + DMA_MODE_WRITE = 0x48; + + ppc_md.setup_arch = chrp_setup_arch; + ppc_md.setup_residual = NULL; + ppc_md.get_cpuinfo = chrp_get_cpuinfo; + ppc_md.irq_cannonicalize = chrp_irq_cannonicalize; + ppc_md.init_IRQ = chrp_init_IRQ; + ppc_md.do_IRQ = chrp_do_IRQ; + + ppc_md.init = chrp_init2; + + ppc_md.restart = chrp_restart; + ppc_md.power_off = chrp_power_off; + ppc_md.halt = chrp_halt; + + ppc_md.time_init = chrp_time_init; + ppc_md.set_rtc_time = chrp_set_rtc_time; + ppc_md.get_rtc_time = chrp_get_rtc_time; + ppc_md.calibrate_decr = chrp_calibrate_decr; + +#ifdef CONFIG_VT +#ifdef CONFIG_MAC_KEYBOAD + if ( adb_hardware == ADB_NONE ) + { + ppc_md.kbd_setkeycode = pckbd_setkeycode; + ppc_md.kbd_getkeycode = pckbd_getkeycode; + ppc_md.kbd_translate = pckbd_translate; + ppc_md.kbd_unexpected_up = pckbd_unexpected_up; + ppc_md.kbd_leds = pckbd_leds; + ppc_md.kbd_init_hw = pckbd_init_hw; +#ifdef CONFIG_MAGIC_SYSRQ + ppc_md.kbd_sysrq_xlate = pckbd_sysrq_xlate; +#endif + } + else + { + ppc_md.kbd_setkeycode = mackbd_setkeycode; + ppc_md.kbd_getkeycode = mackbd_getkeycode; + ppc_md.kbd_translate = mackbd_translate; + ppc_md.kbd_unexpected_up = mackbd_unexpected_up; + ppc_md.kbd_leds = mackbd_leds; + ppc_md.kbd_init_hw = mackbd_init_hw; +#ifdef CONFIG_MAGIC_SYSRQ + ppc_md.kbd_sysrq_xlate = mackbd_sysrq_xlate; +#endif + } +#else + ppc_md.kbd_setkeycode = pckbd_setkeycode; + ppc_md.kbd_getkeycode = pckbd_getkeycode; + ppc_md.kbd_translate = pckbd_translate; + ppc_md.kbd_unexpected_up = pckbd_unexpected_up; + ppc_md.kbd_leds = pckbd_leds; + ppc_md.kbd_init_hw = pckbd_init_hw; +#ifdef CONFIG_MAGIC_SYSRQ + ppc_md.kbd_sysrq_xlate = pckbd_sysrq_xlate; +#endif +#endif +#endif + +#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) + ppc_ide_md.insw = chrp_ide_insw; + ppc_ide_md.outsw = chrp_ide_outsw; + ppc_ide_md.default_irq = chrp_ide_default_irq; + ppc_ide_md.default_io_base = chrp_ide_default_io_base; + ppc_ide_md.check_region = chrp_ide_check_region; + ppc_ide_md.request_region = chrp_ide_request_region; + ppc_ide_md.release_region = chrp_ide_release_region; + ppc_ide_md.fix_driveid = chrp_ide_fix_driveid; + ppc_ide_md.ide_init_hwif = chrp_ide_init_hwif_ports; + + ppc_ide_md.io_base = _IO_BASE; +#endif +} diff -ur --new-file old/linux/arch/ppc/kernel/chrp_time.c new/linux/arch/ppc/kernel/chrp_time.c --- old/linux/arch/ppc/kernel/chrp_time.c Fri May 8 09:18:14 1998 +++ new/linux/arch/ppc/kernel/chrp_time.c Fri Mar 19 19:50:03 1999 @@ -154,7 +154,8 @@ __initfunc(void chrp_calibrate_decr(void)) { struct device_node *cpu; - int freq, *fp, divisor; + int *fp, divisor; + unsigned long freq; if (via_calibrate_decr()) return; @@ -170,10 +171,9 @@ if (fp != 0) freq = *fp; } - freq *= 60; /* try to make freq/1e6 an integer */ divisor = 60; - printk("time_init: decrementer frequency = %d/%d\n", freq, divisor); + printk("time_init: decrementer frequency = %lu/%d\n", freq, divisor); decrementer_count = freq / HZ / divisor; count_period_num = divisor; count_period_den = freq / 1000000; diff -ur --new-file old/linux/arch/ppc/kernel/feature.c new/linux/arch/ppc/kernel/feature.c --- old/linux/arch/ppc/kernel/feature.c Sun Nov 15 19:51:43 1998 +++ new/linux/arch/ppc/kernel/feature.c Thu Mar 11 06:30:31 1999 @@ -41,7 +41,6 @@ OH_BAY_FLOPPY_ENABLE, /* FEATURE_Mediabay_floppy_enable */ 0, /* FEATURE_BMac_reset */ 0, /* FEATURE_BMac_IO_enable */ - 0, /* FEATURE_Modem_PowerOn -> guess...*/ 0 /* FEATURE_Modem_Reset -> guess...*/ }; @@ -64,8 +63,7 @@ OH_BAY_FLOPPY_ENABLE, /* FEATURE_Mediabay_floppy_enable */ 0x80000000, /* FEATURE_BMac_reset */ 0x60000000, /* FEATURE_BMac_IO_enable */ - 0x02000000, /* FEATURE_Modem_PowerOn -> guess...*/ - 0x07000000 /* FEATURE_Modem_Reset -> guess...*/ + 0x02000000 /* FEATURE_Modem_Reset -> guess...*/ }; /* definition of a feature controller object */ diff -ur --new-file old/linux/arch/ppc/kernel/head.S new/linux/arch/ppc/kernel/head.S --- old/linux/arch/ppc/kernel/head.S Wed Dec 30 19:55:07 1998 +++ new/linux/arch/ppc/kernel/head.S Tue May 11 17:24:32 1999 @@ -1,7 +1,7 @@ /* * arch/ppc/kernel/head.S * - * $Id: head.S,v 1.114 1998/12/28 10:28:45 paulus Exp $ + * $Id: head.S,v 1.130 1999/05/09 19:16:43 cort Exp $ * * PowerPC version * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) @@ -44,8 +44,13 @@ /* optimization for 603 to load the tlb directly from the linux table */ #define NO_RELOAD_HTAB 1 +#ifndef CONFIG_8xx CACHE_LINE_SIZE = 32 LG_CACHE_LINE_SIZE = 5 +#else +CACHE_LINE_SIZE = 16 +LG_CACHE_LINE_SIZE = 4 +#endif #define TOPHYS(x) (x - KERNELBASE) @@ -81,13 +86,12 @@ sync; \ isync -/* This instruction is not implemented on the PPC 603 or 601 */ #ifndef CONFIG_8xx /* This instruction is not implemented on the PPC 603 or 601 */ #define tlbia \ li r4,128; \ mtctr r4; \ - lis r4,0xC000; \ + lis r4,KERNELBASE@h; \ 0: tlbie r4; \ addi r4,r4,0x1000; \ bdnz 0b @@ -212,6 +216,7 @@ mr r29,r5 mr r28,r6 mr r27,r7 + li r24,0 /* cpu # */ #ifndef CONFIG_8xx bl prom_init .globl __secondary_start @@ -236,15 +241,33 @@ mtspr IBAT1L,r10 b 5f 4: -#ifndef CONFIG_APUS - ori r11,r11,0x1fe /* set up BAT registers for 604 */ - li r8,2 /* R/W access */ -#else +#ifdef CONFIG_APUS + ori r11,r11,BL_8M<<2|0x2 /* set up an 8MB mapping */ ori r11,r11,0xfe /* set up an 8MB mapping */ lis r8,CYBERBASEp@h lwz r8,0(r8) addis r8,r8,KERNELBASE@h addi r8,r8,2 +#else + ori r11,r11,BL_256M<<2|0x2 /* set up BAT registers for 604 */ + li r8,2 /* R/W access */ + /* + * allow secondary cpus to get at all of ram in early bootup + * since their init_task may be up there -- Cort + */ + oris r18,r8,0x10000000@h + oris r21,r11,(KERNELBASE+0x10000000)@h + mtspr DBAT1L,r18 /* N.B. 6xx (not 601) have valid */ + mtspr DBAT1U,r21 /* bit in upper BAT register */ + mtspr IBAT1L,r18 + mtspr IBAT1U,r21 + + oris r18,r8,0x20000000@h + oris r21,r11,(KERNELBASE+0x20000000)@h + mtspr DBAT2L,r18 /* N.B. 6xx (not 601) have valid */ + mtspr DBAT2U,r21 /* bit in upper BAT register */ + mtspr IBAT2L,r28 + mtspr IBAT2U,r21 #endif mtspr DBAT0L,r8 /* N.B. 6xx (not 601) have valid */ mtspr DBAT0U,r11 /* bit in upper BAT register */ @@ -327,20 +350,28 @@ lis r8, MI_Kp@h /* Set the protection mode */ mtspr MI_AP, r8 mtspr MD_AP, r8 -#ifdef CONFIG_MBX + +/* We will get these from a configuration file as soon as I verify + * the extraneous bits don't cause problems in the TLB. + */ +#if defined(CONFIG_MBX) || defined(CONFIG_RPXLITE) +#define BOOT_IMMR 0xfa000000 +#endif +#ifdef CONFIG_BSEIP +#define BOOT_IMMR 0xff000000 +#endif /* Map another 8 MByte at 0xfa000000 to get the processor * internal registers (among other things). */ - lis r8, 0xfa000000@h /* Create vaddr for TLB */ + lis r8, BOOT_IMMR@h /* Create vaddr for TLB */ ori r8, r8, MD_EVALID /* Mark it valid */ mtspr MD_EPN, r8 li r8, MD_PS8MEG /* Set 8M byte page */ ori r8, r8, MD_SVALID /* Make it valid */ mtspr MD_TWC, r8 - lis r8, 0xfa000000@h /* Create paddr for TLB */ + lis r8, BOOT_IMMR@h /* Create paddr for TLB */ ori r8, r8, MI_BOOTINIT|0x2 /* Inhibit cache -- Cort */ mtspr MD_RPN, r8 -#endif /* Since the cache is enabled according to the information we * just loaded into the TLB, invalidate and enable the caches here. @@ -354,9 +385,8 @@ #if 0 mtspr DC_CST, r8 #else - /* I still have a bug somewhere because the Ethernet driver - * does not want to work with copyback enabled. For now, - * at least enable write through. + /* For a debug option, I left this here to easily enable + * the write through cache mode */ lis r8, DC_SFWT@h mtspr DC_CST, r8 @@ -385,7 +415,7 @@ * this, we leave this much untouched space on the stack on exception * entry. */ -#define STACK_UNDERHEAD 64 +#define STACK_UNDERHEAD 0 /* * Exception entry code. This code runs with address translation @@ -442,7 +472,11 @@ .long int_return /* System reset */ +#ifdef CONFIG_SMP /* MVME/MTX start the secondary here */ + STD_EXCEPTION(0x100, Reset, __secondary_start_psurge) +#else STD_EXCEPTION(0x100, Reset, UnknownException) +#endif /* Machine check */ STD_EXCEPTION(0x200, MachineCheck, MachineCheckException) @@ -1148,6 +1182,8 @@ mflr r23 andi. r24,r23,0x3f00 /* get vector offset */ stw r24,TRAP(r21) + li r22,RESULT + stwcx. r22,r22,r21 /* to clear the reservation */ li r22,0 stw r22,RESULT(r21) mtspr SPRG2,r22 /* r1 is now kernel sp */ @@ -1155,7 +1191,7 @@ cmplw 0,r1,r2 cmplw 1,r1,r24 crand 1,1,4 - bgt stack_ovf /* if r2 < r1 < r2+TASK_STRUCT_SIZE */ + bgt- stack_ovf /* if r2 < r1 < r2+TASK_STRUCT_SIZE */ lwz r24,0(r23) /* virtual address of handler */ lwz r23,4(r23) /* where to go when done */ mtspr SRR0,r24 @@ -1204,13 +1240,10 @@ Hash_bits = 12 /* e.g. 256kB hash table */ Hash_msk = (((1 << Hash_bits) - 1) * 64) - .globl hash_table_lock -hash_table_lock: -.long 0 - .globl hash_page hash_page: #ifdef __SMP__ + eieio lis r2,hash_table_lock@h ori r2,r2,hash_table_lock@l tophys(r2,r2,r6) @@ -1226,7 +1259,7 @@ 12: cmpw r6,r0 bdnzf 2,10b tw 31,31,31 -11: +11: eieio #endif /* Get PTE (linux-style) and check access */ lwz r5,PG_TABLES(r5) @@ -1234,13 +1267,25 @@ rlwimi r5,r3,12,20,29 /* insert top 10 bits of address */ lwz r5,0(r5) /* get pmd entry */ rlwinm. r5,r5,0,0,19 /* extract address of pte page */ +#ifdef __SMP__ beq- hash_page_out /* return if no mapping */ +#else + /* XXX it seems like the 601 will give a machine fault on the + rfi if its alignment is wrong (bottom 4 bits of address are + 8 or 0xc) and we have had a not-taken conditional branch + to the address following the rfi. */ + beqlr- +#endif tophys(r2,r5,r2) rlwimi r2,r3,22,20,29 /* insert next 10 bits of address */ lwz r6,0(r2) /* get linux-style pte */ ori r4,r4,1 /* set _PAGE_PRESENT bit in access */ andc. r0,r4,r6 /* check access & ~permission */ +#ifdef __SMP__ bne- hash_page_out /* return if access not permitted */ +#else + bnelr- +#endif ori r6,r6,0x100 /* set _PAGE_ACCESSED in pte */ rlwinm r5,r4,5,24,24 /* _PAGE_RW access -> _PAGE_DIRTY */ @@ -1257,7 +1302,9 @@ /* Construct the high word of the PPC-style PTE */ mfsrin r5,r3 /* get segment reg for segment */ rlwinm r5,r5,7,1,24 /* put VSID in 0x7fffff80 bits */ +#ifndef __SMP__ /* do this later for SMP */ oris r5,r5,0x8000 /* set V (valid) bit */ +#endif rlwimi r5,r3,10,26,31 /* put in API (abbrev page index) */ /* Get the address of the primary PTE group in the hash table */ @@ -1274,9 +1321,6 @@ li r2,8 /* PTEs/group */ bne 10f /* no PTE: go look for an empty slot */ tlbie r3 /* invalidate TLB entry */ -#ifdef __SMP__ - tlbsync -#endif /* Search the primary PTEG for a PTE whose 1st word matches r5 */ mtctr r2 @@ -1345,18 +1389,43 @@ addi r4,r4,1 stw r4,0(r2) +#ifndef __SMP__ /* Store PTE in PTEG */ found_empty: stw r5,0(r3) found_slot: stw r6,4(r3) - SYNC + sync + +#else /* __SMP__ */ /* - * These nop's seem to be necessary to avoid getting a machine - * check on the rfi on 601 processors. + * Between the tlbie above and updating the hash table entry below, + * another CPU could read the hash table entry and put it in its TLB. + * There are 3 cases: + * 1. using an empty slot + * 2. updating an earlier entry to change permissions (i.e. enable write) + * 3. taking over the PTE for an unrelated address + * + * In each case it doesn't really matter if the other CPUs have the old + * PTE in their TLB. So we don't need to bother with another tlbie here, + * which is convenient as we've overwritten the register that had the + * address. :-) The tlbie above is mainly to make sure that this CPU comes + * and gets the new PTE from the hash table. + * + * We do however have to make sure that the PTE is never in an invalid + * state with the V bit set. */ - nop - nop +found_empty: +found_slot: + stw r5,0(r3) /* clear V (valid) bit in PTE */ + sync + tlbsync + sync + stw r6,4(r3) /* put in correct RPN, WIMG, PP bits */ + sync + oris r5,r5,0x8000 + stw r5,0(r3) /* finally set V bit in PTE */ +#endif /* __SMP__ */ /* * Update the hash table miss count. We only want misses here @@ -1380,6 +1449,7 @@ tophys(r2,r2,r6) li r0,0 stw r0,hash_table_lock@l(r2) + eieio #endif /* Return from the exception */ @@ -1398,17 +1468,22 @@ REST_GPR(20, r21) REST_2GPRS(22, r21) lwz r21,GPR21(r21) - SYNC rfi -hash_page_out: #ifdef __SMP__ +hash_page_out: lis r2,hash_table_lock@ha tophys(r2,r2,r6) li r0,0 stw r0,hash_table_lock@l(r2) -#endif + eieio blr + + .globl hash_table_lock +hash_table_lock: + .long 0 +#endif + next_slot: .long 0 @@ -1420,27 +1495,25 @@ * On SMP we know the fpu is free, since we give it up every * switch. -- Cort */ + mfmsr r5 + ori r5,r5,MSR_FP + SYNC + mtmsr r5 /* enable use of fpu now */ + SYNC +/* + * For SMP, we don't do lazy FPU switching because it just gets too + * horrendously complex, especially when a task switches from one CPU + * to another. Instead we call giveup_fpu in switch_to. + */ +#ifndef __SMP__ #ifndef CONFIG_APUS lis r6,-KERNELBASE@h #else lis r6,CYBERBASEp@h lwz r6,0(r6) #endif - addis r3,r6,last_task_used_math@ha lwz r4,last_task_used_math@l(r3) - mfmsr r5 - ori r5,r5,MSR_FP - SYNC - mtmsr r5 /* enable use of fpu now */ -/* - * All the saving of last_task_used_math is handled - * by a switch_to() call to smp_giveup_fpu() in SMP so - * last_task_used_math is not used. - * -- Cort - */ -#ifndef __SMP__ - SYNC cmpi 0,r4,0 beq 1f add r4,r4,r6 @@ -1454,15 +1527,17 @@ li r20,MSR_FP|MSR_FE0|MSR_FE1 andc r4,r4,r20 /* disable FP for previous task */ stw r4,_MSR-STACK_FRAME_OVERHEAD(r5) +1: #endif /* __SMP__ */ -1: ori r23,r23,MSR_FP|MSR_FE0|MSR_FE1 /* enable use of FP after return */ + /* enable use of FP after return */ + ori r23,r23,MSR_FP|MSR_FE0|MSR_FE1 mfspr r5,SPRG3 /* current task's TSS (phys) */ lfd fr0,TSS_FPSCR-4(r5) mtfsf 0xff,fr0 REST_32FPRS(0, r5) +#ifndef __SMP__ subi r4,r5,TSS sub r4,r4,r6 -#ifndef __SMP__ stw r4,last_task_used_math@l(r3) #endif /* __SMP__ */ /* restore registers and return */ @@ -1499,48 +1574,44 @@ .align 4 /* - * Disable FP for the task which had the FPU previously, - * and save its floating-point registers in its thread_struct. + * giveup_fpu(tsk) + * Disable FP for the task given as the argument, + * and save the floating-point registers in its thread_struct. * Enables the FPU for use in the kernel on return. */ -/* smp_giveup_fpu() takes an arg to tell it where to save the fpu - * regs since last_task_used_math can't be trusted (many many race - * conditions). -- Cort - */ - .globl smp_giveup_fpu -smp_giveup_fpu: - mr r4,r3 - b 12f .globl giveup_fpu giveup_fpu: - lis r3,last_task_used_math@ha - lwz r4,last_task_used_math@l(r3) -12: mfmsr r5 ori r5,r5,MSR_FP SYNC mtmsr r5 /* enable use of fpu now */ SYNC - cmpi 0,r4,0 + cmpi 0,r3,0 beqlr- /* if no previous owner, done */ - addi r4,r4,TSS /* want TSS of last_task_used_math */ + addi r3,r3,TSS /* want TSS of task */ + lwz r5,PT_REGS(r3) + cmpi 0,r5,0 + SAVE_32FPRS(0, r3) + mffs fr0 + stfd fr0,TSS_FPSCR-4(r3) + beq 1f + lwz r4,_MSR-STACK_FRAME_OVERHEAD(r5) + li r3,MSR_FP|MSR_FE0|MSR_FE1 + andc r4,r4,r3 /* disable FP for previous task */ + stw r4,_MSR-STACK_FRAME_OVERHEAD(r5) +1: #ifndef __SMP__ li r5,0 - stw r5,last_task_used_math@l(r3) + lis r4,last_task_used_math@ha + stw r5,last_task_used_math@l(r4) #endif /* __SMP__ */ - SAVE_32FPRS(0, r4) - mffs fr0 - stfd fr0,TSS_FPSCR-4(r4) - lwz r5,PT_REGS(r4) - lwz r3,_MSR-STACK_FRAME_OVERHEAD(r5) - li r4,MSR_FP|MSR_FE0|MSR_FE1 - andc r3,r3,r4 /* disable FP for previous task */ - stw r3,_MSR-STACK_FRAME_OVERHEAD(r5) + blr + #else /* CONFIG_8xx */ .globl giveup_fpu giveup_fpu: -#endif /* CONFIG_8xx */ blr +#endif /* CONFIG_8xx */ /* * This code is jumped to from the startup code to copy @@ -1600,10 +1671,38 @@ . = 0x4000 #endif +#ifdef CONFIG_SMP + .globl __secondary_start_psurge +__secondary_start_psurge: + li r24,1 /* cpu # */ + b __secondary_start + + .globl __secondary_hold +__secondary_hold: + /* tell the master we're here */ + lis r5,0x4@h + ori r5,r5,0x4@l + stw r3,0(r5) + dcbf 0,r5 +100: + lis r5,0 + dcbi 0,r5 + lwz r4,0(r5) + /* wait until we're told to start */ + cmp 0,r4,r3 + bne 100b + /* our cpu # was at addr 0 - go */ + lis r5,__secondary_start@h + ori r5,r5,__secondary_start@l + tophys(r5,r5,r4) + mtlr r5 + mr r24,r3 /* cpu # */ + blr +#endif /* CONFIG_SMP */ + /* * This is where the main kernel code starts. */ - start_here: #ifndef CONFIG_8xx /* @@ -1650,9 +1749,9 @@ /* get current */ lis r2,current_set@h ori r2,r2,current_set@l - addi r2,r2,4 + slwi r24,r24,2 /* cpu # to current_set[cpu#] */ + add r2,r2,r24 lwz r2,0(r2) - b 10f 99: #endif /* __SMP__ */ @@ -1677,12 +1776,10 @@ #ifdef __SMP__ 10: #endif /* __SMP__ */ - /* stack */ addi r1,r2,TASK_UNION_SIZE li r0,0 stwu r0,-STACK_FRAME_OVERHEAD(r1) - /* * Decide what sort of machine this is and initialize the MMU. */ @@ -1693,7 +1790,6 @@ mr r7,r27 bl identify_machine bl MMU_init - /* * Go back to running unmapped so we can load up new values * for SDR1 (hash table pointer) and the segment registers @@ -1725,8 +1821,10 @@ 2: SYNC /* Force all PTE updates to finish */ tlbia /* Clear all TLB entries */ + sync /* wait for tlbia/tlbie to finish */ #ifdef __SMP__ - tlbsync + tlbsync /* ... on all CPUs */ + sync #endif #ifndef CONFIG_8xx mtspr SDR1,r6 @@ -1947,8 +2045,9 @@ stw r0,GPR0(r1) lwz r0,0(r1) stw r0,GPR1(r1) - SAVE_10GPRS(2, r1) - SAVE_10GPRS(12, r1) + /* r3-r13 are caller saved -- Cort */ + SAVE_GPR(2, r1) + SAVE_8GPRS(14, r1) SAVE_10GPRS(22, r1) mflr r20 /* Return to switch caller */ mfmsr r22 @@ -1971,46 +2070,71 @@ mtspr SPRG3,r0 /* Update current TSS phys addr */ SYNC lwz r1,KSP(r4) /* Load new stack pointer */ + /* save the old current 'last' for return value */ + mr r3,r2 addi r2,r4,-TSS /* Update current */ #ifndef CONFIG_8xx /* Set up segment registers for new task */ rlwinm r5,r5,4,8,27 /* VSID = context << 4 */ addis r5,r5,0x6000 /* Set Ks, Ku bits */ - li r0,8 /* TASK_SIZE / SEGMENT_SIZE */ + li r0,12 /* TASK_SIZE / SEGMENT_SIZE */ mtctr r0 - li r3,0 -3: mtsrin r5,r3 + li r9,0 +3: mtsrin r5,r9 addi r5,r5,1 /* next VSID */ - addis r3,r3,0x1000 /* address of next segment */ + addis r9,r9,0x1000 /* address of next segment */ bdnz 3b #else /* On the MPC8xx, we place the physical address of the new task * page directory loaded into the MMU base register, and set the * ASID compare register with the new "context". */ - lwz r3,MM-TSS(r4) /* Get virtual address of mm */ - lwz r3,PGD(r3) /* get new->mm->pgd */ - addis r3,r3,-KERNELBASE@h /* convert to phys addr */ - mtspr M_TWB, r3 /* Update MMU base address */ + lwz r9,MM-TSS(r4) /* Get virtual address of mm */ + lwz r9,PGD(r9) /* get new->mm->pgd */ + addis r9,r9,-KERNELBASE@h /* convert to phys addr */ + mtspr M_TWB, r9 /* Update MMU base address */ mtspr M_CASID, r5 /* Update context */ tlbia #endif SYNC - -/* FALL THROUGH into int_return */ -#ifdef __SMP__ - /* call schedule_tail if this is the first time for a child process */ - lwz r5,TSS_SMP_FORK_RET(r4) - cmpi 0,r5,0 - beq+ int_return - li r3,0 - stw r3,TSS_SMP_FORK_RET(r4) - bl schedule_tail -#endif /* __SMP__ */ +2: lwz r9,_MSR(r1) /* Returning to user mode? */ + andi. r9,r9,MSR_PR + beq+ 10f /* if not, don't adjust kernel stack */ +8: addi r4,r1,INT_FRAME_SIZE+STACK_UNDERHEAD /* size of frame */ + stw r4,TSS+KSP(r2) /* save kernel stack pointer */ + tophys(r9,r1,r9) + mtspr SPRG2,r9 /* phys exception stack pointer */ +10: lwz r2,_CTR(r1) + lwz r0,_LINK(r1) + mtctr r2 + mtlr r0 + lwz r2,_XER(r1) + lwz r0,_CCR(r1) + mtspr XER,r2 + mtcrf 0xFF,r0 + /* r3-r13 are destroyed -- Cort */ + REST_GPR(14, r1) + REST_8GPRS(15, r1) + REST_8GPRS(23, r1) + REST_GPR(31, r1) + lwz r2,_NIP(r1) /* Restore environment */ + lwz r0,_MSR(r1) + mtspr SRR0,r2 + mtspr SRR1,r0 + lwz r0,GPR0(r1) + lwz r2,GPR2(r1) + lwz r1,GPR1(r1) + SYNC + rfi /* * Trap exit. */ +#ifdef __SMP__ + .globl ret_from_smpfork +ret_from_smpfork: + bl schedule_tail +#endif .globl ret_from_syscall ret_from_syscall: .globl int_return @@ -2025,8 +2149,8 @@ lwz r5,_MSR(r1) and. r5,r5,r4 beq 2f -3: lis r4,n_lost_interrupts@ha - lwz r4,n_lost_interrupts@l(r4) +3: lis r4,ppc_n_lost_interrupts@ha + lwz r4,ppc_n_lost_interrupts@l(r4) cmpi 0,r4,0 beq+ 1f addi r3,r1,STACK_FRAME_OVERHEAD @@ -2118,7 +2242,7 @@ _GLOBAL(set_context) rlwinm r3,r3,4,8,27 /* VSID = context << 4 */ addis r3,r3,0x6000 /* Set Ks, Ku bits */ - li r0,8 /* TASK_SIZE / SEGMENT_SIZE */ + li r0,12 /* TASK_SIZE / SEGMENT_SIZE */ mtctr r0 li r4,0 3: mtsrin r3,r4 @@ -2177,6 +2301,27 @@ blr /* + * Like above, but only do the D-cache. This is used by the 8xx + * to push the cache so the CPM doesn't get stale data. + * + * flush_dcache_range(unsigned long start, unsigned long stop) + */ +_GLOBAL(flush_dcache_range) + li r5,CACHE_LINE_SIZE-1 + andc r3,r3,r5 + subf r4,r3,r4 + add r4,r4,r5 + srwi. r4,r4,LG_CACHE_LINE_SIZE + beqlr + mtctr r4 + +1: dcbst 0,r3 + addi r3,r3,CACHE_LINE_SIZE + bdnz 1b + sync /* wait for dcbst's to get to ram */ + blr + +/* * Flush a particular page from the DATA cache * Note: this is necessary because the instruction cache does *not* * snoop from the data cache. @@ -2207,25 +2352,35 @@ blr /* + * Clear a page using the dcbz instruction, which doesn't cause any + * memory traffic (except to write out any cache lines which get + * displaced). This only works on cacheable memory. + */ +_GLOBAL(clear_page) + li r0,4096/CACHE_LINE_SIZE + mtctr r0 +1: dcbz 0,r3 + addi r3,r3,CACHE_LINE_SIZE + bdnz 1b + blr + +/* * Flush entries from the hash table with VSIDs in the range * given. */ #ifndef CONFIG_8xx _GLOBAL(flush_hash_segments) + lis r5,Hash@ha + lwz r5,Hash@l(r5) /* base of hash table */ #ifdef NO_RELOAD_HTAB -/* - * Bitmask of PVR numbers of 603-like chips, - * for which we don't use the hash table at all. - */ -#define PVR_603_LIKE 0x13000000 /* bits 3, 6, 7 set */ - - mfspr r0,PVR - rlwinm r0,r0,16,27,31 - lis r9,PVR_603_LIKE@h - rlwnm. r0,r9,r0,0,0 - beq+ 99f + cmpwi 0,r5,0 + bne+ 99f tlbia - isync + sync +#ifdef __SMP__ + tlbsync + sync +#endif blr 99: #endif /* NO_RELOAD_HTAB */ @@ -2247,14 +2402,13 @@ bne- 10b stwcx. r8,0,r9 bne- 10b + eieio #endif rlwinm r3,r3,7,1,24 /* put VSID lower limit in position */ oris r3,r3,0x8000 /* set V bit */ rlwinm r4,r4,7,1,24 /* put VSID upper limit in position */ oris r4,r4,0x8000 ori r4,r4,0x7f - lis r5,Hash@ha - lwz r5,Hash@l(r5) /* base of hash table */ lis r6,Hash_size@ha lwz r6,Hash_size@l(r6) /* size in bytes */ srwi r6,r6,3 /* # PTEs */ @@ -2270,11 +2424,11 @@ 2: bdnz 1b /* continue with loop */ sync tlbia - isync + sync #ifdef __SMP__ tlbsync + sync lis r3,hash_table_lock@ha - li r0,0 stw r0,hash_table_lock@l(r3) mtmsr r10 SYNC @@ -2287,14 +2441,17 @@ * flush_hash_page(unsigned context, unsigned long va) */ _GLOBAL(flush_hash_page) + lis r6,Hash@ha + lwz r6,Hash@l(r6) /* hash table base */ #ifdef NO_RELOAD_HTAB - mfspr r0,PVR - rlwinm r0,r0,16,27,31 - lis r9,PVR_603_LIKE@h - rlwnm. r0,r9,r0,0,0 - beq+ 99f + cmpwi 0,r6,0 /* hash table in use? */ + bne+ 99f tlbie r4 /* in hw tlb too */ - isync + sync +#ifdef __SMP__ + tlbsync + sync +#endif blr 99: #endif /* NO_RELOAD_HTAB */ @@ -2311,11 +2468,12 @@ ori r9,r9,hash_table_lock@l lwz r8,PROCESSOR(r2) oris r8,r8,9 -10: lwarx r6,0,r9 - cmpi 0,r6,0 +10: lwarx r7,0,r9 + cmpi 0,r7,0 bne- 10b stwcx. r8,0,r9 bne- 10b + eieio #endif rlwinm r3,r3,11,1,20 /* put context into vsid */ rlwimi r3,r4,11,21,24 /* put top 4 bits of va into vsid */ @@ -2328,8 +2486,6 @@ lwz r5,Hash_mask@l(r5) /* hash mask */ slwi r5,r5,6 /* << 6 */ and r7,r7,r5 - lis r6,Hash@ha - lwz r6,Hash@l(r6) /* hash table base */ add r6,r6,r7 /* address of primary PTEG */ li r8,8 mtctr r8 @@ -2350,9 +2506,10 @@ stw r0,0(r7) /* invalidate entry */ 4: sync tlbie r4 /* in hw tlb too */ - isync + sync #ifdef __SMP__ tlbsync + sync lis r3,hash_table_lock@h li r0,0 stw r0,hash_table_lock@l(r3) @@ -2418,30 +2575,27 @@ rfi /* return to caller */ #endif /* CONFIG_8xx */ -#ifdef CONFIG_MBX -/* Jump into the system reset for the MBX rom. +#ifdef CONFIG_8xx +/* Jump into the system reset for the rom. * We first disable the MMU, and then jump to the ROM reset address. * - * This does not work, don't bother trying. There is no place in - * the ROM we can jump to cause a reset. We will have to program - * a watchdog of some type that we don't service to cause a processor - * reset. - */ - .globl MBX_gorom -MBX_gorom: - li r3,MSR_KERNEL & ~(MSR_IR|MSR_DR) - lis r4,2f@h - addis r4,r4,-KERNELBASE@h - ori r4,r4,2f@l - mtspr SRR0,r4 - mtspr SRR1,r3 - rfi + * r3 is the board info structure, r4 is the location for starting. + * I use this for building a small kernel that can load other kernels, + * rather than trying to write or rely on a rom monitor that can tftp load. + */ + .globl m8xx_gorom +m8xx_gorom: + li r5,MSR_KERNEL & ~(MSR_IR|MSR_DR) + lis r6,2f@h + addis r6,r6,-KERNELBASE@h + ori r6,r6,2f@l + mtspr SRR0,r6 + mtspr SRR1,r5 + rfi 2: - lis r4, 0xfe000000@h - addi r4, r4, 0xfe000000@l - mtlr r4 - blr -#endif /* CONFIG_MBX */ + mtlr r4 + blr +#endif /* CONFIG_8xx */ /* * We put a few things here that have to be page-aligned. diff -ur --new-file old/linux/arch/ppc/kernel/i8259.c new/linux/arch/ppc/kernel/i8259.c --- old/linux/arch/ppc/kernel/i8259.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/ppc/kernel/i8259.c Tue May 11 17:24:32 1999 @@ -0,0 +1,130 @@ + +#include +#include +#include +#include +#include +#include "i8259.h" + +unsigned char cached_8259[2] = { 0xff, 0xff }; +#define cached_A1 (cached_8259[0]) +#define cached_21 (cached_8259[1]) + +int i8259_irq(int cpu) +{ + int irq; + + /* + * Perform an interrupt acknowledge cycle on controller 1 + */ + outb(0x0C, 0x20); + irq = inb(0x20) & 7; + if (irq == 2) + { + /* + * Interrupt is cascaded so perform interrupt + * acknowledge on controller 2 + */ + outb(0x0C, 0xA0); + irq = (inb(0xA0) & 7) + 8; + } + else if (irq==7) + { + /* + * This may be a spurious interrupt + * + * Read the interrupt status register. If the most + * significant bit is not set then there is no valid + * interrupt + */ + outb(0x0b, 0x20); + if(~inb(0x20)&0x80) + return -1; + } + return irq; +} + +static void i8259_mask_and_ack_irq(unsigned int irq_nr) +{ + if ( irq_nr >= i8259_pic.irq_offset ) + irq_nr -= i8259_pic.irq_offset; + + if (irq_nr > 7) { + cached_A1 |= 1 << (irq_nr-8); + inb(0xA1); /* DUMMY */ + outb(cached_A1,0xA1); + outb(0x20,0xA0); /* Non-specific EOI */ + outb(0x20,0x20); /* Non-specific EOI to cascade */ + } else { + cached_21 |= 1 << irq_nr; + inb(0x21); /* DUMMY */ + outb(cached_21,0x21); + outb(0x20,0x20); /* Non-specific EOI */ + } +} + +static void i8259_set_irq_mask(int irq_nr) +{ + outb(cached_A1,0xA1); + outb(cached_21,0x21); +} + +static void i8259_mask_irq(unsigned int irq_nr) +{ + if ( irq_nr >= i8259_pic.irq_offset ) + irq_nr -= i8259_pic.irq_offset; + if ( irq_nr < 8 ) + cached_21 |= 1 << irq_nr; + else + cached_A1 |= 1 << (irq_nr-8); + i8259_set_irq_mask(irq_nr); +} + +static void i8259_unmask_irq(unsigned int irq_nr) +{ + + if ( irq_nr >= i8259_pic.irq_offset ) + irq_nr -= i8259_pic.irq_offset; + if ( irq_nr < 8 ) + cached_21 &= ~(1 << irq_nr); + else + cached_A1 &= ~(1 << (irq_nr-8)); + i8259_set_irq_mask(irq_nr); +} + +struct hw_interrupt_type i8259_pic = { + " i8259 ", + NULL, + NULL, + NULL, + i8259_unmask_irq, + i8259_mask_irq, + i8259_mask_and_ack_irq, + 0 +}; + +static void +no_action(int cpl, void *dev_id, struct pt_regs *regs) +{ +} + +void __init 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); + request_irq( i8259_pic.irq_offset + 2, no_action, SA_INTERRUPT, + "82c59 secondary cascade", NULL ); + enable_irq(i8259_pic.irq_offset + 2); /* Enable cascade interrupt */ +} diff -ur --new-file old/linux/arch/ppc/kernel/i8259.h new/linux/arch/ppc/kernel/i8259.h --- old/linux/arch/ppc/kernel/i8259.h Thu Jan 1 01:00:00 1970 +++ new/linux/arch/ppc/kernel/i8259.h Tue May 11 17:24:32 1999 @@ -0,0 +1,12 @@ + +#ifndef _PPC_KERNEL_i8259_H +#define _PPC_KERNEL_i8259_H + +#include "local_irq.h" + +extern struct hw_interrupt_type i8259_pic; + +void i8259_init(void); +int i8259_irq(int); + +#endif /* _PPC_KERNEL_i8259_H */ diff -ur --new-file old/linux/arch/ppc/kernel/idle.c new/linux/arch/ppc/kernel/idle.c --- old/linux/arch/ppc/kernel/idle.c Wed Dec 30 19:55:07 1998 +++ new/linux/arch/ppc/kernel/idle.c Thu Apr 29 21:39:01 1999 @@ -1,5 +1,5 @@ /* - * $Id: idle.c,v 1.57 1998/12/28 10:28:46 paulus Exp $ + * $Id: idle.c,v 1.61 1999/03/18 04:15:45 cort Exp $ * * Idle daemon for PowerPC. Idle daemon will handle any action * that needs to be taken when the system becomes idle. @@ -39,6 +39,12 @@ unsigned long zero_paged_on = 0; unsigned long powersave_nap = 0; +unsigned long *zero_cache; /* head linked list of pre-zero'd pages */ +unsigned long zero_sz; /* # currently pre-zero'd pages */ +unsigned long zeropage_hits; /* # zero'd pages request that we've done */ +unsigned long zeropage_calls; /* # zero'd pages request that've been made */ +unsigned long zerototal; /* # pages zero'd over time */ + int idled(void *unused) { /* endless loop with no priority at all */ @@ -108,8 +114,6 @@ /* if we don't have a htab */ if ( Hash_size == 0 ) return; - lock_dcache(1); - #if 0 /* find a random place in the htab to start each time */ start = &Hash[jiffies%(Hash_size/sizeof(PTE))]; @@ -147,7 +151,6 @@ } out: if ( current->need_resched ) printk("need_resched: %lx\n", current->need_resched); - unlock_dcache(); #endif /* CONFIG_8xx */ } @@ -159,7 +162,7 @@ { unsigned long page = 0; - atomic_inc((atomic_t *)&quicklists.zeropage_calls); + atomic_inc((atomic_t *)&zero_cache_calls); if ( zero_quicklist ) { /* atomically remove this page from the list */ @@ -177,10 +180,10 @@ #endif /* __SMP__ */ /* we can update zerocount after the fact since it is not * used for anything but control of a loop which doesn't - * matter since it won't affect anything if it zero's one + * matter since it won't affect anything if it zeros one * less page -- Cort */ - atomic_inc((atomic_t *)&quicklists.zeropage_hits); + atomic_inc((atomic_t *)&zero_cache_hits); atomic_dec((atomic_t *)&zero_cache_sz); /* zero out the pointer to next in the page */ @@ -222,7 +225,6 @@ /* * Make the page no cache so we don't blow our cache with 0's - * We should just turn off the cache instead. -- Cort */ pte = find_pte(init_task.mm, pageptr); if ( !pte ) @@ -254,8 +256,8 @@ * So we update the list atomically without locking it. * -- Cort */ + /* turn cache on for this page */ - pte_cache(*pte); flush_tlb_page(find_vma(init_task.mm,pageptr),pageptr); /* atomically add this page to the list */ @@ -280,7 +282,7 @@ * reads it. -- Cort */ atomic_inc((atomic_t *)&zero_cache_sz); - atomic_inc((atomic_t *)&quicklists.zerototal); + atomic_inc((atomic_t *)&zero_cache_total); } } @@ -301,11 +303,17 @@ hid0 &= ~(HID0_NAP | HID0_SLEEP | HID0_DOZE); hid0 |= (powersave_nap? HID0_NAP: HID0_DOZE) | HID0_DPM; asm("mtspr 1008,%0" : : "r" (hid0)); - msr |= MSR_POW; + + /* set the POW bit in the MSR, and enable interrupts + * so we wake up sometime! */ + _nmask_and_or_msr(0, MSR_POW | MSR_EE); + + /* Disable interrupts again so restore_flags will + * work. */ + _nmask_and_or_msr(MSR_EE, 0); } restore_flags(msr); default: return; } - } diff -ur --new-file old/linux/arch/ppc/kernel/indirect_pci.c new/linux/arch/ppc/kernel/indirect_pci.c --- old/linux/arch/ppc/kernel/indirect_pci.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/ppc/kernel/indirect_pci.c Tue May 11 17:24:32 1999 @@ -0,0 +1,121 @@ +/* + * Support for indirect PCI bridges. + * + * Copyright (C) 1998 Gabriel Paubert. + * + * 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 + +unsigned int * pci_config_address; +unsigned char * pci_config_data; + +int indirect_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn, + unsigned char offset, unsigned char *val) +{ + unsigned flags; + + save_flags(flags); cli(); + + out_be32(pci_config_address, + ((offset&0xfc)<<24) | (dev_fn<<16) | (bus<<8) | 0x80); + + *val= in_8(pci_config_data + (offset&3)); + + restore_flags(flags); + return PCIBIOS_SUCCESSFUL; +} + +int indirect_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn, + unsigned char offset, unsigned short *val) +{ + unsigned flags; + + if (offset&1) return PCIBIOS_BAD_REGISTER_NUMBER; + + save_flags(flags); cli(); + + out_be32(pci_config_address, + ((offset&0xfc)<<24) | (dev_fn<<16) | (bus<<8) | 0x80); + + *val= in_le16((unsigned short *)(pci_config_data + (offset&3))); + + restore_flags(flags); + return PCIBIOS_SUCCESSFUL; +} + +int indirect_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn, + unsigned char offset, unsigned int *val) +{ + unsigned flags; + + if (offset&3) return PCIBIOS_BAD_REGISTER_NUMBER; + + save_flags(flags); cli(); + + out_be32(pci_config_address, + ((offset&0xfc)<<24) | (dev_fn<<16) | (bus<<8) | 0x80); + + *val= in_le32((unsigned *)pci_config_data); + + restore_flags(flags); + return PCIBIOS_SUCCESSFUL; +} + +int indirect_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn, + unsigned char offset, unsigned char val) +{ + unsigned flags; + + save_flags(flags); cli(); + + out_be32(pci_config_address, + ((offset&0xfc)<<24) | (dev_fn<<16) | (bus<<8) | 0x80); + + out_8(pci_config_data + (offset&3), val); + + restore_flags(flags); + return PCIBIOS_SUCCESSFUL; +} + +int indirect_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn, + unsigned char offset, unsigned short val) +{ + unsigned flags; + + if (offset&1) return PCIBIOS_BAD_REGISTER_NUMBER; + + save_flags(flags); cli(); + + out_be32(pci_config_address, + ((offset&0xfc)<<24) | (dev_fn<<16) | (bus<<8) | 0x80); + + out_le16((unsigned short *)(pci_config_data + (offset&3)), val); + + restore_flags(flags); + return PCIBIOS_SUCCESSFUL; +} + +int indirect_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn, + unsigned char offset, unsigned int val) +{ + unsigned flags; + + if (offset&3) return PCIBIOS_BAD_REGISTER_NUMBER; + + save_flags(flags); cli(); + + out_be32(pci_config_address, + ((offset&0xfc)<<24) | (dev_fn<<16) | (bus<<8) | 0x80); + + out_le32((unsigned *)pci_config_data, val); + + restore_flags(flags); + return PCIBIOS_SUCCESSFUL; +} diff -ur --new-file old/linux/arch/ppc/kernel/irq.c new/linux/arch/ppc/kernel/irq.c --- old/linux/arch/ppc/kernel/irq.c Wed Dec 30 19:55:07 1998 +++ new/linux/arch/ppc/kernel/irq.c Thu Apr 29 21:39:01 1999 @@ -1,5 +1,5 @@ /* - * $Id: irq.c,v 1.91 1998/12/28 10:28:47 paulus Exp $ + * $Id: irq.c,v 1.105 1999/03/25 19:51:51 cort Exp $ * * arch/ppc/kernel/irq.c * @@ -42,6 +42,7 @@ #include #include #include +#include #include #include @@ -56,101 +57,46 @@ #include #include #include -#ifdef CONFIG_8xx -#include -#include -#endif +#include + +#include "local_irq.h" -extern void process_int(unsigned long vec, struct pt_regs *fp); -extern void apus_init_IRQ(void); -extern void amiga_disable_irq(unsigned int irq); -extern void amiga_enable_irq(unsigned int irq); -static void no_action(int cpl, void *dev_id, struct pt_regs *regs) { } -static volatile unsigned char *chrp_int_ack_special; extern volatile unsigned long ipi_count; -static void pmac_fix_gatwick_interrupts(struct device_node *gw, int irq_base); +void enable_irq(unsigned int irq_nr); +void disable_irq(unsigned int irq_nr); + +/* Fixme - Need to figure out a way to get rid of this - Corey */ +volatile unsigned char *chrp_int_ack_special; #ifdef CONFIG_APUS /* Rename a few functions. Requires the CONFIG_APUS protection. */ #define request_irq nop_ppc_request_irq #define free_irq nop_ppc_free_irq #define get_irq_list nop_get_irq_list +#define VEC_SPUR (24) #endif -#ifndef CONFIG_8xx -void (*mask_and_ack_irq)(int irq_nr); -void (*mask_irq)(unsigned int irq_nr); -void (*unmask_irq)(unsigned int irq_nr); -#else /* CONFIG_8xx */ -/* init_IRQ() happens too late for the MBX because we initialize the - * CPM early and it calls request_irq() before we have these function - * pointers initialized. - */ -#define mask_and_ack_irq(irq) mbx_mask_irq(irq) -#define mask_irq(irq) mbx_mask_irq(irq) -#define unmask_irq(irq) mbx_unmask_irq(irq) -#endif /* CONFIG_8xx */ -#define VEC_SPUR (24) -#undef SHOW_IRQ -#undef SHOW_GATWICK_IRQS +#define MAXCOUNT 10000000 + #define NR_MASK_WORDS ((NR_IRQS + 31) / 32) -#define cached_21 (((char *)(cached_irq_mask))[3]) -#define cached_A1 (((char *)(cached_irq_mask))[2]) -#define PREP_IRQ_MASK (((unsigned int)cached_A1)<<8) | (unsigned int)cached_21 - -unsigned int local_bh_count[NR_CPUS]; -unsigned int local_irq_count[NR_CPUS]; -int max_irqs; -int max_real_irqs; -static struct irqaction *irq_action[NR_IRQS]; -static int spurious_interrupts = 0; -static unsigned int cached_irq_mask[NR_MASK_WORDS]; -unsigned int lost_interrupts[NR_MASK_WORDS]; -atomic_t n_lost_interrupts; - -/* pmac */ -struct pmac_irq_hw { - unsigned int flag; - unsigned int enable; - unsigned int ack; - unsigned int level; -}; - -/* XXX these addresses should be obtained from the device tree */ -volatile struct pmac_irq_hw *pmac_irq_hw[4] = { - (struct pmac_irq_hw *) 0xf3000020, - (struct pmac_irq_hw *) 0xf3000010, - (struct pmac_irq_hw *) 0xf4000020, - (struct pmac_irq_hw *) 0xf4000010, -}; - -/* This is the interrupt used on the main controller for the secondary - controller. Happens on PowerBooks G3 Series (a second mac-io) - -- BenH - */ -static int second_irq = -999; -/* Returns the number of 0's to the left of the most significant 1 bit */ -static inline int cntlzw(int bits) -{ - int lz; +int ppc_spurious_interrupts = 0; - asm ("cntlzw %0,%1" : "=r" (lz) : "r" (bits)); - return lz; -} +unsigned int ppc_local_bh_count[NR_CPUS]; +unsigned int ppc_local_irq_count[NR_CPUS]; +struct irqaction *ppc_irq_action[NR_IRQS]; +unsigned int ppc_cached_irq_mask[NR_MASK_WORDS]; +unsigned int ppc_lost_interrupts[NR_MASK_WORDS]; +atomic_t ppc_n_lost_interrupts; -static inline void sync(void) -{ - asm volatile ("sync"); -} /* nasty hack for shared irq's since we need to do kmalloc calls but - * can't very very early in the boot when we need to do a request irq. + * can't very early in the boot when we need to do a request irq. * this needs to be removed. * -- Cort */ static char cache_bitmask = 0; -static struct irqaction malloc_cache[4]; +static struct irqaction malloc_cache[8]; extern int mem_init_done; void *irq_kmalloc(size_t size, int pri) @@ -179,168 +125,80 @@ kfree(ptr); } -#ifndef CONFIG_8xx -void i8259_mask_and_ack_irq(int irq_nr) -{ - /* spin_lock(&irq_controller_lock);*/ - cached_irq_mask[0] |= 1 << irq_nr; - if (irq_nr > 7) { - inb(0xA1); /* DUMMY */ - outb(cached_A1,0xA1); - outb(0x62,0x20); /* Specific EOI to cascade */ - /*outb(0x20,0xA0);*/ - outb(0x60|(irq_nr-8), 0xA0); /* specific eoi */ - } else { - inb(0x21); /* DUMMY */ - outb(cached_21,0x21); - /*outb(0x20,0x20);*/ - outb(0x60|irq_nr,0x20); /* specific eoi */ - - } - /* spin_unlock(&irq_controller_lock);*/ -} - -void __pmac pmac_mask_and_ack_irq(int irq_nr) -{ - unsigned long bit = 1UL << (irq_nr & 0x1f); - int i = irq_nr >> 5; +struct irqdesc irq_desc[NR_IRQS] = {{0, 0}, }; - if ((unsigned)irq_nr >= max_irqs) - return; - /*spin_lock(&irq_controller_lock);*/ - - clear_bit(irq_nr, cached_irq_mask); - if (test_and_clear_bit(irq_nr, lost_interrupts)) - atomic_dec(&n_lost_interrupts); - out_le32(&pmac_irq_hw[i]->ack, bit); - out_le32(&pmac_irq_hw[i]->enable, cached_irq_mask[i]); - out_le32(&pmac_irq_hw[i]->ack, bit); - /* make sure ack gets to controller before we enable interrupts */ - sync(); - - /*spin_unlock(&irq_controller_lock);*/ - /*if ( irq_controller_lock.lock ) - panic("irq controller lock still held in mask and ack\n");*/ -} - -void __openfirmware chrp_mask_and_ack_irq(int irq_nr) +int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), + unsigned long irqflags, const char * devname, void *dev_id) { - /* spinlocks are done by i8259_mask_and_ack() - Cort */ - if (is_8259_irq(irq_nr)) - i8259_mask_and_ack_irq(irq_nr); -} - + struct irqaction *old, **p, *action; + unsigned long flags; -static void i8259_set_irq_mask(int irq_nr) -{ - if (irq_nr > 7) { - outb(cached_A1,0xA1); - } else { - outb(cached_21,0x21); + if (irq >= NR_IRQS) + return -EINVAL; + if (!handler) + { + /* Free */ + for (p = &irq_desc[irq].action; (action = *p) != NULL; p = &action->next) + { + /* Found it - now free it */ + save_flags(flags); + cli(); + *p = action->next; + restore_flags(flags); + irq_kfree(action); + return 0; + } + return -ENOENT; } -} - -static void __pmac pmac_set_irq_mask(int irq_nr) -{ - unsigned long bit = 1UL << (irq_nr & 0x1f); - int i = irq_nr >> 5; - - if ((unsigned)irq_nr >= max_irqs) - return; - - /* enable unmasked interrupts */ - out_le32(&pmac_irq_hw[i]->enable, cached_irq_mask[i]); - - /* - * Unfortunately, setting the bit in the enable register - * when the device interrupt is already on *doesn't* set - * the bit in the flag register or request another interrupt. - */ - if ((bit & cached_irq_mask[i]) - && (ld_le32(&pmac_irq_hw[i]->level) & bit) - && !(ld_le32(&pmac_irq_hw[i]->flag) & bit)) { - if (!test_and_set_bit(irq_nr, lost_interrupts)) - atomic_inc(&n_lost_interrupts); + + action = (struct irqaction *) + irq_kmalloc(sizeof(struct irqaction), GFP_KERNEL); + if (!action) + return -ENOMEM; + + save_flags(flags); + cli(); + + action->handler = handler; + action->flags = irqflags; + action->mask = 0; + action->name = devname; + action->dev_id = dev_id; + action->next = NULL; + enable_irq(irq); + + p = &irq_desc[irq].action; + + if ((old = *p) != NULL) { + /* Can't share interrupts unless both agree to */ + if (!(old->flags & action->flags & SA_SHIRQ)) + return -EBUSY; + /* add new interrupt at end of irq queue */ + do { + p = &old->next; + old = *p; + } while (old); } -} - -/* - * These have to be protected by the spinlock - * before being called. - */ -static void i8259_mask_irq(unsigned int irq_nr) -{ - cached_irq_mask[0] |= 1 << irq_nr; - i8259_set_irq_mask(irq_nr); -} - -static void i8259_unmask_irq(unsigned int irq_nr) -{ - cached_irq_mask[0] &= ~(1 << irq_nr); - i8259_set_irq_mask(irq_nr); -} - -static void __pmac pmac_mask_irq(unsigned int irq_nr) -{ - clear_bit(irq_nr, cached_irq_mask); - pmac_set_irq_mask(irq_nr); - sync(); -} - -static void __pmac pmac_unmask_irq(unsigned int irq_nr) -{ - set_bit(irq_nr, cached_irq_mask); - pmac_set_irq_mask(irq_nr); -} - -static void __openfirmware chrp_mask_irq(unsigned int irq_nr) -{ - if (is_8259_irq(irq_nr)) - i8259_mask_irq(irq_nr); - else - openpic_disable_irq(irq_to_openpic(irq_nr)); -} + *p = action; -static void __openfirmware chrp_unmask_irq(unsigned int irq_nr) -{ - if (is_8259_irq(irq_nr)) - i8259_unmask_irq(irq_nr); - else - openpic_enable_irq(irq_to_openpic(irq_nr)); -} -#else /* CONFIG_8xx */ -static void mbx_mask_irq(unsigned int irq_nr) -{ - cached_irq_mask[0] &= ~(1 << (31-irq_nr)); - ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask = - cached_irq_mask[0]; + restore_flags(flags); + return 0; } -static void mbx_unmask_irq(unsigned int irq_nr) +void free_irq(unsigned int irq, void *dev_id) { - cached_irq_mask[0] |= (1 << (31-irq_nr)); - ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask = - cached_irq_mask[0]; + request_irq(irq, NULL, 0, NULL, dev_id); } -#endif /* CONFIG_8xx */ void disable_irq(unsigned int irq_nr) { - /*unsigned long flags;*/ - - /* spin_lock_irqsave(&irq_controller_lock, flags);*/ mask_irq(irq_nr); - /* spin_unlock_irqrestore(&irq_controller_lock, flags);*/ synchronize_irq(); } void enable_irq(unsigned int irq_nr) { - /*unsigned long flags;*/ - - /* spin_lock_irqsave(&irq_controller_lock, flags);*/ unmask_irq(irq_nr); - /* spin_unlock_irqrestore(&irq_controller_lock, flags);*/ } int get_irq_list(char *buf) @@ -354,8 +212,8 @@ *(char *)(buf+len++) = '\n'; for (i = 0 ; i < NR_IRQS ; i++) { - action = irq_action[i]; - if ((!action || !action->handler) && (i != second_irq)) + action = irq_desc[i].action; + if ( !action || !action->handler ) continue; len += sprintf(buf+len, "%3d: ", i); #ifdef __SMP__ @@ -365,56 +223,83 @@ #else len += sprintf(buf+len, "%10u ", kstat_irqs(i)); #endif /* __SMP__ */ - switch( _machine ) - { - case _MACH_prep: - len += sprintf(buf+len, " 82c59 "); - break; - case _MACH_Pmac: - if (i < 64) - len += sprintf(buf+len, " PMAC-PIC "); - else - len += sprintf(buf+len, " GATWICK "); - break; - case _MACH_chrp: - if ( is_8259_irq(i) ) - len += sprintf(buf+len, " 82c59 "); - else - len += sprintf(buf+len, " OpenPIC "); - break; - case _MACH_mbx: - len += sprintf(buf+len, " MPC8xx "); - break; + if ( irq_desc[i].ctl ) + len += sprintf(buf+len, " %s ", irq_desc[i].ctl->typename ); + len += sprintf(buf+len, " %s",action->name); + for (action=action->next; action; action = action->next) { + len += sprintf(buf+len, ", %s", action->name); } - - if (i != second_irq) { - len += sprintf(buf+len, " %s",action->name); - for (action=action->next; action; action = action->next) { - len += sprintf(buf+len, ", %s", action->name); - } - len += sprintf(buf+len, "\n"); - } else - len += sprintf(buf+len, " Gatwick secondary IRQ controller\n"); + len += sprintf(buf+len, "\n"); } #ifdef __SMP__ /* should this be per processor send/receive? */ - len += sprintf(buf+len, "IPI: %10lu", ipi_count); - for ( i = 0 ; i <= smp_num_cpus-1; i++ ) - len += sprintf(buf+len," "); - len += sprintf(buf+len, " interprocessor messages received\n"); + len += sprintf(buf+len, "IPI: %10lu\n", ipi_count); #endif - len += sprintf(buf+len, "BAD: %10u",spurious_interrupts); - for ( i = 0 ; i <= smp_num_cpus-1; i++ ) - len += sprintf(buf+len," "); - len += sprintf(buf+len, " spurious or short\n"); + len += sprintf(buf+len, "BAD: %10u\n", ppc_spurious_interrupts); return len; } - /* - * Global interrupt locks for SMP. Allow interrupts to come in on any - * CPU, yet make cli/sti act globally to protect critical regions.. + * Eventually, this should take an array of interrupts and an array size + * so it can dispatch multiple interrupts. */ +void ppc_irq_dispatch_handler(struct pt_regs *regs, int irq) +{ + int status; + struct irqaction *action; + int cpu = smp_processor_id(); + + mask_and_ack_irq(irq); + status = 0; + action = irq_desc[irq].action; + kstat.irqs[cpu][irq]++; + if (action && action->handler) { + if (!(action->flags & SA_INTERRUPT)) + __sti(); + do { + status |= action->flags; + action->handler(irq, action->dev_id, regs); + action = action->next; + } while ( action ); + __cli(); + unmask_irq(irq); + } else { + ppc_spurious_interrupts++; + disable_irq( irq ); + } +} + +asmlinkage void do_IRQ(struct pt_regs *regs, int isfake) +{ + int cpu = smp_processor_id(); + + hardirq_enter(cpu); + ppc_md.do_IRQ(regs, cpu, isfake); + hardirq_exit(cpu); +} + +unsigned long probe_irq_on (void) +{ + return 0; +} + +int probe_irq_off (unsigned long irqs) +{ + return 0; +} + +void __init init_IRQ(void) +{ + static int once = 0; + + if ( once ) + return; + else + once++; + + ppc_md.init_IRQ(); +} + #ifdef __SMP__ unsigned char global_irq_holder = NO_PROC_ID; unsigned volatile int global_irq_lock; @@ -431,9 +316,13 @@ printk("\n%s, CPU %d:\n", str, cpu); printk("irq: %d [%d %d]\n", - atomic_read(&global_irq_count), local_irq_count[0], local_irq_count[1]); + atomic_read(&global_irq_count), + ppc_local_irq_count[0], + ppc_local_irq_count[1]); printk("bh: %d [%d %d]\n", - atomic_read(&global_bh_count), local_bh_count[0], local_bh_count[1]); + atomic_read(&global_bh_count), + ppc_local_bh_count[0], + ppc_local_bh_count[1]); stack = (unsigned long *) &str; for (i = 40; i ; i--) { unsigned long x = *++stack; @@ -443,7 +332,6 @@ } } -#define MAXCOUNT 100000000 static inline void wait_on_bh(void) { int count = MAXCOUNT; @@ -469,7 +357,8 @@ * already executing in one.. */ if (!atomic_read(&global_irq_count)) { - if (local_bh_count[cpu] || !atomic_read(&global_bh_count)) + if (ppc_local_bh_count[cpu] + || !atomic_read(&global_bh_count)) break; } @@ -490,7 +379,8 @@ continue; if (global_irq_lock) continue; - if (!local_bh_count[cpu] && atomic_read(&global_bh_count)) + if (!ppc_local_bh_count[cpu] + && atomic_read(&global_bh_count)) continue; if (!test_and_set_bit(0,&global_irq_lock)) break; @@ -512,7 +402,6 @@ wait_on_bh(); } - /* * This is called when we want to synchronize with * interrupts. We may for example tell a device to @@ -581,7 +470,7 @@ if (flags & (1 << 15)) { int cpu = smp_processor_id(); __cli(); - if (!local_irq_count[cpu]) + if (!ppc_local_irq_count[cpu]) get_irqlock(cpu); } } @@ -590,7 +479,7 @@ { int cpu = smp_processor_id(); - if (!local_irq_count[cpu]) + if (!ppc_local_irq_count[cpu]) release_irqlock(cpu); __sti(); } @@ -614,7 +503,7 @@ retval = 2 + local_enabled; /* check for global flags if we're not in an interrupt */ - if (!local_irq_count[smp_processor_id()]) { + if (!ppc_local_irq_count[smp_processor_id()]) { if (local_enabled) retval = 1; if (global_irq_holder == (unsigned char) smp_processor_id()) @@ -623,6 +512,31 @@ return retval; } +int +tb(long vals[], + int max_size) +{ + register unsigned long *orig_sp __asm__ ("r1"); + register unsigned long lr __asm__ ("r3"); + unsigned long *sp; + int i; + + asm volatile ("mflr 3"); + vals[0] = lr; + sp = (unsigned long *) *orig_sp; + sp = (unsigned long *) *sp; + for (i=1; i 0; irq -= 32) { - int i = irq >> 5; - bits = ld_le32(&pmac_irq_hw[i]->flag) - | lost_interrupts[i]; - if (bits == 0) - continue; - irq -= cntlzw(bits); - break; - } - - /* Here, we handle interrupts coming from Gatwick, - * normal interrupt code will take care of acking and - * masking the irq on Gatwick itself but we ack&mask - * the Gatwick main interrupt on Heathrow now. It's - * unmasked later, after interrupt handling. -- BenH - */ - if (irq == second_irq) { - mask_and_ack_irq(second_irq); - for (irq = max_irqs - 1; irq > max_real_irqs; irq -= 32) { - int i = irq >> 5; - bits = ld_le32(&pmac_irq_hw[i]->flag) - | lost_interrupts[i]; - if (bits == 0) - continue; - irq -= cntlzw(bits); - break; - } - /* If not found, on exit, irq is 63 (128-1-32-32). - * We set it to -1 and revalidate second controller - */ - if (irq < max_real_irqs) { - irq = -1; - unmask_irq(second_irq); - } -#ifdef SHOW_GATWICK_IRQS - printk("Gatwick irq %d (i:%d, bits:0x%08lx\n", irq, i, bits); -#endif - } - - break; - case _MACH_chrp: - irq = openpic_irq(0); - if (irq == IRQ_8259_CASCADE) - { - /* - * This magic address generates a PCI IACK cycle. - * - * This should go in the above mask/ack code soon. -- Cort - */ - irq = *chrp_int_ack_special; - /* - * Acknowledge as soon as possible to allow i8259 - * interrupt nesting - */ - openpic_eoi(0); - openpic_eoi_done = 1; - } - else if (irq >= OPENPIC_VEC_TIMER) - { - /* - * OpenPIC interrupts >64 will be used for other purposes - * like interprocessor interrupts and hardware errors - */ - if (irq == OPENPIC_VEC_SPURIOUS) { - /* - * Spurious interrupts should never be - * acknowledged - */ - spurious_interrupts++; - openpic_eoi_done = 1; - } else { - /* - * Here we should process IPI timer - * for now the interrupt is dismissed. - */ - } - goto out; - } - break; - case _MACH_prep: - outb(0x0C, 0x20); - irq = inb(0x20) & 7; - if (irq == 2) - { -retry_cascade: - outb(0x0C, 0xA0); - irq = inb(0xA0); - /* if no intr left */ - if ( !(irq & 128 ) ) - goto out; - irq = (irq&7) + 8; - } - bits = 1UL << irq; - break; -#ifdef CONFIG_APUS - case _MACH_apus: - { - int old_level, new_level; - - old_level = ~(regs->mq) & IPLEMU_IPLMASK; - new_level = (~(regs->mq) >> 3) & IPLEMU_IPLMASK; - - if (new_level == 0) - { - goto apus_out; - } - - APUS_WRITE(APUS_IPL_EMU, IPLEMU_IPLMASK); - APUS_WRITE(APUS_IPL_EMU, (IPLEMU_SETRESET - | (~(new_level) & IPLEMU_IPLMASK))); - APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT); - - process_int (VEC_SPUR+new_level, regs); - - APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET | IPLEMU_DISABLEINT); - APUS_WRITE(APUS_IPL_EMU, IPLEMU_IPLMASK); - APUS_WRITE(APUS_IPL_EMU, (IPLEMU_SETRESET - | (~(old_level) & IPLEMU_IPLMASK))); - -apus_out: - hardirq_exit(cpu); - APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT); - goto out2; - } -#endif - } - - if (irq < 0) { - /* we get here with Gatwick but the 'bogus' isn't correct in that case -- Cort */ - if ( irq != second_irq ) - { - printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n", - irq, regs->nip); - spurious_interrupts++; - } - goto out; - } - -#else /* CONFIG_8xx */ - /* For MPC8xx, read the SIVEC register and shift the bits down - * to get the irq number. - */ - bits = ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sivec; - irq = bits >> 26; -#endif /* CONFIG_8xx */ - mask_and_ack_irq(irq); - status = 0; - action = irq_action[irq]; - kstat.irqs[cpu][irq]++; - if (action && action->handler) { - if (!(action->flags & SA_INTERRUPT)) - __sti(); - do { - status |= action->flags; - action->handler(irq, action->dev_id, regs); - action = action->next; - } while ( action ); - __cli(); - unmask_irq(irq); - } else { -#ifndef CONFIG_8xx - if ( irq == 7 ) /* i8259 gives us irq 7 on 'short' intrs */ -#endif - spurious_interrupts++; - disable_irq( irq ); - } - - /* This was a gatwick sub-interrupt, we re-enable them on Heathrow - now */ - if (_machine == _MACH_Pmac && irq >= max_real_irqs) - unmask_irq(second_irq); - - /* make sure we don't miss any cascade intrs due to eoi-ing irq 2 */ -#ifndef CONFIG_8xx - if ( is_prep && (irq > 7) ) - goto retry_cascade; - /* do_bottom_half is called if necessary from int_return in head.S */ -out: - if (_machine == _MACH_chrp && !openpic_eoi_done) - openpic_eoi(0); -#endif /* CONFIG_8xx */ - hardirq_exit(cpu); - -#ifdef CONFIG_APUS -out2: -#endif - /* restore the HID0 in case dcache was off - see idle.c - * this hack should leave for a better solution -- Cort */ - lock_dcache(dcache_locked); -} - -int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), - unsigned long irqflags, const char * devname, void *dev_id) -{ - struct irqaction *old, **p, *action; - unsigned long flags; - -#ifdef SHOW_IRQ - printk("request_irq(): irq %d handler %08x name %s dev_id %04x\n", - irq,(int)handler,devname,(int)dev_id); -#endif /* SHOW_IRQ */ - - if (irq >= NR_IRQS) - return -EINVAL; - - /* Cannot allocate second controller IRQ */ - if (irq == second_irq) - return -EBUSY; - - if (!handler) - { - /* Free */ - for (p = irq + irq_action; (action = *p) != NULL; p = &action->next) - { - /* Found it - now free it */ - save_flags(flags); - cli(); - *p = action->next; - restore_flags(flags); - irq_kfree(action); - return 0; - } - return -ENOENT; - } - - action = (struct irqaction *) - irq_kmalloc(sizeof(struct irqaction), GFP_KERNEL); - if (!action) - return -ENOMEM; - save_flags(flags); - cli(); - - action->handler = handler; - action->flags = irqflags; - action->mask = 0; - action->name = devname; - action->dev_id = dev_id; - action->next = NULL; - enable_irq(irq); - p = irq_action + irq; - - if ((old = *p) != NULL) { - /* Can't share interrupts unless both agree to */ - if (!(old->flags & action->flags & SA_SHIRQ)) - return -EBUSY; - /* add new interrupt at end of irq queue */ - do { - p = &old->next; - old = *p; - } while (old); - } - *p = action; - - restore_flags(flags); - return 0; -} - -void free_irq(unsigned int irq, void *dev_id) -{ - request_irq(irq, NULL, 0, NULL, dev_id); -} - -unsigned long probe_irq_on (void) -{ - return 0; -} - -int probe_irq_off (unsigned long irqs) -{ - return 0; -} - -#ifndef CONFIG_8xx -__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); - if (request_irq(2, no_action, SA_INTERRUPT, "cascade", NULL) != 0) - panic("Could not allocate cascade IRQ!"); - enable_irq(2); /* Enable cascade interrupt */ -} -#endif /* CONFIG_8xx */ - -/* On MBX8xx, the interrupt control (SIEL) was set by EPPC-bug. External - * interrupts can be either edge or level triggered, but there is no - * reason for us to change the EPPC-bug values (it would not work if we did). - */ -__initfunc(void init_IRQ(void)) -{ - extern void xmon_irq(int, void *, struct pt_regs *); - int i; - struct device_node *irqctrler; - unsigned long addr; - struct device_node *np; - -#ifndef CONFIG_8xx - switch (_machine) - { - case _MACH_Pmac: - mask_and_ack_irq = pmac_mask_and_ack_irq; - mask_irq = pmac_mask_irq; - unmask_irq = pmac_unmask_irq; - - /* G3 powermacs have 64 interrupts, G3 Series PowerBook have 128, - others have 32 */ - max_irqs = max_real_irqs = 32; - irqctrler = find_devices("mac-io"); - if (irqctrler) - { - max_real_irqs = 64; - if (irqctrler->next) - max_irqs = 128; - else - max_irqs = 64; - } - - /* get addresses of first controller */ - if (irqctrler) { - if (irqctrler->n_addrs > 0) { - addr = (unsigned long) - ioremap(irqctrler->addrs[0].address, 0x40); - for (i = 0; i < 2; ++i) - pmac_irq_hw[i] = (volatile struct pmac_irq_hw*) - (addr + (2 - i) * 0x10); - } - - /* get addresses of second controller */ - irqctrler = (irqctrler->next) ? irqctrler->next : NULL; - if (irqctrler && irqctrler->n_addrs > 0) { - addr = (unsigned long) - ioremap(irqctrler->addrs[0].address, 0x40); - for (i = 2; i < 4; ++i) - pmac_irq_hw[i] = (volatile struct pmac_irq_hw*) - (addr + (4 - i) * 0x10); - } - } - - /* disable all interrupts in all controllers */ - for (i = 0; i * 32 < max_irqs; ++i) - out_le32(&pmac_irq_hw[i]->enable, 0); - - - /* get interrupt line of secondary interrupt controller */ - if (irqctrler) { - second_irq = irqctrler->intrs[0].line; - printk(KERN_INFO "irq: secondary controller on irq %d\n", - (int)second_irq); - if (device_is_compatible(irqctrler, "gatwick")) - pmac_fix_gatwick_interrupts(irqctrler, max_real_irqs); - enable_irq(second_irq); - } - printk("System has %d possible interrupts\n", max_irqs); - if (max_irqs != max_real_irqs) - printk(KERN_DEBUG "%d interrupts on main controller\n", - max_real_irqs); - -#ifdef CONFIG_XMON - request_irq(20, xmon_irq, 0, "NMI", 0); -#endif /* CONFIG_XMON */ - break; - case _MACH_chrp: - mask_and_ack_irq = chrp_mask_and_ack_irq; - mask_irq = chrp_mask_irq; - unmask_irq = chrp_unmask_irq; - - if ( !(np = find_devices("pci") ) ) - printk("Cannot find pci to get ack address\n"); - else - { - chrp_int_ack_special = (volatile unsigned char *) - (*(unsigned long *)get_property(np, - "8259-interrupt-acknowledge", NULL)); - } - openpic_init(1); - i8259_init(); - cached_irq_mask[0] = cached_irq_mask[1] = ~0UL; -#ifdef CONFIG_XMON - request_irq(openpic_to_irq(HYDRA_INT_ADB_NMI), - xmon_irq, 0, "NMI", 0); -#endif /* CONFIG_XMON */ - break; - case _MACH_prep: - mask_and_ack_irq = i8259_mask_and_ack_irq; - mask_irq = i8259_mask_irq; - unmask_irq = i8259_unmask_irq; - cached_irq_mask[0] = ~0UL; - - i8259_init(); - /* - * According to the Carolina spec from ibm irqs 0,1,2, and 8 - * must be edge triggered. Also, the pci intrs must be level - * triggered and _only_ isa intrs can be level sensitive - * which are 3-7,9-12,14-15. 13 is special - it can be level. - * - * power on default is 0's in both regs - all edge. - * - * These edge/level control regs allow edge/level status - * to be decided on a irq basis instead of on a PIC basis. - * It's still pretty ugly. - * - Cort - */ - { - unsigned char irq_mode1 = 0, irq_mode2 = 0; - irq_mode1 = 0; /* to get rid of compiler warnings */ - /* - * On Carolina, irq 15 and 13 must be level (scsi/ide/net). - */ - if ( _prep_type == _PREP_IBM ) - irq_mode2 |= 0xa0; + printk("global_restore_flags: %08lx (%08lx)\n", + flags, (&flags)[-1]); + count = tb(trace, 5); + printk("tb:"); + for(i=0; ichild; - while(node) - { - /* Fix SCC */ - if (strcasecmp(node->name, "escc") == 0) - if (node->child && node->child->n_intrs == 0) - { - node->child->n_intrs = 1; - node->child->intrs = &int_pool[0]; - int_pool[0].line = 15+irq_base; - printk(KERN_INFO "irq: fixed SCC on second controller (%d)\n", - int_pool[0].line); - } - /* Fix media-bay & left SWIM */ - if (strcasecmp(node->name, "media-bay") == 0) - { - struct device_node* ya_node; - - if (node->n_intrs == 0) - { - node->n_intrs = 1; - node->intrs = &int_pool[1]; - int_pool[1].line = 29+irq_base; - printk(KERN_INFO "irq: fixed media-bay on second controller (%d)\n", - int_pool[1].line); - } - ya_node = node->child; - while(ya_node) - { - if ((strcasecmp(ya_node->name, "floppy") == 0) && - ya_node->n_intrs == 0) - { - ya_node->n_intrs = 2; - ya_node->intrs = &int_pool[2]; - int_pool[2].line = 19+irq_base; - int_pool[3].line = 1+irq_base; - printk(KERN_INFO "irq: fixed floppy on second controller (%d,%d)\n", - int_pool[2].line, int_pool[3].line); - } - ya_node = ya_node->sibling; - } - } - node = node->sibling; } - } +#endif /* __SMP__ */ diff -ur --new-file old/linux/arch/ppc/kernel/local_irq.h new/linux/arch/ppc/kernel/local_irq.h --- old/linux/arch/ppc/kernel/local_irq.h Thu Jan 1 01:00:00 1970 +++ new/linux/arch/ppc/kernel/local_irq.h Thu Apr 29 21:39:01 1999 @@ -0,0 +1,45 @@ + +#ifndef _PPC_KERNEL_LOCAL_IRQ_H +#define _PPC_KERNEL_LOCAL_IRQ_H + +#include +#include + +void ppc_irq_dispatch_handler(struct pt_regs *regs, int irq); + +/* Structure describing interrupts */ +struct hw_interrupt_type { + const char * typename; + void (*startup)(unsigned int irq); + void (*shutdown)(unsigned int irq); + void (*handle)(unsigned int irq, struct pt_regs * regs); + void (*enable)(unsigned int irq); + void (*disable)(unsigned int irq); + void (*mask_and_ack)(unsigned int irq); + int irq_offset; +}; + +#define mask_irq(irq) ({if (irq_desc[irq].ctl && irq_desc[irq].ctl->disable) irq_desc[irq].ctl->disable(irq);}) +#define unmask_irq(irq) ({if (irq_desc[irq].ctl && irq_desc[irq].ctl->enable) irq_desc[irq].ctl->enable(irq);}) +#define mask_and_ack_irq(irq) ({if (irq_desc[irq].ctl && irq_desc[irq].ctl->mask_and_ack) irq_desc[irq].ctl->mask_and_ack(irq);}) + +struct irqdesc { + struct irqaction *action; + struct hw_interrupt_type *ctl; +}; + +extern struct irqdesc irq_desc[NR_IRQS]; + + +#define NR_MASK_WORDS ((NR_IRQS + 31) / 32) + +extern int ppc_spurious_interrupts; +extern int ppc_second_irq; +extern struct irqaction *ppc_irq_action[NR_IRQS]; +extern unsigned int ppc_local_bh_count[NR_CPUS]; +extern unsigned int ppc_local_irq_count[NR_CPUS]; +extern unsigned int ppc_cached_irq_mask[NR_MASK_WORDS]; +extern unsigned int ppc_lost_interrupts[NR_MASK_WORDS]; +extern atomic_t ppc_n_lost_interrupts; + +#endif /* _PPC_KERNEL_LOCAL_IRQ_H */ diff -ur --new-file old/linux/arch/ppc/kernel/mbx_pci.c new/linux/arch/ppc/kernel/mbx_pci.c --- old/linux/arch/ppc/kernel/mbx_pci.c Wed Apr 15 02:33:57 1998 +++ new/linux/arch/ppc/kernel/mbx_pci.c Thu Apr 29 21:39:01 1999 @@ -252,3 +252,20 @@ } return PCIBIOS_DEVICE_NOT_FOUND; } + +__initfunc( +void +mbx_pcibios_fixup(void)) +{ + /* Nothing to do here? */ +} + +__initfunc( +void +mbx_setup_pci_ptrs(void)) +{ + set_config_access_method(mbx); + + ppc_md.pcibios_fixup = mbx_pcibios_fixup; +} + diff -ur --new-file old/linux/arch/ppc/kernel/mbx_setup.c new/linux/arch/ppc/kernel/mbx_setup.c --- old/linux/arch/ppc/kernel/mbx_setup.c Thu Jan 7 21:06:57 1999 +++ new/linux/arch/ppc/kernel/mbx_setup.c Thu Apr 29 21:39:01 1999 @@ -1,5 +1,5 @@ /* - * $Id: mbx_setup.c,v 1.5 1998/12/29 18:55:07 cort Exp $ + * $Id: mbx_setup.c,v 1.9 1999/04/28 11:54:09 davem Exp $ * * linux/arch/ppc/kernel/setup.c * @@ -39,6 +39,22 @@ #include #include #include +#include + +#include "time.h" +#include "local_irq.h" + +static int mbx_set_rtc_time(unsigned long time); +unsigned long mbx_get_rtc_time(void); +void mbx_calibrate_decr(void); + +extern int mackbd_setkeycode(unsigned int scancode, unsigned int keycode); +extern int mackbd_getkeycode(unsigned int scancode); +extern int mackbd_translate(unsigned char scancode, unsigned char *keycode, + char raw_mode); +extern char mackbd_unexpected_up(unsigned char keycode); +extern void mackbd_leds(unsigned char leds); +extern void mackbd_init_hw(void); extern unsigned long loops_per_sec; @@ -55,35 +71,10 @@ extern unsigned long find_available_memory(void); extern void m8xx_cpm_reset(uint); -/* this really does make things cleaner -- Cort */ -void __init powermac_init(void) -{ -} - void __init adbdev_init(void) { } -void __init mbx_ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq) -{ - ide_ioreg_t port = base; - int i = 8; - - while (i--) - *p++ = port++; - *p++ = base + 0x206; - if (irq != NULL) - *irq = 0; -#ifdef ATA_FLASH - base = (unsigned long) ioremap(PCMCIA_MEM_ADDR, 0x200); - for (i = 0; i < 8; ++i) - *p++ = base++; - *p = ++base; /* Does not matter */ - if (irq) - *irq = 13; -#endif -} - __initfunc(void mbx_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p)) { @@ -144,4 +135,338 @@ xmon(0); #endif machine_restart(NULL); +} + +/* The decrementer counts at the system (internal) clock frequency divided by + * sixteen, or external oscillator divided by four. Currently, we only + * support the MBX, which is system clock divided by sixteen. + */ +__initfunc(void mbx_calibrate_decr(void)) +{ + bd_t *binfo = (bd_t *)&res; + int freq, fp, divisor; + + if ((((immap_t *)MBX_IMAP_ADDR)->im_clkrst.car_sccr & 0x02000000) == 0) + printk("WARNING: Wrong decrementer source clock.\n"); + + /* The manual says the frequency is in Hz, but it is really + * as MHz. The value 'fp' is the number of decrementer ticks + * per second. + */ + fp = (binfo->bi_intfreq * 1000000) / 16; + freq = fp*60; /* try to make freq/1e6 an integer */ + divisor = 60; + printk("time_init: decrementer frequency = %d/%d\n", freq, divisor); + decrementer_count = freq / HZ / divisor; + count_period_num = divisor; + count_period_den = freq / 1000000; +} + +/* A place holder for time base interrupts, if they are ever enabled. +*/ +void timebase_interrupt(int irq, void * dev, struct pt_regs * regs) +{ + printk("timebase_interrupt()\n"); +} + +/* The RTC on the MPC8xx is an internal register. + * We want to protect this during power down, so we need to unlock, + * modify, and re-lock. + */ +static int +mbx_set_rtc_time(unsigned long time) +{ + ((immap_t *)MBX_IMAP_ADDR)->im_sitk.sitk_rtck = KAPWR_KEY; + ((immap_t *)MBX_IMAP_ADDR)->im_sit.sit_rtc = time; + ((immap_t *)MBX_IMAP_ADDR)->im_sitk.sitk_rtck = ~KAPWR_KEY; + return(0); +} + +initfunc(unsigned long +mbx_get_rtc_time(void) +{ + /* First, unlock all of the registers we are going to modify. + * To protect them from corruption during power down, registers + * that are maintained by keep alive power are "locked". To + * modify these registers we have to write the key value to + * the key location associated with the register. + */ + ((immap_t *)MBX_IMAP_ADDR)->im_sitk.sitk_tbscrk = KAPWR_KEY; + ((immap_t *)MBX_IMAP_ADDR)->im_sitk.sitk_rtcsck = KAPWR_KEY; + + + /* Disable the RTC one second and alarm interrupts. + */ + ((immap_t *)MBX_IMAP_ADDR)->im_sit.sit_rtcsc &= + ~(RTCSC_SIE | RTCSC_ALE); + + /* Enabling the decrementer also enables the timebase interrupts + * (or from the other point of view, to get decrementer interrupts + * we have to enable the timebase). The decrementer interrupt + * is wired into the vector table, nothing to do here for that. + */ + ((immap_t *)MBX_IMAP_ADDR)->im_sit.sit_tbscr = + ((mk_int_int_mask(DEC_INTERRUPT) << 8) | + (TBSCR_TBF | TBSCR_TBE)); + if (request_irq(DEC_INTERRUPT, timebase_interrupt, 0, "tbint", NULL) != 0) + panic("Could not allocate timer IRQ!"); + + /* Get time from the RTC. + */ + return ((immap_t *)MBX_IMAP_ADDR)->im_sit.sit_rtc; +} + +void +mbx_restart(char *cmd) +{ + extern void MBX_gorom(void); + + MBX_gorom(); +} + +void +mbx_power_off(void) +{ + mbx_restart(NULL); +} + +void +mbx_halt(void) +{ + mbx_restart(NULL) +} + + +int mbx_setup_residual(char *buffer) +{ + int len = 0; + bd_t *bp; + extern RESIDUAL *res; + + bp = (bd_t *)res; + + len += sprintf(len+buffer,"clock\t\t: %dMHz\n" + "bus clock\t: %dMHz\n", + bp->bi_intfreq /*/ 1000000*/, + bp->bi_busfreq /*/ 1000000*/); + + return len; +} + +void +mbx_do_IRQ(struct pt_regs *regs, + int cpu, + int isfake) +{ + int irq; + unsigned long bits = 0; + + /* For MPC8xx, read the SIVEC register and shift the bits down + * to get the irq number. */ + bits = ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sivec; + irq = bits >> 26; + irq += ppc8xx_pic.irq_offset; + bits = 1UL << irq; + + if (irq < 0) { + printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n", + irq, regs->nip); + spurious_interrupts++; + } + else { + ppc_irq_dispatch_handler( regs, irq ); + } + +} + +static void mbx_i8259_action(int cpl, void *dev_id, struct pt_regs *regs) +{ + int bits, irq; + + /* A bug in the QSpan chip causes it to give us 0xff always + * when doing a character read. So read 32 bits and shift. + * This doesn't seem to return useful values anyway, but + * read it to make sure things are acked. + * -- Cort + */ + irq = (inl(0x508) >> 24)&0xff; + if ( irq != 0xff ) printk("iack %d\n", irq); + + outb(0x0C, 0x20); + irq = inb(0x20) & 7; + if (irq == 2) + { + outb(0x0C, 0xA0); + irq = inb(0xA0); + irq = (irq&7) + 8; + } + bits = 1UL << irq; + irq += i8259_pic.irq_offset; + ppc_irq_dispatch_handler( regs, irq ); +} + + +/* On MBX8xx, the interrupt control (SIEL) was set by EPPC-bug. External + * interrupts can be either edge or level triggered, but there is no + * reason for us to change the EPPC-bug values (it would not work if we did). + */ +__initfunc(void +mbx_init_IRQ(void)) +{ + int i; + + ppc8xx_pic.irq_offset = 16; + for ( i = 16 ; i < 32 ; i++ ) + irq_desc[i].ctl = &ppc8xx_pic; + unmask_irq(CPM_INTERRUPT); + + for ( i = 0 ; i < 16 ; i++ ) + irq_desc[i].ctl = &i8259_pic; + i8259_init(); + request_irq(ISA_BRIDGE_INT, mbx_i8259_action, 0, "8259 cascade", NULL); + enable_irq(ISA_BRIDGE_INT); +} + +#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) +/* + * IDE stuff. + */ +void +mbx_ide_insw(ide_ioreg_t port, void *buf, int ns) +{ + ide_insw(port+_IO_BASE), buf, ns); +} + +void +mbx_ide_outsw(ide_ioreg_t port, void *buf, int ns) +{ + ide_outsw(port+_IO_BASE, buf, ns); +} + +int +mbx_ide_default_irq(ide_ioreg_t base) +{ + return 14; +} + +ide_ioreg_t +mbx_ide_default_io_base(int index) +{ + return index; +} + +int +mbx_ide_check_region(ide_ioreg_t from, unsigned int extent) +{ + return 0 +} + +void +mbx_ide_request_region(ide_ioreg_t from, + unsigned int extent, + const char *name) +{ +} + +void +mbx_ide_release_region(ide_ioreg_t from, + unsigned int extent) +{ +} + +void +mbx_ide_fix_driveid(struct hd_driveid *id) +{ + ppc_generic_ide_fix_driveid(id); +} + +void __init mbx_ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq) +{ + ide_ioreg_t port = base; + int i = 8; + + while (i--) + *p++ = port++; + *p++ = base + 0x206; + if (irq != NULL) + *irq = 0; +#ifdef ATA_FLASH + base = (unsigned long) ioremap(PCMCIA_MEM_ADDR, 0x200); + for (i = 0; i < 8; ++i) + *p++ = base++; + *p = ++base; /* Does not matter */ + if (irq) + *irq = 13; +#endif +} +#endif + +__initfunc(void +mbx_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7)) +{ + + if ( r3 ) + memcpy( (void *)&res,(void *)(r3+KERNELBASE), sizeof(bd_t) ); + +#ifdef CONFIG_PCI + mbx_setup_pci_ptrs(); +#endif + +#ifdef CONFIG_BLK_DEV_INITRD + /* take care of initrd if we have one */ + if ( r4 ) + { + initrd_start = r4 + KERNELBASE; + initrd_end = r5 + KERNELBASE; + } +#endif /* CONFIG_BLK_DEV_INITRD */ + /* take care of cmd line */ + if ( r6 ) + { + + *(char *)(r7+KERNELBASE) = 0; + strcpy(cmd_line, (char *)(r6+KERNELBASE)); + } + + ppc_md.setup_arch = mbx_setup_arch; + ppc_md.setup_residual = mbx_setup_residual; + ppc_md.get_cpuinfo = NULL; + ppc_md.irq_cannonicalize = NULL; + ppc_md.init_IRQ = mbx_init_IRQ; + ppc_md.do_IRQ = mbx_do_IRQ; + ppc_md.init = NULL; + + ppc_md.restart = mbx_restart; + ppc_md.power_off = mbx_power_off; + ppc_md.halt = mbx_halt; + + ppc_md.time_init = NULL; + ppc_md.set_rtc_time = mbx_set_rtc_time; + ppc_md.get_rtc_time = mbx_get_rtc_time; + ppc_md.calibrate_decr = mbx_calibrate_decr; + + ppc_md.kbd_setkeycode = pckbd_setkeycode; + ppc_md.kbd_getkeycode = pckbd_getkeycode; + ppc_md.kbd_translate = pckbd_translate; + ppc_md.kbd_unexpected_up = pckbd_unexpected_up; + ppc_md.kbd_leds = pckbd_leds; + ppc_md.kbd_init_hw = pckbd_init_hw; +#ifdef CONFIG_MAGIC_SYSRQ + ppc_md.kbd_sysrq_xlate = pckbd_sysrq_xlate; +#endif + +#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) + ppc_ide_md.insw = mbx_ide_insw; + ppc_ide_md.outsw = mbx_ide_outsw; + ppc_ide_md.default_irq = mbx_ide_default_irq; + ppc_ide_md.default_io_base = mbx_ide_default_io_base; + ppc_ide_md.check_region = mbx_ide_check_region; + ppc_ide_md.request_region = mbx_ide_request_region; + ppc_ide_md.release_region = mbx_ide_release_region; + ppc_ide_md.fix_driveid = mbx_ide_fix_driveid; + ppc_ide_md.ide_init_hwif = mbx_ide_init_hwif_ports; + + ppc_ide_md.io_base = _IO_BASE; +#endif } diff -ur --new-file old/linux/arch/ppc/kernel/misc.S new/linux/arch/ppc/kernel/misc.S --- old/linux/arch/ppc/kernel/misc.S Wed Dec 30 19:55:07 1998 +++ new/linux/arch/ppc/kernel/misc.S Thu Apr 29 21:39:01 1999 @@ -36,6 +36,7 @@ * Returns (address we're running at) - (address we were linked at) * for use before the text and data are mapped to KERNELBASE. */ + _GLOBAL(reloc_offset) mflr r0 bl 1f @@ -72,8 +73,8 @@ beqlr /* nothing to do if state == 0 */ _GLOBAL(__sti) _GLOBAL(_hard_sti) - lis r4,n_lost_interrupts@ha - lwz r4,n_lost_interrupts@l(r4) + lis r4,ppc_n_lost_interrupts@ha + lwz r4,ppc_n_lost_interrupts@l(r4) mfmsr r3 /* Get current state */ ori r3,r3,MSR_EE /* Turn on 'EE' bit */ cmpi 0,r4,0 /* lost interrupts to process first? */ @@ -93,8 +94,8 @@ stw r0,20(r1) stw r3,8(r1) 1: bl fake_interrupt - lis r4,n_lost_interrupts@ha - lwz r4,n_lost_interrupts@l(r4) + lis r4,ppc_n_lost_interrupts@ha + lwz r4,ppc_n_lost_interrupts@l(r4) cmpi 0,r4,0 bne- 1b lwz r3,8(r1) @@ -105,11 +106,31 @@ addi r1,r1,16 blr + +/* + * complement mask on the msr then "or" some values on. + * _nmask_and_or_msr(nmask, value_to_or) + */ + _GLOBAL(_nmask_and_or_msr) + mfmsr r0 /* Get current msr */ + andc r0,r0,r3 /* And off the bits set in r3 (first parm) */ + or r0,r0,r4 /* Or on the bits in r4 (second parm) */ + sync /* Some chip revs have problems here... */ + mtmsr r0 /* Update machine state */ + blr /* Done */ + + /* * Flush MMU TLB */ _GLOBAL(_tlbia) + sync tlbia + sync +#ifdef __SMP__ + tlbsync + sync +#endif blr /* @@ -117,11 +138,17 @@ */ _GLOBAL(_tlbie) tlbie r3 + sync +#ifdef __SMP__ + tlbsync + sync +#endif blr + /* * Atomic [test&set] exchange * - * void *xchg_u32(void *ptr, unsigned long val) + * unsigned long xchg_u32(void *ptr, unsigned long val) * Changes the memory location '*ptr' to be val and returns * the previous value stored there. */ @@ -133,6 +160,27 @@ blr /* + * Try to acquire a spinlock. + * Only does the stwcx. if the load returned 0 - the Programming + * Environments Manual suggests not doing unnecessary stcwx.'s + * since they may inhibit forward progress by other CPUs in getting + * a lock. + */ +_GLOBAL(__spin_trylock) + mr r4,r3 + eieio /* prevent reordering of stores */ + li r5,-1 + lwarx r3,0,r4 /* fetch old value, establish reservation */ + cmpwi 0,r3,0 /* is it 0? */ + bnelr- /* return failure if not */ + stwcx. r5,0,r4 /* try to update with new value */ + bne- 1f /* if we failed */ + eieio /* prevent reordering of stores */ + blr +1: li r3,1 /* return non-zero for failure */ + blr + +/* * Atomic add/sub/inc/dec operations * * void atomic_add(int c, int *v) @@ -590,6 +638,16 @@ stfd 0,-4(r5) blr + .globl __clear_msr_me +__clear_msr_me: + mfmsr r0 /* Get current interrupt state */ + lis r3,0 + ori r3,r3,MSR_ME + andc r0,r0,r3 /* Clears bit in (r4) */ + sync /* Some chip revs have problems here */ + mtmsr r0 /* Update machine state */ + blr + /* * Fetch the current SR register * get_SR(int index) @@ -608,6 +666,8 @@ sc cmpi 0,r3,0 /* parent or child? */ bnelr /* return if parent */ + li r0,0 /* clear out p->tss.regs */ + stw r0,TSS+PT_REGS(r2) /* since we don't have user ctx */ mtlr r4 /* fn addr in lr */ mr r3,r5 /* load arg and call fn */ blrl @@ -836,4 +896,5 @@ .long sys_sendfile .long sys_ni_syscall /* streams1 */ .long sys_ni_syscall /* streams2 */ + .long sys_vfork .space (NR_syscalls-183)*4 diff -ur --new-file old/linux/arch/ppc/kernel/mk_defs.c new/linux/arch/ppc/kernel/mk_defs.c --- old/linux/arch/ppc/kernel/mk_defs.c Wed Sep 9 17:56:58 1998 +++ new/linux/arch/ppc/kernel/mk_defs.c Tue May 11 17:24:32 1999 @@ -29,7 +29,7 @@ int main(void) { - DEFINE(KERNELBASE, KERNELBASE); + /*DEFINE(KERNELBASE, KERNELBASE);*/ DEFINE(STATE, offsetof(struct task_struct, state)); DEFINE(NEXT_TASK, offsetof(struct task_struct, next_task)); DEFINE(COUNTER, offsetof(struct task_struct, counter)); @@ -48,7 +48,6 @@ DEFINE(NEED_RESCHED, offsetof(struct task_struct, need_resched)); DEFINE(TSS_FPR0, offsetof(struct thread_struct, fpr[0])); DEFINE(TSS_FPSCR, offsetof(struct thread_struct, fpscr)); - DEFINE(TSS_SMP_FORK_RET, offsetof(struct thread_struct, smp_fork_ret)); /* Interrupt register frame */ DEFINE(TASK_UNION_SIZE, sizeof(union task_union)); DEFINE(STACK_FRAME_OVERHEAD, STACK_FRAME_OVERHEAD); diff -ur --new-file old/linux/arch/ppc/kernel/open_pic.c new/linux/arch/ppc/kernel/open_pic.c --- old/linux/arch/ppc/kernel/open_pic.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/ppc/kernel/open_pic.c Tue May 11 17:24:32 1999 @@ -0,0 +1,48 @@ +#include +#include +#include +#include +#include +#include +#include "open_pic.h" +#include "i8259.h" + +#ifdef __SMP__ +void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs) +{ + smp_message_recv(); +} +#endif /* __SMP__ */ + +void chrp_mask_and_ack_irq(unsigned int irq_nr) +{ + if (is_8259_irq(irq_nr)) + i8259_pic.mask_and_ack(irq_nr); +} + +static void chrp_mask_irq(unsigned int irq_nr) +{ + if (is_8259_irq(irq_nr)) + i8259_pic.disable(irq_nr); + else + openpic_disable_irq(irq_to_openpic(irq_nr)); +} + +static void chrp_unmask_irq(unsigned int irq_nr) +{ + if (is_8259_irq(irq_nr)) + i8259_pic.enable(irq_nr); + else + openpic_enable_irq(irq_to_openpic(irq_nr)); +} + +struct hw_interrupt_type open_pic = { + " OpenPIC ", + NULL, + NULL, + NULL, + chrp_unmask_irq, + chrp_mask_irq, + chrp_mask_and_ack_irq, + 0 +}; diff -ur --new-file old/linux/arch/ppc/kernel/open_pic.h new/linux/arch/ppc/kernel/open_pic.h --- old/linux/arch/ppc/kernel/open_pic.h Thu Jan 1 01:00:00 1970 +++ new/linux/arch/ppc/kernel/open_pic.h Thu Apr 29 21:39:01 1999 @@ -0,0 +1,11 @@ + +#ifndef _PPC_KERNEL_OPEN_PIC_H +#define _PPC_KERNEL_OPEN_PIC_H + +#include "local_irq.h" + +extern struct hw_interrupt_type open_pic; + +void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs); + +#endif /* _PPC_KERNEL_OPEN_PIC_H */ diff -ur --new-file old/linux/arch/ppc/kernel/openpic.c new/linux/arch/ppc/kernel/openpic.c --- old/linux/arch/ppc/kernel/openpic.c Wed Sep 30 19:14:17 1998 +++ new/linux/arch/ppc/kernel/openpic.c Thu Apr 29 21:39:01 1999 @@ -107,7 +107,7 @@ } #endif -static inline u_int openpic_read(volatile u_int *addr) +u_int openpic_read(volatile u_int *addr) { u_int val; @@ -176,8 +176,8 @@ __initfunc(void openpic_init(int main_pic)) { u_int t, i; - u_int vendorid, devid, stepping, timerfreq; - const char *version, *vendor, *device; + u_int timerfreq; + const char *version; if (!OpenPIC) panic("No OpenPIC found"); @@ -190,6 +190,9 @@ case 2: version = "1.2"; break; + case 3: + version = "1.3"; + break; default: version = "?"; break; @@ -200,32 +203,6 @@ OPENPIC_FEATURE_LAST_SOURCE_SHIFT) + 1; printk("OpenPIC Version %s (%d CPUs and %d IRQ sources) at %p\n", version, NumProcessors, NumSources, OpenPIC); - - t = openpic_read(&OpenPIC->Global.Vendor_Identification); - vendorid = t & OPENPIC_VENDOR_ID_VENDOR_ID_MASK; - devid = (t & OPENPIC_VENDOR_ID_DEVICE_ID_MASK) >> - OPENPIC_VENDOR_ID_DEVICE_ID_SHIFT; - stepping = (t & OPENPIC_VENDOR_ID_STEPPING_MASK) >> - OPENPIC_VENDOR_ID_STEPPING_SHIFT; - switch (vendorid) { - case OPENPIC_VENDOR_ID_APPLE: - vendor = "Apple"; - break; - default: - vendor = "Unknown"; - break; - } - switch (devid) { - case OPENPIC_DEVICE_ID_APPLE_HYDRA: - device = "Hydra"; - break; - default: - device = "Unknown"; - break; - } - printk("OpenPIC Vendor %d (%s), Device %d (%s), Stepping %d\n", vendorid, - vendor, devid, device, stepping); - timerfreq = openpic_read(&OpenPIC->Global.Timer_Frequency); printk("OpenPIC timer frequency is "); if (timerfreq) diff -ur --new-file old/linux/arch/ppc/kernel/pci.c new/linux/arch/ppc/kernel/pci.c --- old/linux/arch/ppc/kernel/pci.c Thu Jan 7 21:06:57 1999 +++ new/linux/arch/ppc/kernel/pci.c Thu Apr 29 21:39:01 1999 @@ -1,5 +1,5 @@ /* - * $Id: pci.c,v 1.43 1998/12/29 18:55:11 cort Exp $ + * $Id: pci.c,v 1.54 1999/03/18 04:16:04 cort Exp $ * Common pmac/prep/chrp pci routines. -- Cort */ @@ -21,94 +21,41 @@ #include #include -unsigned long isa_io_base; -unsigned long isa_mem_base; -unsigned long pci_dram_offset; - -unsigned int * pci_config_address; -unsigned char * pci_config_data; - -/* - * It would be nice if we could create a include/asm/pci.h and have just - * function ptrs for all these in there, but that isn't the case. - * We have a function, pcibios_*() which calls the function ptr ptr_pcibios_*() - * which has been setup by pcibios_init(). This is all to avoid a check - * for pmac/prep every time we call one of these. It should also make the move - * to a include/asm/pcibios.h easier, we can drop the ptr_ on these functions - * and create pci.h - * -- Cort - */ -int (*ptr_pcibios_read_config_byte)(unsigned char bus, unsigned char dev_fn, - unsigned char offset, unsigned char *val); -int (*ptr_pcibios_read_config_word)(unsigned char bus, unsigned char dev_fn, - unsigned char offset, unsigned short *val); -int (*ptr_pcibios_read_config_dword)(unsigned char bus, unsigned char dev_fn, - unsigned char offset, unsigned int *val); -int (*ptr_pcibios_write_config_byte)(unsigned char bus, unsigned char dev_fn, - unsigned char offset, unsigned char val); -int (*ptr_pcibios_write_config_word)(unsigned char bus, unsigned char dev_fn, - unsigned char offset, unsigned short val); -int (*ptr_pcibios_write_config_dword)(unsigned char bus, unsigned char dev_fn, - unsigned char offset, unsigned int val); - -#define decl_config_access_method(name) \ -extern int name##_pcibios_read_config_byte(unsigned char bus, \ - unsigned char dev_fn, unsigned char offset, unsigned char *val); \ -extern int name##_pcibios_read_config_word(unsigned char bus, \ - unsigned char dev_fn, unsigned char offset, unsigned short *val); \ -extern int name##_pcibios_read_config_dword(unsigned char bus, \ - unsigned char dev_fn, unsigned char offset, unsigned int *val); \ -extern int name##_pcibios_write_config_byte(unsigned char bus, \ - unsigned char dev_fn, unsigned char offset, unsigned char val); \ -extern int name##_pcibios_write_config_word(unsigned char bus, \ - unsigned char dev_fn, unsigned char offset, unsigned short val); \ -extern int name##_pcibios_write_config_dword(unsigned char bus, \ - unsigned char dev_fn, unsigned char offset, unsigned int val) - -#define set_config_access_method(name) \ - ptr_pcibios_read_config_byte = name##_pcibios_read_config_byte; \ - ptr_pcibios_read_config_word = name##_pcibios_read_config_word; \ - ptr_pcibios_read_config_dword = name##_pcibios_read_config_dword; \ - ptr_pcibios_write_config_byte = name##_pcibios_write_config_byte; \ - ptr_pcibios_write_config_word = name##_pcibios_write_config_word; \ - ptr_pcibios_write_config_dword = name##_pcibios_write_config_dword - -decl_config_access_method(pmac); -decl_config_access_method(grackle); -decl_config_access_method(gg2); -decl_config_access_method(raven); -decl_config_access_method(prep); -decl_config_access_method(mbx); +#include "pci.h" + +unsigned long isa_io_base = 0; +unsigned long isa_mem_base = 0; +unsigned long pci_dram_offset = 0; int pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned char *val) { - return ptr_pcibios_read_config_byte(bus,dev_fn,offset,val); + return ppc_md.pcibios_read_config_byte(bus,dev_fn,offset,val); } int pcibios_read_config_word(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned short *val) { - return ptr_pcibios_read_config_word(bus,dev_fn,offset,val); + return ppc_md.pcibios_read_config_word(bus,dev_fn,offset,val); } int pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned int *val) { - return ptr_pcibios_read_config_dword(bus,dev_fn,offset,val); + return ppc_md.pcibios_read_config_dword(bus,dev_fn,offset,val); } int pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned char val) { - return ptr_pcibios_write_config_byte(bus,dev_fn,offset,val); + return ppc_md.pcibios_write_config_byte(bus,dev_fn,offset,val); } int pcibios_write_config_word(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned short val) { - return ptr_pcibios_write_config_word(bus,dev_fn,offset,val); + return ppc_md.pcibios_write_config_word(bus,dev_fn,offset,val); } int pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned int val) { - return ptr_pcibios_write_config_dword(bus,dev_fn,offset,val); + return ppc_md.pcibios_write_config_dword(bus,dev_fn,offset,val); } int pcibios_present(void) @@ -116,167 +63,46 @@ return 1; } -__initfunc(void pcibios_init(void)) +void __init pcibios_init(void) { } -__initfunc(void - setup_pci_ptrs(void)) + +void __init pcibios_fixup(void) { -#ifndef CONFIG_MBX - PPC_DEVICE *hostbridge; - switch (_machine) { - case _MACH_prep: - hostbridge=residual_find_device(PROCESSORDEVICE, NULL, - BridgeController, PCIBridge, - -1, 0); - if (hostbridge && - hostbridge->DeviceId.Interface == PCIBridgeIndirect) { - PnP_TAG_PACKET * pkt; - set_config_access_method(raven); - pkt=PnP_find_large_vendor_packet( - res->DevicePnPHeap+hostbridge->AllocatedOffset, - 3, 0); - if(pkt) { -#define p pkt->L4_Pack.L4_Data.L4_PPCPack - pci_config_address= (unsigned *) - ld_le32((unsigned *) p.PPCData); - pci_config_data= (unsigned char *) - ld_le32((unsigned *) (p.PPCData+8)); - } else {/* default values */ - pci_config_address= (unsigned *) 0x80000cf8; - pci_config_data= (unsigned char *) 0x80000cfc; - } - } else { - set_config_access_method(prep); - } - break; - case _MACH_Pmac: - if (find_devices("pci") != 0) { - /* looks like a G3 powermac */ - set_config_access_method(grackle); - } else { - set_config_access_method(pmac); - } - break; - case _MACH_chrp: - if ( !strncmp("MOT", - get_property(find_path_device("/"), "model", NULL),3) ) - { - isa_io_base = 0xfe000000; - set_config_access_method(grackle); - } - else - { - isa_io_base = GG2_ISA_IO_BASE; - set_config_access_method(gg2); - } - break; - default: - printk("setup_pci_ptrs(): unknown machine type!\n"); - } -#else /* CONFIG_MBX */ - set_config_access_method(mbx); -#endif /* CONFIG_MBX */ -#undef set_config_access_method + ppc_md.pcibios_fixup(); } -__initfunc(void pcibios_fixup(void)) -{ - extern unsigned long route_pci_interrupts(void); - struct pci_dev *dev; - extern struct bridge_data **bridges; - extern unsigned char *Motherboard_map; - extern unsigned char *Motherboard_routes; - unsigned char i; -#ifndef CONFIG_MBX - switch (_machine ) - { - case _MACH_prep: - route_pci_interrupts(); - for(dev=pci_devices; dev; dev=dev->next) - { - /* - * Use our old hard-coded kludge to figure out what - * irq this device uses. This is necessary on things - * without residual data. -- Cort - */ - unsigned char d = PCI_SLOT(dev->devfn); - dev->irq = Motherboard_routes[Motherboard_map[d]]; - for ( i = 0 ; i <= 5 ; i++ ) - { - if ( dev->base_address[i] > 0x10000000 ) - { - printk("Relocating PCI address %x -> %x\n", - dev->base_address[i], - (dev->base_address[i] & 0x00FFFFFF) - | 0x01000000); - dev->base_address[i] = - (dev->base_address[i] & 0x00FFFFFF) | 0x01000000; - pci_write_config_dword(dev, - PCI_BASE_ADDRESS_0+(i*0x4), - dev->base_address[i] ); - } - } -#if 0 - /* - * If we have residual data and if it knows about this - * device ask it what the irq is. - * -- Cort - */ - ppcd = residual_find_device_id( ~0L, dev->device, - -1,-1,-1, 0); -#endif - } - break; - case _MACH_chrp: - /* PCI interrupts are controlled by the OpenPIC */ - for(dev=pci_devices; dev; dev=dev->next) - if (dev->irq) - dev->irq = openpic_to_irq(dev->irq); - break; - case _MACH_Pmac: - for(dev=pci_devices; dev; dev=dev->next) - { - /* - * Open Firmware often doesn't initialize the, - * PCI_INTERRUPT_LINE config register properly, so we - * should find the device node and se if it has an - * AAPL,interrupts property. - */ - struct bridge_data *bp = bridges[dev->bus->number]; - struct device_node *node; - unsigned int *reg; - unsigned char pin; - - if (pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin) || - !pin) - continue; /* No interrupt generated -> no fixup */ - for (node = bp->node->child; node != 0; - node = node->sibling) { - reg = (unsigned int *) get_property(node, "reg", 0); - if (reg == 0 || ((reg[0] >> 8) & 0xff) != dev->devfn) - continue; - /* this is the node, see if it has interrupts */ - if (node->n_intrs > 0) - dev->irq = node->intrs[0].line; - break; - } - } - break; - } -#else /* CONFIG_MBX */ - for(dev=pci_devices; dev; dev=dev->next) - { - } -#endif /* CONFIG_MBX */ +void __init pcibios_fixup_bus(struct pci_bus *bus) +{ } -__initfunc(void pcibios_fixup_bus(struct pci_bus *bus)) +char __init *pcibios_setup(char *str) { + return str; } -__initfunc(char *pcibios_setup(char *str)) +#ifndef CONFIG_MBX +/* Recursively searches any node that is of type PCI-PCI bridge. Without + * this, the old code would miss children of P2P bridges and hence not + * fix IRQ's for cards located behind P2P bridges. + * - Ranjit Deshpande, 01/20/99 + */ +void __init fix_intr(struct device_node *node, struct pci_dev *dev) { - return str; + unsigned int *reg, *class_code; + + for (; node != 0;node = node->sibling) { + class_code = (unsigned int *) get_property(node, "class-code", 0); + if((*class_code >> 8) == PCI_CLASS_BRIDGE_PCI) + fix_intr(node->child, dev); + reg = (unsigned int *) get_property(node, "reg", 0); + if (reg == 0 || ((reg[0] >> 8) & 0xff) != dev->devfn) + continue; + /* this is the node, see if it has interrupts */ + if (node->n_intrs > 0) + dev->irq = node->intrs[0].line; + break; + } } +#endif diff -ur --new-file old/linux/arch/ppc/kernel/pci.h new/linux/arch/ppc/kernel/pci.h --- old/linux/arch/ppc/kernel/pci.h Thu Jan 1 01:00:00 1970 +++ new/linux/arch/ppc/kernel/pci.h Thu Apr 29 21:39:01 1999 @@ -0,0 +1,36 @@ + +#ifndef __PPC_KERNEL_PCI_H__ +#define __PPC_KERNEL_PCI_H__ + +extern unsigned long isa_io_base; +extern unsigned long isa_mem_base; +extern unsigned long pci_dram_offset; + +extern unsigned int *pci_config_address; +extern unsigned char *pci_config_data; + +void fix_intr(struct device_node *node, struct pci_dev *dev); + +#define decl_config_access_method(name) \ +extern int name##_pcibios_read_config_byte(unsigned char bus, \ + unsigned char dev_fn, unsigned char offset, unsigned char *val); \ +extern int name##_pcibios_read_config_word(unsigned char bus, \ + unsigned char dev_fn, unsigned char offset, unsigned short *val); \ +extern int name##_pcibios_read_config_dword(unsigned char bus, \ + unsigned char dev_fn, unsigned char offset, unsigned int *val); \ +extern int name##_pcibios_write_config_byte(unsigned char bus, \ + unsigned char dev_fn, unsigned char offset, unsigned char val); \ +extern int name##_pcibios_write_config_word(unsigned char bus, \ + unsigned char dev_fn, unsigned char offset, unsigned short val); \ +extern int name##_pcibios_write_config_dword(unsigned char bus, \ + unsigned char dev_fn, unsigned char offset, unsigned int val) + +#define set_config_access_method(name) \ + ppc_md.pcibios_read_config_byte = name##_pcibios_read_config_byte; \ + ppc_md.pcibios_read_config_word = name##_pcibios_read_config_word; \ + ppc_md.pcibios_read_config_dword = name##_pcibios_read_config_dword; \ + ppc_md.pcibios_write_config_byte = name##_pcibios_write_config_byte; \ + ppc_md.pcibios_write_config_word = name##_pcibios_write_config_word; \ + ppc_md.pcibios_write_config_dword = name##_pcibios_write_config_dword + +#endif /* __PPC_KERNEL_PCI_H__ */ diff -ur --new-file old/linux/arch/ppc/kernel/pmac_pci.c new/linux/arch/ppc/kernel/pmac_pci.c --- old/linux/arch/ppc/kernel/pmac_pci.c Sun Nov 15 19:51:43 1998 +++ new/linux/arch/ppc/kernel/pmac_pci.c Thu Apr 29 21:39:01 1999 @@ -21,6 +21,9 @@ #include #include #include +#include + +#include "pci.h" struct bridge_data **bridges, *bridge_list; static int max_bus; @@ -84,7 +87,12 @@ (1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8) + (offset & ~3)); } else { - out_le32(bp->cfg_addr, (dev_fn << 8) + (offset & ~3) + 1); + /* Bus number once again taken into consideration. + * Change applied from 2.1.24. This makes devices located + * behind PCI-PCI bridges visible. + * -Ranjit Deshpande, 01/20/99 + */ + out_le32(bp->cfg_addr, (bus << 16) + (dev_fn << 8) + (offset & ~3) + 1); } udelay(2); *val = in_8(bp->cfg_data + (offset & 3)); @@ -109,7 +117,8 @@ (1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8) + (offset & ~3)); } else { - out_le32(bp->cfg_addr, (dev_fn << 8) + (offset & ~3) + 1); + /* See pci_read_config_byte */ + out_le32(bp->cfg_addr, (bus << 16) + (dev_fn << 8) + (offset & ~3) + 1); } udelay(2); *val = in_le16((volatile unsigned short *)(bp->cfg_data + (offset & 3))); @@ -134,7 +143,8 @@ (1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8) + offset); } else { - out_le32(bp->cfg_addr, (dev_fn << 8) + offset + 1); + /* See pci_read_config_byte */ + out_le32(bp->cfg_addr, (bus << 16) + (dev_fn << 8) + offset + 1); } udelay(2); *val = in_le32((volatile unsigned int *)bp->cfg_data); @@ -156,7 +166,8 @@ (1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8) + (offset & ~3)); } else { - out_le32(bp->cfg_addr, (dev_fn << 8) + (offset & ~3) + 1); + /* See pci_read_config_byte */ + out_le32(bp->cfg_addr, (bus << 16) + (dev_fn << 8) + (offset & ~3) + 1); } udelay(2); out_8(bp->cfg_data + (offset & 3), val); @@ -180,7 +191,8 @@ (1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8) + (offset & ~3)); } else { - out_le32(bp->cfg_addr, (dev_fn << 8) + (offset & ~3) + 1); + /* See pci_read_config_byte */ + out_le32(bp->cfg_addr, (bus << 16) + (dev_fn << 8) + (offset & ~3) + 1); } udelay(2); out_le16((volatile unsigned short *)(bp->cfg_data + (offset & 3)), val); @@ -204,7 +216,8 @@ (1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8) + offset); } else { - out_le32(bp->cfg_addr, (dev_fn << 8) + offset + 1); + /* See pci_read_config_byte */ + out_le32(bp->cfg_addr, (bus << 16) + (dev_fn << 8) + (offset & ~3) + 1); } udelay(2); out_le32((volatile unsigned int *)bp->cfg_data, val); @@ -427,5 +440,49 @@ if (strcmp(dev->name, "bandit") == 0) init_bandit(bp); } +} + +__initfunc( +void +pmac_pcibios_fixup(void)) +{ + struct pci_dev *dev; + + /* + * FIXME: This is broken: We should not assign IRQ's to IRQless + * devices (look at PCI_INTERRUPT_PIN) and we also should + * honor the existence of multi-function devices where + * different functions have different interrupt pins. [mj] + */ + for(dev=pci_devices; dev; dev=dev->next) + { + /* + * Open Firmware often doesn't initialize the, + * PCI_INTERRUPT_LINE config register properly, so we + * should find the device node and se if it has an + * AAPL,interrupts property. + */ + struct bridge_data *bp = bridges[dev->bus->number]; + unsigned char pin; + + if (pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin) || + !pin) + continue; /* No interrupt generated -> no fixup */ + fix_intr(bp->node->child, dev); + } +} + +__initfunc( +void +pmac_setup_pci_ptrs(void)) +{ + if (find_devices("pci") != 0) { + /* looks like a G3 powermac */ + set_config_access_method(grackle); + } else { + set_config_access_method(pmac); + } + + ppc_md.pcibios_fixup = pmac_pcibios_fixup; } diff -ur --new-file old/linux/arch/ppc/kernel/pmac_pic.c new/linux/arch/ppc/kernel/pmac_pic.c --- old/linux/arch/ppc/kernel/pmac_pic.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/ppc/kernel/pmac_pic.c Wed May 12 17:50:08 1999 @@ -0,0 +1,362 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "pmac_pic.h" + +/* pmac */struct pmac_irq_hw { + unsigned int flag; + unsigned int enable; + unsigned int ack; + unsigned int level; +}; + +/* XXX these addresses should be obtained from the device tree */ +static volatile struct pmac_irq_hw *pmac_irq_hw[4] = { + (struct pmac_irq_hw *) 0xf3000020, + (struct pmac_irq_hw *) 0xf3000010, + (struct pmac_irq_hw *) 0xf4000020, + (struct pmac_irq_hw *) 0xf4000010, +}; + +static int max_irqs; +static int max_real_irqs; + +#define MAXCOUNT 10000000 + +#define GATWICK_IRQ_POOL_SIZE 10 +static struct interrupt_info gatwick_int_pool[GATWICK_IRQ_POOL_SIZE]; + +static void __pmac pmac_mask_and_ack_irq(unsigned int irq_nr) +{ + unsigned long bit = 1UL << (irq_nr & 0x1f); + int i = irq_nr >> 5; + + if ((unsigned)irq_nr >= max_irqs) + return; + + clear_bit(irq_nr, ppc_cached_irq_mask); + if (test_and_clear_bit(irq_nr, ppc_lost_interrupts)) + atomic_dec(&ppc_n_lost_interrupts); + out_le32(&pmac_irq_hw[i]->ack, bit); + out_le32(&pmac_irq_hw[i]->enable, ppc_cached_irq_mask[i]); + out_le32(&pmac_irq_hw[i]->ack, bit); + do { + /* make sure ack gets to controller before we enable + interrupts */ + mb(); + } while(in_le32(&pmac_irq_hw[i]->flag) & bit); +} + +static void __pmac pmac_set_irq_mask(unsigned int irq_nr) +{ + unsigned long bit = 1UL << (irq_nr & 0x1f); + int i = irq_nr >> 5; + + if ((unsigned)irq_nr >= max_irqs) + return; + + /* enable unmasked interrupts */ + out_le32(&pmac_irq_hw[i]->enable, ppc_cached_irq_mask[i]); + + do { + /* make sure mask gets to controller before we + return to user */ + mb(); + } while((in_le32(&pmac_irq_hw[i]->enable) & bit) + != (ppc_cached_irq_mask[i] & bit)); + + /* + * Unfortunately, setting the bit in the enable register + * when the device interrupt is already on *doesn't* set + * the bit in the flag register or request another interrupt. + */ + if ((bit & ppc_cached_irq_mask[i]) + && (ld_le32(&pmac_irq_hw[i]->level) & bit) + && !(ld_le32(&pmac_irq_hw[i]->flag) & bit)) { + if (!test_and_set_bit(irq_nr, ppc_lost_interrupts)) + atomic_inc(&ppc_n_lost_interrupts); + } +} + +static void __pmac pmac_mask_irq(unsigned int irq_nr) +{ + clear_bit(irq_nr, ppc_cached_irq_mask); + pmac_set_irq_mask(irq_nr); + mb(); +} + +static void __pmac pmac_unmask_irq(unsigned int irq_nr) +{ + set_bit(irq_nr, ppc_cached_irq_mask); + pmac_set_irq_mask(irq_nr); +} + +struct hw_interrupt_type pmac_pic = { + " PMAC-PIC ", + NULL, + NULL, + NULL, + pmac_unmask_irq, + pmac_mask_irq, + pmac_mask_and_ack_irq, + 0 +}; + +struct hw_interrupt_type gatwick_pic = { + " GATWICK ", + NULL, + NULL, + NULL, + pmac_unmask_irq, + pmac_mask_irq, + pmac_mask_and_ack_irq, + 0 +}; + +static void gatwick_action(int cpl, void *dev_id, struct pt_regs *regs) +{ + int irq, bits; + + for (irq = max_irqs - 1; irq > max_real_irqs; irq -= 32) { + int i = irq >> 5; + bits = ld_le32(&pmac_irq_hw[i]->flag) + | ppc_lost_interrupts[i]; + if (bits == 0) + continue; + irq -= cntlzw(bits); + break; + } + /* The previous version of this code allowed for this case, we + * don't. Put this here to check for it. + * -- Cort + */ + if ( irq_desc[irq].ctl != &gatwick_pic ) + printk("gatwick irq not from gatwick pic\n"); + else + ppc_irq_dispatch_handler( regs, irq ); +} + +void +pmac_do_IRQ(struct pt_regs *regs, + int cpu, + int isfake) +{ + int irq; + unsigned long bits = 0; + +#ifdef __SMP__ + /* IPI's are a hack on the powersurge -- Cort */ + if ( cpu != 0 ) + { + if (!isfake) + { +#ifdef CONFIG_XMON + static int xmon_2nd; + if (xmon_2nd) + xmon(regs); +#endif + smp_message_recv(); + goto out; + } + /* could be here due to a do_fake_interrupt call but we don't + mess with the controller from the second cpu -- Cort */ + goto out; + } + + { + unsigned int loops = MAXCOUNT; + while (test_bit(0, &global_irq_lock)) { + if (smp_processor_id() == global_irq_holder) { + printk("uh oh, interrupt while we hold global irq lock!\n"); +#ifdef CONFIG_XMON + xmon(0); +#endif + break; + } + if (loops-- == 0) { + printk("do_IRQ waiting for irq lock (holder=%d)\n", global_irq_holder); +#ifdef CONFIG_XMON + xmon(0); +#endif + } + } + } +#endif /* __SMP__ */ + + for (irq = max_real_irqs - 1; irq > 0; irq -= 32) { + int i = irq >> 5; + bits = ld_le32(&pmac_irq_hw[i]->flag) + | ppc_lost_interrupts[i]; + if (bits == 0) + continue; + irq -= cntlzw(bits); + break; + } + + if (irq < 0) + { + printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n", + irq, regs->nip); + ppc_spurious_interrupts++; + } + else + { + ppc_irq_dispatch_handler( regs, irq ); + } +#ifdef CONFIG_SMP +out: +#endif /* CONFIG_SMP */ +} + +/* This routine will fix some missing interrupt values in the device tree + * on the gatwick mac-io controller used by some PowerBooks + */ +static void __init pmac_fix_gatwick_interrupts(struct device_node *gw, int irq_base) +{ + struct device_node *node; + int count; + + memset(gatwick_int_pool, 0, sizeof(gatwick_int_pool)); + node = gw->child; + count = 0; + while(node) + { + /* Fix SCC */ + if (strcasecmp(node->name, "escc") == 0) + if (node->child) { + if (node->child->n_intrs < 3) { + node->child->intrs = &gatwick_int_pool[count]; + count += 3; + } + node->child->n_intrs = 3; + node->child->intrs[0].line = 15+irq_base; + node->child->intrs[1].line = 4+irq_base; + node->child->intrs[2].line = 5+irq_base; + printk(KERN_INFO "irq: fixed SCC on second controller (%d,%d,%d)\n", + node->child->intrs[0].line, + node->child->intrs[1].line, + node->child->intrs[2].line); + } + /* Fix media-bay & left SWIM */ + if (strcasecmp(node->name, "media-bay") == 0) { + struct device_node* ya_node; + + if (node->n_intrs == 0) + node->intrs = &gatwick_int_pool[count++]; + node->n_intrs = 1; + node->intrs[0].line = 29+irq_base; + printk(KERN_INFO "irq: fixed media-bay on second controller (%d)\n", + node->intrs[0].line); + + ya_node = node->child; + while(ya_node) + { + if (strcasecmp(ya_node->name, "floppy") == 0) { + if (ya_node->n_intrs < 2) { + ya_node->intrs = &gatwick_int_pool[count]; + count += 2; + } + ya_node->n_intrs = 2; + ya_node->intrs[0].line = 19+irq_base; + ya_node->intrs[1].line = 1+irq_base; + printk(KERN_INFO "irq: fixed floppy on second controller (%d,%d)\n", + ya_node->intrs[0].line, ya_node->intrs[1].line); + } + if (strcasecmp(ya_node->name, "ata4") == 0) { + if (ya_node->n_intrs < 2) { + ya_node->intrs = &gatwick_int_pool[count]; + count += 2; + } + ya_node->n_intrs = 2; + ya_node->intrs[0].line = 14+irq_base; + ya_node->intrs[1].line = 3+irq_base; + printk(KERN_INFO "irq: fixed ide on second controller (%d,%d)\n", + ya_node->intrs[0].line, ya_node->intrs[1].line); + } + ya_node = ya_node->sibling; + } + } + node = node->sibling; + } + if (count > 10) { + printk("WARNING !! Gatwick interrupt pool overflow\n"); + printk(" GATWICK_IRQ_POOL_SIZE = %d\n", GATWICK_IRQ_POOL_SIZE); + printk(" requested = %d\n", count); + } +} + +__initfunc(void +pmac_pic_init(void)) +{ + int i; + struct device_node *irqctrler; + unsigned long addr; + int second_irq = -999; + + + /* G3 powermacs have 64 interrupts, G3 Series PowerBook have 128, + others have 32 */ + max_irqs = max_real_irqs = 32; + irqctrler = find_devices("mac-io"); + if (irqctrler) + { + max_real_irqs = 64; + if (irqctrler->next) + max_irqs = 128; + else + max_irqs = 64; + } + for ( i = 0; i < max_real_irqs ; i++ ) + irq_desc[i].ctl = &pmac_pic; + + /* get addresses of first controller */ + if (irqctrler) { + if (irqctrler->n_addrs > 0) { + addr = (unsigned long) + ioremap(irqctrler->addrs[0].address, 0x40); + for (i = 0; i < 2; ++i) + pmac_irq_hw[i] = (volatile struct pmac_irq_hw*) + (addr + (2 - i) * 0x10); + } + + /* get addresses of second controller */ + irqctrler = (irqctrler->next) ? irqctrler->next : NULL; + if (irqctrler && irqctrler->n_addrs > 0) { + addr = (unsigned long) + ioremap(irqctrler->addrs[0].address, 0x40); + for (i = 2; i < 4; ++i) + pmac_irq_hw[i] = (volatile struct pmac_irq_hw*) + (addr + (4 - i) * 0x10); + } + } + + /* disable all interrupts in all controllers */ + for (i = 0; i * 32 < max_irqs; ++i) + out_le32(&pmac_irq_hw[i]->enable, 0); + + /* get interrupt line of secondary interrupt controller */ + if (irqctrler) { + second_irq = irqctrler->intrs[0].line; + printk(KERN_INFO "irq: secondary controller on irq %d\n", + (int)second_irq); + if (device_is_compatible(irqctrler, "gatwick")) + pmac_fix_gatwick_interrupts(irqctrler, max_real_irqs); + for ( i = max_real_irqs ; i < max_irqs ; i++ ) + irq_desc[i].ctl = &gatwick_pic; + request_irq( second_irq, gatwick_action, SA_INTERRUPT, + "gatwick cascade", 0 ); + } + printk("System has %d possible interrupts\n", max_irqs); + if (max_irqs != max_real_irqs) + printk(KERN_DEBUG "%d interrupts on main controller\n", + max_real_irqs); + +#ifdef CONFIG_XMON + request_irq(20, xmon_irq, 0, "NMI - XMON", 0); +#endif /* CONFIG_XMON */ +} diff -ur --new-file old/linux/arch/ppc/kernel/pmac_pic.h new/linux/arch/ppc/kernel/pmac_pic.h --- old/linux/arch/ppc/kernel/pmac_pic.h Thu Jan 1 01:00:00 1970 +++ new/linux/arch/ppc/kernel/pmac_pic.h Thu Apr 29 21:39:01 1999 @@ -0,0 +1,15 @@ +#ifndef _PPC_KERNEL_PMAC_PIC_H +#define _PPC_KERNEL_PMAC_PIC_H + +#include "local_irq.h" + +extern struct hw_interrupt_type pmac_pic; + +void pmac_pic_init(void); +void pmac_do_IRQ(struct pt_regs *regs, + int cpu, + int isfake); + + +#endif /* _PPC_KERNEL_PMAC_PIC_H */ + diff -ur --new-file old/linux/arch/ppc/kernel/pmac_setup.c new/linux/arch/ppc/kernel/pmac_setup.c --- old/linux/arch/ppc/kernel/pmac_setup.c Sun Nov 15 19:51:43 1998 +++ new/linux/arch/ppc/kernel/pmac_setup.c Tue May 11 17:24:32 1999 @@ -44,6 +44,7 @@ #include #include #include +#include #include #include #include @@ -52,10 +53,44 @@ #include #include #include +#include +#include + #include "time.h" +#include "local_irq.h" +#include "pmac_pic.h" + +#undef SHOW_GATWICK_IRQS + +unsigned long pmac_get_rtc_time(void); +int pmac_set_rtc_time(unsigned long nowtime); +void pmac_read_rtc_time(void); +void pmac_calibrate_decr(void); +void pmac_setup_pci_ptrs(void); + +extern int mackbd_setkeycode(unsigned int scancode, unsigned int keycode); +extern int mackbd_getkeycode(unsigned int scancode); +extern int mackbd_translate(unsigned char scancode, unsigned char *keycode, + char raw_mode); +extern char mackbd_unexpected_up(unsigned char keycode); +extern void mackbd_leds(unsigned char leds); +extern void mackbd_init_hw(void); +#ifdef CONFIG_MAGIC_SYSRQ +unsigned char mackbd_sysrq_xlate[128]; +#endif /* CONFIG_MAGIC_SYSRQ */ +extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode); +extern int pckbd_getkeycode(unsigned int scancode); +extern int pckbd_translate(unsigned char scancode, unsigned char *keycode, + char raw_mode); +extern char pckbd_unexpected_up(unsigned char keycode); +extern void pckbd_leds(unsigned char leds); +extern void pckbd_init_hw(void); unsigned char drive_info; +int ppc_override_l2cr = 0; +int ppc_override_l2cr_value; + extern char saved_command_line[]; #define DEFAULT_ROOT_DEVICE 0x0801 /* sda1 - slightly silly choice */ @@ -132,6 +167,16 @@ } } + /* Checks "l2cr-value" property in the registry */ + np = find_devices("cpus"); + if (np != 0) { + unsigned int *l2cr = (unsigned int *) + get_property(np, "l2cr-value", NULL); + if (l2cr != 0) { + len += sprintf(buffer+len, "l2cr override\t: 0x%x\n", *l2cr); + } + } + return len; } @@ -210,6 +255,26 @@ *memory_start_p = pmac_find_bridges(*memory_start_p, *memory_end_p); + /* Checks "l2cr-value" property in the registry */ + if ( (_get_PVR() >> 16) == 8) { + struct device_node *np = find_devices("cpus"); + if (np != 0) { + unsigned int *l2cr = (unsigned int *) + get_property(np, "l2cr-value", NULL); + if (l2cr != 0) { + ppc_override_l2cr = 1; + ppc_override_l2cr_value = *l2cr; + _set_L2CR(0); + _set_L2CR(ppc_override_l2cr_value); + } + } + } + + if (ppc_override_l2cr) + printk(KERN_INFO "L2CR overriden (0x%x), backside cache is %s\n", + ppc_override_l2cr_value, (ppc_override_l2cr_value & 0x80000000) + ? "enabled" : "disabled"); + feature_init(); #ifdef CONFIG_KGDB @@ -258,15 +323,12 @@ int boot_part; kdev_t boot_dev; -void __init powermac_init(void) +__initfunc(void +pmac_init2(void)) { - if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) ) - return; adb_init(); pmac_nvram_init(); - if (_machine == _MACH_Pmac) { - media_bay_init(); - } + media_bay_init(); } #ifdef CONFIG_SCSI @@ -369,5 +431,176 @@ boot_dev = NODEV; printk(" (root)"); } +} + +void +pmac_restart(char *cmd) +{ + struct adb_request req; + + switch (adb_hardware) { + case ADB_VIACUDA: + cuda_request(&req, NULL, 2, CUDA_PACKET, + CUDA_RESET_SYSTEM); + for (;;) + cuda_poll(); + break; + + case ADB_VIAPMU: + pmu_restart(); + break; + default: + } +} + +void +pmac_power_off(void) +{ + struct adb_request req; + + switch (adb_hardware) { + case ADB_VIACUDA: + cuda_request(&req, NULL, 2, CUDA_PACKET, + CUDA_POWERDOWN); + for (;;) + cuda_poll(); + break; + + case ADB_VIAPMU: + pmu_shutdown(); + break; + default: + } +} + +void +pmac_halt(void) +{ + pmac_power_off(); +} + + +#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) +/* + * IDE stuff. + */ +void +pmac_ide_insw(ide_ioreg_t port, void *buf, int ns) +{ + ide_insw(port, buf, ns); +} + +void +pmac_ide_outsw(ide_ioreg_t port, void *buf, int ns) +{ + ide_outsw(port, buf, ns); +} + +int +pmac_ide_default_irq(ide_ioreg_t base) +{ + return 0; +} + +ide_ioreg_t +pmac_ide_default_io_base(int index) +{ +#if defined(CONFIG_BLK_DEV_IDE_PMAC) + return pmac_ide_regbase[index]; +#else + return 0; +#endif +} + +int +pmac_ide_check_region(ide_ioreg_t from, unsigned int extent) +{ + return 0; +} + +void +pmac_ide_request_region(ide_ioreg_t from, + unsigned int extent, + const char *name) +{ +} + +void +pmac_ide_release_region(ide_ioreg_t from, + unsigned int extent) +{ +} + +/* Convert the shorts/longs in hd_driveid from little to big endian; + * chars are endian independant, of course, but strings need to be flipped. + * (Despite what it says in drivers/block/ide.h, they come up as little + * endian...) + * + * Changes to linux/hdreg.h may require changes here. */ +void +pmac_ide_fix_driveid(struct hd_driveid *id) +{ + ppc_generic_ide_fix_driveid(id); +} + +/* This is declared in drivers/block/ide-pmac.c */ +void pmac_ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq); +#endif + +__initfunc(void +pmac_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7)) +{ + pmac_setup_pci_ptrs(); + + /* isa_io_base gets set in pmac_find_bridges */ + isa_mem_base = PMAC_ISA_MEM_BASE; + pci_dram_offset = PMAC_PCI_DRAM_OFFSET; + ISA_DMA_THRESHOLD = ~0L; + DMA_MODE_READ = 1; + DMA_MODE_WRITE = 2; + + ppc_md.setup_arch = pmac_setup_arch; + ppc_md.setup_residual = NULL; + ppc_md.get_cpuinfo = pmac_get_cpuinfo; + ppc_md.irq_cannonicalize = NULL; + ppc_md.init_IRQ = pmac_pic_init; + ppc_md.do_IRQ = pmac_do_IRQ; + ppc_md.init = pmac_init2; + + ppc_md.restart = pmac_restart; + ppc_md.power_off = pmac_power_off; + ppc_md.halt = pmac_halt; + + ppc_md.time_init = NULL; + ppc_md.set_rtc_time = pmac_set_rtc_time; + ppc_md.get_rtc_time = pmac_get_rtc_time; + ppc_md.calibrate_decr = pmac_calibrate_decr; + +#if defined(CONFIG_VT) && defined(CONFIG_MAC_KEYBOARD) + ppc_md.kbd_setkeycode = mackbd_setkeycode; + ppc_md.kbd_getkeycode = mackbd_getkeycode; + ppc_md.kbd_translate = mackbd_translate; + ppc_md.kbd_unexpected_up = mackbd_unexpected_up; + ppc_md.kbd_leds = mackbd_leds; + ppc_md.kbd_init_hw = mackbd_init_hw; +#ifdef CONFIG_MAGIC_SYSRQ + ppc_md.kbd_sysrq_xlate = mackbd_sysrq_xlate; +#endif +#endif + +#if defined(CONFIG_BLK_DEV_IDE_PMAC) + ppc_ide_md.insw = pmac_ide_insw; + ppc_ide_md.outsw = pmac_ide_outsw; + ppc_ide_md.default_irq = pmac_ide_default_irq; + ppc_ide_md.default_io_base = pmac_ide_default_io_base; + ppc_ide_md.check_region = pmac_ide_check_region; + ppc_ide_md.request_region = pmac_ide_request_region; + ppc_ide_md.release_region = pmac_ide_release_region; + ppc_ide_md.fix_driveid = pmac_ide_fix_driveid; + ppc_ide_md.ide_init_hwif = pmac_ide_init_hwif_ports; + + ppc_ide_md.io_base = 0; +#endif } diff -ur --new-file old/linux/arch/ppc/kernel/ppc8xx_pic.c new/linux/arch/ppc/kernel/ppc8xx_pic.c --- old/linux/arch/ppc/kernel/ppc8xx_pic.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/ppc/kernel/ppc8xx_pic.c Thu Apr 29 21:39:01 1999 @@ -0,0 +1,49 @@ + +#include +#include +#include +#include +#include +#include +#include +#include "ppc8xx_pic.h" + + +static void mbx_mask_irq(unsigned int irq_nr) +{ + if ( irq_nr == ISA_BRIDGE_INT ) return; + if ( irq_nr >= ppc8xx_pic.irq_offset ) + irq_nr -= ppc8xx_pic.irq_offset; + ppc_cached_irq_mask[0] &= ~(1 << (31-irq_nr)); + ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask = ppc_cached_irq_mask[0]; +} + +static void mbx_unmask_irq(unsigned int irq_nr) +{ + if ( irq_nr >= ppc8xx_pic.irq_offset ) + irq_nr -= ppc8xx_pic.irq_offset; + ppc_cached_irq_mask[0] |= (1 << (31-irq_nr)); + ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask = ppc_cached_irq_mask[0]; +} + +static void mbx_mask_and_ack(unsigned int irq_nr) +{ + /* this shouldn't be masked, we mask the 8259 if we need to -- Cort */ + if ( irq_nr != ISA_BRIDGE_INT ) + mbx_mask_irq(irq_nr); + if ( irq_nr >= ppc8xx_pic.irq_offset ) + irq_nr -= ppc8xx_pic.irq_offset; + /* clear the pending bits */ + ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sipend = 1 << (31-irq_nr); +} + +struct hw_interrupt_type ppc8xx_pic = { + " 8xx SIU ", + NULL, + NULL, + NULL, + mbx_unmask_irq, + mbx_mask_irq, + mbx_mask_and_ack, + 0 +}; diff -ur --new-file old/linux/arch/ppc/kernel/ppc8xx_pic.h new/linux/arch/ppc/kernel/ppc8xx_pic.h --- old/linux/arch/ppc/kernel/ppc8xx_pic.h Thu Jan 1 01:00:00 1970 +++ new/linux/arch/ppc/kernel/ppc8xx_pic.h Thu Apr 29 21:39:01 1999 @@ -0,0 +1,9 @@ + +#ifndef _PPC_KERNEL_PPC8xx_H +#define _PPC_KERNEL_PPC8xx_H + +#include "local_irq.h" + +extern struct hw_interrupt_type ppc8xx_pic; + +#endif /* _PPC_KERNEL_PPC8xx_H */ diff -ur --new-file old/linux/arch/ppc/kernel/ppc_defs.h new/linux/arch/ppc/kernel/ppc_defs.h --- old/linux/arch/ppc/kernel/ppc_defs.h Wed Sep 30 19:14:17 1998 +++ new/linux/arch/ppc/kernel/ppc_defs.h Thu Jan 1 01:00:00 1970 @@ -1,69 +0,0 @@ -/* - * WARNING! This file is automatically generated - DO NOT EDIT! - */ -#define KERNELBASE -1073741824 -#define STATE 0 -#define NEXT_TASK 48 -#define COUNTER 24 -#define PROCESSOR 36 -#define SIGPENDING 8 -#define TSS 568 -#define MM 872 -#define TASK_STRUCT_SIZE 912 -#define KSP 0 -#define PG_TABLES 4 -#define PGD 8 -#define LAST_SYSCALL 20 -#define PT_REGS 12 -#define PF_TRACESYS 32 -#define TASK_FLAGS 4 -#define NEED_RESCHED 20 -#define TSS_FPR0 24 -#define TSS_FPSCR 284 -#define TSS_SMP_FORK_RET 288 -#define TASK_UNION_SIZE 8192 -#define STACK_FRAME_OVERHEAD 16 -#define INT_FRAME_SIZE 192 -#define GPR0 16 -#define GPR1 20 -#define GPR2 24 -#define GPR3 28 -#define GPR4 32 -#define GPR5 36 -#define GPR6 40 -#define GPR7 44 -#define GPR8 48 -#define GPR9 52 -#define GPR10 56 -#define GPR11 60 -#define GPR12 64 -#define GPR13 68 -#define GPR14 72 -#define GPR15 76 -#define GPR16 80 -#define GPR17 84 -#define GPR18 88 -#define GPR19 92 -#define GPR20 96 -#define GPR21 100 -#define GPR22 104 -#define GPR23 108 -#define GPR24 112 -#define GPR25 116 -#define GPR26 120 -#define GPR27 124 -#define GPR28 128 -#define GPR29 132 -#define GPR30 136 -#define GPR31 140 -#define _NIP 144 -#define _MSR 148 -#define _CTR 156 -#define _LINK 160 -#define _CCR 168 -#define _XER 164 -#define _DAR 180 -#define _DSISR 184 -#define ORIG_GPR3 152 -#define RESULT 188 -#define TRAP 176 diff -ur --new-file old/linux/arch/ppc/kernel/ppc_ksyms.c new/linux/arch/ppc/kernel/ppc_ksyms.c --- old/linux/arch/ppc/kernel/ppc_ksyms.c Thu Jan 7 21:06:57 1999 +++ new/linux/arch/ppc/kernel/ppc_ksyms.c Thu Apr 29 21:39:01 1999 @@ -8,11 +8,12 @@ #include #include +#include #include #include #include -#include #include +#include #include #include #include @@ -26,6 +27,8 @@ #include #include #include +#include +#include #define __KERNEL_SYSCALLS__ #include @@ -39,13 +42,14 @@ extern void ProgramCheckException(struct pt_regs *regs); extern void SingleStepException(struct pt_regs *regs); extern int sys_sigreturn(struct pt_regs *regs); -extern atomic_t n_lost_interrupts; +extern atomic_t ppc_n_lost_interrupts; extern void do_lost_interrupts(unsigned long); extern int do_signal(sigset_t *, struct pt_regs *); asmlinkage long long __ashrdi3(long long, int); asmlinkage int abs(int); +EXPORT_SYMBOL(clear_page); EXPORT_SYMBOL(do_signal); EXPORT_SYMBOL(syscall_trace); EXPORT_SYMBOL(transfer_to_handler); @@ -57,16 +61,21 @@ EXPORT_SYMBOL(ProgramCheckException); EXPORT_SYMBOL(SingleStepException); EXPORT_SYMBOL(sys_sigreturn); -EXPORT_SYMBOL(n_lost_interrupts); +EXPORT_SYMBOL(ppc_n_lost_interrupts); EXPORT_SYMBOL(do_lost_interrupts); EXPORT_SYMBOL(enable_irq); EXPORT_SYMBOL(disable_irq); -EXPORT_SYMBOL(local_irq_count); -EXPORT_SYMBOL(local_bh_count); +EXPORT_SYMBOL(ppc_local_irq_count); +EXPORT_SYMBOL(ppc_local_bh_count); EXPORT_SYMBOL(isa_io_base); EXPORT_SYMBOL(isa_mem_base); EXPORT_SYMBOL(pci_dram_offset); +EXPORT_SYMBOL(ISA_DMA_THRESHOLD); +EXPORT_SYMBOL(DMA_MODE_READ); +EXPORT_SYMBOL(DMA_MODE_WRITE); +EXPORT_SYMBOL(_prep_type); +EXPORT_SYMBOL(ucSystemType); EXPORT_SYMBOL(atomic_add); EXPORT_SYMBOL(atomic_sub); @@ -155,6 +164,7 @@ EXPORT_SYMBOL(flush_instruction_cache); EXPORT_SYMBOL(_get_PVR); EXPORT_SYMBOL(giveup_fpu); +EXPORT_SYMBOL(enable_kernel_fp); EXPORT_SYMBOL(flush_icache_range); EXPORT_SYMBOL(xchg_u32); #ifdef __SMP__ @@ -171,18 +181,14 @@ EXPORT_SYMBOL(_write_unlock); #endif -#ifndef CONFIG_MACH_SPECIFIC EXPORT_SYMBOL(_machine); -#endif +EXPORT_SYMBOL(ppc_md); EXPORT_SYMBOL(adb_request); -EXPORT_SYMBOL(adb_autopoll); EXPORT_SYMBOL(adb_register); EXPORT_SYMBOL(cuda_request); -EXPORT_SYMBOL(cuda_send_request); EXPORT_SYMBOL(cuda_poll); EXPORT_SYMBOL(pmu_request); -EXPORT_SYMBOL(pmu_send_request); EXPORT_SYMBOL(pmu_poll); #ifdef CONFIG_PMAC_PBOOK EXPORT_SYMBOL(sleep_notifier_list); @@ -194,7 +200,6 @@ EXPORT_SYMBOL(find_path_device); EXPORT_SYMBOL(find_phandle); EXPORT_SYMBOL(get_property); -EXPORT_SYMBOL(device_is_compatible); EXPORT_SYMBOL(pci_io_base); EXPORT_SYMBOL(pci_device_loc); EXPORT_SYMBOL(feature_set); @@ -209,9 +214,8 @@ EXPORT_SYMBOL(nvram_write_byte); #endif /* CONFIG_PMAC */ -#ifdef CONFIG_SOUND_MODULE EXPORT_SYMBOL(abs); -#endif +EXPORT_SYMBOL(device_is_compatible); /* The following are special because they're not called explicitly (the C compiler generates them). Fortunately, diff -ur --new-file old/linux/arch/ppc/kernel/prep_nvram.c new/linux/arch/ppc/kernel/prep_nvram.c --- old/linux/arch/ppc/kernel/prep_nvram.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/ppc/kernel/prep_nvram.c Thu Apr 29 21:39:01 1999 @@ -0,0 +1,173 @@ +/* + * linux/arch/ppc/kernel/prep_nvram.c + * + * Copyright (C) 1998 Corey Minyard + * + */ +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* + * Allow for a maximum of 32K of PReP NvRAM data + */ +#define MAX_PREP_NVRAM 0x8000 +static char nvramData[MAX_PREP_NVRAM]; +static NVRAM_MAP *nvram=(NVRAM_MAP *)&nvramData[0]; + +#define PREP_NVRAM_AS0 0x74 +#define PREP_NVRAM_AS1 0x75 +#define PREP_NVRAM_DATA 0x77 + +unsigned char *rs_pcNvRAM; + +unsigned char prep_nvram_read_val(int addr) +{ + outb(addr, PREP_NVRAM_AS0); + outb(addr>>8, PREP_NVRAM_AS1); + return inb(PREP_NVRAM_DATA); +} + +void prep_nvram_write_val(int addr, + unsigned char val) +{ + outb(addr, PREP_NVRAM_AS0); + outb(addr>>8, PREP_NVRAM_AS1); + outb(val, PREP_NVRAM_DATA); +} + +/* + * Most Radstone boards have NvRAM memory mapped at offset 8M in ISA space + */ +unsigned char rs_nvram_read_val(int addr) +{ + return rs_pcNvRAM[addr]; +} + +void rs_nvram_write_val(int addr, + unsigned char val) +{ + rs_pcNvRAM[addr]=val; +} + +__initfunc(void init_prep_nvram(void)) +{ + unsigned char *nvp; + int i; + int nvramSize; + + /* + * I'm making the assumption that 32k will always cover the + * nvramsize. If this isn't the case please let me know and we can + * map the header, then get the size from the header, then map + * the whole size. -- Cort + */ + if ( _prep_type == _PREP_Radstone ) + rs_pcNvRAM = (unsigned char *)ioremap(_ISA_MEM_BASE+0x00800000, + 32<<10); + request_region(PREP_NVRAM_AS0, 0x8, "PReP NVRAM"); + /* + * The following could fail if the NvRAM were corrupt but + * we expect the boot firmware to have checked its checksum + * before boot + */ + nvp = (char *) &nvram->Header; + for (i=0; iHeader.GEAddress+nvram->Header.GELength; + if(nvramSize>MAX_PREP_NVRAM) + { + /* + * NvRAM is too large + */ + nvram->Header.GELength=0; + return; + } + + /* + * Read the remainder of the PReP NvRAM + */ + nvp = (char *) &nvram->GEArea[0]; + for (i=sizeof(HEADER); iGEArea)) < nvram->Header.GELength) + && (*cp == '\0')) + { + cp++; + } + + if ((cp - ((char *) nvram->GEArea)) < nvram->Header.GELength) { + return cp; + } else { + return NULL; + } +} + + + diff -ur --new-file old/linux/arch/ppc/kernel/prep_pci.c new/linux/arch/ppc/kernel/prep_pci.c --- old/linux/arch/ppc/kernel/prep_pci.c Mon Dec 21 17:37:20 1998 +++ new/linux/arch/ppc/kernel/prep_pci.c Tue May 11 17:24:32 1999 @@ -1,5 +1,5 @@ /* - * $Id: prep_pci.c,v 1.24 1998/12/10 02:39:51 cort Exp $ + * $Id: prep_pci.c,v 1.33 1999/05/09 20:15:54 cort Exp $ * PReP pci functions. * Originally by Gary Thomas * rewritten and updated by Cort Dougan (cort@cs.nmt.edu) @@ -11,11 +11,19 @@ #include #include #include +#include #include #include #include +#include +#include +#include #include +#include +#include + +#include "pci.h" #define MAX_DEVNR 22 @@ -27,6 +35,9 @@ /* How is the 82378 PIRQ mapping setup? */ unsigned char *Motherboard_routes; +/* Used for Motorola to store system config register */ +static unsigned long *ProcInfo; + /* Tables for known hardware */ /* Motorola PowerStackII - Utah */ @@ -34,38 +45,39 @@ { 0, /* Slot 0 - unused */ 0, /* Slot 1 - unused */ - 4, /* Slot 2 - SCSI - NCR825A */ + 5, /* Slot 2 - SCSI - NCR825A */ 0, /* Slot 3 - unused */ 1, /* Slot 4 - Ethernet - DEC2114x */ 0, /* Slot 5 - unused */ - 2, /* Slot 6 - PCI Card slot #1 */ - 3, /* Slot 7 - PCI Card slot #2 */ - 4, /* Slot 8 - PCI Card slot #3 */ - 4, /* Slot 9 - PCI Bridge */ + 3, /* Slot 6 - PCI Card slot #1 */ + 4, /* Slot 7 - PCI Card slot #2 */ + 5, /* Slot 8 - PCI Card slot #3 */ + 5, /* Slot 9 - PCI Bridge */ /* added here in case we ever support PCI bridges */ /* Secondary PCI bus cards are at slot-9,6 & slot-9,7 */ 0, /* Slot 10 - unused */ 0, /* Slot 11 - unused */ - 4, /* Slot 12 - SCSI - NCR825A */ + 5, /* Slot 12 - SCSI - NCR825A */ 0, /* Slot 13 - unused */ - 2, /* Slot 14 - enet */ + 3, /* Slot 14 - enet */ 0, /* Slot 15 - unused */ - 0, - 0, - 0, - 0, - 0, - 0, - 0, + 2, /* Slot 16 - unused */ + 3, /* Slot 17 - unused */ + 5, /* Slot 18 - unused */ + 0, /* Slot 19 - unused */ + 0, /* Slot 20 - unused */ + 0, /* Slot 21 - unused */ + 0, /* Slot 22 - unused */ }; static char Utah_pci_IRQ_routes[] __prepdata = { 0, /* Line 0 - Unused */ 9, /* Line 1 */ - 11, /* Line 2 */ - 14, /* Line 3 */ - 15, /* Line 4 */ + 10, /* Line 2 */ + 11, /* Line 3 */ + 14, /* Line 4 */ + 15, /* Line 5 */ }; /* Motorola PowerStackII - Omaha */ @@ -125,9 +137,9 @@ 0, /* Slot 13 - unused */ 1, /* Slot 14 - Ethernet */ 0, /* Slot 15 - unused */ - 1, /* Slot P7 */ - 2, /* Slot P6 */ - 3, /* Slot P5 */ + 1, /* Slot P7 */ + 2, /* Slot P6 */ + 3, /* Slot P5 */ }; static char Blackhawk_pci_IRQ_routes[] __prepdata = @@ -139,6 +151,122 @@ 15 /* Line 4 */ }; +/* Motorola Mesquite */ +static char Mesquite_pci_IRQ_map[23] __prepdata = +{ + 0, /* Slot 0 - unused */ + 0, /* Slot 1 - unused */ + 0, /* Slot 2 - unused */ + 0, /* Slot 3 - unused */ + 0, /* Slot 4 - unused */ + 0, /* Slot 5 - unused */ + 0, /* Slot 6 - unused */ + 0, /* Slot 7 - unused */ + 0, /* Slot 8 - unused */ + 0, /* Slot 9 - unused */ + 0, /* Slot 10 - unxued */ + 0, /* Slot 11 - unused */ + 0, /* Slot 12 - unused */ + 0, /* Slot 13 - unused */ + 2, /* Slot 14 - Ethernet */ + 0, /* Slot 15 - unused */ + 3, /* Slot 16 - PMC */ + 0, /* Slot 17 - unused */ + 0, /* Slot 18 - unused */ + 0, /* Slot 19 - unused */ + 0, /* Slot 20 - unused */ + 0, /* Slot 21 - unused */ + 0, /* Slot 22 - unused */ +}; + +/* Motorola Sitka */ +static char Sitka_pci_IRQ_map[21] __prepdata = +{ + 0, /* Slot 0 - unused */ + 0, /* Slot 1 - unused */ + 0, /* Slot 2 - unused */ + 0, /* Slot 3 - unused */ + 0, /* Slot 4 - unused */ + 0, /* Slot 5 - unused */ + 0, /* Slot 6 - unused */ + 0, /* Slot 7 - unused */ + 0, /* Slot 8 - unused */ + 0, /* Slot 9 - unused */ + 0, /* Slot 10 - unxued */ + 0, /* Slot 11 - unused */ + 0, /* Slot 12 - unused */ + 0, /* Slot 13 - unused */ + 2, /* Slot 14 - Ethernet */ + 0, /* Slot 15 - unused */ + 9, /* Slot 16 - PMC 1 */ + 12, /* Slot 17 - PMC 2 */ + 0, /* Slot 18 - unused */ + 0, /* Slot 19 - unused */ + 4, /* Slot 20 - NT P2P bridge */ +}; + +/* Motorola MTX */ +static char MTX_pci_IRQ_map[23] __prepdata = +{ + 0, /* Slot 0 - unused */ + 0, /* Slot 1 - unused */ + 0, /* Slot 2 - unused */ + 0, /* Slot 3 - unused */ + 0, /* Slot 4 - unused */ + 0, /* Slot 5 - unused */ + 0, /* Slot 6 - unused */ + 0, /* Slot 7 - unused */ + 0, /* Slot 8 - unused */ + 0, /* Slot 9 - unused */ + 0, /* Slot 10 - unused */ + 0, /* Slot 11 - unused */ + 3, /* Slot 12 - SCSI */ + 0, /* Slot 13 - unused */ + 2, /* Slot 14 - Ethernet */ + 0, /* Slot 15 - unused */ + 9, /* Slot 16 - PCI/PMC slot 1 */ + 10, /* Slot 17 - PCI/PMC slot 2 */ + 11, /* Slot 18 - PCI slot 3 */ + 0, /* Slot 19 - unused */ + 0, /* Slot 20 - unused */ + 0, /* Slot 21 - unused */ + 0, /* Slot 22 - unused */ +}; + +/* Motorola MTX Plus */ +/* Secondary bus interrupt routing is not supported yet */ +static char MTXplus_pci_IRQ_map[23] __prepdata = +{ + 0, /* Slot 0 - unused */ + 0, /* Slot 1 - unused */ + 0, /* Slot 2 - unused */ + 0, /* Slot 3 - unused */ + 0, /* Slot 4 - unused */ + 0, /* Slot 5 - unused */ + 0, /* Slot 6 - unused */ + 0, /* Slot 7 - unused */ + 0, /* Slot 8 - unused */ + 0, /* Slot 9 - unused */ + 0, /* Slot 10 - unused */ + 0, /* Slot 11 - unused */ + 3, /* Slot 12 - SCSI */ + 0, /* Slot 13 - unused */ + 2, /* Slot 14 - Ethernet 1 */ + 0, /* Slot 15 - unused */ + 9, /* Slot 16 - PCI slot 1P */ + 10, /* Slot 17 - PCI slot 2P */ + 11, /* Slot 18 - PCI slot 3P */ + 10, /* Slot 19 - Ethernet 2 */ + 0, /* Slot 20 - P2P Bridge */ + 0, /* Slot 21 - unused */ + 0, /* Slot 22 - unused */ +}; + +static char Raven_pci_IRQ_routes[] __prepdata = +{ + 0, /* This is a dummy structure */ +}; + /* Motorola MVME16xx */ static char Genesis_pci_IRQ_map[16] __prepdata = { @@ -169,8 +297,35 @@ 15 /* Line 4 */ }; +static char Genesis2_pci_IRQ_map[23] __prepdata = +{ + 0, /* Slot 0 - unused */ + 0, /* Slot 1 - unused */ + 0, /* Slot 2 - unused */ + 0, /* Slot 3 - unused */ + 0, /* Slot 4 - unused */ + 0, /* Slot 5 - unused */ + 0, /* Slot 6 - unused */ + 0, /* Slot 7 - unused */ + 0, /* Slot 8 - unused */ + 0, /* Slot 9 - unused */ + 0, /* Slot 10 - Ethernet */ + 0, /* Slot 11 - Universe PCI - VME Bridge */ + 3, /* Slot 12 - unused */ + 0, /* Slot 13 - unused */ + 2, /* Slot 14 - SCSI */ + 0, /* Slot 15 - graphics on 3600 */ + 9, /* Slot 16 - PMC */ + 12, /* Slot 17 - pci */ + 11, /* Slot 18 - pci */ + 10, /* Slot 19 - pci */ + 0, /* Slot 20 - pci */ + 0, /* Slot 21 - unused */ + 0, /* Slot 22 - unused */ +}; + /* Motorola Series-E */ -static char Comet_pci_IRQ_map[16] __prepdata = +static char Comet_pci_IRQ_map[23] __prepdata = { 0, /* Slot 0 - unused */ 0, /* Slot 1 - unused */ @@ -188,6 +343,13 @@ 0, /* Slot 13 - unused */ 1, /* Slot 14 - Ethernet */ 0, /* Slot 15 - unused */ + 1, /* Slot 16 - PCI slot 1 */ + 2, /* Slot 17 - PCI slot 2 */ + 3, /* Slot 18 - PCI slot 3 */ + 4, /* Slot 19 - PCI bridge */ + 0, + 0, + 0, }; static char Comet_pci_IRQ_routes[] __prepdata = @@ -199,6 +361,43 @@ 15 /* Line 4 */ }; +/* Motorola Series-EX */ +static char Comet2_pci_IRQ_map[23] __prepdata = +{ + 0, /* Slot 0 - unused */ + 0, /* Slot 1 - unused */ + 3, /* Slot 2 - SCSI - NCR825A */ + 0, /* Slot 3 - unused */ + 1, /* Slot 4 - Ethernet - DEC2104X */ + 0, /* Slot 5 - unused */ + 1, /* Slot 6 - PCI slot 1 */ + 2, /* Slot 7 - PCI slot 2 */ + 3, /* Slot 8 - PCI slot 3 */ + 4, /* Slot 9 - PCI bridge */ + 0, /* Slot 10 - unused */ + 0, /* Slot 11 - unused */ + 3, /* Slot 12 - SCSI - NCR825A */ + 0, /* Slot 13 - unused */ + 1, /* Slot 14 - Ethernet - DEC2104X */ + 0, /* Slot 15 - unused */ + 1, /* Slot 16 - PCI slot 1 */ + 2, /* Slot 17 - PCI slot 2 */ + 3, /* Slot 18 - PCI slot 3 */ + 4, /* Slot 19 - PCI bridge */ + 0, + 0, + 0, +}; + +static char Comet2_pci_IRQ_routes[] __prepdata = +{ + 0, /* Line 0 - Unused */ + 10, /* Line 1 */ + 11, /* Line 2 */ + 14, /* Line 3 */ + 15, /* Line 4 */ +}; + /* * ibm 830 (and 850?). * This is actually based on the Carolina motherboard @@ -312,22 +511,40 @@ #define CAROLINA_IRQ_EDGE_MASK_LO 0x00 /* IRQ's 0-7 */ #define CAROLINA_IRQ_EDGE_MASK_HI 0xA4 /* IRQ's 8-15 [10,13,15] */ +/* + * 8259 edge/level control definitions + */ +#define ISA8259_M_ELCR 0x4d0 +#define ISA8259_S_ELCR 0x4d1 + +#define ELCRS_INT15_LVL 0x80 +#define ELCRS_INT14_LVL 0x40 +#define ELCRS_INT12_LVL 0x10 +#define ELCRS_INT11_LVL 0x08 +#define ELCRS_INT10_LVL 0x04 +#define ELCRS_INT9_LVL 0x02 +#define ELCRS_INT8_LVL 0x01 +#define ELCRM_INT7_LVL 0x80 +#define ELCRM_INT5_LVL 0x20 + +#define CFGPTR(dev) (0x80800000 | (1<<(dev>>3)) | ((dev&7)<<8) | offset) +#define DEVNO(dev) (dev>>3) + __prep int prep_pcibios_read_config_dword (unsigned char bus, unsigned char dev, unsigned char offset, unsigned int *val) { - unsigned long _val; + unsigned long _val; unsigned long *ptr; - dev >>= 3; - - if ((bus != 0) || (dev > MAX_DEVNR)) - { + + if ((bus != 0) || (DEVNO(dev) > MAX_DEVNR)) + { *val = 0xFFFFFFFF; - return PCIBIOS_DEVICE_NOT_FOUND; - } else + return PCIBIOS_DEVICE_NOT_FOUND; + } else { - ptr = (unsigned long *)(0x80800000 | (1<>= 3; - if ((bus != 0) || (dev > MAX_DEVNR)) - { - *val = (unsigned short)0xFFFFFFFF; - return PCIBIOS_DEVICE_NOT_FOUND; - } else + + if ((bus != 0) || (DEVNO(dev) > MAX_DEVNR)) + { + *val = 0xFFFF; + return PCIBIOS_DEVICE_NOT_FOUND; + } else { - ptr = (unsigned short *)(0x80800000 | (1<>= 3; - if ((bus != 0) || (dev > MAX_DEVNR)) - { - *(unsigned long *)val = (unsigned long) 0xFFFFFFFF; - return PCIBIOS_DEVICE_NOT_FOUND; - } else + unsigned char _val; + unsigned char *ptr; + + if ((bus != 0) || (DEVNO(dev) > MAX_DEVNR)) + { + *val = 0xFF; + return PCIBIOS_DEVICE_NOT_FOUND; + } else { - ptr = (unsigned char *)(0x80800000 | (1<>= 3; + _val = le32_to_cpu(val); - if ((bus != 0) || (dev > MAX_DEVNR)) + if ((bus != 0) || (DEVNO(dev) > MAX_DEVNR)) { return PCIBIOS_DEVICE_NOT_FOUND; } else { - ptr = (unsigned long *)(0x80800000 | (1<>= 3; + _val = le16_to_cpu(val); - if ((bus != 0) || (dev > MAX_DEVNR)) + if ((bus != 0) || (DEVNO(dev) > MAX_DEVNR)) { return PCIBIOS_DEVICE_NOT_FOUND; } else { - ptr = (unsigned short *)(0x80800000 | (1<>= 3; + _val = val; - if ((bus != 0) || (dev > MAX_DEVNR)) + if ((bus != 0) || (DEVNO(dev) > MAX_DEVNR)) { return PCIBIOS_DEVICE_NOT_FOUND; } else { - ptr = (unsigned char *)(0x80800000 | (1<> 8) & 0xff, 0x4d1 ); } - outb( irq_mode & 0xff, 0x4d0 ); - outb( (irq_mode >> 8) & 0xff, 0x4d1 ); } else if ( _prep_type == _PREP_IBM ) { unsigned char pl_id; @@ -526,6 +891,71 @@ outb(pl_id|CAROLINA_IRQ_EDGE_MASK_HI, 0x04d1); pl_id=inb(0x04d1); /*printk("Hi mask now %#0x\n", pl_id);*/ + } else if ( _prep_type == _PREP_Radstone ) + { + unsigned char ucElcrM, ucElcrS; + + /* + * Set up edge/level + */ + switch(ucSystemType) + { + case RS_SYS_TYPE_PPC1: + { + if(ucBoardRevMaj<5) + { + ucElcrS=ELCRS_INT15_LVL; + } + else + { + ucElcrS=ELCRS_INT9_LVL | + ELCRS_INT11_LVL | + ELCRS_INT14_LVL | + ELCRS_INT15_LVL; + } + ucElcrM=ELCRM_INT5_LVL | ELCRM_INT7_LVL; + break; + } + + case RS_SYS_TYPE_PPC1a: + { + ucElcrS=ELCRS_INT9_LVL | + ELCRS_INT11_LVL | + ELCRS_INT14_LVL | + ELCRS_INT15_LVL; + ucElcrM=ELCRM_INT5_LVL; + break; + } + + case RS_SYS_TYPE_PPC2: + case RS_SYS_TYPE_PPC2a: + case RS_SYS_TYPE_PPC2ep: + case RS_SYS_TYPE_PPC4: + case RS_SYS_TYPE_PPC4a: + default: + { + ucElcrS=ELCRS_INT9_LVL | + ELCRS_INT10_LVL | + ELCRS_INT11_LVL | + ELCRS_INT14_LVL | + ELCRS_INT15_LVL; + ucElcrM=ELCRM_INT5_LVL | + ELCRM_INT7_LVL; + break; + } + } + + /* + * Write edge/level selection + */ + outb(ucElcrS, ISA8259_S_ELCR); + outb(ucElcrM, ISA8259_M_ELCR); + + /* + * Radstone boards have PCI interrupts all set up + * so leave well alone + */ + return 0; } else { printk("No known machine pci routing!\n"); @@ -540,5 +970,119 @@ /* Enable PCI interrupts */ *ibc_pcicon |= 0x20; return 0; +} + +__initfunc( +void +prep_pcibios_fixup(void)) +{ + struct pci_dev *dev; + extern unsigned char *Motherboard_map; + extern unsigned char *Motherboard_routes; + unsigned char i; + + if ( _prep_type == _PREP_Radstone ) + { + printk("Radstone boards require no PCI fixups\n"); + return; + } + + prep_route_pci_interrupts(); + + printk("Setting PCI interrupts for a \"%s\"\n", Motherboard_map_name); + if (OpenPIC) { + /* PCI interrupts are controlled by the OpenPIC */ + for(dev=pci_devices; dev; dev=dev->next) { + if (dev->bus->number == 0) { + dev->irq = openpic_to_irq(Motherboard_map[PCI_SLOT(dev->devfn)]); + pcibios_write_config_byte(dev->bus->number, dev->devfn, PCI_INTERRUPT_PIN, dev->irq); + } + } + return; + } + + for(dev=pci_devices; dev; dev=dev->next) + { + /* + * Use our old hard-coded kludge to figure out what + * irq this device uses. This is necessary on things + * without residual data. -- Cort + */ + unsigned char d = PCI_SLOT(dev->devfn); + dev->irq = Motherboard_routes[Motherboard_map[d]]; + + for ( i = 0 ; i <= 5 ; i++ ) + { + if ( dev->base_address[i] > 0x10000000 ) + { + printk("Relocating PCI address %lx -> %lx\n", + dev->base_address[i], + (dev->base_address[i] & 0x00FFFFFF) + | 0x01000000); + dev->base_address[i] = + (dev->base_address[i] & 0x00FFFFFF) | 0x01000000; + pci_write_config_dword(dev, + PCI_BASE_ADDRESS_0+(i*0x4), + dev->base_address[i] ); + } + } +#if 0 + /* + * If we have residual data and if it knows about this + * device ask it what the irq is. + * -- Cort + */ + ppcd = residual_find_device_id( ~0L, dev->device, + -1,-1,-1, 0); +#endif + } +} + +decl_config_access_method(indirect); + +__initfunc( +void +prep_setup_pci_ptrs(void)) +{ + PPC_DEVICE *hostbridge; + + printk("PReP architecture\n"); + if ( _prep_type == _PREP_Radstone ) + { + pci_config_address = (unsigned *)0x80000cf8; + pci_config_data = (char *)0x80000cfc; + set_config_access_method(indirect); + } + else + { + hostbridge = residual_find_device(PROCESSORDEVICE, NULL, + BridgeController, PCIBridge, -1, 0); + if (hostbridge && + hostbridge->DeviceId.Interface == PCIBridgeIndirect) { + PnP_TAG_PACKET * pkt; + set_config_access_method(indirect); + pkt = PnP_find_large_vendor_packet( + res->DevicePnPHeap+hostbridge->AllocatedOffset, + 3, 0); + if(pkt) + { +#define p pkt->L4_Pack.L4_Data.L4_PPCPack + pci_config_address= (unsigned *)ld_le32((unsigned *) p.PPCData); + pci_config_data= (unsigned char *)ld_le32((unsigned *) (p.PPCData+8)); + } + else + { + pci_config_address= (unsigned *) 0x80000cf8; + pci_config_data= (unsigned char *) 0x80000cfc; + } + } + else + { + set_config_access_method(prep); + } + + } + + ppc_md.pcibios_fixup = prep_pcibios_fixup; } diff -ur --new-file old/linux/arch/ppc/kernel/prep_setup.c new/linux/arch/ppc/kernel/prep_setup.c --- old/linux/arch/ppc/kernel/prep_setup.c Mon Dec 21 17:37:20 1998 +++ new/linux/arch/ppc/kernel/prep_setup.c Tue May 11 17:24:32 1999 @@ -30,6 +30,9 @@ #include #include #include +#include +#include +#include #include #include @@ -38,12 +41,57 @@ #include #include #include +#include +#include +#include +#include +#include + + +#include "time.h" +#include "local_irq.h" +#include "i8259.h" +#include "open_pic.h" #if defined(CONFIG_SOUND) || defined(CONFIG_SOUND_MODULE) #include <../drivers/sound/sound_config.h> #include <../drivers/sound/dev_table.h> #endif +unsigned char ucSystemType; +unsigned char ucBoardRev; +unsigned char ucBoardRevMaj, ucBoardRevMin; + +extern unsigned long mc146818_get_rtc_time(void); +extern int mc146818_set_rtc_time(unsigned long nowtime); +extern unsigned long mk48t59_get_rtc_time(void); +extern int mk48t59_set_rtc_time(unsigned long nowtime); + +extern unsigned char prep_nvram_read_val(int addr); +extern void prep_nvram_write_val(int addr, + unsigned char val); +extern unsigned char rs_nvram_read_val(int addr); +extern void rs_nvram_write_val(int addr, + unsigned char val); + +extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode); +extern int pckbd_getkeycode(unsigned int scancode); +extern int pckbd_translate(unsigned char scancode, unsigned char *keycode, + char raw_mode); +extern char pckbd_unexpected_up(unsigned char keycode); +extern void pckbd_leds(unsigned char leds); +extern void pckbd_init_hw(void); +extern unsigned char pckbd_sysrq_xlate[128]; + +extern void prep_setup_pci_ptrs(void); +extern void chrp_do_IRQ(struct pt_regs *regs, int cpu, int isfake); +extern char saved_command_line[256]; + +int _prep_type; + +#define cached_21 (((char *)(ppc_cached_irq_mask))[3]) +#define cached_A1 (((char *)(ppc_cached_irq_mask))[2]) + /* for the mac fs */ kdev_t boot_dev; /* used in nasty hack for sound - see prep_setup_arch() -- Cort */ @@ -54,13 +102,15 @@ extern unsigned long Hash_size, Hash_mask; extern int probingmem; extern unsigned long loops_per_sec; -extern unsigned char aux_device_present; #ifdef CONFIG_BLK_DEV_RAM extern int rd_doload; /* 1 = load ramdisk, 0 = don't load */ extern int rd_prompt; /* 1 = prompt for ramdisk, 0 = don't prompt */ extern int rd_image_start; /* starting block # of image */ #endif +#ifdef CONFIG_VGA_CONSOLE +unsigned long vgacon_remap_base; +#endif __prep int @@ -136,6 +186,8 @@ break; } break; + default: + break; } @@ -163,11 +215,12 @@ { extern char cmd_line[]; unsigned char reg; + unsigned char ucMothMemType; + unsigned char ucEquipPres1; /* init to some ~sane value until calibrate_delay() runs */ loops_per_sec = 50000000; - aux_device_present = 0xaa; /* Set up floppy in PS/2 mode */ outb(0x09, SIO_CONFIG_RA); reg = inb(SIO_CONFIG_RD); @@ -175,20 +228,78 @@ outb(reg, SIO_CONFIG_RD); outb(reg, SIO_CONFIG_RD); /* Have to write twice to change! */ + /* + * We need to set up the NvRAM access routines early as prep_init + * has yet to be called + */ + ppc_md.nvram_read_val = prep_nvram_read_val; + ppc_md.nvram_write_val = prep_nvram_write_val; + /* we should determine this according to what we find! -- Cort */ switch ( _prep_type ) { case _PREP_IBM: + /* Enable L2. Assume we don't need to flush -- Cort*/ + *(unsigned char *)(0x8000081c) |= 3; ROOT_DEV = to_kdev_t(0x0301); /* hda1 */ break; case _PREP_Motorola: + /* Enable L2. Assume we don't need to flush -- Cort*/ + *(unsigned char *)(0x8000081c) |= 3; ROOT_DEV = to_kdev_t(0x0801); /* sda1 */ break; + case _PREP_Radstone: + ROOT_DEV = to_kdev_t(0x0801); /* sda1 */ + + /* + * Determine system type + */ + ucMothMemType=inb(0x866); + ucEquipPres1=inb(0x80c); + + ucSystemType=((ucMothMemType&0x03)<<1) | + ((ucEquipPres1&0x80)>>7); + ucSystemType^=7; + + /* + * Determine board revision for use by + * rev. specific code + */ + ucBoardRev=inb(0x854); + ucBoardRevMaj=ucBoardRev>>5; + ucBoardRevMin=ucBoardRev&0x1f; + + /* + * Most Radstone boards have memory mapped NvRAM + */ + if((ucSystemType==RS_SYS_TYPE_PPC1) && (ucBoardRevMaj<5)) + { + ppc_md.nvram_read_val = prep_nvram_read_val; + ppc_md.nvram_write_val = prep_nvram_write_val; + } + else + { + ppc_md.nvram_read_val = rs_nvram_read_val; + ppc_md.nvram_write_val = rs_nvram_write_val; + } + break; } - /* Enable L2. Assume we don't need to flush -- Cort*/ - *(unsigned char *)(0x8000081c) = *(unsigned char *)(0x8000081c)|3; - + /* Read in NVRAM data */ + init_prep_nvram(); + + /* if no bootargs, look in NVRAM */ + if ( cmd_line[0] == '\0' ) { + char *bootargs; + bootargs = prep_nvram_get_var("bootargs"); + if (bootargs != NULL) { + strcpy(cmd_line, bootargs); + + /* again.. */ + strcpy(saved_command_line, cmd_line); + } + } + printk("Boot arguments: %s\n", cmd_line); #ifdef CONFIG_SOUND_CS4232 @@ -238,12 +349,349 @@ request_region(0x80,0x10,"dma page reg"); request_region(0xc0,0x20,"dma2"); + raven_init(); + #ifdef CONFIG_VGA_CONSOLE + /* remap the VGA memory */ + vgacon_remap_base = 0xf0000000; + /*vgacon_remap_base = ioremap(0xc0000000, 0xba000);*/ conswitchp = &vga_con; #endif } -__initfunc(void prep_ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq)) +/* + * Determine the decrementer frequency from the residual data + * This allows for a faster boot as we do not need to calibrate the + * decrementer against another clock. This is important for embedded systems. + */ +__initfunc(void prep_res_calibrate_decr(void)) +{ + int freq, divisor; + + freq = res->VitalProductData.ProcessorBusHz; + divisor = 4; + printk("time_init: decrementer frequency = %d/%d\n", freq, divisor); + decrementer_count = freq / HZ / divisor; + count_period_num = divisor; + count_period_den = freq / 1000000; +} + +/* + * Uses the on-board timer to calibrate the on-chip decrementer register + * for prep systems. On the pmac the OF tells us what the frequency is + * but on prep we have to figure it out. + * -- Cort + */ +int calibrate_done = 0; +volatile int *done_ptr = &calibrate_done; + +__initfunc(void +prep_calibrate_decr_handler(int irq, + void *dev, + struct pt_regs *regs)) +{ + unsigned long freq, divisor; + static unsigned long t1 = 0, t2 = 0; + + if ( !t1 ) + t1 = get_dec(); + else if (!t2) + { + t2 = get_dec(); + t2 = t1-t2; /* decr's in 1/HZ */ + t2 = t2*HZ; /* # decrs in 1s - thus in Hz */ + freq = t2 * 60; /* try to make freq/1e6 an integer */ + divisor = 60; + printk("time_init: decrementer frequency = %lu/%lu (%luMHz)\n", + freq, divisor,t2>>20); + decrementer_count = freq / HZ / divisor; + count_period_num = divisor; + count_period_den = freq / 1000000; + *done_ptr = 1; + } +} + +__initfunc(void prep_calibrate_decr(void)) +{ + unsigned long flags; + + + save_flags(flags); + +#define TIMER0_COUNT 0x40 +#define TIMER_CONTROL 0x43 + /* set timer to periodic mode */ + outb_p(0x34,TIMER_CONTROL);/* binary, mode 2, LSB/MSB, ch 0 */ + /* set the clock to ~100 Hz */ + outb_p(LATCH & 0xff , TIMER0_COUNT); /* LSB */ + outb(LATCH >> 8 , TIMER0_COUNT); /* MSB */ + + if (request_irq(0, prep_calibrate_decr_handler, 0, "timer", NULL) != 0) + panic("Could not allocate timer IRQ!"); + __sti(); + while ( ! *done_ptr ) /* nothing */; /* wait for calibrate */ + restore_flags(flags); + free_irq( 0, NULL); +} + + +/* We use the NVRAM RTC to time a second to calibrate the decrementer. */ +__initfunc(void mk48t59_calibrate_decr(void)) +{ + unsigned long freq, divisor; + unsigned long t1, t2; + unsigned char save_control; + long i; + unsigned char sec; + + + /* Make sure the time is not stopped. */ + save_control = ppc_md.nvram_read_val(MK48T59_RTC_CONTROLB); + + ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA, + (save_control & (~MK48T59_RTC_CB_STOP))); + + /* Now make sure the read bit is off so the value will change. */ + save_control = ppc_md.nvram_read_val(MK48T59_RTC_CONTROLA); + save_control &= ~MK48T59_RTC_CA_READ; + ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA, save_control); + + + /* Read the seconds value to see when it changes. */ + sec = ppc_md.nvram_read_val(MK48T59_RTC_SECONDS); + for (i = 0 ; i < 1000000 ; i++) { /* may take up to 1 second... */ + if (ppc_md.nvram_read_val(MK48T59_RTC_SECONDS) != sec) { + break; + } + } + t1 = get_dec(); + + sec = ppc_md.nvram_read_val(MK48T59_RTC_SECONDS); + for (i = 0 ; i < 1000000 ; i++) { /* Should take up 1 second... */ + if (ppc_md.nvram_read_val(MK48T59_RTC_SECONDS) != sec) { + break; + } + } + + t2 = t1 - get_dec(); + + freq = t2 * 60; /* try to make freq/1e6 an integer */ + divisor = 60; + printk("time_init: decrementer frequency = %lu/%lu (%luMHz)\n", + freq, divisor,t2>>20); + decrementer_count = freq / HZ / divisor; + count_period_num = divisor; + count_period_den = freq / 1000000; +} + +void +prep_restart(char *cmd) +{ + unsigned long i = 10000; + + + _disable_interrupts(); + + /* set exception prefix high - to the prom */ + _nmask_and_or_msr(0, MSR_IP); + + /* make sure bit 0 (reset) is a 0 */ + outb( inb(0x92) & ~1L , 0x92 ); + /* signal a reset to system control port A - soft reset */ + outb( inb(0x92) | 1 , 0x92 ); + + while ( i != 0 ) i++; + panic("restart failed\n"); +} + +/* + * This function will restart a board regardless of port 92 functionality + */ +void +prep_direct_restart(char *cmd) +{ + u32 jumpaddr=0xfff00100; + u32 defaultmsr=MSR_IP; + + /* + * This will ALWAYS work regardless of port 92 + * functionality + */ + _disable_interrupts(); + + __asm__ __volatile__("\n\ + mtspr 26, %1 /* SRR0 */ + mtspr 27, %0 /* SRR1 */ + rfi" + : + : "r" (defaultmsr), "r" (jumpaddr)); + /* + * Not reached + */ +} + +void +prep_halt(void) +{ + unsigned long flags; + _disable_interrupts(); + /* set exception prefix high - to the prom */ + save_flags( flags ); + restore_flags( flags|MSR_IP ); + + /* make sure bit 0 (reset) is a 0 */ + outb( inb(0x92) & ~1L , 0x92 ); + /* signal a reset to system control port A - soft reset */ + outb( inb(0x92) | 1 , 0x92 ); + + while ( 1 ) ; + /* + * Not reached + */ +} + +void +prep_power_off(void) +{ + prep_halt(); +} + +int prep_setup_residual(char *buffer) +{ + int len = 0; + + + /* PREP's without residual data will give incorrect values here */ + len += sprintf(len+buffer, "clock\t\t: "); + if ( res->ResidualLength ) + len += sprintf(len+buffer, "%ldMHz\n", + (res->VitalProductData.ProcessorHz > 1024) ? + res->VitalProductData.ProcessorHz>>20 : + res->VitalProductData.ProcessorHz); + else + len += sprintf(len+buffer, "???\n"); + + return len; +} + +u_int +prep_irq_cannonicalize(u_int irq) +{ + if (irq == 2) + { + return 9; + } + else + { + return irq; + } +} + +void +prep_do_IRQ(struct pt_regs *regs, int cpu, int isfake) +{ + int irq; + + if ( (irq = i8259_irq(0)) < 0 ) + { + printk(KERN_DEBUG "Bogus interrupt from PC = %lx\n", + regs->nip); + ppc_spurious_interrupts++; + return; + } + ppc_irq_dispatch_handler( regs, irq ); +} + +__initfunc(void +prep_init_IRQ(void)) +{ + int i; + + if (OpenPIC != NULL) { + for ( i = 16 ; i < 36 ; i++ ) + irq_desc[i].ctl = &open_pic; + openpic_init(1); + } + + for ( i = 0 ; i < 16 ; i++ ) + irq_desc[i].ctl = &i8259_pic; + i8259_init(); +#ifdef __SMP__ + request_irq(openpic_to_irq(OPENPIC_VEC_SPURIOUS), openpic_ipi_action, + 0, "IPI0", 0); +#endif /* __SMP__ */ +} + +#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) +/* + * IDE stuff. + */ +void +prep_ide_insw(ide_ioreg_t port, void *buf, int ns) +{ + _insw((unsigned short *)((port)+_IO_BASE), buf, ns); +} + +void +prep_ide_outsw(ide_ioreg_t port, void *buf, int ns) +{ + _outsw((unsigned short *)((port)+_IO_BASE), buf, ns); +} + +int +prep_ide_default_irq(ide_ioreg_t base) +{ + switch (base) { + case 0x1f0: return 13; + case 0x170: return 13; + case 0x1e8: return 11; + case 0x168: return 10; + default: + return 0; + } +} + +ide_ioreg_t +prep_ide_default_io_base(int index) +{ + switch (index) { + case 0: return 0x1f0; + case 1: return 0x170; + case 2: return 0x1e8; + case 3: return 0x168; + default: + return 0; + } +} + +int +prep_ide_check_region(ide_ioreg_t from, unsigned int extent) +{ + return check_region(from, extent); +} + +void +prep_ide_request_region(ide_ioreg_t from, + unsigned int extent, + const char *name) +{ + request_region(from, extent, name); +} + +void +prep_ide_release_region(ide_ioreg_t from, + unsigned int extent) +{ + release_region(from, extent); +} + +void +prep_ide_fix_driveid(struct hd_driveid *id) +{ +} + +__initfunc(void +prep_ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq)) { ide_ioreg_t port = base; int i = 8; @@ -253,6 +701,143 @@ *p++ = base + 0x206; if (irq != NULL) *irq = 0; +} +#endif + +__initfunc(void +prep_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7)) +{ + /* make a copy of residual data */ + if ( r3 ) + { + memcpy((void *)res,(void *)(r3+KERNELBASE), + sizeof(RESIDUAL)); + } + + isa_io_base = PREP_ISA_IO_BASE; + isa_mem_base = PREP_ISA_MEM_BASE; + pci_dram_offset = PREP_PCI_DRAM_OFFSET; + ISA_DMA_THRESHOLD = 0x00ffffff; + DMA_MODE_READ = 0x44; + DMA_MODE_WRITE = 0x48; + + /* figure out what kind of prep workstation we are */ + if ( res->ResidualLength != 0 ) + { + if ( !strncmp(res->VitalProductData.PrintableModel,"IBM",3) ) + _prep_type = _PREP_IBM; + else if (!strncmp(res->VitalProductData.PrintableModel, + "Radstone",8)) + { + extern char *Motherboard_map_name; + + _prep_type = _PREP_Radstone; + Motherboard_map_name= + res->VitalProductData.PrintableModel; + } + else + _prep_type = _PREP_Motorola; + } + else /* assume motorola if no residual (netboot?) */ + { + _prep_type = _PREP_Motorola; + } + + prep_setup_pci_ptrs(); + +#ifdef CONFIG_BLK_DEV_INITRD + /* take care of initrd if we have one */ + if ( r4 ) + { + initrd_start = r4 + KERNELBASE; + initrd_end = r5 + KERNELBASE; + } +#endif /* CONFIG_BLK_DEV_INITRD */ + + /* take care of cmd line */ + if ( r6 && (((char *) r6) != '\0')) + { + *(char *)(r7+KERNELBASE) = 0; + strcpy(cmd_line, (char *)(r6+KERNELBASE)); + } + + ppc_md.setup_arch = prep_setup_arch; + ppc_md.setup_residual = prep_setup_residual; + ppc_md.get_cpuinfo = prep_get_cpuinfo; + ppc_md.irq_cannonicalize = prep_irq_cannonicalize; + ppc_md.init_IRQ = prep_init_IRQ; + if ( !OpenPIC ) + ppc_md.do_IRQ = prep_do_IRQ; + else + ppc_md.do_IRQ = chrp_do_IRQ; + ppc_md.init = NULL; + + ppc_md.restart = prep_restart; + ppc_md.power_off = prep_power_off; + ppc_md.halt = prep_halt; + + ppc_md.time_init = NULL; + if (_prep_type == _PREP_Radstone) { + /* + * We require a direct restart as port 92 does not work on + * all Radstone boards + */ + ppc_md.restart = prep_direct_restart; + /* + * The RTC device used varies according to board type + */ + if(((ucSystemType==RS_SYS_TYPE_PPC1) && (ucBoardRevMaj>=5)) || + (ucSystemType==RS_SYS_TYPE_PPC1a)) + { + ppc_md.set_rtc_time = mk48t59_set_rtc_time; + ppc_md.get_rtc_time = mk48t59_get_rtc_time; + } + else + { + ppc_md.set_rtc_time = mc146818_set_rtc_time; + ppc_md.get_rtc_time = mc146818_get_rtc_time; + } + /* + * Determine the decrementer rate from the residual data + */ + ppc_md.calibrate_decr = prep_res_calibrate_decr; + } + else if (_prep_type == _PREP_IBM) { + ppc_md.set_rtc_time = mc146818_set_rtc_time; + ppc_md.get_rtc_time = mc146818_get_rtc_time; + ppc_md.calibrate_decr = prep_calibrate_decr; + } + else { + ppc_md.set_rtc_time = mk48t59_set_rtc_time; + ppc_md.get_rtc_time = mk48t59_get_rtc_time; + ppc_md.calibrate_decr = mk48t59_calibrate_decr; + } + +#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) + ppc_ide_md.insw = prep_ide_insw; + ppc_ide_md.outsw = prep_ide_outsw; + ppc_ide_md.default_irq = prep_ide_default_irq; + ppc_ide_md.default_io_base = prep_ide_default_io_base; + ppc_ide_md.check_region = prep_ide_check_region; + ppc_ide_md.request_region = prep_ide_request_region; + ppc_ide_md.release_region = prep_ide_release_region; + ppc_ide_md.fix_driveid = prep_ide_fix_driveid; + ppc_ide_md.ide_init_hwif = prep_ide_init_hwif_ports; +#endif + ppc_ide_md.io_base = _IO_BASE; + +#ifdef CONFIG_VT + ppc_md.kbd_setkeycode = pckbd_setkeycode; + ppc_md.kbd_getkeycode = pckbd_getkeycode; + ppc_md.kbd_translate = pckbd_translate; + ppc_md.kbd_unexpected_up = pckbd_unexpected_up; + ppc_md.kbd_leds = pckbd_leds; + ppc_md.kbd_init_hw = pckbd_init_hw; +#ifdef CONFIG_MAGIC_SYSRQ + ppc_md.kbd_sysrq_xlate = pckbd_sysrq_xlate; +#endif +#endif } #ifdef CONFIG_SOUND_MODULE diff -ur --new-file old/linux/arch/ppc/kernel/prep_time.c new/linux/arch/ppc/kernel/prep_time.c --- old/linux/arch/ppc/kernel/prep_time.c Wed Aug 5 01:06:36 1998 +++ new/linux/arch/ppc/kernel/prep_time.c Thu Apr 29 21:39:01 1999 @@ -22,7 +22,9 @@ #include #include #include -#include +#include +#include +#include #include "time.h" @@ -41,73 +43,29 @@ * is setup at boot time to use the correct addresses. * -- Cort */ -/* - * translate from mc146818 to m48t18 addresses - */ -unsigned int clock_transl[] __prepdata = { MOTO_RTC_SECONDS,0 /* alarm */, - MOTO_RTC_MINUTES,0 /* alarm */, - MOTO_RTC_HOURS,0 /* alarm */, /* 4,5 */ - MOTO_RTC_DAY_OF_WEEK, - MOTO_RTC_DAY_OF_MONTH, - MOTO_RTC_MONTH, - MOTO_RTC_YEAR, /* 9 */ - MOTO_RTC_CONTROLA, MOTO_RTC_CONTROLB /* 10,11 */ -}; - -__prep -int prep_cmos_clock_read(int addr) -{ - if ( _prep_type == _PREP_IBM ) - return CMOS_READ(addr); - else if ( _prep_type == _PREP_Motorola ) - { - outb(clock_transl[addr]>>8, NVRAM_AS1); - outb(clock_transl[addr], NVRAM_AS0); - return (inb(NVRAM_DATA)); - } - - printk("Unknown machine in prep_cmos_clock_read()!\n"); - return -1; -} - -__prep -void prep_cmos_clock_write(unsigned long val, int addr) -{ - if ( _prep_type == _PREP_IBM ) - { - CMOS_WRITE(val,addr); - return; - } - else if ( _prep_type == _PREP_Motorola ) - { - outb(clock_transl[addr]>>8, NVRAM_AS1); - outb(clock_transl[addr], NVRAM_AS0); - outb(val,NVRAM_DATA); - return; - } - printk("Unknown machine in prep_cmos_clock_write()!\n"); -} /* * Set the hardware clock. -- Cort */ __prep -int prep_set_rtc_time(unsigned long nowtime) +int mc146818_set_rtc_time(unsigned long nowtime) { unsigned char save_control, save_freq_select; struct rtc_time tm; to_tm(nowtime, &tm); - save_control = prep_cmos_clock_read(RTC_CONTROL); /* tell the clock it's being set */ - - prep_cmos_clock_write((save_control|RTC_SET), RTC_CONTROL); - - save_freq_select = prep_cmos_clock_read(RTC_FREQ_SELECT); /* stop and reset prescaler */ + /* tell the clock it's being set */ + save_control = CMOS_READ(RTC_CONTROL); - prep_cmos_clock_write((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); - - tm.tm_year -= 1900; + CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); + + /* stop and reset prescaler */ + save_freq_select = CMOS_READ(RTC_FREQ_SELECT); + + CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); + + tm.tm_year = (tm.tm_year - 1900) % 100; if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { BIN_TO_BCD(tm.tm_sec); BIN_TO_BCD(tm.tm_min); @@ -116,12 +74,12 @@ BIN_TO_BCD(tm.tm_mday); BIN_TO_BCD(tm.tm_year); } - prep_cmos_clock_write(tm.tm_sec,RTC_SECONDS); - prep_cmos_clock_write(tm.tm_min,RTC_MINUTES); - prep_cmos_clock_write(tm.tm_hour,RTC_HOURS); - prep_cmos_clock_write(tm.tm_mon,RTC_MONTH); - prep_cmos_clock_write(tm.tm_mday,RTC_DAY_OF_MONTH); - prep_cmos_clock_write(tm.tm_year,RTC_YEAR); + CMOS_WRITE(tm.tm_sec, RTC_SECONDS); + CMOS_WRITE(tm.tm_min, RTC_MINUTES); + CMOS_WRITE(tm.tm_hour, RTC_HOURS); + CMOS_WRITE(tm.tm_mon, RTC_MONTH); + CMOS_WRITE(tm.tm_mday, RTC_DAY_OF_MONTH); + CMOS_WRITE(tm.tm_year, RTC_YEAR); /* The following flags have to be released exactly in this order, * otherwise the DS12887 (popular MC146818A clone with integrated @@ -130,16 +88,14 @@ * the Dallas Semiconductor data sheets, but who believes data * sheets anyway ... -- Markus Kuhn */ - prep_cmos_clock_write(save_control, RTC_CONTROL); - prep_cmos_clock_write(save_freq_select, RTC_FREQ_SELECT); + CMOS_WRITE(save_control, RTC_CONTROL); + CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); - if ( (time_state == TIME_ERROR) || (time_state == TIME_BAD) ) - time_state = TIME_OK; return 0; } __prep -unsigned long prep_get_rtc_time(void) +unsigned long mc146818_get_rtc_time(void) { unsigned int year, mon, day, hour, min, sec; int i; @@ -151,29 +107,123 @@ */ /* read RTC exactly on falling edge of update flag */ for (i = 0 ; i < 1000000 ; i++) /* may take up to 1 second... */ - if (prep_cmos_clock_read(RTC_FREQ_SELECT) & RTC_UIP) + if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP) break; for (i = 0 ; i < 1000000 ; i++) /* must try at least 2.228 ms */ - if (!(prep_cmos_clock_read(RTC_FREQ_SELECT) & RTC_UIP)) + if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)) break; do { /* Isn't this overkill ? UIP above should guarantee consistency */ - sec = prep_cmos_clock_read(RTC_SECONDS); - min = prep_cmos_clock_read(RTC_MINUTES); - hour = prep_cmos_clock_read(RTC_HOURS); - day = prep_cmos_clock_read(RTC_DAY_OF_MONTH); - mon = prep_cmos_clock_read(RTC_MONTH); - year = prep_cmos_clock_read(RTC_YEAR); - } while (sec != prep_cmos_clock_read(RTC_SECONDS)); - if (!(prep_cmos_clock_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); - } + 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); + } if ((year += 1900) < 1970) year += 100; + return mktime(year, mon, day, hour, min, sec); +} + +__prep +int mk48t59_set_rtc_time(unsigned long nowtime) +{ + unsigned char save_control; + struct rtc_time tm; + + + to_tm(nowtime, &tm); + + /* tell the clock it's being written */ + save_control = ppc_md.nvram_read_val(MK48T59_RTC_CONTROLA); + + ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA, + (save_control | MK48T59_RTC_CA_WRITE)); + + tm.tm_year = (tm.tm_year - 1900) % 100; + BIN_TO_BCD(tm.tm_sec); + BIN_TO_BCD(tm.tm_min); + BIN_TO_BCD(tm.tm_hour); + BIN_TO_BCD(tm.tm_mon); + BIN_TO_BCD(tm.tm_mday); + BIN_TO_BCD(tm.tm_year); + + ppc_md.nvram_write_val(MK48T59_RTC_SECONDS, tm.tm_sec); + ppc_md.nvram_write_val(MK48T59_RTC_MINUTES, tm.tm_min); + ppc_md.nvram_write_val(MK48T59_RTC_HOURS, tm.tm_hour); + ppc_md.nvram_write_val(MK48T59_RTC_MONTH, tm.tm_mon); + ppc_md.nvram_write_val(MK48T59_RTC_DAY_OF_MONTH, tm.tm_mday); + ppc_md.nvram_write_val(MK48T59_RTC_YEAR, tm.tm_year); + + /* Turn off the write bit. */ + ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA, save_control); + + return 0; +} + +__prep +unsigned long mk48t59_get_rtc_time(void) +{ + unsigned char save_control; + unsigned int year, mon, day, hour, min, sec; + int i; + + /* Make sure the time is not stopped. */ + save_control = ppc_md.nvram_read_val(MK48T59_RTC_CONTROLB); + + ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA, + (save_control & (~MK48T59_RTC_CB_STOP))); + + /* Now make sure the read bit is off so the value will change. */ + save_control = ppc_md.nvram_read_val(MK48T59_RTC_CONTROLA); + save_control &= ~MK48T59_RTC_CA_READ; + ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA, save_control); + + /* Read the seconds value to see when it changes. */ + sec = ppc_md.nvram_read_val(MK48T59_RTC_SECONDS); + + /* Wait until the seconds value changes, then read the value. */ + for (i = 0 ; i < 1000000 ; i++) { /* may take up to 1 second... */ + if (ppc_md.nvram_read_val(MK48T59_RTC_SECONDS) != sec) { + break; + } + } + + /* Set the register to read the value. */ + ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA, + (save_control | MK48T59_RTC_CA_READ)); + + sec = ppc_md.nvram_read_val(MK48T59_RTC_SECONDS); + min = ppc_md.nvram_read_val(MK48T59_RTC_MINUTES); + hour = ppc_md.nvram_read_val(MK48T59_RTC_HOURS); + day = ppc_md.nvram_read_val(MK48T59_RTC_DAY_OF_MONTH); + mon = ppc_md.nvram_read_val(MK48T59_RTC_MONTH); + year = ppc_md.nvram_read_val(MK48T59_RTC_YEAR); + + /* Let the time values change again. */ + ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA, save_control); + + BCD_TO_BIN(sec); + BCD_TO_BIN(min); + BCD_TO_BIN(hour); + BCD_TO_BIN(day); + BCD_TO_BIN(mon); + BCD_TO_BIN(year); + + year = year + 1900; + if (year < 1970) { + year += 100; + } + return mktime(year, mon, day, hour, min, sec); } diff -ur --new-file old/linux/arch/ppc/kernel/process.c new/linux/arch/ppc/kernel/process.c --- old/linux/arch/ppc/kernel/process.c Thu Jan 7 21:06:57 1999 +++ new/linux/arch/ppc/kernel/process.c Tue May 11 17:24:32 1999 @@ -1,5 +1,5 @@ /* - * $Id: process.c,v 1.70 1999/01/07 16:28:59 cort Exp $ + * $Id: process.c,v 1.83 1999/05/10 04:43:43 cort Exp $ * * linux/arch/ppc/kernel/process.c * @@ -43,12 +43,18 @@ #include int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs); -void switch_to(struct task_struct *, struct task_struct *); - extern unsigned long _get_SP(void); -extern spinlock_t scheduler_lock; struct task_struct *last_task_used_math = NULL; +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; +union task_union init_task_union = { INIT_TASK }; +/* only used to get secondary processor up */ +struct task_struct *current_set[NR_CPUS] = {&init_task, }; #undef SHOW_TASK_SWITCHES 1 #undef CHECK_STACK 1 @@ -65,32 +71,28 @@ return ((unsigned long)tsk) + sizeof(struct task_struct); } -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; -union task_union init_task_union = { INIT_TASK }; - -/* only used to get secondary processor up */ -struct task_struct *current_set[NR_CPUS] = {&init_task, }; - int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs) { -#ifdef __SMP__ - if ( regs->msr & MSR_FP ) - smp_giveup_fpu(current); -#else - if (last_task_used_math == current) - giveup_fpu(); -#endif + if (regs->msr & MSR_FP) + giveup_fpu(current); memcpy(fpregs, ¤t->tss.fpr[0], sizeof(*fpregs)); return 1; } +void +enable_kernel_fp(void) +{ +#ifdef __SMP__ + if (current->tss.regs && (current->tss.regs->msr & MSR_FP)) + giveup_fpu(current); + else + giveup_fpu(NULL); /* just enables FP for kernel */ +#else + giveup_fpu(last_task_used_math); +#endif /* __SMP__ */ +} + /* check to make sure the kernel stack is healthy */ int check_stack(struct task_struct *tsk) { @@ -155,7 +157,8 @@ } void -switch_to(struct task_struct *prev, struct task_struct *new) +_switch_to(struct task_struct *prev, struct task_struct *new, + struct task_struct **last) { struct thread_struct *new_tss, *old_tss; int s = _disable_interrupts(); @@ -165,10 +168,10 @@ #endif #ifdef SHOW_TASK_SWITCHES - printk("%s/%d -> %s/%d NIP %08lx cpu %d lock %x root %x/%x\n", + printk("%s/%d -> %s/%d NIP %08lx cpu %d root %x/%x\n", prev->comm,prev->pid, new->comm,new->pid,new->tss.regs->nip,new->processor, - scheduler_lock.lock,new->fs->root,prev->fs->root); + new->fs->root,prev->fs->root); #endif #ifdef __SMP__ /* avoid complexity of lazy save/restore of fpu @@ -176,18 +179,19 @@ * this task used the fpu during the last quantum. * * If it tries to use the fpu again, it'll trap and - * reload its fp regs. + * reload its fp regs. So we don't have to do a restore + * every switch, just a save. * -- Cort */ - if ( prev->tss.regs->msr & MSR_FP ) - smp_giveup_fpu(prev); + if (prev->tss.regs && (prev->tss.regs->msr & MSR_FP)) + giveup_fpu(prev); prev->last_processor = prev->processor; current_set[smp_processor_id()] = new; #endif /* __SMP__ */ new_tss = &new->tss; old_tss = ¤t->tss; - _switch(old_tss, new_tss, new->mm->context); + *last = _switch(old_tss, new_tss, new->mm->context); _enable_interrupts(s); } @@ -240,7 +244,12 @@ printk("Instruction DUMP:"); for(i = -3; i < 6; i++) - printk("%c%08lx%c",i?' ':'<',pc[i],i?' ':'>'); + { + unsigned long p; + if (__get_user( p, &pc[i] )) + break; + printk("%c%08lx%c",i?' ':'<',p,i?' ':'>'); + } printk("\n"); } @@ -268,8 +277,12 @@ copy_thread(int nr, unsigned long clone_flags, unsigned long usp, struct task_struct * p, struct pt_regs * regs) { - struct pt_regs * childregs; - + struct pt_regs * childregs, *kregs; +#ifdef __SMP__ + extern void ret_from_smpfork(void); +#else + extern void ret_from_syscall(void); +#endif /* Copy registers */ childregs = ((struct pt_regs *) ((unsigned long)p + sizeof(union task_union) @@ -278,8 +291,19 @@ if ((childregs->msr & MSR_PR) == 0) childregs->gpr[2] = (unsigned long) p; /* `current' in new task */ childregs->gpr[3] = 0; /* Result from fork() */ + p->tss.regs = childregs; p->tss.ksp = (unsigned long) childregs - STACK_FRAME_OVERHEAD; - p->tss.regs = childregs; + p->tss.ksp -= sizeof(struct pt_regs ) + STACK_FRAME_OVERHEAD; + kregs = (struct pt_regs *)(p->tss.ksp + STACK_FRAME_OVERHEAD); +#ifdef __SMP__ + kregs->nip = (unsigned long)ret_from_smpfork; +#else + kregs->nip = (unsigned long)ret_from_syscall; +#endif + kregs->msr = MSR_KERNEL; + kregs->gpr[1] = (unsigned long)childregs - STACK_FRAME_OVERHEAD; + kregs->gpr[2] = (unsigned long)p; + if (usp >= (unsigned long) regs) { /* Stack is in kernel space - must adjust */ childregs->gpr[1] = (unsigned long)(childregs + 1); @@ -293,21 +317,14 @@ * copy fpu info - assume lazy fpu switch now always * -- Cort */ -#ifdef __SMP__ - if ( regs->msr & MSR_FP ) - smp_giveup_fpu(current); -#else - if ( last_task_used_math == current ) - giveup_fpu(); -#endif + if (regs->msr & MSR_FP) + giveup_fpu(current); memcpy(&p->tss.fpr, ¤t->tss.fpr, sizeof(p->tss.fpr)); p->tss.fpscr = current->tss.fpscr; childregs->msr &= ~MSR_FP; #ifdef __SMP__ - if ( (p->pid != 0) || !(clone_flags & CLONE_PID) ) - p->tss.smp_fork_ret = 1; p->last_processor = NO_PROC_ID; #endif /* __SMP__ */ return 0; @@ -374,11 +391,6 @@ int res; lock_kernel(); res = do_fork(clone_flags, regs->gpr[1], regs); - /* - * only parent returns here, child returns to either - * syscall_ret_1() or kernel_thread() - * -- Cort - */ #ifdef __SMP__ /* When we clone the idle task we keep the same pid but * the return value of 0 for both causes problems. @@ -397,9 +409,7 @@ int res; - lock_kernel(); res = do_fork(SIGCHLD, regs->gpr[1], regs); - /* only parent returns here */ #ifdef __SMP__ /* When we clone the idle task we keep the same pid but * the return value of 0 for both causes problems. @@ -408,10 +418,15 @@ if ((current->pid == 0) && (current == &init_task)) res = 1; #endif /* __SMP__ */ - unlock_kernel(); return res; } +asmlinkage int sys_vfork(int p1, int p2, int p3, int p4, int p5, int p6, + struct pt_regs *regs) +{ + return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->gpr[1], regs); +} + asmlinkage int sys_execve(unsigned long a0, unsigned long a1, unsigned long a2, unsigned long a3, unsigned long a4, unsigned long a5, struct pt_regs *regs) @@ -423,13 +438,8 @@ error = PTR_ERR(filename); if (IS_ERR(filename)) goto out; -#ifdef __SMP__ - if ( regs->msr & MSR_FP ) - smp_giveup_fpu(current); -#else - if ( last_task_used_math == current ) - giveup_fpu(); -#endif + if (regs->msr & MSR_FP) + giveup_fpu(current); error = do_execve(filename, (char **) a1, (char **) a2, regs); putname(filename); out: diff -ur --new-file old/linux/arch/ppc/kernel/prom.c new/linux/arch/ppc/kernel/prom.c --- old/linux/arch/ppc/kernel/prom.c Sun Nov 15 19:51:44 1998 +++ new/linux/arch/ppc/kernel/prom.c Tue May 11 17:24:32 1999 @@ -1,5 +1,5 @@ /* - * $Id: prom.c,v 1.46 1998/11/11 03:55:09 paulus Exp $ + * $Id: prom.c,v 1.54 1999/05/10 04:43:46 cort Exp $ * * Procedures for interfacing to the Open Firmware PROM on * Power Macintosh computers. @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -99,10 +100,12 @@ static struct device_node *allnodes = 0; static void clearscreen(void); +static void flushscreen(void); #ifdef CONFIG_BOOTX_TEXT static void drawchar(char c); +static void drawhex(unsigned long v); static void drawstring(const char *c); static void scrollscreen(void); @@ -167,6 +170,11 @@ #define ALIGN(x) (((x) + sizeof(unsigned long)-1) & -sizeof(unsigned long)) +/* Is boot-info compatible ? */ +#define BOOT_INFO_IS_COMPATIBLE(bi) ((bi)->compatible_version <= BOOT_INFO_VERSION) +#define BOOT_INFO_IS_V2_COMPATIBLE(bi) ((bi)->version >= 2) +#define BOOT_INFO_IS_V4_COMPATIBLE(bi) ((bi)->version >= 4) + __init static void prom_exit() @@ -256,6 +264,11 @@ void prom_init(int r3, int r4, prom_entry pp) { +#ifdef CONFIG_SMP + int cpu = 0, i; + phandle node; + char type[16], *path; +#endif unsigned long mem; ihandle prom_rtas; unsigned long offset = reloc_offset(); @@ -273,6 +286,9 @@ unsigned long space; unsigned long ptr, x; char *model; +#ifdef CONFIG_BOOTX_TEXT + unsigned long flags; +#endif RELOC(boot_infos) = PTRUNRELOC(bi); @@ -283,32 +299,72 @@ RELOC(g_loc_Y) = 0; RELOC(g_max_loc_X) = (bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) / 8; RELOC(g_max_loc_Y) = (bi->dispDeviceRect[3] - bi->dispDeviceRect[1]) / 16; - prom_print(RELOC("Welcome to Linux, kernel " UTS_RELEASE " booting...\n")); + + /* Test if boot-info is compatible. Done only in config CONFIG_BOOTX_TEXT since + there is nothing much we can do with an incompatible version, except display + a message and eventually hang the processor... + + I'll try to keep enough of boot-info compatible in the future to always allow + display of this message; + */ + if (!BOOT_INFO_IS_COMPATIBLE(bi)) + prom_print(RELOC(" !!! WARNING - Incompatible version of BootX !!!\n\n\n")); + + prom_print(RELOC("Welcome to Linux, kernel " UTS_RELEASE "\n")); + prom_print(RELOC("\nstarted at : 0x")); + drawhex(reloc_offset() + KERNELBASE); + prom_print(RELOC("\nlinked at : 0x")); + drawhex(KERNELBASE); + prom_print(RELOC("\nframe buffer at : 0x")); + drawhex((unsigned long)bi->dispDeviceBase); + prom_print(RELOC(" (phys), 0x")); + drawhex((unsigned long)bi->logicalDisplayBase); + prom_print(RELOC(" (log)")); + prom_print(RELOC("\nMSR : 0x")); + __asm__ __volatile__ ("mfmsr %0" : "=r" ((flags)) : : "memory"); + drawhex(flags); + prom_print(RELOC("\n\n")); #endif - - /* - * XXX If this is an iMac, turn off the USB controller. + /* Out of the #if/#endif since it flushes the clearscreen too */ + flushscreen(); + + /* New BootX enters kernel with MMU off, i/os are not allowed + here. This hack will have been done by the boostrap anyway. */ - model = (char *) early_get_property - (r4 + bi->deviceTreeOffset, 4, RELOC("model")); - if (model && strcmp(model, RELOC("iMac,1")) == 0) { - out_le32((unsigned *)0x80880008, 1); /* XXX */ + if (bi->version < 4) { + /* + * XXX If this is an iMac, turn off the USB controller. + */ + model = (char *) early_get_property + (r4 + bi->deviceTreeOffset, 4, RELOC("model")); + if (model && strcmp(model, RELOC("iMac,1")) == 0) { + out_le32((unsigned *)0x80880008, 1); /* XXX */ + } } - + space = bi->deviceTreeOffset + bi->deviceTreeSize; if (bi->ramDisk) space = bi->ramDisk + bi->ramDiskSize; RELOC(klimit) = PTRUNRELOC((char *) bi + space); - /* - * Touch each page to make sure the PTEs for them - * are in the hash table - the aim is to try to avoid - * getting DSI exceptions while copying the kernel image. + /* New BootX will have flushed all TLBs and enters kernel with + MMU switched OFF, so this should not be useful anymore. */ - for (ptr = (KERNELBASE + offset) & PAGE_MASK; - ptr < (unsigned long)bi + space; ptr += PAGE_SIZE) - x = *(volatile unsigned long *)ptr; - + if (bi->version < 4) { + /* + * Touch each page to make sure the PTEs for them + * are in the hash table - the aim is to try to avoid + * getting DSI exceptions while copying the kernel image. + */ + for (ptr = (KERNELBASE + offset) & PAGE_MASK; + ptr < (unsigned long)bi + space; ptr += PAGE_SIZE) + x = *(volatile unsigned long *)ptr; + } + +#ifdef CONFIG_BOOTX_TEXT + prom_print(RELOC("booting...\n")); + flushscreen(); +#endif return; } @@ -379,7 +435,7 @@ prom_args.nret = 2; prom_args.args[0] = RELOC("instantiate-rtas"); prom_args.args[1] = prom_rtas; - prom_args.args[2] = ((void *)RELOC(rtas_data)-KERNELBASE-offset); + prom_args.args[2] = ((void *)(RELOC(rtas_data)-KERNELBASE)); RELOC(prom)(&prom_args); if (prom_args.args[nargs] != 0) i = 0; @@ -393,6 +449,81 @@ prom_print(RELOC(" done\n")); } RELOC(klimit) = (char *) (mem - offset); +#ifdef CONFIG_SMP + /* + * With CHRP SMP we need to use the OF to start the other + * processors so we can't wait until smp_boot_cpus (the OF is + * trashed by then) so we have to put the processors into + * a holding pattern controlled by the kernel (not OF) before + * we destroy the OF. + * + * This uses a chunk of high memory, puts some holding pattern + * code there and sends the other processors off to there until + * smp_boot_cpus tells them to do something. We do that by using + * physical address 0x0. The holding pattern checks that address + * until its cpu # is there, when it is that cpu jumps to + * __secondary_start(). smp_boot_cpus() takes care of setting those + * values. + * + * We also use physical address 0x4 here to tell when a cpu + * is in its holding pattern code. + * + * -- Cort + */ + { + extern void __secondary_hold(void); + unsigned long i; + char type[16]; + + + /* + * XXX: hack to make sure we're chrp, assume that if we're + * chrp we have a device_type property -- Cort + */ + node = call_prom(RELOC("finddevice"), 1, 1, RELOC("/")); + if ( (int)call_prom(RELOC("getprop"), 4, 1, node, + RELOC("device_type"),type, sizeof(type)) <= 0) + return; + + /* copy the holding pattern code to someplace safe (8M) */ + memcpy( (void *)(8<<20), RELOC(__secondary_hold), 0x10000 ); + for (i = 8<<20; i < ((8<<20)+0x10000); i += 32) + { + asm volatile("dcbf 0,%0" : : "r" (i) : "memory"); + asm volatile("icbi 0,%0" : : "r" (i) : "memory"); + } + } + + /* look for cpus */ + for (node = 0; prom_next_node(&node);) + { + type[0] = 0; + call_prom(RELOC("getprop"), 4, 1, node, RELOC("device_type"), + type, sizeof(type)); + if (strcmp(type, RELOC("cpu")) != 0) + continue; + path = (char *) mem; + memset(path, 0, 256); + if ((int) call_prom(RELOC("package-to-path"), 3, 1, + node, path, 255) < 0) + continue; + /* XXX: hack - don't start cpu 0, this cpu -- Cort */ + if ( cpu++ == 0 ) + continue; + prom_print(RELOC("starting cpu ")); + prom_print(path); + *(unsigned long *)(0x4) = 0; + asm volatile("dcbf 0,%0": : "r" (0x4) : "memory"); + call_prom(RELOC("start-cpu"), 3, 0, node, 8<<20, cpu-1); + for ( i = 0 ; (i < 10000) && + (*(ulong *)(0x4) == (ulong)0); i++ ) + ; + if (*(ulong *)(0x4) == (ulong)cpu-1 ) + prom_print(RELOC("...ok\n")); + else + prom_print(RELOC("...failed\n")); + } +#endif } /* @@ -631,6 +762,12 @@ mem_start = ifunc(np, mem_start); } + /* the f50 sets the name to 'display' and 'compatible' to what we + * expect for the name -- Cort + */ + if (!strcmp(np->name, "display")) + np->name = get_property(np, "compatible", 0); + if (!strcmp(np->name, "device-tree")) ifunc = interpret_root_props; else if (np->type == 0) @@ -1007,7 +1144,7 @@ if (cp == NULL) return 0; while (cplen > 0) { - if (strcasecmp(cp, compat) == 0) + if (strncasecmp(cp, compat, strlen(compat)) == 0) return 1; l = strlen(cp) + 1; cp += l; @@ -1143,6 +1280,8 @@ } #endif +spinlock_t rtas_lock = SPIN_LOCK_UNLOCKED; + /* this can be called after setup -- Cort */ __openfirmware int @@ -1173,7 +1312,9 @@ for (i = 0; i < nargs; ++i) u.words[i+3] = va_arg(list, unsigned long); va_end(list); + spin_lock(&rtas_lock); enter_rtas((void *)__pa(&u)); + spin_unlock(&rtas_lock); if (nret > 1 && outputs != NULL) for (i = 0; i < nret-1; ++i) outputs[i] = u.words[i+nargs+4]; @@ -1191,8 +1332,11 @@ prom_exit(); } -#define CALC_BASE(y) (bi->dispDeviceBase + bi->dispDeviceRect[0] * \ - (bi->dispDeviceDepth >> 3) + bi->dispDeviceRowBytes * (y)) +/* Calc the base address of a given point (x,y) */ +#define CALC_BASE(x,y) ((BOOT_INFO_IS_V2_COMPATIBLE(bi) ? bi->logicalDisplayBase : \ + bi->dispDeviceBase) + (bi->dispDeviceRect[0] + (x)) * \ + (bi->dispDeviceDepth >> 3) + bi->dispDeviceRowBytes * \ + ((y) + bi->dispDeviceRect[1])) __init static void @@ -1200,7 +1344,7 @@ { unsigned long offset = reloc_offset(); boot_infos_t* bi = PTRRELOC(RELOC(boot_infos)); - unsigned long *base = (unsigned long *)CALC_BASE(0); + unsigned long *base = (unsigned long *)CALC_BASE(0,0); unsigned long width = ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) * (bi->dispDeviceDepth >> 3)) >> 2; int i,j; @@ -1214,6 +1358,33 @@ } } +__inline__ void dcbst(const void* addr) +{ + __asm__ __volatile__ ("dcbst 0,%0" :: "r" (addr)); +} + +__init +static void +flushscreen(void) +{ + unsigned long offset = reloc_offset(); + boot_infos_t* bi = PTRRELOC(RELOC(boot_infos)); + unsigned long *base = (unsigned long *)CALC_BASE(0,0); + unsigned long width = ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) * + (bi->dispDeviceDepth >> 3)) >> 2; + int i,j; + + for (i=0; i<(bi->dispDeviceRect[3] - bi->dispDeviceRect[1]); i++) + { + unsigned long *ptr = base; + for(j=width; j>0; j-=8) { + dcbst(ptr); + ptr += 8; + } + base += (bi->dispDeviceRowBytes >> 2); + } +} + #ifdef CONFIG_BOOTX_TEXT __init @@ -1222,8 +1393,8 @@ { unsigned long offset = reloc_offset(); boot_infos_t* bi = PTRRELOC(RELOC(boot_infos)); - unsigned long *src = (unsigned long *)CALC_BASE(16); - unsigned long *dst = (unsigned long *)CALC_BASE(0); + unsigned long *src = (unsigned long *)CALC_BASE(0,16); + unsigned long *dst = (unsigned long *)CALC_BASE(0,0); unsigned long width = ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) * (bi->dispDeviceDepth >> 3)) >> 2; int i,j; @@ -1252,20 +1423,17 @@ { unsigned long offset = reloc_offset(); - switch(c) - { - case '\r': RELOC(g_loc_X) = 0; break; - case '\n': RELOC(g_loc_X) = 0; RELOC(g_loc_Y)++; break; + switch(c) { + case '\r': RELOC(g_loc_X) = 0; break; + case '\n': RELOC(g_loc_X) = 0; RELOC(g_loc_Y)++; break; default: draw_byte(c, RELOC(g_loc_X)++, RELOC(g_loc_Y)); - if (RELOC(g_loc_X) >= RELOC(g_max_loc_X)) - { + if (RELOC(g_loc_X) >= RELOC(g_max_loc_X)) { RELOC(g_loc_X) = 0; RELOC(g_loc_Y)++; } } - while (RELOC(g_loc_Y) >= RELOC(g_max_loc_Y)) - { + while (RELOC(g_loc_Y) >= RELOC(g_max_loc_Y)) { scrollscreen(); RELOC(g_loc_Y)--; } @@ -1281,17 +1449,32 @@ __init static void +drawhex(unsigned long v) +{ + static char hex_table[] = "0123456789abcdef"; + unsigned long offset = reloc_offset(); + + drawchar(RELOC(hex_table)[(v >> 28) & 0x0000000FUL]); + drawchar(RELOC(hex_table)[(v >> 24) & 0x0000000FUL]); + drawchar(RELOC(hex_table)[(v >> 20) & 0x0000000FUL]); + drawchar(RELOC(hex_table)[(v >> 16) & 0x0000000FUL]); + drawchar(RELOC(hex_table)[(v >> 12) & 0x0000000FUL]); + drawchar(RELOC(hex_table)[(v >> 8) & 0x0000000FUL]); + drawchar(RELOC(hex_table)[(v >> 4) & 0x0000000FUL]); + drawchar(RELOC(hex_table)[(v >> 0) & 0x0000000FUL]); +} + + +__init +static void draw_byte(unsigned char c, long locX, long locY) { unsigned long offset = reloc_offset(); - boot_infos_t* bi = PTRRELOC(RELOC(boot_infos)); - unsigned char *base = bi->dispDeviceBase - + (bi->dispDeviceRowBytes * ((locY * 16) + bi->dispDeviceRect[1])) - + (bi->dispDeviceDepth >> 3) * ((locX * 8) + bi->dispDeviceRect[0]); - unsigned char *font = &RELOC(vga_font)[((unsigned long)c) * 16]; + boot_infos_t* bi = PTRRELOC(RELOC(boot_infos)); + unsigned char *base = CALC_BASE(locX << 3, locY << 4); + unsigned char *font = &RELOC(vga_font)[((unsigned long)c) * 16]; - switch(bi->dispDeviceDepth) - { + switch(bi->dispDeviceDepth) { case 32: draw_byte_32(font, (unsigned long *)base); break; diff -ur --new-file old/linux/arch/ppc/kernel/ptrace.c new/linux/arch/ppc/kernel/ptrace.c --- old/linux/arch/ppc/kernel/ptrace.c Wed Dec 30 01:32:36 1998 +++ new/linux/arch/ppc/kernel/ptrace.c Thu Apr 29 21:39:01 1999 @@ -392,14 +392,8 @@ tmp = get_reg(child, addr); } else if (addr >= PT_FPR0 && addr <= PT_FPSCR) { -#ifdef __SMP__ - if (child->tss.regs->msr & MSR_FP ) - smp_giveup_fpu(child); -#else - /* only current can be last task to use math on SMP */ - if (last_task_used_math == child) - giveup_fpu(); -#endif + if (child->tss.regs->msr & MSR_FP) + giveup_fpu(child); tmp = ((long *)child->tss.fpr)[addr - PT_FPR0]; } else @@ -433,13 +427,8 @@ goto out; } if (addr >= PT_FPR0 && addr < PT_FPR0 + 64) { -#ifndef __SMP__ - if (last_task_used_math == child) - giveup_fpu(); -#else - if (child->tss.regs->msr & MSR_FP ) - smp_giveup_fpu(child); -#endif + if (child->tss.regs->msr & MSR_FP) + giveup_fpu(child); ((long *)child->tss.fpr)[addr - PT_FPR0] = data; ret = 0; goto out; diff -ur --new-file old/linux/arch/ppc/kernel/setup.c new/linux/arch/ppc/kernel/setup.c --- old/linux/arch/ppc/kernel/setup.c Thu Jan 7 21:06:57 1999 +++ new/linux/arch/ppc/kernel/setup.c Thu Apr 29 21:39:01 1999 @@ -1,5 +1,5 @@ /* - * $Id: setup.c,v 1.122 1998/12/31 20:51:19 cort Exp $ + * $Id: setup.c,v 1.132 1999/03/24 00:32:19 cort Exp $ * Common prep/pmac/chrp boot and setup code. */ @@ -27,40 +27,74 @@ #include #ifdef CONFIG_MBX #include +#include #endif #include +#include +#include -/* APUS defs */ -extern unsigned long m68k_machtype; -extern int parse_bootinfo(const struct bi_record *); -extern char _end[]; -#ifdef CONFIG_APUS -extern struct mem_info ramdisk; -unsigned long isa_io_base; -unsigned long isa_mem_base; -unsigned long pci_dram_offset; -#endif -/* END APUS defs */ +extern void pmac_init(unsigned long r3, + unsigned long r4, + unsigned long r5, + unsigned long r6, + unsigned long r7); + +extern void chrp_init(unsigned long r3, + unsigned long r4, + unsigned long r5, + unsigned long r6, + unsigned long r7); + +extern void prep_init(unsigned long r3, + unsigned long r4, + unsigned long r5, + unsigned long r6, + unsigned long r7); + +extern void mbx_init(unsigned long r3, + unsigned long r4, + unsigned long r5, + unsigned long r6, + unsigned long r7); + +extern void apus_init(unsigned long r3, + unsigned long r4, + unsigned long r5, + unsigned long r6, + unsigned long r7); +extern boot_infos_t *boot_infos; extern char cmd_line[512]; char saved_command_line[256]; unsigned char aux_device_present; -#if !defined(CONFIG_MACH_SPECIFIC) +struct ide_machdep_calls ppc_ide_md; + unsigned long ISA_DMA_THRESHOLD; unsigned long DMA_MODE_READ, DMA_MODE_WRITE; -int _machine; -/* if we have openfirmware */ -unsigned long have_of; -#endif /* ! CONFIG_MACH_SPECIFIC */ + +/* Temporary hacks until machdep.h is fully done. */ +int _machine = 0; +/* do we have OF? */ +int have_of = 0; +int is_prep = 0; +int is_chrp = 0; +/* For MTX/MVME boards.. with Raven/Falcon Chipset + Real close to CHRP, but boot like PReP (via PPCbug) + There's probably a nicer way to do this.. --Troy */ +int is_powerplus = 0; + +struct machdep_calls ppc_md; + /* copy of the residual data */ +#ifndef CONFIG_MBX unsigned char __res[sizeof(RESIDUAL)] __prepdata = {0,}; -RESIDUAL *res = (RESIDUAL *)&__res; - -int _prep_type; +#else +unsigned char __res[sizeof(bd_t)] = {0,}; +#endif -extern boot_infos_t *boot_infos; +RESIDUAL *res = (RESIDUAL *)&__res; /* * Perhaps we can put the pmac screen_info[] here @@ -110,160 +144,28 @@ }; #endif /* CONFIG_MBX */ -/* cmd is ignored for now... */ void machine_restart(char *cmd) { -#ifndef CONFIG_MBX - struct adb_request req; - unsigned long flags; - unsigned long i = 10000; -#if 0 - int err; -#endif - - switch(_machine) - { - case _MACH_Pmac: - switch (adb_hardware) { - case ADB_VIACUDA: - cuda_request(&req, NULL, 2, CUDA_PACKET, - CUDA_RESET_SYSTEM); - for (;;) - cuda_poll(); - break; - case ADB_VIAPMU: - pmu_restart(); - break; - default: - } - break; - - case _MACH_chrp: -#if 0 /* RTAS doesn't seem to work on Longtrail. - For now, do it the same way as the PReP. */ - /*err = call_rtas("system-reboot", 0, 1, NULL); - printk("RTAS system-reboot returned %d\n", err); - for (;;);*/ - - { - extern unsigned int rtas_entry, rtas_data, rtas_size; - unsigned long status, value; - printk("rtas_entry: %08x rtas_data: %08x rtas_size: %08x\n", - rtas_entry,rtas_data,rtas_size); - } -#endif - case _MACH_prep: - _disable_interrupts(); - - /* set exception prefix high - to the prom */ - save_flags( flags ); - restore_flags( flags|MSR_IP ); - - /* make sure bit 0 (reset) is a 0 */ - outb( inb(0x92) & ~1L , 0x92 ); - /* signal a reset to system control port A - soft reset */ - outb( inb(0x92) | 1 , 0x92 ); - - while ( i != 0 ) i++; - panic("restart failed\n"); - break; - case _MACH_apus: - cli(); - - APUS_WRITE(APUS_REG_LOCK, - REGLOCK_BLACKMAGICK1|REGLOCK_BLACKMAGICK2); - APUS_WRITE(APUS_REG_LOCK, - REGLOCK_BLACKMAGICK1|REGLOCK_BLACKMAGICK3); - APUS_WRITE(APUS_REG_LOCK, - REGLOCK_BLACKMAGICK2|REGLOCK_BLACKMAGICK3); - APUS_WRITE(APUS_REG_SHADOW, REGSHADOW_SELFRESET); - APUS_WRITE(APUS_REG_RESET, REGRESET_AMIGARESET); - for(;;); - break; - } -#else /* CONFIG_MBX */ - extern void MBX_gorom(void); - MBX_gorom(); -#endif /* CONFIG_MBX */ + ppc_md.restart(cmd); } - + void machine_power_off(void) { -#ifndef CONFIG_MBX - struct adb_request req; -#if 0 - int err; -#endif - - switch (_machine) { - case _MACH_Pmac: - switch (adb_hardware) { - case ADB_VIACUDA: - cuda_request(&req, NULL, 2, CUDA_PACKET, - CUDA_POWERDOWN); - for (;;) - cuda_poll(); - break; - case ADB_VIAPMU: - pmu_shutdown(); - break; - default: - } - break; - - case _MACH_chrp: -#if 0 /* RTAS doesn't seem to work on Longtrail. - For now, do it the same way as the PReP. */ - err = call_rtas("power-off", 2, 1, NULL, 0, 0); - printk("RTAS system-reboot returned %d\n", err); - for (;;); -#endif - - case _MACH_prep: - machine_restart(NULL); - case _MACH_apus: - for (;;); - } - for (;;); -#else /* CONFIG_MBX */ - machine_restart(NULL); -#endif /* CONFIG_MBX */ + ppc_md.power_off(); } - + void machine_halt(void) { - if ( _machine == _MACH_Pmac ) - { - machine_power_off(); - } - else /* prep, chrp or apus */ - machine_restart(NULL); - + ppc_md.halt(); } - + #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) void ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq) { -#if !defined(CONFIG_MBX) && !defined(CONFIG_APUS) - switch (_machine) { -#if defined(CONFIG_BLK_DEV_IDE_PMAC) - case _MACH_Pmac: - pmac_ide_init_hwif_ports(p,base,irq); - break; -#endif - case _MACH_chrp: - chrp_ide_init_hwif_ports(p,base,irq); - break; - case _MACH_prep: - prep_ide_init_hwif_ports(p,base,irq); - break; + if (ppc_ide_md.ide_init_hwif != NULL) { + ppc_ide_md.ide_init_hwif(p, base, irq); } -#endif -#if defined(CONFIG_MBX) - mbx_ide_init_hwif_ports(p,base,irq); -#endif } -EXPORT_SYMBOL(ide_init_hwif_ports); #endif unsigned long cpu_temp(void) @@ -297,10 +199,6 @@ int get_cpuinfo(char *buffer) { - extern int pmac_get_cpuinfo(char *); - extern int chrp_get_cpuinfo(char *); - extern int prep_get_cpuinfo(char *); - extern int apus_get_cpuinfo(char *); unsigned long len = 0; unsigned long bogosum = 0; unsigned long i; @@ -364,7 +262,6 @@ break; } -#ifndef CONFIG_MBX /* * Assume here that all clock rates are the same in a * smp system. -- Cort @@ -381,33 +278,11 @@ len += sprintf(len+buffer, "clock\t\t: %dMHz\n", *fp / 1000000); } - - /* PREP's without residual data for some reason will give - incorrect values here */ - if ( is_prep ) - { - len += sprintf(len+buffer, "clock\t\t: "); - if ( res->ResidualLength ) - len += sprintf(len+buffer, "%ldMHz\n", - (res->VitalProductData.ProcessorHz > 1024) ? - res->VitalProductData.ProcessorHz>>20 : - res->VitalProductData.ProcessorHz); - else - len += sprintf(len+buffer, "???\n"); - } -#else /* CONFIG_MBX */ + + if (ppc_md.setup_residual != NULL) { - bd_t *bp; - extern RESIDUAL *res; - - bp = (bd_t *)res; - - len += sprintf(len+buffer,"clock\t\t: %dMHz\n" - "bus clock\t: %dMHz\n", - bp->bi_intfreq /*/ 1000000*/, - bp->bi_busfreq /*/ 1000000*/); + len += ppc_md.setup_residual(buffer + len); } -#endif /* CONFIG_MBX */ len += sprintf(len+buffer, "revision\t: %ld.%ld\n", (GET_PVR & 0xff00) >> 8, GET_PVR & 0xff); @@ -422,8 +297,8 @@ if ( i ) len += sprintf(buffer+len, "\n"); len += sprintf(buffer+len,"total bogomips\t: %lu.%02lu\n", - (bogosum+2500)/500000, - (bogosum+2500)/5000 % 100); + (bogosum+2500)/500000, + (bogosum+2500)/5000 % 100); #endif /* __SMP__ */ /* @@ -432,34 +307,21 @@ { len += sprintf(buffer+len,"zero pages\t: total %lu (%luKb) " "current: %lu (%luKb) hits: %lu/%lu (%lu%%)\n", - quicklists.zerototal, - (quicklists.zerototal*PAGE_SIZE)>>10, - quicklists.zero_sz, - (quicklists.zero_sz*PAGE_SIZE)>>10, - quicklists.zeropage_hits,quicklists.zeropage_calls, + zero_cache_total, + (zero_cache_total*PAGE_SIZE)>>10, + zero_cache_sz, + (zero_cache_sz*PAGE_SIZE)>>10, + zero_cache_hits,zero_cache_calls, /* : 1 below is so we don't div by zero */ - (quicklists.zeropage_hits*100) / - ((quicklists.zeropage_calls)?quicklists.zeropage_calls:1)); + (zero_cache_hits*100) / + ((zero_cache_calls)?zero_cache_calls:1)); } -#ifndef CONFIG_MBX - switch (_machine) + if (ppc_md.get_cpuinfo != NULL) { - case _MACH_Pmac: - len += pmac_get_cpuinfo(buffer+len); - break; - case _MACH_prep: - len += prep_get_cpuinfo(buffer+len); - break; - case _MACH_chrp: - len += chrp_get_cpuinfo(buffer+len); - break; - case _MACH_apus: - /* Not much point in printing m68k info when it is not - used. */ - break; + len += ppc_md.get_cpuinfo(buffer+len); } -#endif /* ndef CONFIG_MBX */ + return len; } @@ -471,25 +333,22 @@ identify_machine(unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7) { - extern void setup_pci_ptrs(void); #ifdef __SMP__ if ( first_cpu_booted ) return 0; #endif /* __SMP__ */ -#ifndef CONFIG_MBX #ifndef CONFIG_MACH_SPECIFIC /* boot loader will tell us if we're APUS */ if ( r3 == 0x61707573 ) { _machine = _MACH_apus; - have_of = 0; r3 = 0; } /* prep boot loader tells us if we're prep or not */ else if ( *(unsigned long *)(KERNELBASE) == (0xdeadc0de) ) { _machine = _MACH_prep; - have_of = 0; + is_prep = 1; } else { char *model; @@ -500,19 +359,49 @@ /* ask the OF info if we're a chrp or pmac */ model = get_property(find_path_device("/"), "device_type", NULL); if ( model && !strncmp("chrp",model,4) ) + { _machine = _MACH_chrp; + is_chrp = 1; + } else { model = get_property(find_path_device("/"), "model", NULL); if ( model && !strncmp(model, "IBM", 3)) + { _machine = _MACH_chrp; + is_chrp = 1; + } else + { _machine = _MACH_Pmac; + is_prep = 1; + } } } -#endif /* CONFIG_MACH_SPECIFIC */ +#else /* CONFIG_MACH_SPECIFIC */ + +#ifdef CONFIG_PREP + _machine = _MACH_prep; + is_prep = 1; +#elif defined(CONFIG_CHRP) + _machine = _MACH_chrp; + is_chrp = 1; + have_of = 1; +#elif defined(CONFIG_PMAC) + _machine = _MACH_Pmac; + have_of = 1; +#elif defined(CONFIG_MBX) + _machine = _MACH_mbx; +#elif defined(CONFIG_FADS) + _machine = _MACH_fads; +#elif defined(CONFIG_APUS) + _machine = _MACH_apus; +#else +#error "Machine not defined correctly" +#endif /* CONFIG_APUS */ +#endif /* CONFIG_MACH_SPECIFIC */ if ( have_of ) { @@ -571,131 +460,31 @@ cmd_line[sizeof(cmd_line) - 1] = 0; } - switch (_machine) { case _MACH_Pmac: - setup_pci_ptrs(); - /* isa_io_base gets set in pmac_find_bridges */ - isa_mem_base = PMAC_ISA_MEM_BASE; - pci_dram_offset = PMAC_PCI_DRAM_OFFSET; -#if !defined(CONFIG_MACH_SPECIFIC) - ISA_DMA_THRESHOLD = ~0L; - DMA_MODE_READ = 1; - DMA_MODE_WRITE = 2; -#endif /* ! CONFIG_MACH_SPECIFIC */ + pmac_init(r3, r4, r5, r6, r7); break; case _MACH_prep: - /* make a copy of residual data */ - if ( r3 ) - memcpy((void *)res,(void *)(r3+KERNELBASE), - sizeof(RESIDUAL)); - setup_pci_ptrs(); - isa_io_base = PREP_ISA_IO_BASE; - isa_mem_base = PREP_ISA_MEM_BASE; - pci_dram_offset = PREP_PCI_DRAM_OFFSET; -#if !defined(CONFIG_MACH_SPECIFIC) - ISA_DMA_THRESHOLD = 0x00ffffff; - DMA_MODE_READ = 0x44; - DMA_MODE_WRITE = 0x48; -#endif /* ! CONFIG_MACH_SPECIFIC */ - /* figure out what kind of prep workstation we are */ - if ( res->ResidualLength != 0 ) - { - if ( !strncmp(res->VitalProductData.PrintableModel,"IBM",3) ) - _prep_type = _PREP_IBM; - else - _prep_type = _PREP_Motorola; - } - else /* assume motorola if no residual (netboot?) */ - _prep_type = _PREP_Motorola; -#ifdef CONFIG_BLK_DEV_INITRD - /* take care of initrd if we have one */ - if ( r4 ) - { - initrd_start = r4 + KERNELBASE; - initrd_end = r5 + KERNELBASE; - } -#endif /* CONFIG_BLK_DEV_INITRD */ - /* take care of cmd line */ - if ( r6 ) - { - *(char *)(r7+KERNELBASE) = 0; - strcpy(cmd_line, (char *)(r6+KERNELBASE)); - } + prep_init(r3, r4, r5, r6, r7); break; case _MACH_chrp: - setup_pci_ptrs(); -#ifdef CONFIG_BLK_DEV_INITRD - /* take care of initrd if we have one */ - if ( r3 ) - { - initrd_start = r3 + KERNELBASE; - initrd_end = r3 + r4 + KERNELBASE; - } -#endif /* CONFIG_BLK_DEV_INITRD */ - /* isa_io_base set by setup_pci_ptrs() */ - isa_mem_base = CHRP_ISA_MEM_BASE; - pci_dram_offset = CHRP_PCI_DRAM_OFFSET; -#if !defined(CONFIG_MACH_SPECIFIC) - ISA_DMA_THRESHOLD = ~0L; - DMA_MODE_READ = 0x44; - DMA_MODE_WRITE = 0x48; -#endif /* ! CONFIG_MACH_SPECIFIC */ + chrp_init(r3, r4, r5, r6, r7); break; -#ifdef CONFIG_APUS +#ifdef CONFIG_APUS case _MACH_apus: - /* Parse bootinfo. The bootinfo is located right after - the kernel bss */ - parse_bootinfo((const struct bi_record *)&_end); -#ifdef CONFIG_BLK_DEV_INITRD - /* Take care of initrd if we have one. Use data from - bootinfo to avoid the need to initialize PPC - registers when kernel is booted via a PPC reset. */ - if ( ramdisk.addr ) { - initrd_start = (unsigned long) __va(ramdisk.addr); - initrd_end = (unsigned long) - __va(ramdisk.size + ramdisk.addr); - } - /* Make sure code below is not executed. */ - r4 = 0; - r6 = 0; -#endif /* CONFIG_BLK_DEV_INITRD */ -#if !defined(CONFIG_MACH_SPECIFIC) - ISA_DMA_THRESHOLD = 0x00ffffff; -#endif /* ! CONFIG_MACH_SPECIFIC */ + apus_init(r3, r4, r5, r6, r7); break; #endif +#ifdef CONFIG_MBX + case _MACH_mbx: + mbx_init(r3, r4, r5, r6, r7); + break; +#endif default: printk("Unknown machine type in identify_machine!\n"); } -#else /* CONFIG_MBX */ - - if ( r3 ) - memcpy( (void *)res,(void *)(r3+KERNELBASE), sizeof(bd_t) ); - -#ifdef CONFIG_PCI - setup_pci_ptrs(); -#endif - -#ifdef CONFIG_BLK_DEV_INITRD - /* take care of initrd if we have one */ - if ( r4 ) - { - initrd_start = r4 + KERNELBASE; - initrd_end = r5 + KERNELBASE; - } -#endif /* CONFIG_BLK_DEV_INITRD */ - /* take care of cmd line */ - if ( r6 ) - { - - *(char *)(r7+KERNELBASE) = 0; - strcpy(cmd_line, (char *)(r6+KERNELBASE)); - } -#endif /* CONFIG_MBX */ - /* Check for nobats option (used in mapin_ram). */ if (strstr(cmd_line, "nobats")) { extern int __map_without_bats; @@ -717,14 +506,17 @@ } } +__initfunc(void + ppc_init(void)) +{ + if (ppc_md.init != NULL) { + ppc_md.init(); + } +} + __initfunc(void setup_arch(char **cmdline_p, - unsigned long * memory_start_p, unsigned long * memory_end_p)) + unsigned long * memory_start_p, unsigned long * memory_end_p)) { - extern void pmac_setup_arch(unsigned long *, unsigned long *); - extern void chrp_setup_arch(unsigned long *, unsigned long *); - extern void prep_setup_arch(unsigned long *, unsigned long *); - extern void mbx_setup_arch(unsigned long *, unsigned long *); - extern void apus_setup_arch(unsigned long *, unsigned long *); extern int panic_timeout; extern char _etext[], _edata[]; extern char *klimit; @@ -737,7 +529,7 @@ if (strstr(cmd_line, "xmon")) xmon(0); #endif /* CONFIG_XMON */ - + /* reboot on panic */ panic_timeout = 180; @@ -753,27 +545,113 @@ *memory_start_p = find_available_memory(); *memory_end_p = (unsigned long) end_of_DRAM; -#ifdef CONFIG_MBX - mbx_setup_arch(memory_start_p,memory_end_p); -#else /* CONFIG_MBX */ - switch (_machine) { - case _MACH_Pmac: - pmac_setup_arch(memory_start_p, memory_end_p); - break; - case _MACH_prep: - prep_setup_arch(memory_start_p, memory_end_p); - break; - case _MACH_chrp: - chrp_setup_arch(memory_start_p, memory_end_p); - break; -#ifdef CONFIG_APUS - case _MACH_apus: - m68k_machtype = MACH_AMIGA; - apus_setup_arch(memory_start_p,memory_end_p); - break; -#endif - default: - printk("Unknown machine %d in setup_arch()\n", _machine); - } -#endif /* CONFIG_MBX */ + ppc_md.setup_arch(memory_start_p, memory_end_p); +} + +void ppc_generic_ide_fix_driveid(struct hd_driveid *id) +{ + int i; + unsigned short *stringcast; + + + id->config = __le16_to_cpu(id->config); + id->cyls = __le16_to_cpu(id->cyls); + id->reserved2 = __le16_to_cpu(id->reserved2); + id->heads = __le16_to_cpu(id->heads); + id->track_bytes = __le16_to_cpu(id->track_bytes); + id->sector_bytes = __le16_to_cpu(id->sector_bytes); + id->sectors = __le16_to_cpu(id->sectors); + id->vendor0 = __le16_to_cpu(id->vendor0); + id->vendor1 = __le16_to_cpu(id->vendor1); + id->vendor2 = __le16_to_cpu(id->vendor2); + stringcast = (unsigned short *)&id->serial_no[0]; + for (i=0; i<(20/2); i++) + stringcast[i] = __le16_to_cpu(stringcast[i]); + id->buf_type = __le16_to_cpu(id->buf_type); + id->buf_size = __le16_to_cpu(id->buf_size); + id->ecc_bytes = __le16_to_cpu(id->ecc_bytes); + stringcast = (unsigned short *)&id->fw_rev[0]; + for (i=0; i<(8/2); i++) + stringcast[i] = __le16_to_cpu(stringcast[i]); + stringcast = (unsigned short *)&id->model[0]; + for (i=0; i<(40/2); i++) + stringcast[i] = __le16_to_cpu(stringcast[i]); + id->dword_io = __le16_to_cpu(id->dword_io); + id->reserved50 = __le16_to_cpu(id->reserved50); + id->field_valid = __le16_to_cpu(id->field_valid); + id->cur_cyls = __le16_to_cpu(id->cur_cyls); + id->cur_heads = __le16_to_cpu(id->cur_heads); + id->cur_sectors = __le16_to_cpu(id->cur_sectors); + id->cur_capacity0 = __le16_to_cpu(id->cur_capacity0); + id->cur_capacity1 = __le16_to_cpu(id->cur_capacity1); + id->lba_capacity = __le32_to_cpu(id->lba_capacity); + id->dma_1word = __le16_to_cpu(id->dma_1word); + id->dma_mword = __le16_to_cpu(id->dma_mword); + id->eide_pio_modes = __le16_to_cpu(id->eide_pio_modes); + id->eide_dma_min = __le16_to_cpu(id->eide_dma_min); + id->eide_dma_time = __le16_to_cpu(id->eide_dma_time); + id->eide_pio = __le16_to_cpu(id->eide_pio); + id->eide_pio_iordy = __le16_to_cpu(id->eide_pio_iordy); + id->word69 = __le16_to_cpu(id->word69); + id->word70 = __le16_to_cpu(id->word70); + id->word71 = __le16_to_cpu(id->word71); + id->word72 = __le16_to_cpu(id->word72); + id->word73 = __le16_to_cpu(id->word73); + id->word74 = __le16_to_cpu(id->word74); + id->word75 = __le16_to_cpu(id->word75); + id->word76 = __le16_to_cpu(id->word76); + id->word77 = __le16_to_cpu(id->word77); + id->word78 = __le16_to_cpu(id->word78); + id->word79 = __le16_to_cpu(id->word79); + id->word80 = __le16_to_cpu(id->word80); + id->word81 = __le16_to_cpu(id->word81); + id->command_sets = __le16_to_cpu(id->command_sets); + id->word83 = __le16_to_cpu(id->word83); + id->word84 = __le16_to_cpu(id->word84); + id->word85 = __le16_to_cpu(id->word85); + id->word86 = __le16_to_cpu(id->word86); + id->word87 = __le16_to_cpu(id->word87); + id->dma_ultra = __le16_to_cpu(id->dma_ultra); + id->word89 = __le16_to_cpu(id->word89); + id->word90 = __le16_to_cpu(id->word90); + id->word91 = __le16_to_cpu(id->word91); + id->word92 = __le16_to_cpu(id->word92); + id->word93 = __le16_to_cpu(id->word93); + id->word94 = __le16_to_cpu(id->word94); + id->word95 = __le16_to_cpu(id->word95); + id->word96 = __le16_to_cpu(id->word96); + id->word97 = __le16_to_cpu(id->word97); + id->word98 = __le16_to_cpu(id->word98); + id->word99 = __le16_to_cpu(id->word99); + id->word100 = __le16_to_cpu(id->word100); + id->word101 = __le16_to_cpu(id->word101); + id->word102 = __le16_to_cpu(id->word102); + id->word103 = __le16_to_cpu(id->word103); + id->word104 = __le16_to_cpu(id->word104); + id->word105 = __le16_to_cpu(id->word105); + id->word106 = __le16_to_cpu(id->word106); + id->word107 = __le16_to_cpu(id->word107); + id->word108 = __le16_to_cpu(id->word108); + id->word109 = __le16_to_cpu(id->word109); + id->word110 = __le16_to_cpu(id->word110); + id->word111 = __le16_to_cpu(id->word111); + id->word112 = __le16_to_cpu(id->word112); + id->word113 = __le16_to_cpu(id->word113); + id->word114 = __le16_to_cpu(id->word114); + id->word115 = __le16_to_cpu(id->word115); + id->word116 = __le16_to_cpu(id->word116); + id->word117 = __le16_to_cpu(id->word117); + id->word118 = __le16_to_cpu(id->word118); + id->word119 = __le16_to_cpu(id->word119); + id->word120 = __le16_to_cpu(id->word120); + id->word121 = __le16_to_cpu(id->word121); + id->word122 = __le16_to_cpu(id->word122); + id->word123 = __le16_to_cpu(id->word123); + id->word124 = __le16_to_cpu(id->word124); + id->word125 = __le16_to_cpu(id->word125); + id->word126 = __le16_to_cpu(id->word126); + id->word127 = __le16_to_cpu(id->word127); + id->security = __le16_to_cpu(id->security); + for (i=0; i<127; i++) + id->reserved[i] = __le16_to_cpu(id->reserved[i]); } diff -ur --new-file old/linux/arch/ppc/kernel/signal.c new/linux/arch/ppc/kernel/signal.c --- old/linux/arch/ppc/kernel/signal.c Sun Nov 15 19:51:44 1998 +++ new/linux/arch/ppc/kernel/signal.c Thu Apr 29 21:39:01 1999 @@ -1,7 +1,7 @@ /* * linux/arch/ppc/kernel/signal.c * - * $Id: signal.c,v 1.21 1998/10/22 19:37:49 paulus Exp $ + * $Id: signal.c,v 1.24 1999/04/03 11:25:16 paulus Exp $ * * PowerPC version * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) @@ -218,13 +218,8 @@ if (sc == (struct sigcontext_struct *)(sigctx.regs)) { /* Last stacked signal - restore registers */ sr = (struct sigregs *) sigctx.regs; -#ifdef __SMP__ - if ( regs->msr & MSR_FP ) - smp_giveup_fpu(current); -#else - if (last_task_used_math == current) - giveup_fpu(); -#endif + if (regs->msr & MSR_FP ) + giveup_fpu(current); if (copy_from_user(saved_regs, &sr->gp_regs, sizeof(sr->gp_regs))) goto badframe; @@ -271,13 +266,8 @@ if (verify_area(VERIFY_WRITE, frame, sizeof(*frame))) goto badframe; -#ifdef __SMP__ - if ( regs->msr & MSR_FP ) - smp_giveup_fpu(current); -#else - if (last_task_used_math == current) - giveup_fpu(); -#endif + if (regs->msr & MSR_FP) + giveup_fpu(current); if (__copy_to_user(&frame->gp_regs, regs, GP_REGS_SIZE) || __copy_to_user(&frame->fp_regs, current->tss.fpr, ELF_NFPREG * sizeof(double)) @@ -374,7 +364,7 @@ if (!oldset) oldset = ¤t->blocked; - newsp = frame = regs->gpr[1] - sizeof(struct sigregs); + newsp = frame = 0; for (;;) { unsigned long signr; @@ -470,6 +460,13 @@ /* NOTREACHED */ } } + + if ( (ka->sa.sa_flags & SA_ONSTACK) + && (! on_sig_stack(regs->gpr[1]))) + newsp = (current->sas_ss_sp + current->sas_ss_size); + else + newsp = regs->gpr[1]; + newsp = frame = newsp - sizeof(struct sigregs); /* Whee! Actually deliver the signal. */ handle_signal(signr, ka, &info, oldset, regs, &newsp, frame); diff -ur --new-file old/linux/arch/ppc/kernel/smp.c new/linux/arch/ppc/kernel/smp.c --- old/linux/arch/ppc/kernel/smp.c Wed Dec 30 19:55:07 1998 +++ new/linux/arch/ppc/kernel/smp.c Thu Apr 29 21:39:01 1999 @@ -1,10 +1,13 @@ /* - * $Id: smp.c,v 1.39 1998/12/28 10:28:51 paulus Exp $ + * $Id: smp.c,v 1.49 1999/03/18 04:16:31 cort Exp $ * * Smp support for ppc. * * Written by Cort Dougan (cort@cs.nmt.edu) borrowing a great * deal of code from the sparc and intel versions. + * + * Support for PReP (Motorola MTX/MVME) SMP by Troy Benjegerdes + * (troy@microux.com, hozer@drgw.net) */ #include @@ -18,6 +21,7 @@ #define __KERNEL_SYSCALLS__ #include #include +#include #include #include @@ -29,9 +33,10 @@ #include #include #include +#include #include "time.h" - +int first_cpu_booted = 0; int smp_threads_ready = 0; volatile int smp_commenced = 0; int smp_num_cpus = 1; @@ -42,7 +47,6 @@ spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED; unsigned int prof_multiplier[NR_CPUS]; unsigned int prof_counter[NR_CPUS]; -int first_cpu_booted = 0; cycles_t cacheflush_time; /* all cpu mappings are 1-1 -- Cort */ @@ -51,6 +55,10 @@ int start_secondary(void *); extern int cpu_idle(void *unused); +u_int openpic_read(volatile u_int *addr); + +/* register for interrupting the secondary processor on the powersurge */ +#define PSURGE_INTR ((volatile unsigned *)0xf80000c0) void smp_local_timer_interrupt(struct pt_regs * regs) { @@ -99,29 +107,33 @@ /* * Dirty hack to get smp message passing working. - * Right now it only works for stop cpu's but will be setup - * later for more general message passing. * * As it is now, if we're sending two message at the same time - * we have race conditions. I avoided doing locks here since - * all that works right now is the stop cpu message. + * we have race conditions. The PowerSurge doesn't easily + * allow us to send IPI messages so we put the messages in + * smp_message[]. * + * This is because don't have several IPI's on the PowerSurge even though + * we do on the chrp. It would be nice to use the actual IPI's on the chrp + * rather than this but having two methods of doing IPI isn't a good idea + * right now. * -- Cort */ int smp_message[NR_CPUS]; void smp_message_recv(void) { int msg = smp_message[smp_processor_id()]; - - /* clear interrupt */ - *(volatile unsigned long *)(0xf80000c0) = ~0L; - eieio(); + + if ( _machine == _MACH_Pmac ) + { + /* clear interrupt */ + out_be32(PSURGE_INTR, ~0); + } /* make sure msg is for us */ if ( msg == -1 ) return; ipi_count++; - /*printk("SMP %d: smp_message_recv() msg %x\n", smp_processor_id(),msg);*/ switch( msg ) { @@ -158,12 +170,17 @@ spinlock_t mesg_pass_lock = SPIN_LOCK_UNLOCKED; void smp_message_pass(int target, int msg, unsigned long data, int wait) { - if ( _machine != _MACH_Pmac ) + int i; + if ( !(_machine & (_MACH_Pmac|_MACH_chrp)) ) return; -printk("SMP %d: sending smp message %x\n", current->processor, msg); -if (smp_processor_id() ) printk("pass from cpu 1\n"); + spin_lock(&mesg_pass_lock); -#define OTHER (~smp_processor_id() & 1) + + /* + * We assume here that the msg is not -1. If it is, + * the recipient won't know the message was destined + * for it. -- Cort + */ switch( target ) { @@ -171,105 +188,180 @@ smp_message[smp_processor_id()] = msg; /* fall through */ case MSG_ALL_BUT_SELF: - smp_message[OTHER] = msg; + for ( i = 0 ; i < smp_num_cpus ; i++ ) + if ( i != smp_processor_id () ) + smp_message[i] = msg; break; default: smp_message[target] = msg; break; } - /* interrupt secondary processor */ - *(volatile unsigned long *)(0xf80000c0) = ~0L; - eieio(); - *(volatile unsigned long *)(0xf80000c0) = 0L; - eieio(); - /* interrupt primary */ - /**(volatile unsigned long *)(0xf3019000);*/ - spin_unlock(&mesg_pass_lock); + + if ( _machine == _MACH_Pmac ) + { + /* interrupt secondary processor */ + out_be32(PSURGE_INTR, ~0); + out_be32(PSURGE_INTR, 0); + /* + * Assume for now that the secondary doesn't send + * IPI's -- Cort + */ + /* interrupt primary */ + /**(volatile unsigned long *)(0xf3019000);*/ + } + + if ( _machine == _MACH_chrp ) + { + /* + * There has to be some way of doing this better - + * perhaps a sent-to-all or send-to-all-but-self + * in the openpic. This gets us going for now, though. + * -- Cort + */ + switch ( target ) + { + case MSG_ALL: + for ( i = 0 ; i < smp_num_cpus ; i++ ) + openpic_cause_IPI(i, 0, 0xffffffff ); + break; + case MSG_ALL_BUT_SELF: + for ( i = 0 ; i < smp_num_cpus ; i++ ) + if ( i != smp_processor_id () ) + openpic_cause_IPI(i, 0, + 0xffffffff & ~(1 << smp_processor_id())); + break; + default: + openpic_cause_IPI(target, 0, 1U << target); + break; + } + } + + spin_unlock(&mesg_pass_lock); } void __init smp_boot_cpus(void) { extern struct task_struct *current_set[NR_CPUS]; - extern void __secondary_start(void); + extern void __secondary_start_psurge(void); int i; struct task_struct *p; unsigned long a; printk("Entering SMP Mode...\n"); - + /* let other processors know to not do certain initialization */ first_cpu_booted = 1; - /*dcbf(&first_cpu_booted);*/ + + /* + * assume for now that the first cpu booted is + * cpu 0, the master -- Cort + */ + cpu_callin_map[0] = 1; + cpu_callin_map[1] = 0; + smp_store_cpu_info(0); + active_kernel_processor = 0; + current->processor = 0; for (i = 0; i < NR_CPUS; i++) { prof_counter[i] = 1; prof_multiplier[i] = 1; } - cpu_callin_map[0] = 1; - smp_store_cpu_info(0); - active_kernel_processor = 0; - current->processor = 0; - /* * XXX very rough, assumes 20 bus cycles to read a cache line, * timebase increments every 4 bus cycles, 32kB L1 data cache. */ cacheflush_time = 5 * 1024; - if ( _machine != _MACH_Pmac ) + if ( !(_machine & (_MACH_Pmac|_MACH_chrp)) ) { printk("SMP not supported on this machine.\n"); return; } - /* create a process for second processor */ - kernel_thread(start_secondary, NULL, CLONE_PID); - p = task[1]; - if ( !p ) - panic("No idle task for secondary processor\n"); - p->processor = 1; - p->has_cpu = 1; - current_set[1] = p; - - /* need to flush here since secondary bat's aren't setup */ - /* XXX ??? */ - for (a = KERNELBASE; a < KERNELBASE + 0x800000; a += 32) - asm volatile("dcbf 0,%0" : : "r" (a) : "memory"); - asm volatile("sync"); - - /*dcbf((void *)¤t_set[1]);*/ - /* setup entry point of secondary processor */ - *(volatile unsigned long *)(0xf2800000) = - (unsigned long)__secondary_start-KERNELBASE; - eieio(); - /* interrupt secondary to begin executing code */ - *(volatile unsigned long *)(0xf80000c0) = ~0L; - eieio(); - *(volatile unsigned long *)(0xf80000c0) = 0L; - eieio(); + switch ( _machine ) + { + case _MACH_Pmac: + /* assume powersurge board - 2 processors -- Cort */ + smp_num_cpus = 2; + break; + case _MACH_chrp: + smp_num_cpus = ((openpic_read(&OpenPIC->Global.Feature_Reporting0) + & OPENPIC_FEATURE_LAST_PROCESSOR_MASK) >> + OPENPIC_FEATURE_LAST_PROCESSOR_SHIFT)+1; + /* get our processor # - we may not be cpu 0 */ + printk("SMP %d processors, boot CPU is %d (should be 0)\n", + smp_num_cpus, + 10/*openpic_read(&OpenPIC->Processor[0]._Who_Am_I)*/); + break; + } + /* - * wait to see if the secondary made a callin (is actually up). - * udelay() isn't accurate here since we haven't yet called - * calibrate_delay() so use this value that I found through - * experimentation. -- Cort + * only check for cpus we know exist. We keep the callin map + * with cpus at the bottom -- Cort */ - for ( i = 1000; i && !cpu_callin_map[1] ; i-- ) - udelay(100); + for ( i = 1 ; i < smp_num_cpus; i++ ) + { + int c; + + /* create a process for the processor */ + kernel_thread(start_secondary, NULL, CLONE_PID); + p = task[i]; + if ( !p ) + panic("No idle task for secondary processor\n"); + p->processor = i; + p->has_cpu = 1; + current_set[i] = p; + + /* need to flush here since secondary bats aren't setup */ + for (a = KERNELBASE; a < KERNELBASE + 0x800000; a += 32) + asm volatile("dcbf 0,%0" : : "r" (a) : "memory"); + asm volatile("sync"); + + /* wake up cpus */ + switch ( _machine ) + { + case _MACH_Pmac: + /* setup entry point of secondary processor */ + *(volatile unsigned long *)(0xf2800000) = + (unsigned long)__secondary_start_psurge-KERNELBASE; + eieio(); + /* interrupt secondary to begin executing code */ + out_be32(PSURGE_INTR, ~0); + out_be32(PSURGE_INTR, 0); + break; + case _MACH_chrp: + *(unsigned long *)KERNELBASE = i; + asm volatile("dcbf 0,%0"::"r"(KERNELBASE):"memory"); + break; + } + + /* + * wait to see if the cpu made a callin (is actually up). + * use this value that I found through experimentation. + * -- Cort + */ + for ( c = 1000; c && !cpu_callin_map[i] ; c-- ) + udelay(100); + + if ( cpu_callin_map[i] ) + { + printk("Processor %d found.\n", i); + /* this sync's the decr's -- Cort */ + if ( _machine == _MACH_Pmac ) + set_dec(decrementer_count); + } else { + printk("Processor %d is stuck.\n", i); + } + } - if(cpu_callin_map[1]) { - printk("Processor %d found.\n", smp_num_cpus); - smp_num_cpus++; -#if 1 /* this sync's the decr's, but we don't want this now -- Cort */ - set_dec(decrementer_count); -#endif - } else { - printk("Processor %d is stuck. \n", smp_num_cpus); + if ( _machine == _MACH_Pmac ) + { + /* reset the entry point so if we get another intr we won't + * try to startup again */ + *(volatile unsigned long *)(0xf2800000) = 0x100; + /* send interrupt to other processors to start decr's on all cpus */ + smp_message_pass(1,0xf0f0, 0, 0); } - /* reset the entry point so if we get another intr we won't - * try to startup again */ - *(volatile unsigned long *)(0xf2800000) = 0x100; - /* send interrupt to other processors to start decr's on all cpus */ - smp_message_pass(1,0xf0f0, 0, 0); } void __init smp_commence(void) @@ -308,7 +400,6 @@ while(!smp_commenced) barrier(); __sti(); - printk("SMP %d: smp_callin done\n", current->processor); } void __init smp_setup(char *str, int *ints) diff -ur --new-file old/linux/arch/ppc/kernel/softemu8xx.c new/linux/arch/ppc/kernel/softemu8xx.c --- old/linux/arch/ppc/kernel/softemu8xx.c Fri May 8 09:18:23 1998 +++ new/linux/arch/ppc/kernel/softemu8xx.c Thu Mar 11 06:30:32 1999 @@ -38,6 +38,7 @@ #define LFDU 51 #define STFD 54 #define STFDU 55 +#define FMR 63 /* * We return 0 on success, 1 on unimplemented instruction, and EFAULT @@ -49,6 +50,7 @@ uint inst, instword; uint flreg, idxreg, disp; uint retval; + signed short sdisp; uint *ea, *ip; retval = 0; @@ -66,6 +68,11 @@ switch ( inst ) { case LFD: + /* this is a 16 bit quantity that is sign extended + * so use a signed short here -- Cort + */ + sdisp = (instword & 0xffff); + ea = (uint *)(regs->gpr[idxreg] + sdisp); if (copy_from_user(ip, ea, sizeof(double))) retval = EFAULT; break; @@ -77,6 +84,11 @@ regs->gpr[idxreg] = (uint)ea; break; case STFD: + /* this is a 16 bit quantity that is sign extended + * so use a signed short here -- Cort + */ + sdisp = (instword & 0xffff); + ea = (uint *)(regs->gpr[idxreg] + sdisp); if (copy_to_user(ea, ip, sizeof(double))) retval = EFAULT; break; @@ -87,6 +99,11 @@ else regs->gpr[idxreg] = (uint)ea; break; + case FMR: + /* assume this is a fp move -- Cort */ + memcpy( ip, ¤t->tss.fpr[(instword>>11)&0x1f], + sizeof(double) ); + break; default: retval = 1; printk("Bad emulation %s/%d\n" @@ -98,7 +115,7 @@ (instword>>16)&0x1f, (instword>>11)&0x1f, (instword>>6)&0x1f, - (instword>>1)&0x1f, + (instword>>1)&0x3ff, instword&1); { int pa; diff -ur --new-file old/linux/arch/ppc/kernel/syscalls.c new/linux/arch/ppc/kernel/syscalls.c --- old/linux/arch/ppc/kernel/syscalls.c Wed Sep 30 19:14:17 1998 +++ new/linux/arch/ppc/kernel/syscalls.c Sat May 8 20:14:01 1999 @@ -205,12 +205,15 @@ lock_kernel(); if (!(flags & MAP_ANONYMOUS)) { - if (fd >= NR_OPEN || !(file = current->files->fd[fd])) + file = fget(fd); + if (!file) goto out; } flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); ret = do_mmap(file, addr, len, prot, flags, offset); + if (file) + fput(file); out: unlock_kernel(); return ret; diff -ur --new-file old/linux/arch/ppc/kernel/time.c new/linux/arch/ppc/kernel/time.c --- old/linux/arch/ppc/kernel/time.c Tue Jan 19 19:19:50 1999 +++ new/linux/arch/ppc/kernel/time.c Thu Apr 29 21:39:01 1999 @@ -1,5 +1,5 @@ /* - * $Id: time.c,v 1.39 1998/12/28 10:28:51 paulus Exp $ + * $Id: time.c,v 1.47 1999/03/18 05:11:11 cort Exp $ * Common time routines among all ppc machines. * * Written by Cort Dougan (cort@cs.nmt.edu) to merge @@ -18,8 +18,8 @@ * Since it is not possible to get a nice 100 Hz clock out of this, without * creating a software PLL, I have set HZ to 128. -- Dan * - * 1997-09-10 Updated NTP code according to technical memorandum Jan '96 - * "A Kernel Model for Precision Timekeeping" by Dave Mills + * 1997-09-10 Updated NTP code according to technical memorandum Jan '96 + * "A Kernel Model for Precision Timekeeping" by Dave Mills */ #include @@ -41,18 +41,14 @@ #include #include #include -#ifdef CONFIG_MBX -#include -#endif +/* Fixme - Why is this here? - Corey */ #ifdef CONFIG_8xx #include #endif +#include #include "time.h" -/* this is set to the appropriate pmac/prep/chrp func in init_IRQ() */ -int (*set_rtc_time)(unsigned long); - void smp_local_timer_interrupt(struct pt_regs *); /* keep track of when we need to update the rtc */ @@ -76,9 +72,6 @@ { int dval, d; unsigned long cpu = smp_processor_id(); - /* save the HID0 in case dcache was off - see idle.c - * this hack should leave for a better solution -- Cort */ - unsigned dcache_locked = unlock_dcache(); hardirq_enter(cpu); #ifdef __SMP__ @@ -119,16 +112,21 @@ */ if ( xtime.tv_sec > last_rtc_update + 660 ) { - if (set_rtc_time(xtime.tv_sec) == 0) + if (ppc_md.set_rtc_time(xtime.tv_sec) == 0) { last_rtc_update = xtime.tv_sec; - else - last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */ + } + else { + /* do it again in 60 s */ + last_rtc_update = xtime.tv_sec - 60; + } } } } #ifdef __SMP__ smp_local_timer_interrupt(regs); #endif + + /* Fixme - make this more generic - Corey */ #ifdef CONFIG_APUS { extern void apus_heartbeat (void); @@ -136,33 +134,8 @@ } #endif hardirq_exit(cpu); - /* restore the HID0 in case dcache was off - see idle.c - * this hack should leave for a better solution -- Cort */ - lock_dcache(dcache_locked); } -#ifdef CONFIG_MBX -/* A place holder for time base interrupts, if they are ever enabled. -*/ -void timebase_interrupt(int irq, void * dev, struct pt_regs * regs) -{ - printk("timebase_interrupt()\n"); -} - -/* The RTC on the MPC8xx is an internal register. - * We want to protect this during power down, so we need to unlock, - * modify, and re-lock. - */ -static int -mbx_set_rtc_time(unsigned long time) -{ - ((immap_t *)IMAP_ADDR)->im_sitk.sitk_rtck = KAPWR_KEY; - ((immap_t *)IMAP_ADDR)->im_sit.sit_rtc = time; - ((immap_t *)IMAP_ADDR)->im_sitk.sitk_rtck = ~KAPWR_KEY; - return(0); -} -#endif /* CONFIG_MBX */ - /* * This version of gettimeofday has microsecond resolution. */ @@ -198,9 +171,9 @@ xtime.tv_sec = tv->tv_sec; xtime.tv_usec = tv->tv_usec - frac_tick; set_dec(frac_tick * count_period_den / count_period_num); - time_adjust = 0; /* stop active adjtime() */ + time_adjust = 0; /* stop active adjtime() */ time_status |= STA_UNSYNC; - time_state = TIME_ERROR; /* p. 24, (a) */ + time_state = TIME_ERROR; /* p. 24, (a) */ time_maxerror = NTP_PHASE_LIMIT; time_esterror = NTP_PHASE_LIMIT; restore_flags(flags); @@ -209,81 +182,23 @@ __initfunc(void time_init(void)) { -#ifndef CONFIG_MBX + if (ppc_md.time_init != NULL) + { + ppc_md.time_init(); + } + if ((_get_PVR() >> 16) == 1) { /* 601 processor: dec counts down by 128 every 128ns */ decrementer_count = DECREMENTER_COUNT_601; count_period_num = COUNT_PERIOD_NUM_601; count_period_den = COUNT_PERIOD_DEN_601; + } else if (!smp_processor_id()) { + ppc_md.calibrate_decr(); } - switch (_machine) { - case _MACH_Pmac: - xtime.tv_sec = pmac_get_rtc_time(); - if ( (_get_PVR() >> 16) != 1 && (!smp_processor_id()) ) - pmac_calibrate_decr(); - if ( !smp_processor_id() ) - set_rtc_time = pmac_set_rtc_time; - break; - case _MACH_chrp: - chrp_time_init(); - xtime.tv_sec = chrp_get_rtc_time(); - if ((_get_PVR() >> 16) != 1) - chrp_calibrate_decr(); - set_rtc_time = chrp_set_rtc_time; - break; - case _MACH_prep: - xtime.tv_sec = prep_get_rtc_time(); - prep_calibrate_decr(); - set_rtc_time = prep_set_rtc_time; - break; -#ifdef CONFIG_APUS - case _MACH_apus: - { - xtime.tv_sec = apus_get_rtc_time(); - apus_calibrate_decr(); - set_rtc_time = apus_set_rtc_time; - break; - } -#endif - } - xtime.tv_usec = 0; -#else /* CONFIG_MBX */ - mbx_calibrate_decr(); - set_rtc_time = mbx_set_rtc_time; - - /* First, unlock all of the registers we are going to modify. - * To protect them from corruption during power down, registers - * that are maintained by keep alive power are "locked". To - * modify these registers we have to write the key value to - * the key location associated with the register. - */ - ((immap_t *)IMAP_ADDR)->im_sitk.sitk_tbscrk = KAPWR_KEY; - ((immap_t *)IMAP_ADDR)->im_sitk.sitk_rtcsck = KAPWR_KEY; - + xtime.tv_sec = ppc_md.get_rtc_time(); + xtime.tv_usec = 0; - /* Disable the RTC one second and alarm interrupts. - */ - ((immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc &= - ~(RTCSC_SIE | RTCSC_ALE); - - /* Enabling the decrementer also enables the timebase interrupts - * (or from the other point of view, to get decrementer interrupts - * we have to enable the timebase). The decrementer interrupt - * is wired into the vector table, nothing to do here for that. - */ - ((immap_t *)IMAP_ADDR)->im_sit.sit_tbscr = - ((mk_int_int_mask(DEC_INTERRUPT) << 8) | - (TBSCR_TBF | TBSCR_TBE)); - if (request_irq(DEC_INTERRUPT, timebase_interrupt, 0, "tbint", NULL) != 0) - panic("Could not allocate timer IRQ!"); - - /* Get time from the RTC. - */ - xtime.tv_sec = ((immap_t *)IMAP_ADDR)->im_sit.sit_rtc; - xtime.tv_usec = 0; - -#endif /* CONFIG_MBX */ set_dec(decrementer_count); /* mark the rtc/on-chip timer as in sync * so we don't update right away @@ -291,109 +206,6 @@ last_rtc_update = xtime.tv_sec; } -#ifndef CONFIG_MBX -/* - * Uses the on-board timer to calibrate the on-chip decrementer register - * for prep systems. On the pmac the OF tells us what the frequency is - * but on prep we have to figure it out. - * -- Cort - */ -int calibrate_done = 0; -volatile int *done_ptr = &calibrate_done; -__initfunc(void prep_calibrate_decr(void)) -{ - unsigned long flags; - - /* the Powerstack II's have trouble with the timer so - * we use a default value -- Cort - */ - if ( (_prep_type == _PREP_Motorola) && - ((inb(0x800) & 0xF0) & 0x40) ) - { - unsigned long freq, divisor; - static unsigned long t2 = 0; - - t2 = 998700000/60; - freq = t2 * 60; /* try to make freq/1e6 an integer */ - divisor = 60; - printk("time_init: decrementer frequency = %lu/%lu (%luMHz)\n", - freq, divisor,t2>>20); - decrementer_count = freq / HZ / divisor; - count_period_num = divisor; - count_period_den = freq / 1000000; - return; - } - - - save_flags(flags); - -#define TIMER0_COUNT 0x40 -#define TIMER_CONTROL 0x43 - /* set timer to periodic mode */ - outb_p(0x34,TIMER_CONTROL);/* binary, mode 2, LSB/MSB, ch 0 */ - /* set the clock to ~100 Hz */ - outb_p(LATCH & 0xff , TIMER0_COUNT); /* LSB */ - outb(LATCH >> 8 , TIMER0_COUNT); /* MSB */ - - if (request_irq(0, prep_calibrate_decr_handler, 0, "timer", NULL) != 0) - panic("Could not allocate timer IRQ!"); - __sti(); - while ( ! *done_ptr ) /* nothing */; /* wait for calibrate */ - restore_flags(flags); - free_irq( 0, NULL); -} - -__initfunc(void prep_calibrate_decr_handler(int irq, void *dev, struct pt_regs * regs)) -{ - unsigned long freq, divisor; - static unsigned long t1 = 0, t2 = 0; - - if ( !t1 ) - t1 = get_dec(); - else if (!t2) - { - t2 = get_dec(); - t2 = t1-t2; /* decr's in 1/HZ */ - t2 = t2*HZ; /* # decrs in 1s - thus in Hz */ - freq = t2 * 60; /* try to make freq/1e6 an integer */ - divisor = 60; - printk("time_init: decrementer frequency = %lu/%lu (%luMHz)\n", - freq, divisor,t2>>20); - decrementer_count = freq / HZ / divisor; - count_period_num = divisor; - count_period_den = freq / 1000000; - *done_ptr = 1; - } -} - -#else /* CONFIG_MBX */ - -/* The decrementer counts at the system (internal) clock frequency divided by - * sixteen, or external oscillator divided by four. Currently, we only - * support the MBX, which is system clock divided by sixteen. - */ -__initfunc(void mbx_calibrate_decr(void)) -{ - bd_t *binfo = (bd_t *)res; - int freq, fp, divisor; - - if ((((immap_t *)IMAP_ADDR)->im_clkrst.car_sccr & 0x02000000) == 0) - printk("WARNING: Wrong decrementer source clock.\n"); - - /* The manual says the frequency is in Hz, but it is really - * as MHz. The value 'fp' is the number of decrementer ticks - * per second. - */ - fp = (binfo->bi_intfreq * 1000000) / 16; - freq = fp*60; /* try to make freq/1e6 an integer */ - divisor = 60; - printk("time_init: decrementer frequency = %d/%d\n", freq, divisor); - decrementer_count = freq / HZ / divisor; - count_period_num = divisor; - count_period_den = freq / 1000000; -} -#endif /* CONFIG_MBX */ - /* 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. @@ -439,6 +251,49 @@ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; +/* + * This only works for the Gregorian calendar - i.e. after 1752 (in the UK) + */ +void GregorianDay(struct rtc_time * tm) +{ + int leapsToDate; + int lastYear; + int day; + int MonthOffset[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; + + lastYear=tm->tm_year-1; + + /* + * Number of leap corrections to apply up to end of last year + */ + leapsToDate = lastYear/4 - lastYear/100 + lastYear/400; + + /* + * This year is a leap year if it is divisible by 4 except when it is + * divisible by 100 unless it is divisible by 400 + * + * e.g. 1904 was a leap year, 1900 was not, 1996 is, and 2000 will be + */ + if((tm->tm_year%4==0) && + ((tm->tm_year%100!=0) || (tm->tm_year%400==0)) && + (tm->tm_mon>2)) + { + /* + * We are past Feb. 29 in a leap year + */ + day=1; + } + else + { + day=0; + } + + day += lastYear*365 + leapsToDate + MonthOffset[tm->tm_mon-1] + + tm->tm_mday; + + tm->tm_wday=day%7; +} + void to_tm(int tim, struct rtc_time * tm) { register int i; @@ -467,6 +322,11 @@ /* Days are what is left over (+1) from all that. */ tm->tm_mday = day + 1; + + /* + * Determine the day of week + */ + GregorianDay(tm); } diff -ur --new-file old/linux/arch/ppc/kernel/time.h new/linux/arch/ppc/kernel/time.h --- old/linux/arch/ppc/kernel/time.h Wed Apr 15 02:33:58 1998 +++ new/linux/arch/ppc/kernel/time.h Thu Apr 29 21:39:01 1999 @@ -1,5 +1,5 @@ /* - * $Id: time.h,v 1.10 1998/04/01 07:46:03 geert Exp $ + * $Id: time.h,v 1.11 1999/03/18 04:16:34 cort Exp $ * Common time prototypes and such for all ppc machines. * * Written by Cort Dougan (cort@cs.nmt.edu) to merge @@ -9,32 +9,15 @@ #include /* time.c */ -void prep_calibrate_decr_handler(int, void *,struct pt_regs *); -void prep_calibrate_decr(void); -void pmac_calibrate_decr(void); -extern void apus_calibrate_decr(void); extern unsigned decrementer_count; extern unsigned count_period_num; extern unsigned count_period_den; -extern unsigned long mktime(unsigned int, unsigned int,unsigned int, +extern unsigned long mktime(unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int); extern void to_tm(int tim, struct rtc_time * tm); extern unsigned long last_rtc_update; -/* pmac/prep/chrp_time.c */ -unsigned long prep_get_rtc_time(void); -unsigned long pmac_get_rtc_time(void); -unsigned long chrp_get_rtc_time(void); -unsigned long apus_get_rtc_time(void); -int prep_set_rtc_time(unsigned long nowtime); -int pmac_set_rtc_time(unsigned long nowtime); -int chrp_set_rtc_time(unsigned long nowtime); -int apus_set_rtc_time(unsigned long nowtime); -void pmac_read_rtc_time(void); -void chrp_calibrate_decr(void); -void chrp_time_init(void); int via_calibrate_decr(void); -void mbx_calibrate_decr(void); /* Accessor functions for the decrementer register. */ static __inline__ unsigned int get_dec(void) diff -ur --new-file old/linux/arch/ppc/kernel/traps.c new/linux/arch/ppc/kernel/traps.c --- old/linux/arch/ppc/kernel/traps.c Tue Jan 5 20:13:56 1999 +++ new/linux/arch/ppc/kernel/traps.c Thu Apr 29 21:39:01 1999 @@ -191,13 +191,8 @@ { int fixed; -#ifdef __SMP__ - if (regs->msr & MSR_FP ) - smp_giveup_fpu(current); -#else - if (last_task_used_math == current) - giveup_fpu(); -#endif + if (regs->msr & MSR_FP) + giveup_fpu(current); fixed = fix_alignment(regs); if (fixed == 1) { regs->nip += 4; /* skip over emulated instruction */ diff -ur --new-file old/linux/arch/ppc/lib/locks.c new/linux/arch/ppc/lib/locks.c --- old/linux/arch/ppc/lib/locks.c Wed Dec 30 19:55:07 1998 +++ new/linux/arch/ppc/lib/locks.c Thu Mar 11 06:30:32 1999 @@ -1,5 +1,5 @@ /* - * $Id: locks.c,v 1.21 1998/12/28 10:28:53 paulus Exp $ + * $Id: locks.c,v 1.23 1999/02/12 07:06:32 cort Exp $ * * Locks for smp ppc * @@ -26,24 +26,18 @@ #ifdef DEBUG_LOCKS unsigned int stuck = INIT_STUCK; #endif /* DEBUG_LOCKS */ - /* try expensive atomic load/store to get lock */ - while((unsigned long )xchg_u32((void *)&lock->lock,0xffffffff)) { - /* try cheap load until it's free */ - while(lock->lock) { + while (__spin_trylock(&lock->lock)) { #ifdef DEBUG_LOCKS - if(!--stuck) - { - printk("_spin_lock(%p) CPU#%d NIP %p" - " holder: cpu %ld pc %08lX\n", - lock, cpu, __builtin_return_address(0), - lock->owner_cpu,lock->owner_pc); - stuck = INIT_STUCK; - /* steal the lock */ - /*xchg_u32((void *)&lock->lock,0);*/ - } -#endif /* DEBUG_LOCKS */ - barrier(); + if(!--stuck) { + printk("_spin_lock(%p) CPU#%d NIP %p" + " holder: cpu %ld pc %08lX\n", + lock, cpu, __builtin_return_address(0), + lock->owner_cpu,lock->owner_pc); + stuck = INIT_STUCK; + /* steal the lock */ + /*xchg_u32((void *)&lock->lock,0);*/ } +#endif /* DEBUG_LOCKS */ } lock->owner_pc = (unsigned long)__builtin_return_address(0); lock->owner_cpu = cpu; @@ -51,15 +45,11 @@ int spin_trylock(spinlock_t *lock) { - unsigned long result; - - result = (unsigned long )xchg_u32((void *)&lock->lock,0xffffffff); - if ( !result ) - { - lock->owner_cpu = smp_processor_id(); - lock->owner_pc = (unsigned long)__builtin_return_address(0); - } - return (result == 0); + if (__spin_trylock(&lock->lock)) + return 0; + lock->owner_cpu = smp_processor_id(); + lock->owner_pc = (unsigned long)__builtin_return_address(0); + return 1; } @@ -76,11 +66,11 @@ lp->owner_pc,lp->lock); #endif /* DEBUG_LOCKS */ lp->owner_pc = lp->owner_cpu = 0; - eieio(); /* actually I believe eieio only orders */ - lp->lock = 0; /* non-cacheable accesses (on 604 at least) */ - eieio(); /* - paulus. */ + wmb(); + lp->lock = 0; + wmb(); } - + /* * Just like x86, implement read-write locks as a 32-bit counter * with the high bit (sign) being the "write" bit. @@ -95,6 +85,7 @@ again: /* get our read lock in there */ + wmb(); atomic_inc((atomic_t *) &(rw)->lock); if ( (signed long)((rw)->lock) < 0) /* someone has a write lock */ { @@ -114,6 +105,7 @@ /* try to get the read lock again */ goto again; } + wmb(); } void _read_unlock(rwlock_t *rw) @@ -124,7 +116,9 @@ current->comm,current->pid,current->tss.regs->nip, rw->lock); #endif /* DEBUG_LOCKS */ + wmb(); atomic_dec((atomic_t *) &(rw)->lock); + wmb(); } void _write_lock(rwlock_t *rw) @@ -134,7 +128,8 @@ int cpu = smp_processor_id(); #endif /* DEBUG_LOCKS */ -again: +again: + wmb(); if ( test_and_set_bit(31,&(rw)->lock) ) /* someone has a write lock */ { while ( (rw)->lock & (1<<31) ) /* wait for write lock */ @@ -170,6 +165,7 @@ } goto again; } + wmb(); } void _write_unlock(rwlock_t *rw) @@ -180,7 +176,9 @@ current->comm,current->pid,current->tss.regs->nip, rw->lock); #endif /* DEBUG_LOCKS */ + wmb(); clear_bit(31,&(rw)->lock); + wmb(); } void __lock_kernel(struct task_struct *task) @@ -196,24 +194,18 @@ } #endif /* DEBUG_LOCKS */ - if ( atomic_inc_return((atomic_t *) &task->lock_depth) != 1 ) + if (atomic_inc_return((atomic_t *) &task->lock_depth) != 1) return; /* mine! */ - while ( xchg_u32( (void *)&klock_info.kernel_flag, KLOCK_HELD) ) - { - /* try cheap load until it's free */ - while(klock_info.kernel_flag) { + while (__spin_trylock(&klock_info.kernel_flag)) { #ifdef DEBUG_LOCKS - if(!--stuck) - { - printk("_lock_kernel() CPU#%d NIP %p\n", - smp_processor_id(), - __builtin_return_address(0)); - stuck = INIT_STUCK; - } -#endif /* DEBUG_LOCKS */ - barrier(); + if(!--stuck) { + printk("_lock_kernel() CPU#%d NIP %p\n", + smp_processor_id(), + __builtin_return_address(0)); + stuck = INIT_STUCK; } +#endif /* DEBUG_LOCKS */ } klock_info.akp = smp_processor_id(); @@ -223,7 +215,7 @@ void __unlock_kernel(struct task_struct *task) { #ifdef DEBUG_LOCKS - if ( (task->lock_depth == 0) || (klock_info.kernel_flag != KLOCK_HELD) ) + if ((task->lock_depth == 0) || (klock_info.kernel_flag != KLOCK_HELD)) { printk("__unlock_kernel(): %s/%d (nip %08lX) " "lock depth %x flags %lx\n", @@ -234,10 +226,13 @@ return; } #endif /* DEBUG_LOCKS */ - if ( atomic_dec_and_test((atomic_t *) &task->lock_depth) ) + if (atomic_dec_and_test((atomic_t *) &task->lock_depth)) { + wmb(); klock_info.akp = NO_PROC_ID; + wmb(); klock_info.kernel_flag = KLOCK_CLEAR; + wmb(); } } @@ -249,5 +244,5 @@ __lock_kernel(task); task->lock_depth = depth; __sti(); - } + } } diff -ur --new-file old/linux/arch/ppc/lib/strcase.c new/linux/arch/ppc/lib/strcase.c --- old/linux/arch/ppc/lib/strcase.c Sat Aug 16 18:51:08 1997 +++ new/linux/arch/ppc/lib/strcase.c Thu Apr 29 21:39:01 1999 @@ -10,3 +10,14 @@ } while (c1 == c2 && c1 != 0); return c1 - c2; } + +int strncasecmp(const char *s1, const char *s2, int n) +{ + int c1, c2; + + do { + c1 = tolower(*s1++); + c2 = tolower(*s2++); + } while ((--n > 0) && c1 == c2 && c1 != 0); + return c1 - c2; +} diff -ur --new-file old/linux/arch/ppc/lib/string.S new/linux/arch/ppc/lib/string.S --- old/linux/arch/ppc/lib/string.S Wed Sep 30 19:14:17 1998 +++ new/linux/arch/ppc/lib/string.S Fri Apr 16 17:20:23 1999 @@ -8,7 +8,6 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ -#include #include "../kernel/ppc_asm.tmpl" #include #include @@ -321,8 +320,6 @@ .long 75b,76b .text -#undef CLEAR_USE_DCBZ 1 -#undef CLEAR_NO_CACHE 1 .globl __clear_user __clear_user: addi r6,r3,-4 @@ -333,15 +330,6 @@ /* clear a single word */ 11: stwu r5,4(r6) beqlr -#if defined(CLEAR_NO_CACHE) && defined (CONFIG_6xx) - /* - * no reason to turn off the cache for a single word - * or a few bytes -- Cort - */ - mfspr r7,HID0 - ori r8,r7,HID0_DLOCK - mtspr HID0,r8 -#endif /* CLEAR_NO_CACHE */ /* clear word sized chunks */ andi. r0,r6,3 add r4,r0,r4 @@ -353,10 +341,6 @@ 1: stwu r5,4(r6) bdnz 1b 6: andi. r4,r4,3 -#if defined(CLEAR_NO_CACHE) && defined (CONFIG_6xx) - /* restore the original state of HID0 in case cache was off -- Cort */ - mtspr HID0,r7 -#endif /* CLEAR_NO_CACHE */ /* clear byte sized chunks */ 7: cmpwi 0,r4,0 beqlr @@ -371,9 +355,6 @@ .align 2 .long 11b,99b .long 1b,99b -#ifdef CLEAR_USE_DCBZ - /*.long 66b,99b*/ -#endif .long 8b,99b .text diff -ur --new-file old/linux/arch/ppc/mbx_defconfig new/linux/arch/ppc/mbx_defconfig --- old/linux/arch/ppc/mbx_defconfig Wed Dec 23 16:34:11 1998 +++ new/linux/arch/ppc/mbx_defconfig Thu Mar 11 06:30:32 1999 @@ -14,8 +14,8 @@ # CONFIG_ALL_PPC is not set # CONFIG_APUS is not set CONFIG_MBX=y -CONFIG_SMP=n CONFIG_MACH_SPECIFIC=y +# CONFIG_SMP is not set CONFIG_SERIAL_CONSOLE=y # @@ -58,8 +58,26 @@ # Block devices # # CONFIG_BLK_DEV_FD is not set -# CONFIG_BLK_DEV_IDE is not set -# CONFIG_BLK_DEV_HD_ONLY is not set +CONFIG_BLK_DEV_IDE=y +# CONFIG_BLK_DEV_HD_IDE is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_RZ1000 is not set +CONFIG_BLK_DEV_IDEPCI=y +CONFIG_BLK_DEV_IDEDMA=y +# CONFIG_BLK_DEV_OFFBOARD is not set +CONFIG_IDEDMA_AUTO=y +# CONFIG_BLK_DEV_OPTI621 is not set +# CONFIG_BLK_DEV_TRM290 is not set +# CONFIG_BLK_DEV_NS87415 is not set +# CONFIG_BLK_DEV_VIA82C586 is not set +# CONFIG_BLK_DEV_CMD646 is not set +CONFIG_BLK_DEV_SL82C105=y +# CONFIG_IDE_CHIPSETS is not set # CONFIG_BLK_DEV_LOOP is not set # CONFIG_BLK_DEV_NBD is not set # CONFIG_BLK_DEV_MD is not set @@ -75,7 +93,6 @@ # CONFIG_PACKET is not set # CONFIG_NETLINK is not set # CONFIG_FIREWALL is not set -# CONFIG_NET_ALIAS is not set # CONFIG_FILTER is not set CONFIG_UNIX=y CONFIG_INET=y @@ -91,7 +108,7 @@ # CONFIG_SYN_COOKIES is not set # CONFIG_INET_RARP is not set CONFIG_IP_NOSR=y -# CONFIG_SKB_LARGE is not set +CONFIG_SKB_LARGE=y # CONFIG_IPV6 is not set # CONFIG_IPX is not set # CONFIG_ATALK is not set @@ -103,7 +120,11 @@ # CONFIG_WAN_ROUTER is not set # CONFIG_NET_FASTROUTE is not set # CONFIG_NET_HW_FLOWCONTROL is not set -# CONFIG_CPU_IS_SLOW is not set +CONFIG_CPU_IS_SLOW=y + +# +# QoS and/or fair queueing +# # CONFIG_NET_SCHED is not set # @@ -127,6 +148,7 @@ # CONFIG_NET_VENDOR_RACAL is not set # CONFIG_RTL8139 is not set # CONFIG_YELLOWFIN is not set +# CONFIG_ACENIC is not set # CONFIG_NET_ISA is not set # CONFIG_NET_EISA is not set # CONFIG_NET_POCKET is not set @@ -139,6 +161,8 @@ # CONFIG_TR is not set # CONFIG_SHAPER is not set # CONFIG_HOSTESS_SV11 is not set +# CONFIG_COSA is not set +# CONFIG_RCPCI is not set # # Amateur Radio support @@ -162,7 +186,8 @@ # # Character devices # -# CONFIG_VT is not set +CONFIG_VT=y +# CONFIG_VT_CONSOLE is not set CONFIG_SERIAL=y CONFIG_SERIAL_CONSOLE=y # CONFIG_SERIAL_EXTENDED is not set @@ -171,9 +196,17 @@ # CONFIG_MOUSE is not set # CONFIG_QIC02_TAPE is not set # CONFIG_WATCHDOG is not set +# CONFIG_NVRAM is not set # CONFIG_RTC is not set + +# +# Video For Linux +# # CONFIG_VIDEO_DEV is not set -# CONFIG_NVRAM is not set + +# +# Joystick support +# # CONFIG_JOYSTICK is not set # @@ -185,35 +218,46 @@ # Filesystems # # CONFIG_QUOTA is not set -# CONFIG_MINIX_FS is not set -# CONFIG_EXT2_FS is not set -# CONFIG_ISO9660_FS is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set # CONFIG_FAT_FS is not set # CONFIG_MSDOS_FS is not set # CONFIG_UMSDOS_FS is not set # CONFIG_VFAT_FS is not set +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_MINIX_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_ROMFS_FS is not set +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=y CONFIG_ROOT_NFS=y # CONFIG_NFSD is not set 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_AFFS_FS is not set -# CONFIG_HFS_FS is not set -# CONFIG_ROMFS_FS is not set -# CONFIG_AUTOFS_FS is not set -# CONFIG_UFS_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_SMD_DISKLABEL is not set # CONFIG_SOLARIS_X86_PARTITION is not set -# CONFIG_ADFS_FS is not set -# CONFIG_QNX4FS_FS is not set -# CONFIG_MAC_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set # CONFIG_NLS is not set # diff -ur --new-file old/linux/arch/ppc/mbxboot/Makefile new/linux/arch/ppc/mbxboot/Makefile --- old/linux/arch/ppc/mbxboot/Makefile Thu Jan 1 01:00:00 1970 +++ new/linux/arch/ppc/mbxboot/Makefile Fri Mar 19 19:50:03 1999 @@ -0,0 +1,101 @@ +# +# arch/ppc/boot/Makefile +# +# 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 by Linus Torvalds +# Adapted for PowerPC by Gary Thomas +# modified by Cort (cort@cs.nmt.edu) +# +.c.s: + $(CC) $(CFLAGS) -S -o $*.s $< +.s.o: + $(AS) -o $*.o $< +.c.o: + $(CC) $(CFLAGS) -DINITRD_OFFSET=$(IOFF) -DINITRD_SIZE=$(ISZ) -DZIMAGE_OFFSET=$(ZOFF) -DZIMAGE_SIZE=$(ZSZ) -DKERNELBASE=$(KERNELBASE) -c -o $*.o $< +.S.s: + $(CC) -D__ASSEMBLY__ -traditional -E -o $*.o $< +.S.o: + $(CC) -D__ASSEMBLY__ -traditional -c -o $*.o $< + +ZOFF = 0 +ZSZ = 0 +IOFF = 0 +ISZ = 0 + +TFTPIMAGE=/tftpboot/zImage.mbx +ZLINKFLAGS = -T ../vmlinux.lds -Ttext 0x00100000 +GZIP_FLAGS = -v9 + +OBJECTS := head.o misc.o ../coffboot/zlib.o mbxtty.o +CFLAGS = -O2 -DSTDC_HEADERS -fno-builtin -I$(TOPDIR)/include -DCONFIG_MBX +OBJCOPY = $(CROSS_COMPILE)objcopy +OBJCOPY_ARGS = -O elf32-powerpc + +all: zImage + +zvmlinux.initrd: zvmlinux + $(LD) $(ZLINKFLAGS) -o zvmlinux.initrd.tmp $(OBJECTS) + $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \ + --add-section=initrd=ramdisk.image.gz \ + --add-section=image=../coffboot/vmlinux.gz \ + zvmlinux.initrd.tmp zvmlinux.initrd + $(CC) $(CFLAGS) -DINITRD_OFFSET=`sh offset $(OBJDUMP) zvmlinux.initrd initrd` \ + -DINITRD_SIZE=`sh size $(OBJDUMP) zvmlinux.initrd initrd` \ + -DZIMAGE_OFFSET=`sh offset $(OBJDUMP) zvmlinux.initrd image` \ + -DZIMAGE_SIZE=`sh size $(OBJDUMP) zvmlinux.initrd image` \ + -DKERNELBASE=$(KERNELBASE) -c -o misc.o misc.c + $(LD) $(ZLINKFLAGS) -o zvmlinux.initrd.tmp $(OBJECTS) + $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \ + --add-section=initrd=ramdisk.image.gz \ + --add-section=image=../coffboot/vmlinux.gz \ + zvmlinux.initrd.tmp $@ + rm zvmlinux.initrd.tmp + +zImage: zvmlinux + ln -sf zvmlinux zImage + +zImage.initrd: zvmlinux.initrd + ln -sf zvmlinux.initrd zImage.initrd + +zvmlinux: $(OBJECTS) ../coffboot/vmlinux.gz +# +# build the boot loader image and then compute the offset into it +# for the kernel image +# + $(LD) $(ZLINKFLAGS) -o zvmlinux.tmp $(OBJECTS) + $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment --add-section=image=../coffboot/vmlinux.gz \ + zvmlinux.tmp $@ +# +# then with the offset rebuild the bootloader so we know where the kernel is +# + $(CC) $(CFLAGS) -DINITRD_OFFSET=0 -DINITRD_SIZE=0 \ + -DZIMAGE_OFFSET=`sh offset $(OBJDUMP) zvmlinux image` \ + -DZIMAGE_SIZE=`sh size $(OBJDUMP) zvmlinux image` -DKERNELBASE=$(KERNELBASE) \ + -c -o misc.o misc.c + $(LD) $(ZLINKFLAGS) -o zvmlinux.tmp $(OBJECTS) + $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment --add-section=image=../coffboot/vmlinux.gz \ + zvmlinux.tmp $@ + rm zvmlinux.tmp + +znetboot : zImage + cp zImage $(TFTPIMAGE) + +znetboot.initrd : zImage.initrd + cp zImage.initrd $(TFTPIMAGE) + +clean: + rm -f vmlinux* zvmlinux* zImage* + +fastdep: + $(TOPDIR)/scripts/mkdep *.[Sch] > .depend + +dep: + $(CPP) -M *.S *.c > .depend + +# just here to match coffboot/Makefile +vmlinux.coff: + +vmlinux.coff.initrd: diff -ur --new-file old/linux/arch/ppc/mbxboot/head.S new/linux/arch/ppc/mbxboot/head.S --- old/linux/arch/ppc/mbxboot/head.S Thu Jan 1 01:00:00 1970 +++ new/linux/arch/ppc/mbxboot/head.S Thu Apr 29 21:39:01 1999 @@ -0,0 +1,200 @@ +#include "../kernel/ppc_defs.h" +#include "../kernel/ppc_asm.tmpl" +#include +#include + + .text + +/* + * $Id: head.S,v 1.4 1999/04/22 06:32:09 davem Exp $ + * + * This code is loaded by the ROM loader at some arbitrary location. + * Move it to high memory so that it can load the kernel at 0x0000. + * + * The MBX EPPC-Bug understands ELF, so it loads us into the location + * specified in the header. This is a two step process. First, EPPC-Bug + * loads the file into the intermediate buffer memory location specified + * by the environment parameters. When it discovers this is an ELF + * binary, it relocates to the link address for us. Unfortunately, the + * header does not move with the file, so we have to find the + * intermediate load location and read the header from there. From + * information provided by Motorola (thank you), we know this intermediate + * location can be found from the NVRAM environment. + * All of these addresses must be somewhat carefully chosen to make sure + * we don't overlap the regions. I chose to load the kernel at 0, the + * compressed image loads at 0x00100000, and the MBX intermediate buffer + * was set to 0x00200000. Provided the loaded kernel image never grows + * over one megabyte (which I am going to ensure never happens :-), these + * will work fine. When we get called from EPPC-Bug, registers are: + * R1 - Stack pointer at a high memory address. + * R3 - Pointer to Board Information Block. + * R4 - Pointer to argument string. + * Interrupts masked, cache and MMU disabled. + */ + + .globl start +start: + bl start_ +start_: + mr r11,r3 /* Save pointer to residual/board data */ +/* Clear all of BSS */ + lis r3,edata@h + ori r3,r3,edata@l + lis r4,end@h + ori r4,r4,end@l + subi r3,r3,4 + subi r4,r4,4 + li r0,0 +50: stwu r0,4(r3) + cmp 0,r3,r4 + bne 50b +90: mr r9,r1 /* Save old stack pointer (in case it matters) */ + lis r1,.stack@h + ori r1,r1,.stack@l + addi r1,r1,4096*2 + subi r1,r1,256 + li r2,0x000F /* Mask pointer to 16-byte boundary */ + andc r1,r1,r2 +/* Run loader */ + mr r3, r11 + mr r21, r11 + bl serial_init /* Init MBX serial port */ + + lis r8, 0xfa200000@h /* Disable Ethernet SCC */ + li r0, 0 + stw r0, 0x0a00(r8) + + mr r11, r21 + lis r8,start@h + ori r8,r8,start@l + lis r9,end@h + ori r9,r9,end@l + sub r7,r8,r9 + srwi r7,r7,2 +#define ILAP_ADDRESS 0xfa000020 + lis r8, ILAP_ADDRESS@h + lwz r8, ILAP_ADDRESS@l(r8) + addis r8, r8, 1 /* Add 64K */ + mr r3,r8 /* Load point */ + mr r4,r7 /* Program length */ + mr r5,r6 /* Checksum */ + mr r6,r11 /* Residual data */ + bl decompress_kernel + + /* changed to use r3 (as firmware does) for kernel + as ptr to residual -- Cort*/ + lis r6,cmd_line@h + ori r6,r6,cmd_line@l + lwz r6, 0(r6) + subi r7,r6,1 +00: lbzu r2,1(r7) + cmpi 0,r2,0 + bne 00b + + /* r4,r5 have initrd_start, size */ + lis r2,initrd_start@h + ori r2,r2,initrd_start@l + lwz r4,0(r2) + lis r2,initrd_end@h + ori r2,r2,initrd_end@l + lwz r5,0(r2) + + /* tell kernel we're prep */ + /* + * get start address of kernel code which is stored as a coff + * entry. see boot/head.S -- Cort + */ + li r9,0x0 + lwz r9,0(r9) + mtlr r9 + blr +hang: + b hang + +/* + * Delay for a number of microseconds + * -- Use the BUS timer (assumes 66MHz) + */ + .globl udelay +udelay: + mfspr r4,PVR + srwi r4,r4,16 + cmpi 0,r4,1 /* 601 ? */ + bne .udelay_not_601 +00: li r0,86 /* Instructions / microsecond? */ + mtctr r0 +10: addi r0,r0,0 /* NOP */ + bdnz 10b + subic. r3,r3,1 + bne 00b + blr + +.udelay_not_601: + mulli r4,r3,1000 /* nanoseconds */ + addi r4,r4,59 + li r5,60 + divw r4,r4,r5 /* BUS ticks */ +1: mftbu r5 + mftb r6 + mftbu r7 + cmp 0,r5,r7 + bne 1b /* Get [synced] base time */ + addc r9,r6,r4 /* Compute end time */ + addze r8,r5 +2: mftbu r5 + cmp 0,r5,r8 + blt 2b + bgt 3f + mftb r6 + cmp 0,r6,r9 + blt 2b +3: blr + +.globl _get_HID0 +_get_HID0: + mfspr r3,HID0 + blr + +.globl _put_HID0 +_put_HID0: + mtspr HID0,r3 + blr + +.globl _get_MSR +_get_MSR: + mfmsr r3 + blr + +.globl _put_MSR +_put_MSR: + mtmsr r3 + blr + +/* + * Flush instruction cache + * *** I'm really paranoid here! + */ +_GLOBAL(flush_instruction_cache) + mflr r5 + bl flush_data_cache + mtlr r5 + blr + +#define NUM_CACHE_LINES 128*8 +#define CACHE_LINE_SIZE 32 +#define cache_flush_buffer 0x1000 + +/* + * Flush data cache + * *** I'm really paranoid here! + */ +_GLOBAL(flush_data_cache) + lis r3,cache_flush_buffer@h + ori r3,r3,cache_flush_buffer@l + li r4,NUM_CACHE_LINES + mtctr r4 +00: lwz r4,0(r3) + addi r3,r3,CACHE_LINE_SIZE /* Next line, please */ + bdnz 00b +10: blr + .comm .stack,4096*2,4 diff -ur --new-file old/linux/arch/ppc/mbxboot/mbxtty.c new/linux/arch/ppc/mbxboot/mbxtty.c --- old/linux/arch/ppc/mbxboot/mbxtty.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/ppc/mbxboot/mbxtty.c Fri Mar 19 19:50:03 1999 @@ -0,0 +1,201 @@ + + +/* Minimal serial functions needed to send messages out the serial + * port on the MBX console. + * + * The MBX uxes SMC1 for the serial port. We reset the port and use + * only the first BD that EPPC-Bug set up as a character FIFO. + * + * Later versions (at least 1.4, maybe earlier) of the MBX EPPC-Bug + * use COM1 instead of SMC1 as the console port. This kinda sucks + * for the rest of the kernel, so here we force the use of SMC1 again. + * I f**ked around for a day trying to figure out how to make EPPC-Bug + * use SMC1, but gave up and decided to fix it here. + */ +#include +#include +#ifdef CONFIG_MBX +#include +#endif +#ifdef CONFIG_FADS +#include +#endif +#include "../8xx_io/commproc.h" + +#ifdef CONFIG_MBX +#define MBX_CSR1 ((volatile u_char *)0xfa100000) +#define CSR1_COMEN (u_char)0x02 +#endif + +static cpm8xx_t *cpmp = (cpm8xx_t *)&(((immap_t *)IMAP_ADDR)->im_cpm); + +void +serial_init(bd_t *bd) +{ + volatile smc_t *sp; + volatile smc_uart_t *up; + volatile cbd_t *tbdf, *rbdf; + volatile cpm8xx_t *cp; + uint dpaddr, memaddr; + + cp = cpmp; + sp = (smc_t*)&(cp->cp_smc[0]); + up = (smc_uart_t *)&cp->cp_dparam[PROFF_SMC1]; + + /* Disable transmitter/receiver. + */ + sp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN); + +#ifdef CONFIG_MBX + if (*MBX_CSR1 & CSR1_COMEN) { + /* COM1 is enabled. Initialize SMC1 and use it for + * the console port. + */ + + /* Enable SDMA. + */ + ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sdcr = 1; + + /* Use Port B for SMCs instead of other functions. + */ + cp->cp_pbpar |= 0x00000cc0; + cp->cp_pbdir &= ~0x00000cc0; + cp->cp_pbodr &= ~0x00000cc0; + + /* Allocate space for two buffer descriptors in the DP ram. + * For now, this address seems OK, but it may have to + * change with newer versions of the firmware. + */ + dpaddr = 0x0800; + + /* Grab a few bytes from the top of memory. EPPC-Bug isn't + * running any more, so we can do this. + */ + memaddr = (bd->bi_memsize - 32) & ~15; + + /* Set the physical address of the host memory buffers in + * the buffer descriptors. + */ + rbdf = (cbd_t *)&cp->cp_dpmem[dpaddr]; + rbdf->cbd_bufaddr = memaddr; + rbdf->cbd_sc = 0; + tbdf = rbdf + 1; + tbdf->cbd_bufaddr = memaddr+4; + tbdf->cbd_sc = 0; + + /* Set up the uart parameters in the parameter ram. + */ + up->smc_rbase = dpaddr; + up->smc_tbase = dpaddr+sizeof(cbd_t); + up->smc_rfcr = SMC_EB; + up->smc_tfcr = SMC_EB; + + /* Set UART mode, 8 bit, no parity, one stop. + * Enable receive and transmit. + */ + sp->smc_smcmr = smcr_mk_clen(9) | SMCMR_SM_UART; + + /* Mask all interrupts and remove anything pending. + */ + sp->smc_smcm = 0; + sp->smc_smce = 0xff; + + /* Set up the baud rate generator. + * See 8xx_io/commproc.c for details. + */ + cp->cp_simode = 0x10000000; + cp->cp_brgc1 = + ((((bd->bi_intfreq * 1000000)/16) / 9600) << 1) | CPM_BRG_EN; + + /* Enable SMC1 for console output. + */ + *MBX_CSR1 &= ~CSR1_COMEN; + } + else { +#endif + /* SMC1 is used as console port. + */ + tbdf = (cbd_t *)&cp->cp_dpmem[up->smc_tbase]; + rbdf = (cbd_t *)&cp->cp_dpmem[up->smc_rbase]; + + /* Issue a stop transmit, and wait for it. + */ + cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SMC1, + CPM_CR_STOP_TX) | CPM_CR_FLG; + while (cp->cp_cpcr & CPM_CR_FLG); +#ifdef CONFIG_MBX + } +#endif + + /* Make the first buffer the only buffer. + */ + tbdf->cbd_sc |= BD_SC_WRAP; + rbdf->cbd_sc |= BD_SC_EMPTY | BD_SC_WRAP; + + /* Single character receive. + */ + up->smc_mrblr = 1; + up->smc_maxidl = 0; + + /* Initialize Tx/Rx parameters. + */ + cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SMC1, CPM_CR_INIT_TRX) | CPM_CR_FLG; + while (cp->cp_cpcr & CPM_CR_FLG); + + /* Enable transmitter/receiver. + */ + sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN; +} + +void +serial_putchar(const char c) +{ + volatile cbd_t *tbdf; + volatile char *buf; + volatile smc_uart_t *up; + + up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_SMC1]; + tbdf = (cbd_t *)&cpmp->cp_dpmem[up->smc_tbase]; + + /* Wait for last character to go. + */ + buf = (char *)tbdf->cbd_bufaddr; + while (tbdf->cbd_sc & BD_SC_READY); + + *buf = c; + tbdf->cbd_datlen = 1; + tbdf->cbd_sc |= BD_SC_READY; +} + +char +serial_getc() +{ + volatile cbd_t *rbdf; + volatile char *buf; + volatile smc_uart_t *up; + char c; + + up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_SMC1]; + rbdf = (cbd_t *)&cpmp->cp_dpmem[up->smc_rbase]; + + /* Wait for character to show up. + */ + buf = (char *)rbdf->cbd_bufaddr; + while (rbdf->cbd_sc & BD_SC_EMPTY); + c = *buf; + rbdf->cbd_sc |= BD_SC_EMPTY; + + return(c); +} + +int +serial_tstc() +{ + volatile cbd_t *rbdf; + volatile smc_uart_t *up; + + up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_SMC1]; + rbdf = (cbd_t *)&cpmp->cp_dpmem[up->smc_rbase]; + + return(!(rbdf->cbd_sc & BD_SC_EMPTY)); +} diff -ur --new-file old/linux/arch/ppc/mbxboot/misc.c new/linux/arch/ppc/mbxboot/misc.c --- old/linux/arch/ppc/mbxboot/misc.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/ppc/mbxboot/misc.c Fri Mar 19 19:50:03 1999 @@ -0,0 +1,637 @@ +/* + * misc.c + * + * $Id: misc.c,v 1.1 1999/02/17 05:00:06 cort Exp $ + * + * Adapted for PowerPC by Gary Thomas + * + * Rewritten by Cort Dougan (cort@cs.nmt.edu) + * One day to be replaced by a single bootloader for chrp/prep/pmac. -- Cort + */ + +#include +#include "../coffboot/zlib.h" +#include "asm/residual.h" +#include +#include +#include +#include +#include +#ifdef CONFIG_MBX +#include +#endif +#ifdef CONFIG_FADS +#include +#endif + +/* + * Please send me load/board info and such data for hardware not + * listed here so I can keep track since things are getting tricky + * with the different load addrs with different firmware. This will + * help to avoid breaking the load/boot process. + * -- Cort + */ +char *avail_ram; +char *end_avail; + +/* Because of the limited amount of memory on the MBX, it presents + * loading problems. The biggest is that we load this boot program + * into a relatively low memory address, and the Linux kernel Bss often + * extends into this space when it get loaded. When the kernel starts + * and zeros the BSS space, it also writes over the information we + * save here and pass to the kernel (command line and board info). + * On the MBX we grab some known memory holes to hold this information. + */ +#if defined(CONFIG_SERIAL_CONSOLE) +char cmd_preset[] = "console=ttyS0,9600n8"; +#else +char cmd_preset[] = ""; +#endif +char cmd_buf[256]; +char *cmd_line = cmd_buf; + +char *root_string = "root=/dev/nfs"; +char *nfsaddrs_string = "nfsaddrs="; +char *nfsroot_string = "nfsroot="; +char *defroot_string = "/sys/mbxroot"; +int do_ipaddrs(char **cmd_cp, int echo); +void do_nfsroot(char **cmd_cp, char *dp); +int strncmp(const char * cs,const char * ct,size_t count); +char *strrchr(const char * s, int c); + +RESIDUAL hold_resid_buf; +RESIDUAL *hold_residual = &hold_resid_buf; +unsigned long initrd_start = 0, initrd_end = 0; +char *zimage_start; +int zimage_size; + +char *vidmem = (char *)0xC00B8000; +int lines, cols; +int orig_x, orig_y; + +void puts(const char *); +void putc(const char c); +void puthex(unsigned long val); +void _bcopy(char *src, char *dst, int len); +void * memcpy(void * __dest, __const void * __src, + int __n); +void gunzip(void *, int, unsigned char *, int *); + +void pause() +{ + puts("pause\n"); +} + +void exit() +{ + puts("exit\n"); + while(1); +} + +/* The MBX is just the serial port. +*/ +tstc(void) +{ + return (serial_tstc()); +} + +getc(void) +{ + while (1) { + if (serial_tstc()) return (serial_getc()); + } +} + +void +putc(const char c) +{ + serial_putchar(c); +} + +void puts(const char *s) +{ + char c; + + while ( ( c = *s++ ) != '\0' ) { + serial_putchar(c); + if ( c == '\n' ) + serial_putchar('\r'); + } +} + + +void * memcpy(void * __dest, __const void * __src, + int __n) +{ + int i; + char *d = (char *)__dest, *s = (char *)__src; + + for (i=0;i<__n;i++) d[i] = s[i]; +} + +int memcmp(__const void * __dest, __const void * __src, + int __n) +{ + int i; + char *d = (char *)__dest, *s = (char *)__src; + + for (i=0;i<__n;i++, d++, s++) + { + if (*d != *s) + { + return (*s - *d); + } + } + return (0); +} + +void error(char *x) +{ + puts("\n\n"); + puts(x); + puts("\n\n -- System halted"); + + while(1); /* Halt */ +} + +void *zalloc(void *x, unsigned items, unsigned size) +{ + void *p = avail_ram; + + size *= items; + size = (size + 7) & -8; + avail_ram += size; + if (avail_ram > end_avail) { + puts("oops... out of memory\n"); + pause(); + } + return p; +} + +void zfree(void *x, void *addr, unsigned nb) +{ +} + +#define HEAD_CRC 2 +#define EXTRA_FIELD 4 +#define ORIG_NAME 8 +#define COMMENT 0x10 +#define RESERVED 0xe0 + +#define DEFLATED 8 + + +void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp) +{ + z_stream s; + int r, i, flags; + + /* skip header */ + i = 10; + flags = src[3]; + if (src[2] != DEFLATED || (flags & RESERVED) != 0) { + puts("bad gzipped data\n"); + exit(); + } + if ((flags & EXTRA_FIELD) != 0) + i = 12 + src[10] + (src[11] << 8); + if ((flags & ORIG_NAME) != 0) + while (src[i++] != 0) + ; + if ((flags & COMMENT) != 0) + while (src[i++] != 0) + ; + if ((flags & HEAD_CRC) != 0) + i += 2; + if (i >= *lenp) { + puts("gunzip: ran out of data in header\n"); + exit(); + } + + s.zalloc = zalloc; + s.zfree = zfree; + r = inflateInit2(&s, -MAX_WBITS); + if (r != Z_OK) { + puts("inflateInit2 returned %d\n"); + exit(); + } + s.next_in = src + i; + s.avail_in = *lenp - i; + s.next_out = dst; + s.avail_out = dstlen; + r = inflate(&s, Z_FINISH); + if (r != Z_OK && r != Z_STREAM_END) { + puts("inflate returned %d\n"); + exit(); + } + *lenp = s.next_out - (unsigned char *) dst; + inflateEnd(&s); +} + +unsigned char sanity[0x2000]; + +unsigned long +decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, RESIDUAL *residual) +{ + int timer; + extern unsigned long start; + char *cp, ch; + unsigned long i, motorola_id = 0; + char needs_reloc = 0; + BATU *u; + BATL *l; + char *dp; + + lines = 25; + cols = 80; + orig_x = 0; + orig_y = 24; + + /* Grab some space for the command line and board info. Since + * we no longer use the ELF header, but it was loaded, grab + * that space. + */ + cmd_line = (char *)(load_addr - 0x10000); + hold_residual = (RESIDUAL *)(cmd_line + sizeof(cmd_buf)); + /* copy board data */ + if (residual) + memcpy(hold_residual,residual,sizeof(bd_t)); + + /* MBX/prep sometimes put the residual/board info at the end of mem + * assume 16M for now -- Cort + * To boot on standard MBX boards with 4M, we can't use initrd, + * and we have to assume less memory. -- Dan + */ + if ( INITRD_OFFSET ) + end_avail = (char *)0x01000000; + else + end_avail = (char *)0x00400000; + + /* let residual data tell us it's higher */ + if ( (unsigned long)residual > 0x00800000 ) + end_avail = (char *)PAGE_ALIGN((unsigned long)residual); + + puts("loaded at: "); puthex(load_addr); + puts(" "); puthex((unsigned long)(load_addr + (4*num_words))); puts("\n"); + if ( (unsigned long)load_addr != (unsigned long)&start ) + { + puts("relocated to: "); puthex((unsigned long)&start); + puts(" "); + puthex((unsigned long)((unsigned long)&start + (4*num_words))); + puts("\n"); + } + + if ( residual ) + { + puts("board data at: "); puthex((unsigned long)residual); + puts(" "); + puthex((unsigned long)((unsigned long)residual + sizeof(bd_t))); + puts("\n"); + puts("relocated to: "); + puthex((unsigned long)hold_residual); + puts(" "); + puthex((unsigned long)((unsigned long)hold_residual + sizeof(bd_t))); + puts("\n"); + } + + /* we have to subtract 0x10000 here to correct for objdump including the + size of the elf header which we strip -- Cort */ + zimage_start = (char *)(load_addr - 0x10000 + ZIMAGE_OFFSET); + zimage_size = ZIMAGE_SIZE; + + if ( INITRD_OFFSET ) + initrd_start = load_addr - 0x10000 + INITRD_OFFSET; + else + initrd_start = 0; + initrd_end = INITRD_SIZE + initrd_start; + + /* + * setup avail_ram - this is the first part of ram usable + * by the uncompress code. -- Cort + */ + avail_ram = (char *)PAGE_ALIGN((unsigned long)zimage_start+zimage_size); + if ( ((load_addr+(num_words*4)) > (unsigned long) avail_ram) + && (load_addr <= 0x01000000) ) + avail_ram = (char *)(load_addr+(num_words*4)); + if ( (((unsigned long)&start+(num_words*4)) > (unsigned long) avail_ram) + && (load_addr <= 0x01000000) ) + avail_ram = (char *)((unsigned long)&start+(num_words*4)); + + /* relocate zimage */ + puts("zimage at: "); puthex((unsigned long)zimage_start); + puts(" "); puthex((unsigned long)(zimage_size+zimage_start)); puts("\n"); + /* + * don't relocate the zimage if it was loaded above 16M since + * things get weird if we try to relocate -- Cort + * We don't relocate zimage on a base MBX board because of + * insufficient memory. In this case we don't have initrd either, + * so use that as an indicator. -- Dan + */ + + /* Determine if we have a Motorola board */ + needs_reloc = 0; + if ( (( (unsigned long)zimage_start <= 0x01000000 ) && initrd_start) + || needs_reloc) + { + memcpy ((void *)PAGE_ALIGN(-PAGE_SIZE+(unsigned long)end_avail-zimage_size), + (void *)zimage_start, zimage_size ); + zimage_start = (char *)PAGE_ALIGN(-PAGE_SIZE+(unsigned long)end_avail-zimage_size); + end_avail = (char *)zimage_start; + puts("relocated to: "); puthex((unsigned long)zimage_start); + puts(" "); + puthex((unsigned long)zimage_size+(unsigned long)zimage_start); + puts("\n"); + } + + /* relocate initrd */ + if ( initrd_start ) + { + puts("initrd at: "); puthex(initrd_start); + puts(" "); puthex(initrd_end); puts("\n"); + /* + * Memory is really tight on the MBX (we can assume 4M) + * so put the initrd at the TOP of ram, and set end_avail + * to right after that. + * + * I should do something like this for prep, too and keep + * a variable end_of_DRAM to keep track of what we think the + * max ram is. + * -- Cort + */ + if (needs_reloc) + { + memcpy ((void *)PAGE_ALIGN(-PAGE_SIZE+ + (unsigned long)end_avail-INITRD_SIZE), + (void *)initrd_start, + INITRD_SIZE ); + initrd_start = PAGE_ALIGN(-PAGE_SIZE+ + (unsigned long)end_avail-INITRD_SIZE); + initrd_end = initrd_start + INITRD_SIZE; + end_avail = (char *)initrd_start; + puts("relocated to: "); puthex(initrd_start); + puts(" "); puthex(initrd_end); puts("\n"); + } + } + + puts("avail ram: "); puthex((unsigned long)avail_ram); puts(" "); + puthex((unsigned long)end_avail); puts("\n"); + + puts("\nLinux/PPC load: "); + timer = 0; + cp = cmd_line; + memcpy (cmd_line, cmd_preset, sizeof(cmd_preset)); + while ( *cp ) putc(*cp++); + while (timer++ < 5*1000) { + if (tstc()) { + while ((ch = getc()) != '\n' && ch != '\r') { + if (ch == '\b') { + if (cp != cmd_line) { + cp--; + puts("\b \b"); + } + } else if (ch == '?') { + if (!do_ipaddrs(&cp, 1)) { + *cp++ = ch; + putc(ch); + } + } else { + *cp++ = ch; + putc(ch); + } + } + break; /* Exit 'timer' loop */ + } + udelay(1000); /* 1 msec */ + } + *cp = 0; + /* The MBX does not currently have any default boot strategy. + * If the command line is not filled in, we will automatically + * create the default network boot. + */ + if (cmd_line[0] == 0) { + dp = root_string; + while (*dp != 0) + *cp++ = *dp++; + *cp++ = ' '; + + dp = nfsaddrs_string; + while (*dp != 0) + *cp++ = *dp++; + dp = cp; + do_ipaddrs(&cp, 0); + *cp++ = ' '; + + /* Add the server address to the root file system path. + */ + dp = strrchr(dp, ':'); + dp++; + do_nfsroot(&cp, dp); + *cp = 0; + } + puts("\n"); + + /* mappings on early boot can only handle 16M */ + if ( (int)(cmd_line[0]) > (16<<20)) + puts("cmd_line located > 16M\n"); + if ( (int)hold_residual > (16<<20)) + puts("hold_residual located > 16M\n"); + if ( initrd_start > (16<<20)) + puts("initrd_start located > 16M\n"); + + puts("Uncompressing Linux..."); + + gunzip(0, 0x400000, zimage_start, &zimage_size); + puts("done.\n"); + puts("Now booting the kernel\n"); + return (unsigned long)hold_residual; +} + +int +do_ipaddrs(char **cmd_cp, int echo) +{ + char *cp, *ip, ch; + unsigned char ipd; + int i, j, retval; + + /* We need to create the string: + * : + */ + cp = *cmd_cp; + retval = 0; + + if ((cp - 9) >= cmd_line) { + if (strncmp(cp - 9, "nfsaddrs=", 9) == 0) { + ip = (char *)0xfa000060; + retval = 1; + for (j=0; j<2; j++) { + for (i=0; i<4; i++) { + ipd = *ip++; + + ch = ipd/100; + if (ch) { + ch += '0'; + if (echo) + putc(ch); + *cp++ = ch; + ipd -= 100 * (ch - '0'); + } + + ch = ipd/10; + if (ch) { + ch += '0'; + if (echo) + putc(ch); + *cp++ = ch; + ipd -= 10 * (ch - '0'); + } + + ch = ipd + '0'; + if (echo) + putc(ch); + *cp++ = ch; + + ch = '.'; + if (echo) + putc(ch); + *cp++ = ch; + } + + /* At the end of the string, remove the + * '.' and replace it with a ':'. + */ + *(cp - 1) = ':'; + if (echo) { + putc('\b'); putc(':'); + } + } + + /* At the end of the second string, remove the + * '.' from both the command line and the + * screen. + */ + --cp; + putc('\b'); putc(' '); putc('\b'); + } + } + *cmd_cp = cp; + return(retval); +} + +void +do_nfsroot(char **cmd_cp, char *dp) +{ + char *cp, *rp, *ep; + + /* The boot argument (i.e /sys/mbxroot/zImage) is stored + * at offset 0x0078 in NVRAM. We use this path name to + * construct the root file system path. + */ + cp = *cmd_cp; + + /* build command string. + */ + rp = nfsroot_string; + while (*rp != 0) + *cp++ = *rp++; + + /* Add the server address to the path. + */ + while (*dp != ' ') + *cp++ = *dp++; + *cp++ = ':'; + + rp = (char *)0xfa000078; + ep = strrchr(rp, '/'); + + if (ep != 0) { + while (rp < ep) + *cp++ = *rp++; + } + else { + rp = defroot_string; + while (*rp != 0) + *cp++ = *rp++; + } + + *cmd_cp = cp; +} + +size_t strlen(const char * s) +{ + const char *sc; + + for (sc = s; *sc != '\0'; ++sc) + /* nothing */; + return sc - s; +} + +int strncmp(const char * cs,const char * ct,size_t count) +{ + register signed char __res = 0; + + while (count) { + if ((__res = *cs - *ct++) != 0 || !*cs++) + break; + count--; + } + + return __res; +} + +char * strrchr(const char * s, int c) +{ + const char *p = s + strlen(s); + do { + if (*p == (char)c) + return (char *)p; + } while (--p >= s); + return NULL; +} + +void puthex(unsigned long val) +{ + unsigned char buf[10]; + int i; + for (i = 7; i >= 0; i--) + { + buf[i] = "0123456789ABCDEF"[val & 0x0F]; + val >>= 4; + } + buf[8] = '\0'; + puts(buf); +} + +/* + * PCI/ISA I/O support + */ + +volatile unsigned char *ISA_io = (unsigned char *)0x80000000; +volatile unsigned char *ISA_mem = (unsigned char *)0xC0000000; + +void +outb(int port, char val) +{ + /* Ensure I/O operations complete */ + __asm__ volatile("eieio"); + ISA_io[port] = val; +} + +unsigned char +inb(int port) +{ + /* Ensure I/O operations complete */ + __asm__ volatile("eieio"); + return (ISA_io[port]); +} + +unsigned long +local_to_PCI(unsigned long addr) +{ + return ((addr & 0x7FFFFFFF) | 0x80000000); +} + +void +_bcopy(char *src, char *dst, int len) +{ + while (len--) *dst++ = *src++; +} diff -ur --new-file old/linux/arch/ppc/mbxboot/offset new/linux/arch/ppc/mbxboot/offset --- old/linux/arch/ppc/mbxboot/offset Thu Jan 1 01:00:00 1970 +++ new/linux/arch/ppc/mbxboot/offset Fri Mar 19 19:50:03 1999 @@ -0,0 +1,4 @@ +#!/bin/bash + +OFFSET=`$1 -h $2 | grep $3 | grep -v zvmlinux| awk '{print $6}'` +echo "0x"$OFFSET diff -ur --new-file old/linux/arch/ppc/mbxboot/size new/linux/arch/ppc/mbxboot/size --- old/linux/arch/ppc/mbxboot/size Thu Jan 1 01:00:00 1970 +++ new/linux/arch/ppc/mbxboot/size Fri Mar 19 19:50:03 1999 @@ -0,0 +1,4 @@ +#!/bin/bash + +OFFSET=`$1 -h $2 | grep $3 | grep -v zvmlinux | awk '{print $3}'` +echo "0x"$OFFSET diff -ur --new-file old/linux/arch/ppc/mm/fault.c new/linux/arch/ppc/mm/fault.c --- old/linux/arch/ppc/mm/fault.c Tue Jan 5 20:13:56 1999 +++ new/linux/arch/ppc/mm/fault.c Tue May 11 17:24:32 1999 @@ -140,7 +140,8 @@ if (!(vma->vm_flags & (VM_READ | VM_EXEC))) goto bad_area; } - handle_mm_fault(current, vma, address, error_code & 0x02000000); + if (!handle_mm_fault(current, vma, address, error_code & 0x02000000)) + goto bad_area; up(&mm->mmap_sem); /* * keep track of tlb+htab misses that are good addrs but diff -ur --new-file old/linux/arch/ppc/mm/init.c new/linux/arch/ppc/mm/init.c --- old/linux/arch/ppc/mm/init.c Thu Jan 7 21:06:57 1999 +++ new/linux/arch/ppc/mm/init.c Tue May 11 17:24:32 1999 @@ -1,5 +1,5 @@ /* - * $Id: init.c,v 1.139 1998/12/29 19:53:49 cort Exp $ + * $Id: init.c,v 1.164 1999/05/05 17:33:55 cort Exp $ * * PowerPC version * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) @@ -34,6 +34,7 @@ #include #include #include +#include #ifdef CONFIG_BLK_DEV_INITRD #include /* for initrd_* */ #endif @@ -70,10 +71,12 @@ unsigned long ioremap_base; unsigned long ioremap_bot; unsigned long avail_start; -struct pgtable_cache_struct quicklists; extern int num_memory; extern struct mem_info memory[NUM_MEMINFO]; extern boot_infos_t *boot_infos; +#ifndef __SMP__ +struct pgtable_cache_struct quicklists; +#endif void MMU_init(void); static void *MMU_get_page(void); @@ -116,12 +119,19 @@ PTE *Hash, *Hash_end; unsigned long Hash_size, Hash_mask; #ifndef CONFIG_8xx +#ifdef CONFIG_PPC64 +unsigned long long _SDR1; +#else unsigned long _SDR1; +#endif static void hash_init(void); union ubat { /* BAT register values to be loaded */ BAT bat; - P601_BAT bat_601; +#ifdef CONFIG_PPC64 + u64 word[2]; +#else u32 word[2]; +#endif } BATS[4][2]; /* 4 pairs of IBAT, DBAT */ struct batrange { /* stores address ranges mapped by BATs */ @@ -129,6 +139,8 @@ unsigned long limit; unsigned long phys; } bat_addrs[4]; +unsigned long inline v_mapped_by_bats(unsigned long); +unsigned long inline p_mapped_by_bats(unsigned long); #endif /* CONFIG_8xx */ /* @@ -329,15 +341,40 @@ * virt == phys; for addresses below this we use * space going down from ioremap_base (ioremap_bot * records where we're up to). - * - * We should also look out for a frame buffer and - * map it with a free BAT register, if there is one. */ p = addr & PAGE_MASK; size = PAGE_ALIGN(addr + size) - p; + + /* + * Don't allow anybody to remap normal RAM that we're using. + * mem_init() sets high_memory so only do the check after that. + */ + if ( mem_init_done && (p < virt_to_phys(high_memory)) ) + { + printk("__ioremap(): phys addr %0lx is RAM lr %p\n", p, + __builtin_return_address(0)); + return NULL; + } + if (size == 0) return NULL; +#ifndef CONFIG_8xx + /* + * Is it already mapped? Perhaps overlapped by a previous + * BAT mapping. If the whole area is mapped then we're done, + * otherwise remap it since we want to keep the virt addrs for + * each request contiguous. + * + * We make the assumption here that if the bottom and top + * of the range we want are mapped then it's mapped to the + * same virt address (and this is contiguous). + * -- Cort + */ + if ( (v = p_mapped_by_bats(addr)) /*&& p_mapped_by_bats(addr+(size-1))*/ ) + goto out; +#endif /* CONFIG_8xx */ + if (mem_init_done) { struct vm_struct *area; area = get_vm_area(size); @@ -355,10 +392,17 @@ flags |= pgprot_val(PAGE_KERNEL); if (flags & (_PAGE_NO_CACHE | _PAGE_WRITETHRU)) flags |= _PAGE_GUARDED; + +#ifndef CONFIG_8xx + /* + * Is it a candidate for a BAT mapping? + */ +#endif /* CONFIG_8xx */ + for (i = 0; i < size; i += PAGE_SIZE) map_page(&init_task, v+i, p+i, flags); - - return (void *) (v + (addr & ~PAGE_MASK)); +out: + return (void *) (v + (p & ~PAGE_MASK)); } void iounmap(void *addr) @@ -409,9 +453,7 @@ { pmd_t *pd; pte_t *pg; -#ifndef CONFIG_8xx - int b; -#endif + if (tsk->mm->pgd == NULL) { /* Allocate upper level page map */ tsk->mm->pgd = (pgd_t *) MMU_get_page(); @@ -419,20 +461,8 @@ /* Use upper 10 bits of VA to index the first level map */ pd = (pmd_t *) (tsk->mm->pgd + (va >> PGDIR_SHIFT)); if (pmd_none(*pd)) { -#ifndef CONFIG_8xx - /* - * Need to allocate second-level table, but first - * check whether this address is already mapped by - * the BATs; if so, don't bother allocating the page. - */ - for (b = 0; b < 4; ++b) { - if (va >= bat_addrs[b].start - && va <= bat_addrs[b].limit) { - /* XXX should check the phys address matches */ - return; - } - } -#endif /* CONFIG_8xx */ + if ( v_mapped_by_bats(va) ) + return; pg = (pte_t *) MMU_get_page(); pmd_val(*pd) = (unsigned long) pg; } @@ -677,6 +707,33 @@ static void sort_mem_pieces(struct mem_pieces *); static void coalesce_mem_pieces(struct mem_pieces *); +/* + * Return 1 if this VA is mapped by BATs + */ +unsigned long inline v_mapped_by_bats(unsigned long va) +{ + int b; + for (b = 0; b < 4; ++b) + if (va >= bat_addrs[b].start + && va < bat_addrs[b].limit) + return 1; + return 0; +} + +/* + * Return VA for a given PA or 0 if not mapped + */ +unsigned long inline p_mapped_by_bats(unsigned long pa) +{ + int b; + for (b = 0; b < 4; ++b) + if (pa >= bat_addrs[b].phys + && pa < (bat_addrs[b].limit-bat_addrs[b].start) + +bat_addrs[b].phys) + return bat_addrs[b].start+(pa-bat_addrs[b].phys); + return 0; +} + __initfunc(static void sort_mem_pieces(struct mem_pieces *mp)) { unsigned long a, s; @@ -833,7 +890,7 @@ setbat(2, KERNELBASE, mem_base, bl, RAM_PAGE); done = (unsigned long)bat_addrs[2].limit - KERNELBASE + 1; - if (done < tot) { + if ((done < tot) && !bat_addrs[3].limit) { /* use BAT3 to cover a bit more */ tot -= done; for (bl = 128<<10; bl < max_size; bl <<= 1) @@ -883,7 +940,8 @@ } } -__initfunc(static void *MMU_get_page(void)) +/* This can get called from ioremap, so don't make it an initfunc, OK? */ +static void *MMU_get_page(void) { void *p; @@ -926,14 +984,16 @@ break; case _MACH_prep: FREESEC(__pmac_begin,__pmac_end,num_pmac_pages); - FREESEC(__openfirmware_begin,__openfirmware_end,num_openfirmware_pages); break; case _MACH_mbx: FREESEC(__pmac_begin,__pmac_end,num_pmac_pages); - FREESEC(__openfirmware_begin,__openfirmware_end,num_openfirmware_pages); FREESEC(__prep_begin,__prep_end,num_prep_pages); break; } + + if ( !have_of ) + FREESEC( __openfirmware_begin, __openfirmware_end, + num_openfirmware_pages ); printk ("Freeing unused kernel memory: %ldk init", (num_freed_pages * PAGE_SIZE) >> 10); @@ -955,7 +1015,6 @@ */ __initfunc(void MMU_init(void)) { - #ifdef __SMP__ if ( first_cpu_booted ) return; #endif /* __SMP__ */ @@ -985,10 +1044,13 @@ switch (_machine) { case _MACH_prep: setbat(0, 0x80000000, 0x80000000, 0x10000000, IO_PAGE); - setbat(1, 0xd0000000, 0xc0000000, 0x10000000, IO_PAGE); + setbat(1, 0xf0000000, 0xc0000000, 0x08000000, IO_PAGE); + ioremap_base = 0xf0000000; break; case _MACH_chrp: setbat(0, 0xf8000000, 0xf8000000, 0x08000000, IO_PAGE); + setbat(1, 0x80000000, 0x80000000, 0x10000000, IO_PAGE); + setbat(3, 0x90000000, 0x90000000, 0x10000000, IO_PAGE); break; case _MACH_Pmac: { @@ -1029,6 +1091,7 @@ ioremap(PCI_CSR_ADDR, PCI_CSR_SIZE); /* ide needs to be able to get at PCI space -- Cort */ ioremap(0x80000000, 0x4000); + ioremap(0x81000000, 0x4000); #endif /* CONFIG_8xx */ } @@ -1236,6 +1299,9 @@ unsigned long a, total; unsigned long kstart, ksize; int i; + + /* max amount of RAM we allow -- Cort */ +#define RAM_LIMIT (768<<20) memory_node = find_devices("memory"); if (memory_node == NULL) { @@ -1260,7 +1326,18 @@ a = phys_mem.regions[0].address; if (a != 0) panic("RAM doesn't start at physical address 0"); + /* + * XXX: + * Make sure ram mappings don't stomp on IO space + * This is a temporary hack to keep this from happening + * until we move the KERNELBASE and can allocate RAM up + * to our nearest IO area. + * -- Cort + */ + if ( phys_mem.regions[0].size >= RAM_LIMIT ) + phys_mem.regions[0].size = RAM_LIMIT; total = phys_mem.regions[0].size; + if (phys_mem.n_regions > 1) { printk("RAM starting at 0x%x is not contiguous\n", phys_mem.regions[1].address); @@ -1277,8 +1354,15 @@ } prom_mem = phys_mem; for (i = 0; i < phys_avail.n_regions; ++i) + { + if ( phys_avail.regions[i].address >= RAM_LIMIT ) + continue; + if ( (phys_avail.regions[i].address+phys_avail.regions[i].size) + >= RAM_LIMIT ) + phys_avail.regions[i].size = RAM_LIMIT - phys_avail.regions[i].address; remove_mem_piece(&prom_mem, phys_avail.regions[i].address, phys_avail.regions[i].size, 1); + } /* * phys_avail records memory we can use now. @@ -1292,7 +1376,7 @@ remove_mem_piece(&prom_mem, kstart, ksize, 0); remove_mem_piece(&phys_avail, 0, 0x4000, 0); remove_mem_piece(&prom_mem, 0, 0x4000, 0); - +#undef RAM_LIMIT return __va(total); } @@ -1421,10 +1505,18 @@ * up to a maximum of 2MB. */ ramsize = (ulong)end_of_DRAM - KERNELBASE; +#ifdef CONFIG_PPC64 + Hash_mask = 0; + for (h = 256<<10; h < ramsize / 256 && h < 4<<20; h *= 2, Hash_mask++) + ; + Hash_size = h; + Hash_mask << 10; /* so setting _SDR1 works the same -- Cort */ +#else for (h = 64<<10; h < ramsize / 256 && h < 2<<20; h *= 2) ; Hash_size = h; Hash_mask = (h >> 6) - 1; +#endif #ifdef NO_RELOAD_HTAB /* shrink the htab since we don't use it on 603's -- Cort */ @@ -1502,4 +1594,3 @@ } } #endif /* ndef CONFIG_8xx */ - diff -ur --new-file old/linux/arch/ppc/pmac_defconfig new/linux/arch/ppc/pmac_defconfig --- old/linux/arch/ppc/pmac_defconfig Tue Jan 5 00:32:42 1999 +++ new/linux/arch/ppc/pmac_defconfig Thu Mar 11 06:30:32 1999 @@ -102,7 +102,6 @@ # CONFIG_RTNETLINK is not set # CONFIG_NETLINK_DEV is not set # CONFIG_FIREWALL is not set -CONFIG_NET_ALIAS=y # CONFIG_FILTER is not set CONFIG_UNIX=y CONFIG_INET=y @@ -263,6 +262,7 @@ # CONFIG_SHAPER is not set # CONFIG_HOSTESS_SV11 is not set # CONFIG_COSA is not set +# CONFIG_RCPCI is not set # # Amateur Radio support diff -ur --new-file old/linux/arch/ppc/prep_defconfig new/linux/arch/ppc/prep_defconfig --- old/linux/arch/ppc/prep_defconfig Wed Dec 23 16:34:11 1998 +++ new/linux/arch/ppc/prep_defconfig Thu Feb 25 19:46:47 1999 @@ -84,7 +84,6 @@ # CONFIG_PACKET is not set # CONFIG_NETLINK is not set # CONFIG_FIREWALL is not set -# CONFIG_NET_ALIAS is not set # CONFIG_FILTER is not set CONFIG_UNIX=y CONFIG_INET=y diff -ur --new-file old/linux/arch/sparc/boot/piggyback.c new/linux/arch/sparc/boot/piggyback.c --- old/linux/arch/sparc/boot/piggyback.c Thu Jul 17 04:22:50 1997 +++ new/linux/arch/sparc/boot/piggyback.c Thu Mar 11 01:53:36 1999 @@ -1,4 +1,4 @@ -/* $Id: piggyback.c,v 1.1 1997/07/11 11:05:17 jj Exp $ +/* $Id: piggyback.c,v 1.2 1998/12/15 12:24:43 jj Exp $ Simple utility to make a single-image install kernel with initial ramdisk for Sparc tftpbooting without need to set up nfs. @@ -46,16 +46,21 @@ struct stat s; int image, tail; + start = end = 0; if (stat (argv[3], &s) < 0) die (argv[3]); map = fopen (argv[2], "r"); if (!map) die(argv[2]); while (fgets (buffer, 1024, map)) { - if (!strcmp (buffer + 11, "start\n")) + if (!strcmp (buffer + 8, " T start\n") || !strcmp (buffer + 16, " T start\n")) start = strtoul (buffer, NULL, 16); - else if (!strcmp (buffer + 11, "end\n")) + else if (!strcmp (buffer + 8, " A end\n") || !strcmp (buffer + 16, " A end\n")) end = strtoul (buffer, NULL, 16); } fclose (map); + if (!start || !end) { + fprintf (stderr, "Could not determine start and end from System.map\n"); + exit(1); + } if ((image = open(argv[1],O_RDWR)) < 0) die(argv[1]); if (read(image,buffer,512) != 512) die(argv[1]); if (!memcmp (buffer, "\177ELF", 4)) { diff -ur --new-file old/linux/arch/sparc/config.in new/linux/arch/sparc/config.in --- old/linux/arch/sparc/config.in Thu Jun 3 02:11:11 1999 +++ new/linux/arch/sparc/config.in Thu Jun 3 02:12:04 1999 @@ -1,4 +1,4 @@ -# $Id: config.in,v 1.63 1998/09/21 05:05:56 jj Exp $ +# $Id: config.in,v 1.68 1999/03/14 03:12:42 anton Exp $ # For a description of the syntax of this configuration file, # see the Configure script. # @@ -25,7 +25,7 @@ define_bool CONFIG_VT_CONSOLE y bool 'Support for AP1000 multicomputer' CONFIG_AP1000 -bool 'Symmetric multi-processing support' CONFIG_SMP +bool 'Symmetric multi-processing support (does not work on sun4/sun4c)' CONFIG_SMP if [ "$CONFIG_AP1000" = "y" ]; then define_bool CONFIG_NO_KEYBOARD y @@ -165,6 +165,9 @@ fi tristate 'Sun LANCE support' CONFIG_SUNLANCE tristate 'Sun Happy Meal 10/100baseT support' CONFIG_HAPPYMEAL + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate 'Sun BigMAC 10/100baseT support' CONFIG_SUNBMAC + fi tristate 'Sun QuadEthernet support' CONFIG_SUNQE tristate 'MyriCOM Gigabit Ethernet support' CONFIG_MYRI_SBUS # bool 'FDDI driver support' CONFIG_FDDI @@ -176,6 +179,15 @@ fi endmenu fi + +# This one must be before the filesystem configs. -DaveM +mainmenu_option next_comment +comment 'Unix98 PTY support' +bool 'Unix98 PTY support' CONFIG_UNIX98_PTYS +if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then + int 'Maximum number of Unix98 PTYs in use (0-2048)' CONFIG_UNIX98_PTY_COUNT 256 +fi +endmenu source fs/Config.in diff -ur --new-file old/linux/arch/sparc/defconfig new/linux/arch/sparc/defconfig --- old/linux/arch/sparc/defconfig Fri Dec 18 23:01:48 1998 +++ new/linux/arch/sparc/defconfig Fri Apr 23 04:24:51 1999 @@ -101,7 +101,6 @@ CONFIG_PACKET=y # CONFIG_NETLINK is not set # CONFIG_FIREWALL is not set -# CONFIG_NET_ALIAS is not set # CONFIG_FILTER is not set CONFIG_UNIX=y CONFIG_INET=y @@ -118,7 +117,6 @@ # (it is safe to leave these untouched) # CONFIG_INET_RARP=m -CONFIG_IP_NOSR=y CONFIG_SKB_LARGE=y CONFIG_IPV6=m # CONFIG_IPV6_EUI64 is not set @@ -139,6 +137,10 @@ # CONFIG_NET_FASTROUTE is not set # CONFIG_NET_HW_FLOWCONTROL is not set # CONFIG_CPU_IS_SLOW is not set + +# +# QoS and/or fair queueing +# # CONFIG_NET_SCHED is not set # @@ -181,11 +183,13 @@ # FC4 drivers # CONFIG_FC4_SOC=m +CONFIG_FC4_SOCAL=m # # FC4 targets # CONFIG_SCSI_PLUTO=m +CONFIG_SCSI_FCAL=m # # Network device support @@ -203,28 +207,51 @@ # CONFIG_SLIP_MODE_SLIP6 is not set CONFIG_SUNLANCE=y CONFIG_HAPPYMEAL=m +CONFIG_SUNBMAC=m CONFIG_SUNQE=m CONFIG_MYRI_SBUS=m # +# Unix98 PTY support +# +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 + +# # Filesystems # # CONFIG_QUOTA is not set -CONFIG_MINIX_FS=m -CONFIG_EXT2_FS=y -CONFIG_ISO9660_FS=m -# CONFIG_JOLIET is not set +CONFIG_AUTOFS_FS=m +# CONFIG_ADFS_FS is not set +CONFIG_AFFS_FS=m +# CONFIG_HFS_FS is not set CONFIG_FAT_FS=m CONFIG_MSDOS_FS=m # CONFIG_UMSDOS_FS is not set CONFIG_VFAT_FS=m +CONFIG_ISO9660_FS=m +# CONFIG_JOLIET is not set +CONFIG_MINIX_FS=m +# CONFIG_NTFS_FS is not set +CONFIG_HPFS_FS=m CONFIG_PROC_FS=y +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +CONFIG_ROMFS_FS=m +CONFIG_EXT2_FS=y +CONFIG_SYSV_FS=m +CONFIG_UFS_FS=m +CONFIG_UFS_FS_WRITE=y + +# +# Network File Systems +# +CONFIG_CODA_FS=m CONFIG_NFS_FS=y CONFIG_NFSD=m # CONFIG_NFSD_SUN is not set CONFIG_SUNRPC=y CONFIG_LOCKD=y -CONFIG_CODA_FS=m CONFIG_SMB_FS=m CONFIG_SMB_WIN95=y CONFIG_NCP_FS=m @@ -234,21 +261,18 @@ # CONFIG_NCPFS_NFS_NS is not set # CONFIG_NCPFS_OS2_NS is not set # CONFIG_NCPFS_MOUNT_SUBDIR is not set -CONFIG_HPFS_FS=m -# CONFIG_NTFS_FS is not set -CONFIG_SYSV_FS=m -CONFIG_AFFS_FS=m -# CONFIG_HFS_FS is not set -CONFIG_ROMFS_FS=m -CONFIG_AUTOFS_FS=m -CONFIG_AMIGA_PARTITION=y -CONFIG_UFS_FS=m +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set + +# +# Partition Types +# CONFIG_BSD_DISKLABEL=y +# CONFIG_MAC_PARTITION is not set CONFIG_SMD_DISKLABEL=y CONFIG_SOLARIS_X86_PARTITION=y -# CONFIG_ADFS_FS is not set -# CONFIG_QNX4FS_FS is not set -# CONFIG_MAC_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +CONFIG_AMIGA_PARTITION=y CONFIG_NLS=y # @@ -279,6 +303,7 @@ # CONFIG_NLS_ISO8859_7 is not set # CONFIG_NLS_ISO8859_8 is not set # CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_15 is not set # CONFIG_NLS_KOI8_R is not set # diff -ur --new-file old/linux/arch/sparc/kernel/Makefile new/linux/arch/sparc/kernel/Makefile --- old/linux/arch/sparc/kernel/Makefile Fri Dec 18 23:01:48 1998 +++ new/linux/arch/sparc/kernel/Makefile Thu Mar 11 01:53:36 1999 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.48 1998/09/21 05:04:46 jj Exp $ +# $Id: Makefile,v 1.49 1999/01/02 16:45:37 davem Exp $ # Makefile for the linux kernel. # # Note! Dependencies are done automagically by 'make dep', which also diff -ur --new-file old/linux/arch/sparc/kernel/devices.c new/linux/arch/sparc/kernel/devices.c --- old/linux/arch/sparc/kernel/devices.c Tue Oct 27 18:52:20 1998 +++ new/linux/arch/sparc/kernel/devices.c Thu Mar 11 01:53:36 1999 @@ -29,24 +29,25 @@ prom_getstring(prom_root_node, "device_type", node_str, sizeof(node_str)); + prom_printf("Booting Linux...\n"); if(strcmp(node_str, "cpu") == 0) { linux_num_cpus++; } else { int scan; scan = prom_getchild(prom_root_node); - prom_printf("root child is %08lx\n", (unsigned long) scan); + /* One can look it up in PROM instead */ + /* prom_printf("root child is %08lx\n", (unsigned long) scan); */ while((scan = prom_getsibling(scan)) != 0) { prom_getstring(scan, "device_type", node_str, sizeof(node_str)); if(strcmp(node_str, "cpu") == 0) { linux_cpus[linux_num_cpus].prom_node = scan; prom_getproperty(scan, "mid", (char *) &thismid, sizeof(thismid)); linux_cpus[linux_num_cpus].mid = thismid; - prom_printf("Found CPU %d \n", - linux_num_cpus, (unsigned long) scan, - thismid); + /* prom_printf("Found CPU %d \n", linux_num_cpus, (unsigned long) scan, thismid); */ + printk("Found CPU %d \n", linux_num_cpus, (unsigned long) scan, thismid); linux_num_cpus++; } - }; + } if(linux_num_cpus == 0) { if (sparc_cpu_model == sun4d) { scan = prom_getchild(prom_root_node); @@ -59,9 +60,10 @@ prom_getproperty(node, "cpu-id", (char *) &thismid, sizeof(thismid)); linux_cpus[linux_num_cpus].prom_node = node; linux_cpus[linux_num_cpus].mid = thismid; - prom_printf("Found CPU %d \n", - linux_num_cpus, (unsigned long) node, - thismid); + /* prom_printf("Found CPU %d \n", + linux_num_cpus, (unsigned long) node, thismid); */ + printk("Found CPU %d \n", + linux_num_cpus, (unsigned long) node, thismid); linux_num_cpus++; } } diff -ur --new-file old/linux/arch/sparc/kernel/entry.S new/linux/arch/sparc/kernel/entry.S --- old/linux/arch/sparc/kernel/entry.S Mon Nov 16 19:37:28 1998 +++ new/linux/arch/sparc/kernel/entry.S Tue May 11 17:24:31 1999 @@ -1,10 +1,10 @@ -/* $Id: entry.S,v 1.153 1998/11/11 15:12:33 jj Exp $ +/* $Id: entry.S,v 1.159 1999/05/08 03:00:03 davem Exp $ * arch/sparc/kernel/entry.S: Sparc trap low-level entry points. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be) * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx) - * Copyright (C) 1996,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * Copyright (C) 1996-1999 Jakub Jelinek (jj@sunsite.mff.cuni.cz) * Copyright (C) 1997 Anton Blanchard (anton@progsoc.uts.edu.au) */ @@ -874,7 +874,7 @@ ! We want error in %l5, vaddr in %l6 sun4c_fault: #ifdef CONFIG_SUN4 - sethi C_LABEL(sun4c_memerr_reg), %l4 + sethi %hi(C_LABEL(sun4c_memerr_reg)), %l4 ld [%l4+%lo(C_LABEL(sun4c_memerr_reg))], %l4 ! memerr ctrl reg addr ld [%l4], %l6 ! memerr ctrl reg ld [%l4 + 4], %l5 ! memerr vaddr reg @@ -956,7 +956,7 @@ sll %l6, 2, %l6 ld [%l4 + %l6], %l4 #ifdef CONFIG_SUN4 - sethi PAGE_MASK, %l6 + sethi %hi(PAGE_MASK), %l6 andcc %l4, %l6, %g0 #else andcc %l4, PAGE_MASK, %g0 @@ -1117,7 +1117,7 @@ #ifndef CONFIG_SUN4 and %l4, PAGE_MASK, %l4 #else - sethi PAGE_MASK, %l6 + sethi %hi(PAGE_MASK), %l6 and %l4, %l6, %l4 #endif @@ -1380,11 +1380,13 @@ /* Now that we have a real sys_clone, sys_fork() is * implemented in terms of it. Our _real_ implementation - * of SunOS vfork() will use sys_clone() instead. + * of SunOS vfork() will use sys_vfork(). + * + * XXX These three should be consolidated into mostly shared + * XXX code just like on sparc64... -DaveM */ .align 4 - .globl C_LABEL(sys_fork), C_LABEL(sys_vfork), flush_patch_two -C_LABEL(sys_vfork): + .globl C_LABEL(sys_fork), flush_patch_two C_LABEL(sys_fork): mov %o7, %l5 flush_patch_two: @@ -1422,6 +1424,23 @@ call C_LABEL(do_fork) mov %l5, %o7 + /* Whee, real vfork! */ + .globl C_LABEL(sys_vfork), flush_patch_four +C_LABEL(sys_vfork): +flush_patch_four: + FLUSH_ALL_KERNEL_WINDOWS; + rd %psr, %g4 + WRITE_PAUSE + rd %wim, %g5 + WRITE_PAUSE + std %g4, [%curptr + AOFF_task_tss + AOFF_thread_fork_kpsr] + sethi %hi(0x4000 | 0x0100 | SIGCHLD), %o0 + mov %fp, %o1 + or %o0, %lo(0x4000 | 0x0100 | SIGCHLD), %o0 + sethi %hi(C_LABEL(do_fork)), %l1 + jmpl %l1 + %lo(C_LABEL(do_fork)), %g0 + add %sp, REGWIN_SZ, %o2 + .align 4 linux_sparc_ni_syscall: sethi %hi(C_LABEL(sys_ni_syscall)), %l7 @@ -1454,11 +1473,10 @@ #ifdef __SMP__ .globl C_LABEL(ret_from_smpfork) C_LABEL(ret_from_smpfork): - /* Nowadays all we need to do is drop the scheduler lock. */ - sethi %hi(C_LABEL(scheduler_lock)), %o4 - stb %g0, [%o4 + %lo(C_LABEL(scheduler_lock))] wr %l0, PSR_ET, %psr WRITE_PAUSE + call schedule_tail + mov %g3, %o0 b C_LABEL(ret_sys_call) ld [%sp + REGWIN_SZ + PT_I0], %o0 #endif diff -ur --new-file old/linux/arch/sparc/kernel/head.S new/linux/arch/sparc/kernel/head.S --- old/linux/arch/sparc/kernel/head.S Wed Aug 5 01:03:34 1998 +++ new/linux/arch/sparc/kernel/head.S Fri Apr 23 04:24:51 1999 @@ -1,4 +1,4 @@ -/* $Id: head.S,v 1.92 1998/06/10 07:21:55 davem Exp $ +/* $Id: head.S,v 1.95 1999/04/13 07:40:34 anton Exp $ * head.S: The initial boot code for the Sparc port of Linux. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -408,13 +408,11 @@ /* This was the only reasonable way I could think of to properly align * these page-table data structures. */ - .globl C_LABEL(bootup_user_stack) .globl C_LABEL(pg0), C_LABEL(pg1), C_LABEL(pg2), C_LABEL(pg3) .globl C_LABEL(empty_bad_page) .globl C_LABEL(empty_bad_page_table) .globl C_LABEL(empty_zero_page) .globl C_LABEL(swapper_pg_dir) -C_LABEL(bootup_user_stack): .skip 0x2000 C_LABEL(swapper_pg_dir): .skip PAGE_SIZE C_LABEL(pg0): .skip PAGE_SIZE C_LABEL(pg1): .skip PAGE_SIZE @@ -427,8 +425,8 @@ .global C_LABEL(root_flags) .global C_LABEL(ram_flags) .global C_LABEL(root_dev) - .global C_LABEL(ramdisk_image) - .global C_LABEL(ramdisk_size) + .global C_LABEL(sparc_ramdisk_image) + .global C_LABEL(sparc_ramdisk_size) /* This stuff has to be in sync with SILO and other potential boot loaders * Fields should be kept upward compatible and whenever any change is made, @@ -443,9 +441,9 @@ .half 0 C_LABEL(ram_flags): .half 0 -C_LABEL(ramdisk_image): +C_LABEL(sparc_ramdisk_image): .word 0 -C_LABEL(ramdisk_size): +C_LABEL(sparc_ramdisk_size): .word 0 .word C_LABEL(reboot_command) @@ -1005,8 +1003,8 @@ WRITE_PAUSE /* I want a kernel stack NOW! */ - set C_LABEL(bootup_user_stack), %g1 - set (0x2000 - REGWIN_SZ), %g2 + set C_LABEL(init_task_union), %g1 + set (TASK_UNION_SIZE - REGWIN_SZ), %g2 add %g1, %g2, %sp mov 0, %fp /* And for good luck */ @@ -1108,6 +1106,9 @@ st %g4, [%g5 + 0x18] st %g4, [%g5 + 0x1c] set flush_patch_three, %g5 + st %g4, [%g5 + 0x18] + st %g4, [%g5 + 0x1c] + set flush_patch_four, %g5 st %g4, [%g5 + 0x18] st %g4, [%g5 + 0x1c] set flush_patch_exception, %g5 diff -ur --new-file old/linux/arch/sparc/kernel/irq.c new/linux/arch/sparc/kernel/irq.c --- old/linux/arch/sparc/kernel/irq.c Tue Oct 27 18:52:20 1998 +++ new/linux/arch/sparc/kernel/irq.c Fri Apr 23 04:24:51 1999 @@ -1,4 +1,4 @@ -/* $Id: irq.c,v 1.91 1998/10/14 07:04:17 jj Exp $ +/* $Id: irq.c,v 1.93 1999/04/21 06:15:45 anton Exp $ * arch/sparc/kernel/irq.c: Interrupt request handling routines. On the * Sparc the IRQ's are basically 'cast in stone' * and you are supposed to probe the prom's device @@ -8,7 +8,7 @@ * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx) * Copyright (C) 1995 Pete A. Zaitcev (zaitcev@metabyte.com) * Copyright (C) 1996 Dave Redman (djhr@tadpole.co.uk) - * Copyright (C) 1998 Anton Blanchard (anton@progsoc.uts.edu.au) + * Copyright (C) 1998-99 Anton Blanchard (anton@progsoc.uts.edu.au) */ #include @@ -24,6 +24,8 @@ #include #include #include +#include +#include #include #include @@ -192,12 +194,18 @@ restore_flags(flags); } -/* Per-processor IRQ and bh locking depth, both SMP and non-SMP code use this. */ +#ifndef __SMP__ +unsigned int local_bh_count; +unsigned int local_irq_count; + +#else +/* SMP interrupt locking on Sparc. */ + unsigned int local_bh_count[NR_CPUS]; unsigned int local_irq_count[NR_CPUS]; -#ifdef __SMP__ -/* SMP interrupt locking on Sparc. */ +atomic_t global_bh_lock = ATOMIC_INIT(0); +spinlock_t global_bh_count = SPIN_LOCK_UNLOCKED; /* Who has global_irq_lock. */ unsigned char global_irq_holder = NO_PROC_ID; @@ -208,58 +216,71 @@ /* Global IRQ locking depth. */ atomic_t global_irq_count = ATOMIC_INIT(0); -atomic_t global_bh_count = ATOMIC_INIT(0); -atomic_t global_bh_lock = ATOMIC_INIT(0); - /* This protects BH software state (masks, things like that). */ spinlock_t sparc_bh_lock = SPIN_LOCK_UNLOCKED; -#ifdef DEBUG_IRQLOCK +void smp_show_backtrace_all_cpus(void); +void show_backtrace(void); -#undef INIT_STUCK -#define INIT_STUCK 100000000 +#define MAXCOUNT 100000000 +#define VERBOSE_DEBUG_IRQLOCK -#undef STUCK -#define STUCK \ -if (!--stuck) {printk("wait_on_bh CPU#%d stuck at %08lx\n", cpu, where); stuck = INIT_STUCK; } - -static inline void wait_on_bh(int cpu, unsigned long where) +static void show(char * str) { - int stuck = INIT_STUCK; - do { - STUCK; - /* nothing .. wait for the other bh's to go away */ - } while (atomic_read(&global_bh_count) != 0); -} + int i; + int cpu = smp_processor_id(); + + printk("\n%s, CPU %d:\n", str, cpu); + printk("irq: %d [ ", atomic_read(&global_irq_count)); -static unsigned long previous_irqholder; + for (i = 0; i < NR_CPUS; i++) { + printk("%d ", local_irq_count[i]); + } + printk("]\n"); -#undef INIT_STUCK -#define INIT_STUCK 100000000 + printk("bh: %d [ ", (spin_is_locked(&global_bh_count) ? 1 : 0)); -#undef STUCK -#define STUCK \ -if (!--stuck) {printk("wait_on_irq CPU#%d stuck at %08lx, waiting for %08lx (local=%d, global=%d)\n", cpu, where, previous_irqholder, local_count, atomic_read(&global_irq_count)); stuck = INIT_STUCK; } + for (i = 0; i < NR_CPUS; i++) { + printk("%d ", local_bh_count[cpu]); + } + printk("]\n"); + +#ifdef VERBOSE_DEBUG_IRQLOCK + smp_show_backtrace_all_cpus(); +#else + show_backtrace(); +#endif +} + +static inline void wait_on_bh(void) +{ + int count = MAXCOUNT; + do { + if(!--count) { + show("wait_on_bh"); + count = 0; + } + barrier(); + } while(spin_is_locked(&global_bh_count)); +} /* * We have to allow irqs to arrive between __sti and __cli */ -#define SYNC_OTHER_CORES(x) __asm__ __volatile__ ("nop") +#define SYNC_OTHER_CORES(x) udelay(x+1) -static inline void wait_on_irq(int cpu, unsigned long where) +static inline void wait_on_irq(int cpu) { - int stuck = INIT_STUCK; - int local_count = local_irq_count[cpu]; + int count = MAXCOUNT; for (;;) { - /* * Wait until all interrupts are gone. Wait * for bottom half handlers unless we're * already executing in one.. */ if (!atomic_read(&global_irq_count)) { - if (local_bh_count[cpu] || !atomic_read(&global_bh_count)) + if (local_bh_count[cpu] || !spin_is_locked(&global_bh_count)) break; } @@ -267,17 +288,18 @@ spin_unlock(&global_irq_lock); for (;;) { - STUCK; - + if (!--count) { + show("wait_on_irq"); + count = ~0; + } __sti(); SYNC_OTHER_CORES(cpu); __cli(); - if (atomic_read(&global_irq_count)) continue; - if (*((unsigned char *)&global_irq_lock)) + if (spin_is_locked (&global_irq_lock)) continue; - if (!local_bh_count[cpu] && atomic_read(&global_bh_count)) + if (!local_bh_count[cpu] && spin_is_locked(&global_bh_count)) continue; if (spin_trylock(&global_irq_lock)) break; @@ -295,14 +317,8 @@ */ void synchronize_bh(void) { - unsigned long where; - - __asm__("mov %%i7, %0" : "=r" (where)); - - if (atomic_read(&global_bh_count) && !in_interrupt()) { - int cpu = smp_processor_id(); - wait_on_bh(cpu, where); - } + if (spin_is_locked (&global_bh_count) && !in_interrupt()) + wait_on_bh(); } /* @@ -321,16 +337,9 @@ } } -#undef INIT_STUCK -#define INIT_STUCK 10000000 - -#undef STUCK -#define STUCK \ -if (!--stuck) {printk("get_irqlock stuck at %08lx, waiting for %08lx\n", where, previous_irqholder); stuck = INIT_STUCK;} - -static inline void get_irqlock(int cpu, unsigned long where) +static inline void get_irqlock(int cpu) { - int stuck = INIT_STUCK; + int count = MAXCOUNT; if (!spin_trylock(&global_irq_lock)) { /* do we already hold the lock? */ @@ -338,23 +347,25 @@ return; /* Uhhuh.. Somebody else got it. Wait.. */ do { - do { - STUCK; + while (spin_is_locked(&global_irq_lock)) { + if (!--count) { + show("get_irqlock"); + count = ~0; + } barrier(); - } while (*((volatile unsigned char *)&global_irq_lock)); + } } while (!spin_trylock(&global_irq_lock)); } /* * We also to make sure that nobody else is running * in an interrupt context. */ - wait_on_irq(cpu, where); + wait_on_irq(cpu); /* * Ok, finally.. */ global_irq_holder = cpu; - previous_irqholder = where; } /* @@ -372,9 +383,6 @@ void __global_cli(void) { unsigned int flags; - unsigned long where; - - __asm__("mov %%i7, %0" : "=r" (where)); __save_flags(flags); @@ -382,7 +390,7 @@ int cpu = smp_processor_id(); __cli(); if (!local_irq_count[cpu]) - get_irqlock(cpu, where); + get_irqlock(cpu); } } @@ -442,65 +450,14 @@ __sti(); break; default: - printk("global_restore_flags: %08lx (%08lx)\n", - flags, (&flags)[-1]); + { + unsigned long pc; + __asm__ __volatile__("mov %%i7, %0" : "=r" (pc)); + printk("global_restore_flags: Bogon flags(%08lx) caller %08lx\n", flags, pc); } -} - -#undef INIT_STUCK -#define INIT_STUCK 200000000 - -#undef STUCK -#define STUCK \ -if (!--stuck) {printk("irq_enter stuck (irq=%d, cpu=%d, global=%d)\n",irq,cpu,global_irq_holder); stuck = INIT_STUCK;} - -#define VERBOSE_IRQLOCK_DEBUGGING - -void irq_enter(int cpu, int irq, void *_opaque) -{ -#ifdef VERBOSE_IRQLOCK_DEBUGGING - extern void smp_show_backtrace_all_cpus(void); -#endif - int stuck = INIT_STUCK; - - hardirq_enter(cpu); - barrier(); - while (*((volatile unsigned char *)&global_irq_lock)) { - if ((unsigned char) cpu == global_irq_holder) { - struct pt_regs *regs = _opaque; - int sbh_cnt = atomic_read(&global_bh_count); - int globl_locked = *((unsigned char *)&global_irq_lock); - int globl_icount = atomic_read(&global_irq_count); - int local_count = local_irq_count[cpu]; - unsigned long pc = regs->pc; - - /* It is very important that we load the state variables - * before we do the first call to printk() as printk() - * could end up changing them... - */ - - printk("CPU[%d]: BAD! Local IRQ's enabled, global disabled " - "interrupt at PC[%08lx]\n", cpu, pc); - printk("CPU[%d]: bhcnt[%d] glocked[%d] gicnt[%d] licnt[%d]\n", - cpu, sbh_cnt, globl_locked, globl_icount, local_count); -#ifdef VERBOSE_IRQLOCK_DEBUGGING - printk("Performing backtrace on all cpus, write this down!\n"); - smp_show_backtrace_all_cpus(); -#endif - break; - } - STUCK; - barrier(); } } -void irq_exit(int cpu, int irq) -{ - hardirq_exit(cpu); - release_irqlock(cpu); -} - -#endif /* DEBUG_IRQLOCK */ #endif /* __SMP__ */ void unexpected_irq(int irq, void *dev_id, struct pt_regs * regs) @@ -542,7 +499,7 @@ smp4m_irq_rotate(cpu); #endif #endif - irq_enter(cpu, irq, regs); + irq_enter(cpu, irq); action = *(irq + irq_action); kstat.irqs[cpu][irq]++; do { @@ -563,7 +520,7 @@ int cpu = smp_processor_id(); disable_pil_irq(irq); - irq_enter(cpu, irq, regs); + irq_enter(cpu, irq); kstat.irqs[cpu][irq]++; floppy_interrupt(irq, dev_id, regs); irq_exit(cpu, irq); diff -ur --new-file old/linux/arch/sparc/kernel/pcic.c new/linux/arch/sparc/kernel/pcic.c --- old/linux/arch/sparc/kernel/pcic.c Tue Oct 27 18:52:20 1998 +++ new/linux/arch/sparc/kernel/pcic.c Wed Mar 17 06:52:05 1999 @@ -1,4 +1,4 @@ -/* $Id: pcic.c,v 1.3 1998/10/07 11:34:56 jj Exp $ +/* $Id: pcic.c,v 1.5 1999/03/16 00:15:20 davem Exp $ * pcic.c: Sparc/PCI controller support * * Copyright (C) 1998 V. Roganov and G. Raiko @@ -498,9 +498,10 @@ tv->tv_sec--; } xtime = *tv; - time_state = TIME_BAD; - time_maxerror = 0x70000000; - time_esterror = 0x70000000; + time_adjust = 0; /* stop active adjtime() */ + time_status |= STA_UNSYNC; + time_maxerror = NTP_PHASE_LIMIT; + time_esterror = NTP_PHASE_LIMIT; sti(); } diff -ur --new-file old/linux/arch/sparc/kernel/process.c new/linux/arch/sparc/kernel/process.c --- old/linux/arch/sparc/kernel/process.c Sun Oct 4 19:22:42 1998 +++ new/linux/arch/sparc/kernel/process.c Tue May 11 17:24:31 1999 @@ -1,4 +1,4 @@ -/* $Id: process.c,v 1.126 1998/09/21 05:05:18 jj Exp $ +/* $Id: process.c,v 1.137 1999/05/08 03:00:10 davem Exp $ * linux/arch/sparc/kernel/process.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -62,7 +62,9 @@ /* endless idle loop with no priority at all */ current->priority = 0; - current->counter = 0; + current->counter = -100; + init_idle(); + for (;;) { if (ARCH_SUN4C_SUN4) { static int count = HZ; @@ -108,13 +110,17 @@ /* This is being executed in task 0 'user space'. */ int cpu_idle(void *unused) { + /* endless idle loop with no priority at all */ current->priority = 0; + current->counter = -100; + init_idle(); + while(1) { - check_pgt_cache(); - run_task_queue(&tq_scheduler); - /* endless idle loop with no priority at all */ - current->counter = 0; - schedule(); + if(current->need_resched) { + schedule(); + check_pgt_cache(); + } + barrier(); /* or else gcc optimizes... */ } } @@ -203,8 +209,10 @@ int cpu = smp_processor_id(); spin_lock_irqsave(&sparc_backtrace_lock, flags); - rw = (struct reg_window *) fp; - while(rw) { + + rw = (struct reg_window *)fp; + while(rw && (((unsigned long) rw) >= PAGE_OFFSET) && + !(((unsigned long) rw) & 0x7)) { printk("CPU[%d]: ARGS[%08lx,%08lx,%08lx,%08lx,%08lx,%08lx] " "FP[%08lx] CALLER[%08lx]\n", cpu, rw->ins[0], rw->ins[1], rw->ins[2], rw->ins[3], @@ -216,28 +224,21 @@ spin_unlock_irqrestore(&sparc_backtrace_lock, flags); } +#define __SAVE __asm__ __volatile__("save %sp, -0x40, %sp\n\t") +#define __RESTORE __asm__ __volatile__("restore %g0, %g0, %g0\n\t") +#define __GET_FP(fp) __asm__ __volatile__("mov %%i6, %0" : "=r" (fp)) + void show_backtrace(void) { unsigned long fp; - __asm__ __volatile__( - "save %%sp, -64, %%sp\n\t" - "save %%sp, -64, %%sp\n\t" - "save %%sp, -64, %%sp\n\t" - "save %%sp, -64, %%sp\n\t" - "save %%sp, -64, %%sp\n\t" - "save %%sp, -64, %%sp\n\t" - "save %%sp, -64, %%sp\n\t" - "save %%sp, -64, %%sp\n\t" - "restore\n\t" - "restore\n\t" - "restore\n\t" - "restore\n\t" - "restore\n\t" - "restore\n\t" - "restore\n\t" - "restore\n\t" - "mov %%i6, %0" : "=r" (fp)); + __SAVE; __SAVE; __SAVE; __SAVE; + __SAVE; __SAVE; __SAVE; __SAVE; + __RESTORE; __RESTORE; __RESTORE; __RESTORE; + __RESTORE; __RESTORE; __RESTORE; __RESTORE; + + __GET_FP(fp); + __show_backtrace(fp); } @@ -379,8 +380,21 @@ current->tss.current_ds = USER_DS; if (current->tss.flags & SPARC_FLAG_KTHREAD) { current->tss.flags &= ~SPARC_FLAG_KTHREAD; - switch_to_context(current); + + /* We must fixup kregs as well. */ + current->tss.kregs = (struct pt_regs *) + (((unsigned long)current) + + (TASK_UNION_SIZE - TRACEREG_SZ)); } + + /* Exec'ing out of a vfork() shared address space is + * tricky on sparc32. exec_mmap will not set the mmu + * context because it sets the new current->mm after + * calling init_new_context and activate_context is + * a nop on sparc32, so we gotta catch it here. And + * clone()'s had the same problem. -DaveM + */ + switch_to_context(current); } static __inline__ void copy_regs(struct pt_regs *dst, struct pt_regs *src) @@ -440,10 +454,17 @@ size = ((unsigned long)src->fp) - ((unsigned long)src); sp = (struct sparc_stackf *)(((unsigned long)dst) - size); + /* do_fork() grabs the parent semaphore, we must release it + * temporarily so we can build the child clone stack frame + * without deadlocking. + */ + up(¤t->mm->mmap_sem); if (copy_to_user(sp, src, size)) - return 0; - if (put_user(dst, &sp->fp)) - return 0; + sp = (struct sparc_stackf *) 0; + else if (put_user(dst, &sp->fp)) + sp = (struct sparc_stackf *) 0; + down(¤t->mm->mmap_sem); + return sp; } @@ -505,14 +526,24 @@ p->tss.kpsr = current->tss.fork_kpsr; #endif p->tss.kwim = current->tss.fork_kwim; - p->tss.kregs = childregs; if(regs->psr & PSR_PS) { - childregs->u_regs[UREG_FP] = p->tss.ksp; + extern struct pt_regs fake_swapper_regs; + + p->tss.kregs = &fake_swapper_regs; + new_stack = (struct reg_window *) + ((((unsigned long)p) + + (TASK_UNION_SIZE)) - + (REGWIN_SZ)); + childregs->u_regs[UREG_FP] = (unsigned long) new_stack; p->tss.flags |= SPARC_FLAG_KTHREAD; p->tss.current_ds = KERNEL_DS; + memcpy((void *)new_stack, + (void *)regs->u_regs[UREG_FP], + sizeof(struct reg_window)); childregs->u_regs[UREG_G6] = (unsigned long) p; } else { + p->tss.kregs = childregs; childregs->u_regs[UREG_FP] = sp; p->tss.flags &= ~SPARC_FLAG_KTHREAD; p->tss.current_ds = USER_DS; @@ -657,4 +688,38 @@ out: unlock_kernel(); return error; +} + +/* + * This is the mechanism for creating a new kernel thread. + * + * NOTE! Only a kernel-only process(ie the swapper or direct descendants + * who haven't done an "execve()") should use this: it will work within + * a system call from a "real" process, but the process memory space will + * not be free'd until both the parent and the child have exited. + */ +pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) +{ + long retval; + + __asm__ __volatile("mov %4, %%g2\n\t" /* Set aside fn ptr... */ + "mov %5, %%g3\n\t" /* and arg. */ + "mov %1, %%g1\n\t" + "mov %2, %%o0\n\t" /* Clone flags. */ + "mov 0, %%o1\n\t" /* usp arg == 0 */ + "t 0x10\n\t" /* Linux/Sparc clone(). */ + "cmp %%o1, 0\n\t" + "be 1f\n\t" /* The parent, just return. */ + " nop\n\t" /* Delay slot. */ + "jmpl %%g2, %%o7\n\t" /* Call the function. */ + " mov %%g3, %%o0\n\t" /* Get back the arg in delay. */ + "mov %3, %%g1\n\t" + "t 0x10\n\t" /* Linux/Sparc exit(). */ + /* Notreached by child. */ + "1: mov %%o0, %0\n\t" : + "=r" (retval) : + "i" (__NR_clone), "r" (flags | CLONE_VM), + "i" (__NR_exit), "r" (fn), "r" (arg) : + "g1", "g2", "g3", "o0", "o1", "memory", "cc"); + return retval; } diff -ur --new-file old/linux/arch/sparc/kernel/ptrace.c new/linux/arch/sparc/kernel/ptrace.c --- old/linux/arch/sparc/kernel/ptrace.c Wed Dec 30 01:35:08 1998 +++ new/linux/arch/sparc/kernel/ptrace.c Thu Mar 25 00:10:40 1999 @@ -528,6 +528,8 @@ if (((current->personality & PER_BSD) && (request == PTRACE_SUNATTACH)) || (!(current->personality & PER_BSD) && (request == PTRACE_ATTACH))) { + unsigned long flags; + if(child == current) { /* Try this under SunOS/Solaris, bwa haha * You'll never be able to kill the process. ;-) @@ -539,8 +541,9 @@ (current->uid != child->euid) || (current->uid != child->uid) || (current->gid != child->egid) || - (current->gid != child->gid)) && - !capable(CAP_SYS_PTRACE)) { + (current->gid != child->sgid) || + (!cap_issubset(child->cap_permitted, current->cap_permitted)) || + (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE)) { pt_error_return(regs, EPERM); goto out; } @@ -550,14 +553,13 @@ goto out; } child->flags |= PF_PTRACED; + write_lock_irqsave(&tasklist_lock, flags); if(child->p_pptr != current) { - unsigned long flags; - write_lock_irqsave(&tasklist_lock, flags); REMOVE_LINKS(child); child->p_pptr = current; SET_LINKS(child); - write_unlock_irqrestore(&tasklist_lock, flags); } + write_unlock_irqrestore(&tasklist_lock, flags); send_sig(SIGSTOP, child, 1); pt_succ_return(regs, 0); goto out; diff -ur --new-file old/linux/arch/sparc/kernel/setup.c new/linux/arch/sparc/kernel/setup.c --- old/linux/arch/sparc/kernel/setup.c Sun Oct 4 19:22:42 1998 +++ new/linux/arch/sparc/kernel/setup.c Fri Apr 23 04:24:51 1999 @@ -1,4 +1,4 @@ -/* $Id: setup.c,v 1.103 1998/09/21 05:05:23 jj Exp $ +/* $Id: setup.c,v 1.105 1999/04/13 14:17:08 jj Exp $ * linux/arch/sparc/kernel/setup.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -271,8 +271,8 @@ extern unsigned short root_flags; extern unsigned short root_dev; extern unsigned short ram_flags; -extern unsigned ramdisk_image; -extern unsigned ramdisk_size; +extern unsigned sparc_ramdisk_image; +extern unsigned sparc_ramdisk_size; #define RAMDISK_IMAGE_START_MASK 0x07FF #define RAMDISK_PROMPT_FLAG 0x8000 #define RAMDISK_LOAD_FLAG 0x4000 @@ -285,7 +285,7 @@ struct tt_entry *sparc_ttable; -static struct pt_regs fake_swapper_regs = { 0, 0, 0, 0, { 0, } }; +struct pt_regs fake_swapper_regs = { 0, 0, 0, 0, { 0, } }; static void prom_cons_write(struct console *con, const char *str, unsigned count) { @@ -375,7 +375,7 @@ sun4c_probe_vac(); load_mmu(); total = prom_probe_memory(); - *memory_start_p = (((unsigned long) &end)); + *memory_start_p = PAGE_ALIGN(((unsigned long) &end)); if(!packed) { for(i=0; sp_banks[i].num_bytes != 0; i++) { @@ -404,10 +404,10 @@ rd_doload = ((ram_flags & RAMDISK_LOAD_FLAG) != 0); #endif #ifdef CONFIG_BLK_DEV_INITRD - if (ramdisk_image) { - initrd_start = ramdisk_image; + if (sparc_ramdisk_image) { + initrd_start = sparc_ramdisk_image; if (initrd_start < KERNBASE) initrd_start += KERNBASE; - initrd_end = initrd_start + ramdisk_size; + initrd_end = initrd_start + sparc_ramdisk_size; if (initrd_end > *memory_end_p) { printk(KERN_CRIT "initrd extends beyond end of memory " "(0x%08lx > 0x%08lx)\ndisabling initrd\n", @@ -417,6 +417,14 @@ if (initrd_start >= *memory_start_p && initrd_start < *memory_start_p + 2 * PAGE_SIZE) { initrd_below_start_ok = 1; *memory_start_p = PAGE_ALIGN (initrd_end); + } else if (initrd_start && sparc_ramdisk_image < KERNBASE) { + switch (sparc_cpu_model) { + case sun4m: + case sun4d: + initrd_start -= KERNBASE; + initrd_end -= KERNBASE; + break; + } } } #endif diff -ur --new-file old/linux/arch/sparc/kernel/signal.c new/linux/arch/sparc/kernel/signal.c --- old/linux/arch/sparc/kernel/signal.c Tue Oct 27 18:52:20 1998 +++ new/linux/arch/sparc/kernel/signal.c Thu Mar 11 01:53:36 1999 @@ -1,4 +1,4 @@ -/* $Id: signal.c,v 1.90 1998/10/18 03:31:05 davem Exp $ +/* $Id: signal.c,v 1.91 1999/01/26 11:00:44 jj Exp $ * linux/arch/sparc/kernel/signal.c * * Copyright (C) 1991, 1992 Linus Torvalds @@ -38,6 +38,8 @@ /* This turned off for production... */ /* #define DEBUG_SIGNALS 1 */ +/* #define DEBUG_SIGNALS_TRACE 1 */ +/* #define DEBUG_SIGNALS_MAPS 1 */ /* Signal frames: the original one (compatible with SunOS): * @@ -1004,6 +1006,59 @@ } } +#ifdef DEBUG_SIGNALS_MAPS + +#define MAPS_LINE_FORMAT "%08lx-%08lx %s %08lx %s %lu " + +static inline void read_maps (void) +{ + struct vm_area_struct * map, * next; + char * buffer; + ssize_t i; + + buffer = (char*)__get_free_page(GFP_KERNEL); + if (!buffer) + return; + + for (map = current->mm->mmap ; map ; map = next ) { + /* produce the next line */ + char *line; + char str[5], *cp = str; + int flags; + kdev_t dev; + unsigned long ino; + + /* + * Get the next vma now (but it won't be used if we sleep). + */ + next = map->vm_next; + flags = map->vm_flags; + + *cp++ = flags & VM_READ ? 'r' : '-'; + *cp++ = flags & VM_WRITE ? 'w' : '-'; + *cp++ = flags & VM_EXEC ? 'x' : '-'; + *cp++ = flags & VM_MAYSHARE ? 's' : 'p'; + *cp++ = 0; + + dev = 0; + ino = 0; + if (map->vm_file != NULL) { + dev = map->vm_file->f_dentry->d_inode->i_dev; + ino = map->vm_file->f_dentry->d_inode->i_ino; + line = d_path(map->vm_file->f_dentry, buffer, PAGE_SIZE); + } + printk(MAPS_LINE_FORMAT, map->vm_start, map->vm_end, str, map->vm_offset, + kdevname(dev), ino); + if (map->vm_file != NULL) + printk("%s\n", line); + else + printk("\n"); + } + free_page((unsigned long)buffer); + return; +} +#endif + /* Note that 'init' is a special process: it doesn't get signals it doesn't * want to handle. Thus you cannot kill init even with a SIGKILL even by * mistake. @@ -1115,8 +1170,25 @@ } #ifdef DEBUG_SIGNALS /* Very useful to debug dynamic linker problems */ - printk ("Sig ILL going...\n"); + printk ("Sig %ld going for %s[%d]...\n", signr, current->comm, current->pid); show_regs (regs); +#ifdef DEBUG_SIGNALS_TRACE + { + struct reg_window *rw = (struct reg_window *)regs->u_regs[UREG_FP]; + unsigned int ins[8]; + + while(rw && + !(((unsigned long) rw) & 0x3)) { + copy_from_user(ins, &rw->ins[0], sizeof(ins)); + printk("Caller[%08x](%08x,%08x,%08x,%08x,%08x,%08x)\n", ins[7], ins[0], ins[1], ins[2], ins[3], ins[4], ins[5]); + rw = (struct reg_window *)(unsigned long)ins[6]; + } + } +#endif +#ifdef DEBUG_SIGNALS_MAPS + printk("Maps:\n"); + read_maps(); +#endif #endif /* fall through */ default: diff -ur --new-file old/linux/arch/sparc/kernel/smp.c new/linux/arch/sparc/kernel/smp.c --- old/linux/arch/sparc/kernel/smp.c Tue Oct 27 18:52:20 1998 +++ new/linux/arch/sparc/kernel/smp.c Thu Mar 11 01:53:36 1999 @@ -52,6 +52,7 @@ int smp_activated = 0; volatile int cpu_number_map[NR_CPUS]; volatile int __cpu_logical_map[NR_CPUS]; +cycles_t cacheflush_time = 0; /* XXX */ /* The only guaranteed locking primitive available on all Sparc * processors is 'ldstub [%reg + immediate], %dest_reg' which atomically diff -ur --new-file old/linux/arch/sparc/kernel/sparc_ksyms.c new/linux/arch/sparc/kernel/sparc_ksyms.c --- old/linux/arch/sparc/kernel/sparc_ksyms.c Mon Nov 16 19:37:28 1998 +++ new/linux/arch/sparc/kernel/sparc_ksyms.c Sun Mar 21 16:23:38 1999 @@ -1,4 +1,4 @@ -/* $Id: sparc_ksyms.c,v 1.73 1998/11/06 13:49:54 jj Exp $ +/* $Id: sparc_ksyms.c,v 1.77 1999/03/21 06:37:43 davem Exp $ * arch/sparc/kernel/ksyms.c: Sparc specific ksyms support. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -66,6 +66,7 @@ extern void bcopy (const char *, char *, int); extern int __ashrdi3(int, int); +extern int __lshrdi3(int, int); extern void dump_thread(struct pt_regs *, struct user *); @@ -91,6 +92,7 @@ /* used by various drivers */ EXPORT_SYMBOL(sparc_cpu_model); EXPORT_SYMBOL_PRIVATE(_spinlock_waitfor); +EXPORT_SYMBOL(kernel_thread); #ifdef SPIN_LOCK_DEBUG EXPORT_SYMBOL(_do_spin_lock); EXPORT_SYMBOL(_do_spin_unlock); @@ -118,6 +120,7 @@ #endif EXPORT_SYMBOL(page_offset); +EXPORT_SYMBOL(sparc_valid_addr_bitmap); #ifndef CONFIG_SUN4 EXPORT_SYMBOL(stack_top); @@ -211,6 +214,7 @@ EXPORT_SYMBOL(prom_apply_obio_ranges); EXPORT_SYMBOL(prom_getname); EXPORT_SYMBOL(prom_feval); +EXPORT_SYMBOL(prom_getbool); EXPORT_SYMBOL(prom_getstring); EXPORT_SYMBOL(prom_apply_sbus_ranges); EXPORT_SYMBOL(prom_getint); @@ -268,6 +272,7 @@ EXPORT_SYMBOL_NOVERS(memset); EXPORT_SYMBOL_NOVERS(memmove); EXPORT_SYMBOL_NOVERS(__ashrdi3); +EXPORT_SYMBOL_NOVERS(__lshrdi3); EXPORT_SYMBOL_DOT(rem); EXPORT_SYMBOL_DOT(urem); diff -ur --new-file old/linux/arch/sparc/kernel/sun4d_irq.c new/linux/arch/sparc/kernel/sun4d_irq.c --- old/linux/arch/sparc/kernel/sun4d_irq.c Tue Oct 27 18:52:20 1998 +++ new/linux/arch/sparc/kernel/sun4d_irq.c Fri Apr 23 04:24:51 1999 @@ -1,4 +1,4 @@ -/* $Id: sun4d_irq.c,v 1.17 1998/10/18 03:31:03 davem Exp $ +/* $Id: sun4d_irq.c,v 1.18 1999/04/20 13:22:30 anton Exp $ * arch/sparc/kernel/sun4d_irq.c: * SS1000/SC2000 interrupt handling. * @@ -193,7 +193,7 @@ cc_set_iclr(1 << irq); - irq_enter(cpu, irq, regs); + irq_enter(cpu, irq); kstat.irqs[cpu][irq]++; if (!sbusl) { action = *(irq + irq_action); diff -ur --new-file old/linux/arch/sparc/kernel/sun4d_smp.c new/linux/arch/sparc/kernel/sun4d_smp.c --- old/linux/arch/sparc/kernel/sun4d_smp.c Mon Nov 16 19:37:28 1998 +++ new/linux/arch/sparc/kernel/sun4d_smp.c Tue May 11 17:24:31 1999 @@ -190,6 +190,7 @@ current->processor = boot_cpu_id; smp_store_cpu_info(boot_cpu_id); smp_setup_percpu_timer(); + init_idle(); local_flush_cache_all(); if(linux_num_cpus == 1) return; /* Not an MP box. */ @@ -211,6 +212,7 @@ p = task[++cpucount]; p->processor = i; + p->has_cpu = 1; /* we schedule the first task manually */ current_set[i] = p; for (no = 0; no < linux_num_cpus; no++) diff -ur --new-file old/linux/arch/sparc/kernel/sun4m_irq.c new/linux/arch/sparc/kernel/sun4m_irq.c --- old/linux/arch/sparc/kernel/sun4m_irq.c Sun Oct 4 19:22:42 1998 +++ new/linux/arch/sparc/kernel/sun4m_irq.c Fri Apr 23 04:24:51 1999 @@ -253,7 +253,7 @@ /* Map the per-cpu Counter registers. */ sun4m_timers = sparc_alloc_io(cnt_regs[0].phys_addr, 0, - PAGE_SIZE*NCPUS, "counters_percpu", + PAGE_SIZE*SUN4M_NCPUS, "counters_percpu", cnt_regs[0].which_io, 0x0); /* Map the system Counter register. */ @@ -334,7 +334,7 @@ /* Map the interrupt registers for all possible cpus. */ sun4m_interrupts = sparc_alloc_io(int_regs[0].phys_addr, 0, - PAGE_SIZE*NCPUS, "interrupts_percpu", + PAGE_SIZE*SUN4M_NCPUS, "interrupts_percpu", int_regs[0].which_io, 0x0); /* Map the system interrupt control registers. */ diff -ur --new-file old/linux/arch/sparc/kernel/sun4m_smp.c new/linux/arch/sparc/kernel/sun4m_smp.c --- old/linux/arch/sparc/kernel/sun4m_smp.c Mon Nov 16 19:37:28 1998 +++ new/linux/arch/sparc/kernel/sun4m_smp.c Tue May 11 17:24:31 1999 @@ -161,6 +161,7 @@ smp_store_cpu_info(boot_cpu_id); set_irq_udt(mid_xlate[boot_cpu_id]); smp_setup_percpu_timer(); + init_idle(); local_flush_cache_all(); if(linux_num_cpus == 1) return; /* Not an MP box. */ @@ -180,6 +181,7 @@ p = task[++cpucount]; p->processor = i; + p->has_cpu = 1; /* we schedule the first task manually */ current_set[i] = p; /* See trampoline.S for details... */ @@ -448,6 +450,7 @@ if(!--prof_counter[cpu]) { int user = user_mode(regs); + irq_enter(cpu, 0); if(current->pid) { update_one_process(current, 1, user, !user, cpu); @@ -456,7 +459,6 @@ current->need_resched = 1; } - spin_lock(&ticker_lock); if(user) { if(current->priority < DEF_PRIORITY) { kstat.cpu_nice++; @@ -469,9 +471,9 @@ kstat.cpu_system++; kstat.per_cpu_system[cpu]++; } - spin_unlock(&ticker_lock); } prof_counter[cpu] = prof_multiplier[cpu]; + irq_exit(cpu, 0); } } diff -ur --new-file old/linux/arch/sparc/kernel/sys_sparc.c new/linux/arch/sparc/kernel/sys_sparc.c --- old/linux/arch/sparc/kernel/sys_sparc.c Tue Oct 27 18:52:20 1998 +++ new/linux/arch/sparc/kernel/sys_sparc.c Tue May 11 17:24:31 1999 @@ -1,4 +1,4 @@ -/* $Id: sys_sparc.c,v 1.49 1998/10/11 06:57:53 davem Exp $ +/* $Id: sys_sparc.c,v 1.52 1999/05/08 08:09:48 anton Exp $ * linux/arch/sparc/kernel/sys_sparc.c * * This file contains various random system calls that @@ -25,6 +25,8 @@ #include #include +/* #define DEBUG_UNIMP_SYSCALL */ + /* XXX Make this per-binary type, this way we can detect the type of * XXX a binary. Every Sparc executable calls this very early on. */ @@ -189,6 +191,7 @@ goto out; } retval = -ENOMEM; + len = PAGE_ALIGN(len); if(!(flags & MAP_FIXED) && !addr) { addr = get_unmapped_area(addr, len); if(!addr) @@ -202,6 +205,7 @@ if(ARCH_SUN4C_SUN4) { if(((addr >= 0x20000000) && (addr < 0xe0000000))) { + /* VM hole */ retval = current->mm->brk; goto out_putf; } @@ -223,9 +227,14 @@ asmlinkage unsigned long c_sys_nis_syscall (struct pt_regs *regs) { + static int count = 0; + + if (count++ > 5) return -ENOSYS; lock_kernel(); - printk ("Unimplemented SPARC system call %d\n",(int)regs->u_regs[1]); + printk ("%s[%d]: Unimplemented SPARC system call %d\n", current->comm, current->pid, (int)regs->u_regs[1]); +#ifdef DEBUG_UNIMP_SYSCALL show_regs (regs); +#endif unlock_kernel(); return -ENOSYS; } diff -ur --new-file old/linux/arch/sparc/kernel/systbls.S new/linux/arch/sparc/kernel/systbls.S --- old/linux/arch/sparc/kernel/systbls.S Sun Oct 4 19:22:42 1998 +++ new/linux/arch/sparc/kernel/systbls.S Fri Apr 23 04:24:51 1999 @@ -1,4 +1,4 @@ -/* $Id: systbls.S,v 1.80 1998/09/21 05:04:59 jj Exp $ +/* $Id: systbls.S,v 1.83 1999/04/07 17:14:06 davem Exp $ * systbls.S: System call entry point tables for OS compatibility. * The native Linux system call table lives here also. * @@ -25,7 +25,7 @@ /*30*/ .long sys_utime, sys_nis_syscall, sys_nis_syscall, sys_access, sys_nice /*35*/ .long sys_nis_syscall, sys_sync, sys_kill, sys_newstat, sys_sendfile /*40*/ .long sys_newlstat, sys_dup, sys_pipe, sys_times, sys_nis_syscall -/*45*/ .long sys_nis_syscall, sys_setgid, sys_getgid, sys_signal, sys_geteuid +/*45*/ .long sys_umount, sys_setgid, sys_getgid, sys_signal, sys_geteuid /*50*/ .long sys_getegid, sys_acct, sys_nis_syscall, sys_nis_syscall, sys_ioctl /*55*/ .long sys_reboot, sys_nis_syscall, sys_symlink, sys_readlink, sys_execve /*60*/ .long sys_umask, sys_chroot, sys_newfstat, sys_nis_syscall, sys_getpagesize @@ -47,7 +47,7 @@ /*140*/ .long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getrlimit /*145*/ .long sys_setrlimit, sys_nis_syscall, sys_prctl, sys_pciconfig_read, sys_pciconfig_write /*150*/ .long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_nis_syscall -/*155*/ .long sys_nis_syscall, sys_nis_syscall, sys_statfs, sys_fstatfs, sys_umount +/*155*/ .long sys_nis_syscall, sys_nis_syscall, sys_statfs, sys_fstatfs, sys_oldumount /*160*/ .long sys_nis_syscall, sys_nis_syscall, sys_getdomainname, sys_setdomainname, sys_nis_syscall /*165*/ .long sys_quotactl, sys_nis_syscall, sys_mount, sys_ustat, sys_nis_syscall /*170*/ .long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getdents @@ -129,7 +129,7 @@ /*150*/ .long sys_getsockname, sunos_nosys, sunos_nosys .long sys_poll, sunos_nosys, sunos_nosys .long sunos_getdirentries, sys_statfs, sys_fstatfs - .long sys_umount, sunos_nosys, sunos_nosys + .long sys_oldumount, sunos_nosys, sunos_nosys .long sys_getdomainname, sys_setdomainname .long sunos_nosys, sys_quotactl, sunos_nosys .long sunos_mount, sys_ustat, sunos_semsys diff -ur --new-file old/linux/arch/sparc/kernel/time.c new/linux/arch/sparc/kernel/time.c --- old/linux/arch/sparc/kernel/time.c Tue Jan 19 19:19:52 1999 +++ new/linux/arch/sparc/kernel/time.c Tue Mar 16 01:10:43 1999 @@ -1,4 +1,4 @@ -/* $Id: time.c,v 1.39 1998/09/29 09:46:15 davem Exp $ +/* $Id: time.c,v 1.43 1999/03/15 22:13:31 davem Exp $ * linux/arch/sparc/kernel/time.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -39,6 +39,8 @@ #include #include +extern rwlock_t xtime_lock; + enum sparc_clock_type sp_clock_typ; struct mostek48t02 *mstk48t02_regs = 0; struct mostek48t08 *mstk48t08_regs = 0; @@ -80,7 +82,7 @@ #ifdef CONFIG_SUN4 if((idprom->id_machtype == (SM_SUN4 | SM_4_260)) || - (idprom->id_machtype == (SM_SUN4 | SM_4_110))) { + (idprom->id_machtype == (SM_SUN4 | SM_4_110))) { int temp; intersil_read_intr(intersil_clock, temp); /* re-enable the irq */ @@ -89,6 +91,8 @@ #endif clear_clock_irq(); + write_lock(&xtime_lock); + do_timer(regs); /* Determine when to update the Mostek clock. */ @@ -101,6 +105,7 @@ else last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */ } + write_unlock(&xtime_lock); } /* Converts Gregorian date to seconds since 1970-01-01 00:00:00. @@ -436,6 +441,9 @@ return offset + count; } +/* This need not obtain the xtime_lock as it is coded in + * an implicitly SMP safe way already. + */ void do_gettimeofday(struct timeval *tv) { #if CONFIG_AP1000 @@ -485,12 +493,13 @@ void do_settimeofday(struct timeval *tv) { + write_lock_irq(&xtime_lock); bus_do_settimeofday(tv); + write_unlock_irq(&xtime_lock); } static void sbus_do_settimeofday(struct timeval *tv) { - cli(); #if !CONFIG_AP1000 tv->tv_usec -= do_gettimeoffset(); if(tv->tv_usec < 0) { @@ -501,10 +510,8 @@ xtime = *tv; time_adjust = 0; /* stop active adjtime() */ time_status |= STA_UNSYNC; - time_state = TIME_ERROR; /* p. 24, (a) */ time_maxerror = NTP_PHASE_LIMIT; time_esterror = NTP_PHASE_LIMIT; - sti(); } /* @@ -544,7 +551,7 @@ } else { printk(KERN_WARNING "set_rtc_mmss: can't update from %d to %d\n", - cmos_minutes, real_minutes); + mostek_minutes, real_minutes); return -1; } diff -ur --new-file old/linux/arch/sparc/kernel/traps.c new/linux/arch/sparc/kernel/traps.c --- old/linux/arch/sparc/kernel/traps.c Sun Oct 4 19:22:42 1998 +++ new/linux/arch/sparc/kernel/traps.c Thu Mar 11 01:53:36 1999 @@ -1,4 +1,4 @@ -/* $Id: traps.c,v 1.57 1998/09/17 11:04:51 jj Exp $ +/* $Id: traps.c,v 1.59 1999/03/06 12:07:31 anton Exp $ * arch/sparc/kernel/traps.c * * Copyright 1995 David S. Miller (davem@caip.rutgers.edu) @@ -82,8 +82,13 @@ printk("\n"); } +#define __SAVE __asm__ __volatile__("save %sp, -0x40, %sp\n\t") +#define __RESTORE __asm__ __volatile__("restore %g0, %g0, %g0\n\t") + void die_if_kernel(char *str, struct pt_regs *regs) { + int count = 0; + /* Amuse the user. */ printk( " \\|/ ____ \\|/\n" @@ -93,6 +98,27 @@ printk("%s(%d): %s\n", current->comm, current->pid, str); show_regs(regs); + + __SAVE; __SAVE; __SAVE; __SAVE; + __SAVE; __SAVE; __SAVE; __SAVE; + __RESTORE; __RESTORE; __RESTORE; __RESTORE; + __RESTORE; __RESTORE; __RESTORE; __RESTORE; + + { + struct reg_window *rw = (struct reg_window *)regs->u_regs[UREG_FP]; + + /* Stop the back trace when we hit userland or we + * find some badly aligned kernel stack. Set an upper + * bound in case our stack is trashed and we loop. + */ + while(rw && + count++ < 30 && + (((unsigned long) rw) >= PAGE_OFFSET) && + !(((unsigned long) rw) & 0x7)) { + printk("Caller[%08lx]\n", rw->ins[7]); + rw = (struct reg_window *)rw->ins[6]; + } + } printk("Instruction DUMP:"); instruction_dump ((unsigned long *) regs->pc); if(regs->psr & PSR_PS) diff -ur --new-file old/linux/arch/sparc/kernel/unaligned.c new/linux/arch/sparc/kernel/unaligned.c --- old/linux/arch/sparc/kernel/unaligned.c Tue Apr 15 01:28:07 1997 +++ new/linux/arch/sparc/kernel/unaligned.c Fri Apr 23 04:24:51 1999 @@ -1,4 +1,4 @@ -/* $Id: unaligned.c,v 1.17 1997/04/11 00:42:08 davem Exp $ +/* $Id: unaligned.c,v 1.18 1999/04/03 11:36:17 anton Exp $ * unaligned.c: Unaligned load/store trap handling with special * cases for the kernel to do them more quickly. * @@ -332,7 +332,6 @@ enum direction dir = decode_direction(insn); int size = decode_access_size(insn); - lock_kernel(); if(!ok_for_kernel(insn) || dir == both) { printk("Unsupported unaligned load/store trap for kernel at <%08lx>.\n", regs->pc); @@ -380,7 +379,6 @@ } advance(regs); } - unlock_kernel(); } static inline int ok_for_user(struct pt_regs *regs, unsigned int insn, diff -ur --new-file old/linux/arch/sparc/lib/Makefile new/linux/arch/sparc/lib/Makefile --- old/linux/arch/sparc/lib/Makefile Fri Dec 18 23:01:48 1998 +++ new/linux/arch/sparc/lib/Makefile Sun Mar 21 16:23:38 1999 @@ -1,11 +1,11 @@ -# $Id: Makefile,v 1.26 1998/07/26 03:02:43 davem Exp $ +# $Id: Makefile,v 1.28 1999/03/21 06:37:44 davem Exp $ # Makefile for Sparc library files.. # OBJS = mul.o rem.o sdiv.o udiv.o umul.o urem.o ashrdi3.o memcpy.o memset.o \ strlen.o checksum.o blockops.o memscan.o memcmp.o strncmp.o \ strncpy_from_user.o divdi3.o udivdi3.o strlen_user.o \ - copy_user.o locks.o atomic.o bitops.o debuglocks.o + copy_user.o locks.o atomic.o bitops.o debuglocks.o lshrdi3.o ifdef CONFIG_SMP OBJS += irqlock.o @@ -88,6 +88,9 @@ ashrdi3.o: ashrdi3.S $(CC) -D__ASSEMBLY__ -c -o ashrdi3.o ashrdi3.S + +lshrdi3.o: lshrdi3.S + $(CC) -D__ASSEMBLY__ -c -o lshrdi3.o lshrdi3.S dep: diff -ur --new-file old/linux/arch/sparc/lib/atomic.S new/linux/arch/sparc/lib/atomic.S --- old/linux/arch/sparc/lib/atomic.S Wed Apr 15 02:44:19 1998 +++ new/linux/arch/sparc/lib/atomic.S Fri Apr 23 04:24:51 1999 @@ -44,6 +44,7 @@ .globl ___atomic_add ___atomic_add: rd %psr, %g3 ! Keep the code small, old way was stupid + nop; nop; nop; ! Let the bits set or %g3, PSR_PIL, %g7 ! Disable interrupts wr %g7, 0x0, %psr ! Set %psr nop; nop; nop; ! Let the bits set @@ -51,12 +52,16 @@ 1: ldstub [%g1 + 3], %g7 ! Spin on the byte lock for SMP. orcc %g7, 0x0, %g0 ! Did we get it? bne 1b ! Nope... -#endif ld [%g1], %g7 ! Load locked atomic_t sra %g7, 8, %g7 ! Get signed 24-bit integer add %g7, %g2, %g2 ! Add in argument sll %g2, 8, %g7 ! Transpose back to atomic_t st %g7, [%g1] ! Clever: This releases the lock as well. +#else + ld [%g1], %g7 ! Load locked atomic_t + add %g7, %g2, %g2 ! Add in argument + st %g2, [%g1] ! Store it back +#endif wr %g3, 0x0, %psr ! Restore original PSR_PIL nop; nop; nop; ! Let the bits set jmpl %o7, %g0 ! NOTE: not + 8, see callers in atomic.h @@ -65,6 +70,7 @@ .globl ___atomic_sub ___atomic_sub: rd %psr, %g3 ! Keep the code small, old way was stupid + nop; nop; nop; ! Let the bits set or %g3, PSR_PIL, %g7 ! Disable interrupts wr %g7, 0x0, %psr ! Set %psr nop; nop; nop; ! Let the bits set @@ -72,12 +78,16 @@ 1: ldstub [%g1 + 3], %g7 ! Spin on the byte lock for SMP. orcc %g7, 0x0, %g0 ! Did we get it? bne 1b ! Nope... -#endif ld [%g1], %g7 ! Load locked atomic_t sra %g7, 8, %g7 ! Get signed 24-bit integer sub %g7, %g2, %g2 ! Subtract argument sll %g2, 8, %g7 ! Transpose back to atomic_t st %g7, [%g1] ! Clever: This releases the lock as well +#else + ld [%g1], %g7 ! Load locked atomic_t + sub %g7, %g2, %g2 ! Subtract argument + st %g2, [%g1] ! Store it back +#endif wr %g3, 0x0, %psr ! Restore original PSR_PIL nop; nop; nop; ! Let the bits set jmpl %o7, %g0 ! NOTE: not + 8, see callers in atomic.h diff -ur --new-file old/linux/arch/sparc/lib/bitops.S new/linux/arch/sparc/lib/bitops.S --- old/linux/arch/sparc/lib/bitops.S Tue Oct 27 18:52:20 1998 +++ new/linux/arch/sparc/lib/bitops.S Fri Apr 23 04:24:51 1999 @@ -20,12 +20,10 @@ .globl ___set_bit ___set_bit: rd %psr, %g3 - andcc %g3, PSR_PIL, %g0 - bne 1f - nop - wr %g3, PSR_PIL, %psr + nop; nop; nop; + or %g3, PSR_PIL, %g5 + wr %g5, 0x0, %psr nop; nop; nop -1: #ifdef __SMP__ set C_LABEL(bitops_spinlock), %g5 2: ldstub [%g5], %g7 ! Spin on the byte lock for SMP. @@ -38,17 +36,12 @@ #ifdef __SMP__ st %g5, [%g1] set C_LABEL(bitops_spinlock), %g5 - andcc %g3, PSR_PIL, %g0 - bne 1f - stb %g0, [%g5] + stb %g0, [%g5] #else - andcc %g3, PSR_PIL, %g0 - bne 1f - st %g5, [%g1] + st %g5, [%g1] #endif wr %g3, 0x0, %psr nop; nop; nop -1: jmpl %o7, %g0 mov %g4, %o7 @@ -56,12 +49,10 @@ .globl ___clear_bit ___clear_bit: rd %psr, %g3 - andcc %g3, PSR_PIL, %g0 - bne 1f - nop - wr %g3, PSR_PIL, %psr nop; nop; nop -1: + or %g3, PSR_PIL, %g5 + wr %g5, 0x0, %psr + nop; nop; nop #ifdef __SMP__ set C_LABEL(bitops_spinlock), %g5 2: ldstub [%g5], %g7 ! Spin on the byte lock for SMP. @@ -74,17 +65,12 @@ #ifdef __SMP__ st %g5, [%g1] set C_LABEL(bitops_spinlock), %g5 - andcc %g3, PSR_PIL, %g0 - bne 1f - stb %g0, [%g5] + stb %g0, [%g5] #else - andcc %g3, PSR_PIL, %g0 - bne 1f - st %g5, [%g1] + st %g5, [%g1] #endif wr %g3, 0x0, %psr nop; nop; nop -1: jmpl %o7, %g0 mov %g4, %o7 @@ -92,12 +78,10 @@ .globl ___change_bit ___change_bit: rd %psr, %g3 - andcc %g3, PSR_PIL, %g0 - bne 1f - nop - wr %g3, PSR_PIL, %psr nop; nop; nop -1: + or %g3, PSR_PIL, %g5 + wr %g5, 0x0, %psr + nop; nop; nop #ifdef __SMP__ set C_LABEL(bitops_spinlock), %g5 2: ldstub [%g5], %g7 ! Spin on the byte lock for SMP. @@ -110,17 +94,12 @@ #ifdef __SMP__ st %g5, [%g1] set C_LABEL(bitops_spinlock), %g5 - andcc %g3, PSR_PIL, %g0 - bne 1f - stb %g0, [%g5] + stb %g0, [%g5] #else - andcc %g3, PSR_PIL, %g0 - bne 1f - st %g5, [%g1] + st %g5, [%g1] #endif wr %g3, 0x0, %psr nop; nop; nop -1: jmpl %o7, %g0 mov %g4, %o7 @@ -128,12 +107,10 @@ .globl ___set_le_bit ___set_le_bit: rd %psr, %g3 - andcc %g3, PSR_PIL, %g0 - bne 1f - nop - wr %g3, PSR_PIL, %psr nop; nop; nop -1: + or %g3, PSR_PIL, %g5 + wr %g5, 0x0, %psr + nop; nop; nop #ifdef __SMP__ set C_LABEL(bitops_spinlock), %g5 2: ldstub [%g5], %g7 ! Spin on the byte lock for SMP. @@ -146,29 +123,22 @@ #ifdef __SMP__ stb %g5, [%g1] set C_LABEL(bitops_spinlock), %g5 - andcc %g3, PSR_PIL, %g0 - bne 1f - stb %g0, [%g5] + stb %g0, [%g5] #else - andcc %g3, PSR_PIL, %g0 - bne 1f - stb %g5, [%g1] + stb %g5, [%g1] #endif wr %g3, 0x0, %psr nop; nop; nop -1: jmpl %o7, %g0 mov %g4, %o7 .globl ___clear_le_bit ___clear_le_bit: rd %psr, %g3 - andcc %g3, PSR_PIL, %g0 - bne 1f - nop - wr %g3, PSR_PIL, %psr nop; nop; nop -1: + or %g3, PSR_PIL, %g5 + wr %g5, 0x0, %psr + nop; nop; nop #ifdef __SMP__ set C_LABEL(bitops_spinlock), %g5 2: ldstub [%g5], %g7 ! Spin on the byte lock for SMP. @@ -181,16 +151,11 @@ #ifdef __SMP__ stb %g5, [%g1] set C_LABEL(bitops_spinlock), %g5 - andcc %g3, PSR_PIL, %g0 - bne 1f - stb %g0, [%g5] + stb %g0, [%g5] #else - andcc %g3, PSR_PIL, %g0 - bne 1f - stb %g5, [%g1] + stb %g5, [%g1] #endif wr %g3, 0x0, %psr nop; nop; nop -1: jmpl %o7, %g0 mov %g4, %o7 diff -ur --new-file old/linux/arch/sparc/lib/debuglocks.c new/linux/arch/sparc/lib/debuglocks.c --- old/linux/arch/sparc/lib/debuglocks.c Tue Oct 27 18:52:20 1998 +++ new/linux/arch/sparc/lib/debuglocks.c Fri Apr 23 04:24:51 1999 @@ -1,12 +1,13 @@ -/* $Id: debuglocks.c,v 1.5 1998/10/14 09:19:04 jj Exp $ +/* $Id: debuglocks.c,v 1.7 1999/04/21 02:26:58 anton Exp $ * debuglocks.c: Debugging versions of SMP locking primitives. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) - * Copyright (C) 1998 Anton Blanchard (anton@progsoc.uts.edu.au) + * Copyright (C) 1998-99 Anton Blanchard (anton@progsoc.uts.edu.au) */ #include #include +#include /* For NR_CPUS */ #include #include #include @@ -28,29 +29,33 @@ static inline void show(char *str, spinlock_t *lock, unsigned long caller) { int cpu = smp_processor_id(); + extern spinlock_t console_lock; - printk("%s(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n",str, - lock, cpu, caller, lock->owner_pc & ~3, lock->owner_pc & 3); + if (lock != &console_lock) + printk("%s(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n",str, + lock, cpu, caller, lock->owner_pc & ~3, lock->owner_pc & 3); } static inline void show_read(char *str, rwlock_t *lock, unsigned long caller) { int cpu = smp_processor_id(); - printk("%s(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n",str, + printk("%s(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", str, lock, cpu, caller, lock->owner_pc & ~3, lock->owner_pc & 3); } static inline void show_write(char *str, rwlock_t *lock, unsigned long caller) { int cpu = smp_processor_id(); + int i; + + printk("%s(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)", str, + lock, cpu, caller, lock->owner_pc & ~3, lock->owner_pc & 3); + + for(i = 0; i < NR_CPUS; i++) + printk(" reader[i]=%08lx", lock->reader_pc[i]); - printk("%s(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx) reader[0]=%08lx reader[1]=%08lx reader[2]=%08lx reader[3]=%08lx\n", - str, lock, cpu, caller, lock->owner_pc & ~3, lock->owner_pc & 3, - lock->reader_pc[0], - lock->reader_pc[1], - lock->reader_pc[2], - lock->reader_pc[3]); + printk("\n"); } #undef INIT_STUCK @@ -103,9 +108,6 @@ lock->lock = 0; } -#undef INIT_STUCK -#define INIT_STUCK 100000000 - void _do_read_lock(rwlock_t *rw, char *str) { unsigned long caller; @@ -133,9 +135,6 @@ rw->lock++; } -#undef INIT_STUCK -#define INIT_STUCK 100000000 - void _do_read_unlock(rwlock_t *rw, char *str) { unsigned long caller; @@ -162,9 +161,6 @@ barrier(); rw->lock -= 0x1ff; } - -#undef INIT_STUCK -#define INIT_STUCK 100000000 void _do_write_lock(rwlock_t *rw, char *str) { diff -ur --new-file old/linux/arch/sparc/lib/irqlock.S new/linux/arch/sparc/lib/irqlock.S --- old/linux/arch/sparc/lib/irqlock.S Wed May 14 07:41:03 1997 +++ new/linux/arch/sparc/lib/irqlock.S Fri Apr 23 04:24:51 1999 @@ -1,4 +1,4 @@ -/* $Id: irqlock.S,v 1.4 1997/05/01 02:26:54 davem Exp $ +/* $Id: irqlock.S,v 1.5 1999/04/20 13:22:37 anton Exp $ * irqlock.S: High performance IRQ global locking and interrupt entry. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -9,69 +9,6 @@ .text .align 4 - - /* This is incredibly insane... */ - .globl ___irq_enter -___irq_enter: - sethi %hi(local_irq_count), %g2 - sll %g1, 2, %g1 - or %g2, %lo(local_irq_count), %g2 - ld [%g2 + %g1], %g3 - sethi %hi(global_irq_count), %g5 - add %g3, 1, %g3 - or %g5, %lo(global_irq_count), %g5 - st %g3, [%g2 + %g1] -1: - ldstub [%g5 + 3], %g2 - orcc %g2, 0x0, %g0 - bne 1b - ld [%g5], %g3 - sra %g3, 8, %g3 - add %g3, 1, %g3 - sll %g3, 8, %g3 - st %g3, [%g5] - sethi %hi(global_irq_lock), %g1 - ldub [%g1 + %lo(global_irq_lock)], %g2 -1: - orcc %g2, 0x0, %g0 - bne,a 1b - ldub [%g1 + %lo(global_irq_lock)], %g2 -___irq_enter_out: - jmpl %o7, %g0 - mov %g4, %o7 - - .globl ___irq_exit -___irq_exit: - rd %psr, %g3 - sethi %hi(global_irq_count), %g1 - or %g3, PSR_PIL, %g3 - or %g1, %lo(global_irq_count), %g1 - wr %g3, 0x0, %psr - sethi %hi(local_irq_count), %g2 - sll %g7, 2, %g7 - or %g2, %lo(local_irq_count), %g2 - ld [%g2 + %g7], %g3 -1: - ldstub [%g1 + 3], %g5 - orcc %g5, 0x0, %g0 - bne 1b - ld [%g1], %g5 - sra %g5, 8, %g5 - sub %g5, 1, %g5 - sll %g5, 8, %g5 - st %g5, [%g1] - sub %g3, 1, %g3 - sethi %hi(global_irq_holder), %g1 - st %g3, [%g2 + %g7] - srl %g7, 2, %g7 - ldub [%g1 + %lo(global_irq_holder)], %g5 - cmp %g5, %g7 - bne ___irq_enter_out - mov NO_PROC_ID, %g2 - stb %g2, [%g1 + %lo(global_irq_holder)] - sethi %hi(global_irq_lock), %g5 - b ___irq_enter_out - stb %g0, [%g5 + %lo(global_irq_lock)] /* Weird calling conventions... %g7=flags, %g4=%prev_o7 * Very clever for the __global_sti case, the inline which diff -ur --new-file old/linux/arch/sparc/lib/lshrdi3.S new/linux/arch/sparc/lib/lshrdi3.S --- old/linux/arch/sparc/lib/lshrdi3.S Thu Jan 1 01:00:00 1970 +++ new/linux/arch/sparc/lib/lshrdi3.S Sun Mar 21 16:23:38 1999 @@ -0,0 +1,29 @@ +/* $Id: lshrdi3.S,v 1.1 1999/03/21 06:37:45 davem Exp $ */ + +#include + + .globl C_LABEL(__lshrdi3) +C_LABEL(__lshrdi3): + cmp %o2, 0 + be 3f + mov 0x20, %g2 + + sub %g2, %o2, %g2 + cmp %g2, 0 + bg 1f + srl %o0, %o2, %o4 + + clr %o4 + neg %g2 + b 2f + srl %o0, %g2, %o5 +1: + sll %o0, %g2, %g3 + srl %o1, %o2, %g2 + or %g2, %g3, %o5 +2: + mov %o4, %o0 + mov %o5, %o1 +3: + retl + nop diff -ur --new-file old/linux/arch/sparc/math-emu/fabss.c new/linux/arch/sparc/math-emu/fabss.c --- old/linux/arch/sparc/math-emu/fabss.c Wed Apr 15 02:44:19 1998 +++ new/linux/arch/sparc/math-emu/fabss.c Thu Mar 11 01:53:36 1999 @@ -2,5 +2,5 @@ { /* Clear the sign bit (high bit of word 0) */ rd[0] = rs2[0] & 0x7fffffffUL; - return 1; + return 0; } diff -ur --new-file old/linux/arch/sparc/math-emu/fcmpd.c new/linux/arch/sparc/math-emu/fcmpd.c --- old/linux/arch/sparc/math-emu/fcmpd.c Wed Apr 15 02:44:19 1998 +++ new/linux/arch/sparc/math-emu/fcmpd.c Thu Mar 11 01:53:36 1999 @@ -14,5 +14,5 @@ ret = 2; *fsr = (*fsr & ~0xc00) | (ret << 10); - return 1; + return 0; } diff -ur --new-file old/linux/arch/sparc/math-emu/fcmped.c new/linux/arch/sparc/math-emu/fcmped.c --- old/linux/arch/sparc/math-emu/fcmped.c Wed Apr 15 02:44:19 1998 +++ new/linux/arch/sparc/math-emu/fcmped.c Thu Mar 11 01:53:36 1999 @@ -14,5 +14,5 @@ ret = 2; *fsr = (*fsr & ~0xc00) | (ret << 10); - return 1; + return 0; } diff -ur --new-file old/linux/arch/sparc/math-emu/fcmpeq.c new/linux/arch/sparc/math-emu/fcmpeq.c --- old/linux/arch/sparc/math-emu/fcmpeq.c Wed Apr 15 02:44:19 1998 +++ new/linux/arch/sparc/math-emu/fcmpeq.c Thu Mar 11 01:53:36 1999 @@ -14,5 +14,5 @@ fsr = *(unsigned long *)rd; fsr &= ~0xc00; fsr |= (ret << 10); *(unsigned long *)rd = fsr; - return 1; + return 0; } diff -ur --new-file old/linux/arch/sparc/math-emu/fcmpes.c new/linux/arch/sparc/math-emu/fcmpes.c --- old/linux/arch/sparc/math-emu/fcmpes.c Wed Apr 15 02:44:19 1998 +++ new/linux/arch/sparc/math-emu/fcmpes.c Thu Mar 11 01:53:36 1999 @@ -14,5 +14,5 @@ ret = 2; *fsr = (*fsr & ~0xc00) | (ret << 10); - return 1; + return 0; } diff -ur --new-file old/linux/arch/sparc/math-emu/fcmpq.c new/linux/arch/sparc/math-emu/fcmpq.c --- old/linux/arch/sparc/math-emu/fcmpq.c Wed Apr 15 02:44:19 1998 +++ new/linux/arch/sparc/math-emu/fcmpq.c Thu Mar 11 01:53:36 1999 @@ -14,5 +14,5 @@ fsr = *(unsigned long *)rd; fsr &= ~0xc00; fsr |= (ret << 10); *(unsigned long *)rd = fsr; - return 1; + return 0; } diff -ur --new-file old/linux/arch/sparc/math-emu/fcmps.c new/linux/arch/sparc/math-emu/fcmps.c --- old/linux/arch/sparc/math-emu/fcmps.c Wed Apr 15 02:44:19 1998 +++ new/linux/arch/sparc/math-emu/fcmps.c Thu Mar 11 01:53:36 1999 @@ -14,5 +14,5 @@ ret = 2; *fsr = (*fsr & ~0xc00) | (ret << 10); - return 1; + return 0; } diff -ur --new-file old/linux/arch/sparc/math-emu/fdmulq.c new/linux/arch/sparc/math-emu/fdmulq.c --- old/linux/arch/sparc/math-emu/fdmulq.c Wed Apr 15 02:44:19 1998 +++ new/linux/arch/sparc/math-emu/fdmulq.c Thu Mar 11 01:53:36 1999 @@ -11,6 +11,5 @@ __FP_UNPACK_D(IN, rs2); FP_CONV(Q,D,4,2,B,IN); FP_MUL_Q(R, A, B); - __FP_PACK_Q(rd, R); - return 1; + return __FP_PACK_Q(rd, R); } diff -ur --new-file old/linux/arch/sparc/math-emu/fdtoq.c new/linux/arch/sparc/math-emu/fdtoq.c --- old/linux/arch/sparc/math-emu/fdtoq.c Wed Apr 15 02:44:19 1998 +++ new/linux/arch/sparc/math-emu/fdtoq.c Thu Mar 11 01:53:36 1999 @@ -8,6 +8,5 @@ __FP_UNPACK_D(A, rs2); FP_CONV(Q,D,4,2,R,A); - __FP_PACK_Q(rd, R); - return 1; + return __FP_PACK_Q(rd, R); } diff -ur --new-file old/linux/arch/sparc/math-emu/fdtos.c new/linux/arch/sparc/math-emu/fdtos.c --- old/linux/arch/sparc/math-emu/fdtos.c Wed Apr 15 02:44:19 1998 +++ new/linux/arch/sparc/math-emu/fdtos.c Thu Mar 11 01:53:36 1999 @@ -8,6 +8,5 @@ __FP_UNPACK_D(A, rs2); FP_CONV(S,D,1,2,R,A); - __FP_PACK_S(rd, R); - return 1; + return __FP_PACK_S(rd, R); } diff -ur --new-file old/linux/arch/sparc/math-emu/fnegs.c new/linux/arch/sparc/math-emu/fnegs.c --- old/linux/arch/sparc/math-emu/fnegs.c Fri May 8 09:11:28 1998 +++ new/linux/arch/sparc/math-emu/fnegs.c Thu Mar 11 01:53:36 1999 @@ -2,5 +2,5 @@ { /* just change the sign bit */ rd[0] = rs2[0] ^ 0x80000000UL; - return 1; + return 0; } diff -ur --new-file old/linux/arch/sparc/math-emu/fqtod.c new/linux/arch/sparc/math-emu/fqtod.c --- old/linux/arch/sparc/math-emu/fqtod.c Wed Apr 15 02:44:19 1998 +++ new/linux/arch/sparc/math-emu/fqtod.c Thu Mar 11 01:53:36 1999 @@ -8,6 +8,5 @@ __FP_UNPACK_Q(A, rs2); FP_CONV(D,Q,2,4,R,A); - __FP_PACK_D(rd, R); - return 1; + return __FP_PACK_D(rd, R); } diff -ur --new-file old/linux/arch/sparc/math-emu/fqtos.c new/linux/arch/sparc/math-emu/fqtos.c --- old/linux/arch/sparc/math-emu/fqtos.c Wed Apr 15 02:44:19 1998 +++ new/linux/arch/sparc/math-emu/fqtos.c Thu Mar 11 01:53:36 1999 @@ -8,6 +8,5 @@ __FP_UNPACK_Q(A, rs2); FP_CONV(S,Q,1,4,R,A); - __FP_PACK_S(rd, R); - return 1; + return __FP_PACK_S(rd, R); } diff -ur --new-file old/linux/arch/sparc/math-emu/fsmuld.c new/linux/arch/sparc/math-emu/fsmuld.c --- old/linux/arch/sparc/math-emu/fsmuld.c Wed Apr 15 02:44:19 1998 +++ new/linux/arch/sparc/math-emu/fsmuld.c Thu Mar 11 01:53:36 1999 @@ -11,6 +11,5 @@ __FP_UNPACK_S(IN, rs2); FP_CONV(D,S,2,1,B,IN); FP_MUL_D(R, A, B); - __FP_PACK_D(rd, R); - return 1; + return __FP_PACK_D(rd, R); } diff -ur --new-file old/linux/arch/sparc/math-emu/fstod.c new/linux/arch/sparc/math-emu/fstod.c --- old/linux/arch/sparc/math-emu/fstod.c Wed Apr 15 02:44:19 1998 +++ new/linux/arch/sparc/math-emu/fstod.c Thu Mar 11 01:53:36 1999 @@ -8,6 +8,5 @@ __FP_UNPACK_S(A, rs2); FP_CONV(D,S,2,1,R,A); - __FP_PACK_D(rd, R); - return 1; + return __FP_PACK_D(rd, R); } diff -ur --new-file old/linux/arch/sparc/math-emu/fstoq.c new/linux/arch/sparc/math-emu/fstoq.c --- old/linux/arch/sparc/math-emu/fstoq.c Wed Apr 15 02:44:19 1998 +++ new/linux/arch/sparc/math-emu/fstoq.c Thu Mar 11 01:53:36 1999 @@ -8,6 +8,5 @@ __FP_UNPACK_S(A, rs2); FP_CONV(Q,S,4,1,R,A); - __FP_PACK_Q(rd, R); - return 1; + return __FP_PACK_Q(rd, R); } diff -ur --new-file old/linux/arch/sparc/math-emu/math.c new/linux/arch/sparc/math-emu/math.c --- old/linux/arch/sparc/math-emu/math.c Wed Apr 15 02:44:19 1998 +++ new/linux/arch/sparc/math-emu/math.c Thu Mar 11 01:53:36 1999 @@ -124,6 +124,7 @@ #include #include +#include "soft-fp.h" #define FLOATFUNC(x) extern int x(void *,void *,void *) @@ -189,6 +190,13 @@ FLOATFUNC(FITOS); /* v6 */ FLOATFUNC(FITOD); /* v6 */ +#define FSR_TEM_SHIFT 23UL +#define FSR_TEM_MASK (0x1fUL << FSR_TEM_SHIFT) +#define FSR_AEXC_SHIFT 5UL +#define FSR_AEXC_MASK (0x1fUL << FSR_AEXC_SHIFT) +#define FSR_CEXC_SHIFT 0UL +#define FSR_CEXC_MASK (0x1fUL << FSR_CEXC_SHIFT) + static int do_one_mathemu(u32 insn, unsigned long *fsr, unsigned long *fregs); /* Unlike the Sparc64 version (which has a struct fpustate), we @@ -254,12 +262,85 @@ break; } /* Now empty the queue and clear the queue_not_empty flag */ - fpt->tss.fsr &= ~0x3000; + if(retcode) + fpt->tss.fsr &= ~(0x3000 | FSR_CEXC_MASK); + else + fpt->tss.fsr &= ~0x3000; fpt->tss.fpqdepth = 0; return retcode; } +/* All routines returning an exception to raise should detect + * such exceptions _before_ rounding to be consistant with + * the behavior of the hardware in the implemented cases + * (and thus with the recommendations in the V9 architecture + * manual). + * + * We return 0 if a SIGFPE should be sent, 1 otherwise. + */ +static int record_exception(unsigned long *pfsr, int eflag) +{ + unsigned long fsr = *pfsr; + int would_trap; + + /* Determine if this exception would have generated a trap. */ + would_trap = (fsr & ((long)eflag << FSR_TEM_SHIFT)) != 0UL; + + /* If trapping, we only want to signal one bit. */ + if(would_trap != 0) { + eflag &= ((fsr & FSR_TEM_MASK) >> FSR_TEM_SHIFT); + if((eflag & (eflag - 1)) != 0) { + if(eflag & EFLAG_INVALID) + eflag = EFLAG_INVALID; + else if(eflag & EFLAG_DIVZERO) + eflag = EFLAG_DIVZERO; + else if(eflag & EFLAG_INEXACT) + eflag = EFLAG_INEXACT; + } + } + + /* Set CEXC, here are the rules: + * + * 1) In general all FPU ops will set one and only one + * bit in the CEXC field, this is always the case + * when the IEEE exception trap is enabled in TEM. + * + * 2) As a special case, if an overflow or underflow + * is being signalled, AND the trap is not enabled + * in TEM, then the inexact field shall also be set. + */ + fsr &= ~(FSR_CEXC_MASK); + if(would_trap || + (eflag & (EFLAG_OVERFLOW | EFLAG_UNDERFLOW)) == 0) { + fsr |= ((long)eflag << FSR_CEXC_SHIFT); + } else { + fsr |= (((long)eflag << FSR_CEXC_SHIFT) | + (EFLAG_INEXACT << FSR_CEXC_SHIFT)); + } + + /* Set the AEXC field, rules are: + * + * 1) If a trap would not be generated, the + * CEXC just generated is OR'd into the + * existing value of AEXC. + * + * 2) When a trap is generated, AEXC is cleared. + */ + if(would_trap == 0) + fsr |= ((long)eflag << FSR_AEXC_SHIFT); + else + fsr &= ~(FSR_AEXC_MASK); + + /* If trapping, indicate fault trap type IEEE. */ + if(would_trap != 0) + fsr |= (1UL << 14); + + *pfsr = fsr; + + return (would_trap ? 0 : 1); +} + static int do_one_mathemu(u32 insn, unsigned long *fsr, unsigned long *fregs) { /* Emulate the given insn, updating fsr and fregs appropriately. */ @@ -270,7 +351,7 @@ * (this field not used on sparc32 code, as we can't * extract trap type info for ops on the FP queue) */ - int freg; + int freg, eflag; int (*func)(void *,void *,void *) = NULL; void *rs1 = NULL, *rs2 = NULL, *rd = NULL; @@ -411,6 +492,8 @@ #ifdef DEBUG_MATHEMU printk("executing insn...\n"); #endif - func(rd, rs2, rs1); /* do the Right Thing */ - return 1; /* success! */ + eflag = func(rd, rs2, rs1); /* do the Right Thing */ + if(eflag == 0) + return 1; /* success! */ + return record_exception(fsr, eflag); } diff -ur --new-file old/linux/arch/sparc/math-emu/sfp-machine.h new/linux/arch/sparc/math-emu/sfp-machine.h --- old/linux/arch/sparc/math-emu/sfp-machine.h Wed Apr 15 02:44:19 1998 +++ new/linux/arch/sparc/math-emu/sfp-machine.h Thu Mar 11 01:53:36 1999 @@ -115,16 +115,6 @@ X##_s = _flo->bits.sign; \ } while (0) -#define __FP_PACK_RAW_1(fs, val, X) \ - do { \ - union _FP_UNION_##fs *_flo = \ - (union _FP_UNION_##fs *)val; \ - \ - _flo->bits.frac = X##_f; \ - _flo->bits.exp = X##_e; \ - _flo->bits.sign = X##_s; \ - } while (0) - #define __FP_UNPACK_RAW_2(fs, X, val) \ do { \ union _FP_UNION_##fs *_flo = \ @@ -136,17 +126,6 @@ X##_s = _flo->bits.sign; \ } while (0) -#define __FP_PACK_RAW_2(fs, val, X) \ - do { \ - union _FP_UNION_##fs *_flo = \ - (union _FP_UNION_##fs *)val; \ - \ - _flo->bits.frac0 = X##_f0; \ - _flo->bits.frac1 = X##_f1; \ - _flo->bits.exp = X##_e; \ - _flo->bits.sign = X##_s; \ - } while (0) - #define __FP_UNPACK_RAW_4(fs, X, val) \ do { \ union _FP_UNION_##fs *_flo = \ @@ -160,55 +139,103 @@ X##_s = _flo->bits.sign; \ } while (0) -#define __FP_PACK_RAW_4(fs, val, X) \ - do { \ - union _FP_UNION_##fs *_flo = \ - (union _FP_UNION_##fs *)val; \ - \ - _flo->bits.frac0 = X##_f[0]; \ - _flo->bits.frac1 = X##_f[1]; \ - _flo->bits.frac2 = X##_f[2]; \ - _flo->bits.frac3 = X##_f[3]; \ - _flo->bits.exp = X##_e; \ - _flo->bits.sign = X##_s; \ - } while (0) - #define __FP_UNPACK_S(X,val) \ do { \ __FP_UNPACK_RAW_1(S,X,val); \ _FP_UNPACK_CANONICAL(S,1,X); \ } while (0) -#define __FP_PACK_S(val,X) \ - do { \ - _FP_PACK_CANONICAL(S,1,X); \ - __FP_PACK_RAW_1(S,val,X); \ - } while (0) - #define __FP_UNPACK_D(X,val) \ do { \ __FP_UNPACK_RAW_2(D,X,val); \ _FP_UNPACK_CANONICAL(D,2,X); \ } while (0) -#define __FP_PACK_D(val,X) \ - do { \ - _FP_PACK_CANONICAL(D,2,X); \ - __FP_PACK_RAW_2(D,val,X); \ - } while (0) - #define __FP_UNPACK_Q(X,val) \ do { \ __FP_UNPACK_RAW_4(Q,X,val); \ _FP_UNPACK_CANONICAL(Q,4,X); \ } while (0) -#define __FP_PACK_Q(val,X) \ - do { \ - _FP_PACK_CANONICAL(Q,4,X); \ - __FP_PACK_RAW_4(Q,val,X); \ +#define __FP_PACK_RAW_1(fs, val, X) \ + do { \ + union _FP_UNION_##fs *_flo = \ + (union _FP_UNION_##fs *)val; \ + \ + _flo->bits.frac = X##_f; \ + _flo->bits.exp = X##_e; \ + _flo->bits.sign = X##_s; \ + } while (0) + +#define __FP_PACK_RAW_2(fs, val, X) \ + do { \ + union _FP_UNION_##fs *_flo = \ + (union _FP_UNION_##fs *)val; \ + \ + _flo->bits.frac0 = X##_f0; \ + _flo->bits.frac1 = X##_f1; \ + _flo->bits.exp = X##_e; \ + _flo->bits.sign = X##_s; \ + } while (0) + +#define __FP_PACK_RAW_4(fs, val, X) \ + do { \ + union _FP_UNION_##fs *_flo = \ + (union _FP_UNION_##fs *)val; \ + \ + _flo->bits.frac0 = X##_f[0]; \ + _flo->bits.frac1 = X##_f[1]; \ + _flo->bits.frac2 = X##_f[2]; \ + _flo->bits.frac3 = X##_f[3]; \ + _flo->bits.exp = X##_e; \ + _flo->bits.sign = X##_s; \ } while (0) +#include +#include + +/* We only actually write to the destination register + * if exceptions signalled (if any) will not trap. + */ +#ifdef __SMP__ +#define __FPU_TEM \ + (((current->tss.fsr)>>23)&0x1f) +#else +extern struct task_struct *last_task_used_math; +#define __FPU_TEM \ + (((last_task_used_math->tss.fsr)>>23)&0x1f) +#endif +#define __FPU_TRAP_P(bits) \ + ((__FPU_TEM & (bits)) != 0) + +#define __FP_PACK_S(val,X) \ +({ int __exc = _FP_PACK_CANONICAL(S,1,X); \ + if(!__exc || !__FPU_TRAP_P(__exc)) \ + __FP_PACK_RAW_1(S,val,X); \ + __exc; \ +}) + +#define __FP_PACK_D(val,X) \ +({ int __exc = _FP_PACK_CANONICAL(D,2,X); \ + if(!__exc || !__FPU_TRAP_P(__exc)) \ + __FP_PACK_RAW_2(D,val,X); \ + __exc; \ +}) + +#define __FP_PACK_Q(val,X) \ +({ int __exc = _FP_PACK_CANONICAL(Q,4,X); \ + if(!__exc || !__FPU_TRAP_P(__exc)) \ + __FP_PACK_RAW_4(Q,val,X); \ + __exc; \ +}) + +/* Obtain the current rounding mode. */ +#ifdef __SMP__ +#define FP_ROUNDMODE ((current->tss.fsr >> 30) & 0x3) +#else +#define FP_ROUNDMODE ((last_task_used_math->tss.fsr >> 30) & 0x3) +#endif + /* the asm fragments go here: all these are taken from glibc-2.0.5's stdlib/longlong.h */ #include @@ -361,3 +388,9 @@ #define __BYTE_ORDER __LITTLE_ENDIAN #endif +/* Exception flags. */ +#define EFLAG_INVALID (1 << 4) +#define EFLAG_OVERFLOW (1 << 3) +#define EFLAG_UNDERFLOW (1 << 2) +#define EFLAG_DIVZERO (1 << 1) +#define EFLAG_INEXACT (1 << 0) diff -ur --new-file old/linux/arch/sparc/mm/Makefile new/linux/arch/sparc/mm/Makefile --- old/linux/arch/sparc/mm/Makefile Fri Dec 18 23:01:48 1998 +++ new/linux/arch/sparc/mm/Makefile Thu Mar 11 01:53:36 1999 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.32 1998/08/16 16:02:25 ecd Exp $ +# $Id: Makefile,v 1.33 1999/01/02 16:45:47 davem Exp $ # Makefile for the linux Sparc-specific parts of the memory manager. # # Note! Dependencies are done automagically by 'make dep', which also diff -ur --new-file old/linux/arch/sparc/mm/fault.c new/linux/arch/sparc/mm/fault.c --- old/linux/arch/sparc/mm/fault.c Mon Nov 16 19:37:28 1998 +++ new/linux/arch/sparc/mm/fault.c Thu Mar 11 01:53:36 1999 @@ -1,4 +1,4 @@ -/* $Id: fault.c,v 1.96 1998/11/08 11:13:56 davem Exp $ +/* $Id: fault.c,v 1.101 1999/01/04 06:24:52 jj Exp $ * fault.c: Page fault handlers for the Sparc. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -13,11 +13,13 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include @@ -149,9 +151,7 @@ (unsigned long) tsk->mm->context); printk(KERN_ALERT "tsk->mm->pgd = %08lx\n", (unsigned long) tsk->mm->pgd); - lock_kernel(); die_if_kernel("Oops", regs); - unlock_kernel(); } asmlinkage int lookup_fault(unsigned long pc, unsigned long ret_pc, @@ -201,6 +201,13 @@ if(text_fault) address = regs->pc; + + /* + * If we're in an interrupt or have no user + * context, we must not take the fault.. + */ + if (in_interrupt() || mm == &init_mm) + goto do_kernel_fault; down(&mm->mmap_sem); /* The kernel referencing a bad kernel pointer can lock up diff -ur --new-file old/linux/arch/sparc/mm/init.c new/linux/arch/sparc/mm/init.c --- old/linux/arch/sparc/mm/init.c Sun Oct 4 19:22:43 1998 +++ new/linux/arch/sparc/mm/init.c Fri Apr 23 04:24:51 1999 @@ -1,4 +1,4 @@ -/* $Id: init.c,v 1.60 1998/09/13 04:30:31 davem Exp $ +/* $Id: init.c,v 1.65 1999/04/09 16:28:03 davem Exp $ * linux/arch/sparc/mm/init.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -37,6 +37,8 @@ extern void show_net_buffers(void); +unsigned long *sparc_valid_addr_bitmap; + struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS]; unsigned long sparc_unmapped_base; @@ -215,16 +217,20 @@ unsigned long limit = base + sp_banks[tmp2].num_bytes; if((phys_addr >= base) && (phys_addr < limit) && - ((phys_addr + PAGE_SIZE) < limit)) + ((phys_addr + PAGE_SIZE) < limit)) { mem_map[MAP_NR(addr)].flags &= ~(1<> 8, sparc_valid_addr_bitmap); + } } } } else { if((sparc_cpu_model == sun4m) || (sparc_cpu_model == sun4d)) { srmmu_frob_mem_map(start_mem); } else { - for(addr = start_mem; addr < end_mem; addr += PAGE_SIZE) + for(addr = start_mem; addr < end_mem; addr += PAGE_SIZE) { mem_map[MAP_NR(addr)].flags &= ~(1<> 8, sparc_valid_addr_bitmap); + } } } } @@ -234,6 +240,7 @@ int codepages = 0; int datapages = 0; int initpages = 0; + int i; unsigned long addr; struct page *page, *end; @@ -243,6 +250,12 @@ end_mem &= PAGE_MASK; max_mapnr = MAP_NR(end_mem); high_memory = (void *) end_mem; + + sparc_valid_addr_bitmap = (unsigned long *)start_mem; + i = max_mapnr >> (8 + 5); + i += 1; + memset(sparc_valid_addr_bitmap, 0, i << 2); + start_mem += i << 2; start_mem = PAGE_ALIGN(start_mem); num_physpages = 0; @@ -255,6 +268,7 @@ else #endif mem_map[MAP_NR(addr)].flags |= (1<> 8, sparc_valid_addr_bitmap); addr += PAGE_SIZE; } @@ -266,6 +280,9 @@ if (PageSkip(page)) { unsigned long low, high; + /* See srmmu_frob_mem_map() for why this is done. -DaveM */ + page++; + low = PAGE_ALIGN((unsigned long)(page+1)); if (page->next_hash < page) high = ((unsigned long)end) & PAGE_MASK; @@ -313,11 +330,18 @@ initpages << (PAGE_SHIFT-10), (unsigned long)PAGE_OFFSET, end_mem); - freepages.min = nr_free_pages >> 7; - if(freepages.min < 16) - freepages.min = 16; - freepages.low = freepages.min + (freepages.min >> 1); - freepages.high = freepages.min + freepages.min; + /* NOTE NOTE NOTE NOTE + * Please keep track of things and make sure this + * always matches the code in mm/page_alloc.c -DaveM + */ + i = nr_free_pages >> 7; + if (i < 48) + i = 48; + if (i > 256) + i = 256; + freepages.min = i; + freepages.low = i << 1; + freepages.high = freepages.low + i; } void free_initmem (void) diff -ur --new-file old/linux/arch/sparc/mm/iommu.c new/linux/arch/sparc/mm/iommu.c --- old/linux/arch/sparc/mm/iommu.c Fri May 8 09:11:28 1998 +++ new/linux/arch/sparc/mm/iommu.c Tue May 11 17:24:31 1999 @@ -1,4 +1,4 @@ -/* $Id: iommu.c,v 1.9 1998/04/15 14:58:37 jj Exp $ +/* $Id: iommu.c,v 1.10 1999/05/07 17:03:34 jj Exp $ * iommu.c: IOMMU specific routines for memory management. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -51,8 +51,7 @@ unsigned long tmp; struct iommu_struct *iommu; struct linux_prom_registers iommu_promregs[PROMREG_MAX]; - int i, j, k, l, m; - struct iommu_alloc { unsigned long addr; int next; } *ia; + int i; iommu = kmalloc(sizeof(struct iommu_struct), GFP_ATOMIC); prom_getproperty(iommund, "reg", (void *) iommu_promregs, @@ -97,62 +96,18 @@ ptsize = (ptsize >> PAGE_SHIFT) * sizeof(iopte_t); /* Stupid alignment constraints give me a headache. - We want to get very large aligned memory area, larger than - maximum what get_free_pages gives us (128K): we need - 256K or 512K or 1M or 2M aligned to its size. */ - ia = (struct iommu_alloc *) kmalloc (sizeof(struct iommu_alloc) * 128, GFP_ATOMIC); - for (i = 0; i < 128; i++) { - ia[i].addr = 0; - ia[i].next = -1; - } - k = 0; - for (i = 0; i < 128; i++) { - ia[i].addr = __get_free_pages(GFP_DMA, 5); - if (ia[i].addr <= ia[k].addr) { - if (i) { - ia[i].next = k; - k = i; - } - } else { - for (m = k, l = ia[k].next; l != -1; m = l, l = ia[l].next) - if (ia[i].addr <= ia[l].addr) { - ia[i].next = l; - ia[m].next = i; - } - if (l == -1) - ia[m].next = i; - } - for (m = -1, j = 0, l = k; l != -1; l = ia[l].next) { - if (!(ia[l].addr & (ptsize - 1))) { - tmp = ia[l].addr; - m = l; - j = 128 * 1024; - } else if (m != -1) { - if (ia[l].addr != tmp + j) - m = -1; - else { - j += 128 * 1024; - if (j == ptsize) { - break; - } - } - } - } - if (l != -1) + We need 256K or 512K or 1M or 2M area aligned to + its size and current gfp will fortunately give + it to us. */ + for (i = 6; i < 9; i++) + if ((1 << (i + PAGE_SHIFT)) == ptsize) break; - } - if (i == 128) { + tmp = __get_free_pages(GFP_DMA, i); + if (!tmp) { prom_printf("Could not allocate iopte of size 0x%08x\n", ptsize); prom_halt(); } - for (l = m, j = 0; j < ptsize; j += 128 * 1024, l = ia[l].next) - ia[l].addr = 0; - for (l = k; l != -1; l = ia[l].next) - if (ia[l].addr) - free_pages(ia[l].addr, 5); - kfree (ia); iommu->lowest = iommu->page_table = (iopte_t *)tmp; - /* Initialize new table. */ flush_cache_all(); diff -ur --new-file old/linux/arch/sparc/mm/nosrmmu.c new/linux/arch/sparc/mm/nosrmmu.c --- old/linux/arch/sparc/mm/nosrmmu.c Wed Apr 15 02:44:20 1998 +++ new/linux/arch/sparc/mm/nosrmmu.c Fri Apr 23 04:24:51 1999 @@ -1,4 +1,4 @@ -/* $Id: nosrmmu.c,v 1.1 1998/03/09 14:04:15 jj Exp $ +/* $Id: nosrmmu.c,v 1.2 1999/03/30 10:17:39 jj Exp $ * nosrmmu.c: This file is a bunch of dummies for sun4 compiles, * so that it does not need srmmu and avoid ifdefs. * @@ -45,6 +45,16 @@ } __initfunc(void srmmu_end_memory(unsigned long memory_size, unsigned long *mem_end_p)) +{ + return 0; +} + +__u32 iounit_map_dma_init(struct linux_sbus *sbus, int size) +{ + return 0; +} + +__u32 iounit_map_dma_page(__u32 vaddr, void *addr, struct linux_sbus *sbus) { return 0; } diff -ur --new-file old/linux/arch/sparc/mm/srmmu.c new/linux/arch/sparc/mm/srmmu.c --- old/linux/arch/sparc/mm/srmmu.c Wed Jan 20 22:35:46 1999 +++ new/linux/arch/sparc/mm/srmmu.c Wed Apr 28 19:58:10 1999 @@ -1,4 +1,4 @@ -/* $Id: srmmu.c,v 1.175 1998/08/28 18:57:31 zaitcev Exp $ +/* $Id: srmmu.c,v 1.187 1999/04/28 17:00:45 davem Exp $ * srmmu.c: SRMMU specific routines for memory management. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -12,7 +12,9 @@ #include #include #include +#include #include +#include #include #include @@ -216,24 +218,36 @@ mem_map[MAP_NR(pg1)].flags &= ~(1< 2 * PAGE_SIZE) { + /* Making a one or two pages PG_skip holes + * is not necessary. We add one more because + * we must set the PG_skip flag on the first + * two mem_map[] entries for the hole. Go and + * see the mm/filemap.c:shrink_mmap() loop for + * details. -DaveM + */ + if (i && bank_start - bank_end > 3 * PAGE_SIZE) { mem_map[MAP_NR(bank_end)].flags |= (1< KERNBASE && bank_start < KERNBASE) { mem_map[0].flags |= (1<> 8, sparc_valid_addr_bitmap); if((bank_start >= KERNBASE) && (bank_start < start_mem)) { bank_start += PAGE_SIZE; @@ -250,14 +264,19 @@ if (bank_end < KERNBASE) { mem_map[MAP_NR(bank_end)].flags |= (1<mm->context != NO_CONTEXT) { + if(tsk->mm->context != NO_CONTEXT && + tsk->mm->pgd != pgdp) { flush_cache_mm(tsk->mm); ctxd_set(&srmmu_context_table[tsk->mm->context], pgdp); flush_tlb_mm(tsk->mm); @@ -800,9 +820,7 @@ { if(tsk->mm->context == NO_CONTEXT) { alloc_context(tsk->mm); - flush_cache_mm(tsk->mm); ctxd_set(&srmmu_context_table[tsk->mm->context], tsk->mm->pgd); - flush_tlb_mm(tsk->mm); } srmmu_set_context(tsk->mm->context); } @@ -1273,6 +1291,12 @@ unsigned long end); extern void viking_flush_tlb_page(struct vm_area_struct *vma, unsigned long page); +extern void sun4dsmp_flush_tlb_all(void); +extern void sun4dsmp_flush_tlb_mm(struct mm_struct *mm); +extern void sun4dsmp_flush_tlb_range(struct mm_struct *mm, unsigned long start, + unsigned long end); +extern void sun4dsmp_flush_tlb_page(struct vm_area_struct *vma, + unsigned long page); /* hypersparc.S */ extern void hypersparc_flush_cache_all(void); @@ -1311,7 +1335,8 @@ if(pgdp != swapper_pg_dir) hypersparc_flush_page_to_ram(page); - if(tsk->mm->context != NO_CONTEXT) { + if(tsk->mm->context != NO_CONTEXT && + tsk->mm->pgd != pgdp) { flush_cache_mm(tsk->mm); ctxd_set(&srmmu_context_table[tsk->mm->context], pgdp); flush_tlb_mm(tsk->mm); @@ -1320,11 +1345,13 @@ static void viking_update_rootmmu_dir(struct task_struct *tsk, pgd_t *pgdp) { - viking_flush_page((unsigned long)pgdp); - if(tsk->mm->context != NO_CONTEXT) { - flush_cache_mm(current->mm); + if(pgdp != swapper_pg_dir) + flush_chunk((unsigned long)pgdp); + if(tsk->mm->context != NO_CONTEXT && + tsk->mm->pgd != pgdp) { + flush_cache_mm(tsk->mm); ctxd_set(&srmmu_context_table[tsk->mm->context], pgdp); - flush_tlb_mm(current->mm); + flush_tlb_mm(tsk->mm); } } @@ -1334,6 +1361,9 @@ unsigned long page = ((unsigned long) pgdp) & PAGE_MASK; unsigned long line; + if(pgdp == swapper_pg_dir) + goto skip_flush; + a = 0x20; b = 0x40; c = 0x60; d = 0x80; e = 0xa0; f = 0xc0; g = 0xe0; page &= PAGE_MASK; line = (page + PAGE_SIZE) - 0x100; @@ -1354,11 +1384,12 @@ "r" (a), "r" (b), "r" (c), "r" (d), "r" (e), "r" (f), "r" (g)); } while(line != page); - - if(tsk->mm->context != NO_CONTEXT) { - flush_cache_mm(current->mm); +skip_flush: + if(tsk->mm->context != NO_CONTEXT && + tsk->mm->pgd != pgdp) { + flush_cache_mm(tsk->mm); ctxd_set(&srmmu_context_table[tsk->mm->context], pgdp); - flush_tlb_mm(current->mm); + flush_tlb_mm(tsk->mm); } } @@ -1386,9 +1417,10 @@ srmmu_set_entry((pte_t *)ctxp, __pte((SRMMU_ET_PTD | (srmmu_v2p((unsigned long) mm->pgd) >> 4)))); hypersparc_flush_page_to_ram((unsigned long)ctxp); - hyper_flush_whole_icache(); - if(mm == current->mm) + if(mm == current->mm) { + hyper_flush_whole_icache(); srmmu_set_context(mm->context); + } } static unsigned long mempool; @@ -1917,12 +1949,13 @@ /* Find the number of contexts on the srmmu. */ cpunode = prom_getchild(prom_root_node); num_contexts = 0; - while((cpunode = prom_getsibling(cpunode)) != 0) { + while(cpunode != 0) { prom_getstring(cpunode, "device_type", node_str, sizeof(node_str)); if(!strcmp(node_str, "cpu")) { num_contexts = prom_getintdefault(cpunode, "mmu-nctx", 0x8); break; } + cpunode = prom_getsibling(cpunode); } } @@ -1969,6 +2002,18 @@ start_mem = sparc_context_init(start_mem, num_contexts); start_mem = free_area_init(start_mem, end_mem); + +#ifdef CONFIG_BLK_DEV_INITRD + /* If initial ramdisk was specified with physical address, + translate it here, as the p2v translation in srmmu + is not straightforward. */ + if (initrd_start && initrd_start < KERNBASE) { + initrd_start = srmmu_p2v(initrd_start); + initrd_end = srmmu_p2v(initrd_end); + if (initrd_end <= initrd_start) + initrd_start = 0; + } +#endif return PAGE_ALIGN(start_mem); } @@ -1998,6 +2043,11 @@ static void srmmu_destroy_context(struct mm_struct *mm) { if(mm->context != NO_CONTEXT && atomic_read(&mm->count) == 1) { + /* XXX This could be drastically improved. + * XXX We are only called from __exit_mm and it just did + * XXX cache/tlb mm flush and right after this will (re-) + * XXX SET_PAGE_DIR to swapper_pg_dir. -DaveM + */ flush_cache_mm(mm); ctxd_set(&srmmu_context_table[mm->context], swapper_pg_dir); flush_tlb_mm(mm); @@ -2028,8 +2078,11 @@ offset = (address & PAGE_MASK) - vma->vm_start; vmaring = inode->i_mmap; do { - vaddr = vmaring->vm_start + offset; + /* Do not mistake ourselves as another mapping. */ + if(vmaring == vma) + continue; + vaddr = vmaring->vm_start + offset; if ((vaddr ^ address) & vac_badbits) { alias_found++; start = vmaring->vm_start; @@ -2042,7 +2095,7 @@ if(!ptep) goto next; if((pte_val(*ptep) & SRMMU_ET_MASK) == SRMMU_VALID) { -#if 1 +#if 0 printk("Fixing USER/USER alias [%ld:%08lx]\n", vmaring->vm_mm->context, start); #endif @@ -2057,11 +2110,12 @@ } } while ((vmaring = vmaring->vm_next_share) != NULL); - if(alias_found && !(pte_val(pte) & _SUN4C_PAGE_NOCACHE)) { + if(alias_found && ((pte_val(pte) & SRMMU_CACHE) != 0)) { pgdp = srmmu_pgd_offset(vma->vm_mm, address); - ptep = srmmu_pte_offset((pmd_t *) pgdp, address); + pmdp = srmmu_pmd_offset(pgdp, address); + ptep = srmmu_pte_offset(pmdp, address); flush_cache_page(vma, address); - *ptep = __pte(pte_val(*ptep) | _SUN4C_PAGE_NOCACHE); + set_pte(ptep, __pte((pte_val(*ptep) & ~SRMMU_CACHE))); flush_tlb_page(vma, address); } done: @@ -2652,15 +2706,8 @@ /* Ahhh, the viking. SRMMU VLSI abortion number two... */ if(mreg & VIKING_MMODE) { - unsigned long bpreg; - srmmu_name = "TI Viking"; viking_mxcc_present = 0; - - bpreg = viking_get_bpreg(); - bpreg &= ~(VIKING_ACTION_MIX); - viking_set_bpreg(bpreg); - msi_set_sync(); BTFIXUPSET_CALL(set_pte, srmmu_set_pte_nocache_viking, BTFIXUPCALL_NORM); @@ -2691,16 +2738,25 @@ BTFIXUPSET_CALL(flush_page_for_dma, viking_flush_page_for_dma, BTFIXUPCALL_NOP); } - /* flush_cache_* are nops */ - BTFIXUPSET_CALL(flush_cache_all, viking_flush_cache_all, BTFIXUPCALL_NOP); - BTFIXUPSET_CALL(flush_cache_mm, viking_flush_cache_mm, BTFIXUPCALL_NOP); - BTFIXUPSET_CALL(flush_cache_page, viking_flush_cache_page, BTFIXUPCALL_NOP); - BTFIXUPSET_CALL(flush_cache_range, viking_flush_cache_range, BTFIXUPCALL_NOP); - - BTFIXUPSET_CALL(flush_tlb_all, viking_flush_tlb_all, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(flush_tlb_mm, viking_flush_tlb_mm, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(flush_tlb_page, viking_flush_tlb_page, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(flush_tlb_range, viking_flush_tlb_range, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(flush_cache_all, viking_flush_cache_all, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(flush_cache_mm, viking_flush_cache_mm, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(flush_cache_page, viking_flush_cache_page, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(flush_cache_range, viking_flush_cache_range, BTFIXUPCALL_NORM); + +#ifdef __SMP__ + if (sparc_cpu_model == sun4d) { + BTFIXUPSET_CALL(flush_tlb_all, sun4dsmp_flush_tlb_all, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(flush_tlb_mm, sun4dsmp_flush_tlb_mm, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(flush_tlb_page, sun4dsmp_flush_tlb_page, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(flush_tlb_range, sun4dsmp_flush_tlb_range, BTFIXUPCALL_NORM); + } else +#endif + { + BTFIXUPSET_CALL(flush_tlb_all, viking_flush_tlb_all, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(flush_tlb_mm, viking_flush_tlb_mm, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(flush_tlb_page, viking_flush_tlb_page, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(flush_tlb_range, viking_flush_tlb_range, BTFIXUPCALL_NORM); + } BTFIXUPSET_CALL(flush_page_to_ram, viking_flush_page_to_ram, BTFIXUPCALL_NOP); BTFIXUPSET_CALL(flush_sig_insns, viking_flush_sig_insns, BTFIXUPCALL_NOP); @@ -3027,10 +3083,12 @@ BTFIXUPSET_CALL(flush_cache_mm, smp_flush_cache_mm, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(flush_cache_range, smp_flush_cache_range, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(flush_cache_page, smp_flush_cache_page, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(flush_tlb_all, smp_flush_tlb_all, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(flush_tlb_mm, smp_flush_tlb_mm, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(flush_tlb_range, smp_flush_tlb_range, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(flush_tlb_page, smp_flush_tlb_page, BTFIXUPCALL_NORM); + if (sparc_cpu_model != sun4d) { + BTFIXUPSET_CALL(flush_tlb_all, smp_flush_tlb_all, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(flush_tlb_mm, smp_flush_tlb_mm, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(flush_tlb_range, smp_flush_tlb_range, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(flush_tlb_page, smp_flush_tlb_page, BTFIXUPCALL_NORM); + } BTFIXUPSET_CALL(flush_page_to_ram, smp_flush_page_to_ram, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(flush_sig_insns, smp_flush_sig_insns, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(flush_page_for_dma, smp_flush_page_for_dma, BTFIXUPCALL_NORM); diff -ur --new-file old/linux/arch/sparc/mm/sun4c.c new/linux/arch/sparc/mm/sun4c.c --- old/linux/arch/sparc/mm/sun4c.c Sun Oct 4 19:22:43 1998 +++ new/linux/arch/sparc/mm/sun4c.c Thu Mar 11 01:53:36 1999 @@ -1,4 +1,4 @@ -/* $Id: sun4c.c,v 1.171 1998/09/21 05:05:41 jj Exp $ +/* $Id: sun4c.c,v 1.173 1999/01/17 02:20:37 davem Exp $ * sun4c.c: Doing in software what should be done in hardware. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -2688,6 +2688,10 @@ unsigned long vaddr = vmaring->vm_start + offset; unsigned long start; + /* Do not mistake ourselves as another mapping. */ + if(vmaring == vma) + continue; + if (S4CVAC_BADALIAS(vaddr, address)) { alias_found++; start = vmaring->vm_start; @@ -2699,8 +2703,8 @@ if(pte_val(*ptep) & _SUN4C_PAGE_PRESENT) { flush_cache_page(vmaring, start); - pte_val(*ptep) = (pte_val(*ptep) | - _SUN4C_PAGE_NOCACHE); + *ptep = __pte(pte_val(*ptep) | + _SUN4C_PAGE_NOCACHE); flush_tlb_page(vmaring, start); } next: @@ -2712,7 +2716,7 @@ if(alias_found && !(pte_val(pte) & _SUN4C_PAGE_NOCACHE)) { pgdp = sun4c_pgd_offset(vma->vm_mm, address); ptep = sun4c_pte_offset((pmd_t *) pgdp, address); - pte_val(*ptep) = (pte_val(*ptep) | _SUN4C_PAGE_NOCACHE); + *ptep = __pte(pte_val(*ptep) | _SUN4C_PAGE_NOCACHE); pte = pte_val(*ptep); } } diff -ur --new-file old/linux/arch/sparc/mm/viking.S new/linux/arch/sparc/mm/viking.S --- old/linux/arch/sparc/mm/viking.S Wed Apr 15 02:44:20 1998 +++ new/linux/arch/sparc/mm/viking.S Thu Mar 25 18:23:33 1999 @@ -1,8 +1,9 @@ -/* $Id: viking.S,v 1.11 1998/02/20 18:07:50 jj Exp $ +/* $Id: viking.S,v 1.13 1999/03/24 11:42:32 davem Exp $ * viking.S: High speed Viking cache/mmu operations * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) - * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * Copyright (C) 1997,1998,1999 Jakub Jelinek (jj@ultra.linux.cz) + * Copyright (C) 1999 Pavel Semerad (semerad@ss1000.ms.mff.cuni.cz) */ #include @@ -15,16 +16,12 @@ #include #include -#define WINDOW_FLUSH(tmp1, tmp2) \ - mov 0, tmp1; \ -98: ld [%g6 + AOFF_task_tss + AOFF_thread_uwinmask], tmp2; \ - orcc %g0, tmp2, %g0; \ - add tmp1, 1, tmp1; \ - bne 98b; \ - save %sp, -64, %sp; \ -99: subcc tmp1, 1, tmp1; \ - bne 99b; \ - restore %g0, %g0, %g0; +#ifdef __SMP__ + .data + .align 4 +sun4dsmp_flush_tlb_spin: + .word 0 +#endif .text .align 4 @@ -70,7 +67,7 @@ clr %o1 ! set counter, 0 - 127 sethi %hi(KERNBASE + PAGE_SIZE - 0x80000000), %o3 sethi %hi(0x80000000), %o4 - sethi %hi(VIKING_PTAG_VALID | VIKING_PTAG_DIRTY), %o5 + sethi %hi(VIKING_PTAG_VALID), %o5 sethi %hi(2*PAGE_SIZE), %o0 sethi %hi(PAGE_SIZE), %g7 clr %o2 ! block counter, 0 - 3 @@ -83,15 +80,12 @@ or %g5, %g4, %g5 ldda [%g5] ASI_M_DATAC_TAG, %g2 cmp %g3, %g1 ! ptag == ppage? - bne,a 7f - inc %o2 - - and %g2, %o5, %g3 ! ptag VALID and DIRTY? - cmp %g3, %o5 - bne,a 7f + bne 7f inc %o2 - add %g4, %o3, %g2 ! (KERNBASE + PAGE_SIZE) | (set << 5) + andcc %g2, %o5, %g0 ! ptag VALID? + be 7f + add %g4, %o3, %g2 ! (KERNBASE + PAGE_SIZE) | (set << 5) ld [%g2], %g3 ld [%g2 + %g7], %g3 add %g2, %o0, %g2 @@ -102,18 +96,15 @@ ld [%g2 + %g7], %g3 add %g2, %o0, %g2 ld [%g2], %g3 - ld [%g2 + %g7], %g3 - b 8f - inc %o1 + ld [%g2 + %g7], %g3 7: cmp %o2, 3 ble 6b sll %o2, 26, %g5 ! block << 26 - inc %o1 -8: +8: inc %o1 cmp %o1, 0x7f ble 5b clr %o2 @@ -151,10 +142,33 @@ retl nop -viking_flush_cache_all: +#define WINDOW_FLUSH(tmp1, tmp2) \ + mov 0, tmp1; \ +98: ld [%g6 + AOFF_task_tss + AOFF_thread_uwinmask], tmp2; \ + orcc %g0, tmp2, %g0; \ + add tmp1, 1, tmp1; \ + bne 98b; \ + save %sp, -64, %sp; \ +99: subcc tmp1, 1, tmp1; \ + bne 99b; \ + restore %g0, %g0, %g0; + +viking_flush_cache_page: +#ifndef __SMP__ + ld [%o0 + 0x0], %o0 /* XXX vma->vm_mm, GROSS XXX */ +#endif viking_flush_cache_mm: viking_flush_cache_range: -viking_flush_cache_page: +#ifndef __SMP__ + ld [%o0 + AOFF_mm_context], %g1 + cmp %g1, -1 + bne viking_flush_cache_all + nop + b,a viking_flush_cache_out +#endif +viking_flush_cache_all: + WINDOW_FLUSH(%g4, %g5) +viking_flush_cache_out: retl nop @@ -176,8 +190,10 @@ sta %g0, [%g2] ASI_M_FLUSH_PROBE retl sta %g5, [%g1] ASI_M_MMUREGS +#ifndef __SMP__ 1: retl nop +#endif viking_flush_tlb_range: mov SRMMU_CTX_REG, %g1 @@ -198,8 +214,10 @@ sta %g0, [%o1] ASI_M_FLUSH_PROBE retl sta %g5, [%g1] ASI_M_MMUREGS +#ifndef __SMP__ 2: retl nop +#endif viking_flush_tlb_page: ld [%o0 + 0x00], %o0 /* XXX vma->vm_mm GROSS XXX */ @@ -215,11 +233,96 @@ sta %g0, [%o1] ASI_M_FLUSH_PROBE retl sta %g5, [%g1] ASI_M_MMUREGS +#ifndef __SMP__ 1: retl nop +#endif viking_flush_page_to_ram: viking_flush_page_for_dma: viking_flush_sig_insns: retl nop + +#ifdef __SMP__ + .globl sun4dsmp_flush_tlb_all, sun4dsmp_flush_tlb_mm + .globl sun4dsmp_flush_tlb_range, sun4dsmp_flush_tlb_page +sun4dsmp_flush_tlb_all: + sethi %hi(sun4dsmp_flush_tlb_spin), %g3 +1: ldstub [%g3 + %lo(sun4dsmp_flush_tlb_spin)], %g5 + tst %g5 + bne 2f + mov 0x400, %g1 + sta %g0, [%g1] ASI_M_FLUSH_PROBE + retl + stb %g0, [%g3 + %lo(sun4dsmp_flush_tlb_spin)] +2: tst %g5 + bne,a 2b + ldub [%g3 + %lo(sun4dsmp_flush_tlb_spin)], %g5 + b,a 1b + +sun4dsmp_flush_tlb_mm: + sethi %hi(sun4dsmp_flush_tlb_spin), %g3 +1: ldstub [%g3 + %lo(sun4dsmp_flush_tlb_spin)], %g5 + tst %g5 + bne 2f + mov SRMMU_CTX_REG, %g1 + ld [%o0 + AOFF_mm_context], %o1 + lda [%g1] ASI_M_MMUREGS, %g5 + mov 0x300, %g2 + sta %o1, [%g1] ASI_M_MMUREGS + sta %g0, [%g2] ASI_M_FLUSH_PROBE + sta %g5, [%g1] ASI_M_MMUREGS + retl + stb %g0, [%g3 + %lo(sun4dsmp_flush_tlb_spin)] +2: tst %g5 + bne,a 2b + ldub [%g3 + %lo(sun4dsmp_flush_tlb_spin)], %g5 + b,a 1b + +sun4dsmp_flush_tlb_range: + sethi %hi(sun4dsmp_flush_tlb_spin), %g3 +1: ldstub [%g3 + %lo(sun4dsmp_flush_tlb_spin)], %g5 + tst %g5 + bne 3f + mov SRMMU_CTX_REG, %g1 + ld [%o0 + AOFF_mm_context], %o3 + lda [%g1] ASI_M_MMUREGS, %g5 + sethi %hi(~((1 << SRMMU_PGDIR_SHIFT) - 1)), %o4 + sta %o3, [%g1] ASI_M_MMUREGS + and %o1, %o4, %o1 + add %o1, 0x200, %o1 + sta %g0, [%o1] ASI_M_FLUSH_PROBE +2: sub %o1, %o4, %o1 + cmp %o1, %o2 + blu,a 2b + sta %g0, [%o1] ASI_M_FLUSH_PROBE + sta %g5, [%g1] ASI_M_MMUREGS + retl + stb %g0, [%g3 + %lo(sun4dsmp_flush_tlb_spin)] +3: tst %g5 + bne,a 3b + ldub [%g3 + %lo(sun4dsmp_flush_tlb_spin)], %g5 + b,a 1b + +sun4dsmp_flush_tlb_page: + sethi %hi(sun4dsmp_flush_tlb_spin), %g3 +1: ldstub [%g3 + %lo(sun4dsmp_flush_tlb_spin)], %g5 + tst %g5 + bne 2f + mov SRMMU_CTX_REG, %g1 + ld [%o0 + 0x00], %o0 /* XXX vma->vm_mm GROSS XXX */ + ld [%o0 + AOFF_mm_context], %o3 + lda [%g1] ASI_M_MMUREGS, %g5 + and %o1, PAGE_MASK, %o1 + sta %o3, [%g1] ASI_M_MMUREGS + sta %g0, [%o1] ASI_M_FLUSH_PROBE + sta %g5, [%g1] ASI_M_MMUREGS + retl + stb %g0, [%g3 + %lo(sun4dsmp_flush_tlb_spin)] +2: tst %g5 + bne,a 2b + ldub [%g3 + %lo(sun4dsmp_flush_tlb_spin)], %g5 + b,a 1b + nop +#endif diff -ur --new-file old/linux/arch/sparc/vmlinux.lds new/linux/arch/sparc/vmlinux.lds --- old/linux/arch/sparc/vmlinux.lds Sun Oct 4 19:22:43 1998 +++ new/linux/arch/sparc/vmlinux.lds Thu Mar 11 01:53:36 1999 @@ -31,6 +31,10 @@ __start___ksymtab = .; __ksymtab : { *(__ksymtab) } __stop___ksymtab = .; + + . = ALIGN(32); + .data.cacheline_aligned : { *(.data.cacheline_aligned) } + . = ALIGN(4096); __init_begin = .; .text.init : { *(.text.init) } diff -ur --new-file old/linux/arch/sparc64/Makefile new/linux/arch/sparc64/Makefile --- old/linux/arch/sparc64/Makefile Fri Dec 18 23:01:48 1998 +++ new/linux/arch/sparc64/Makefile Thu Mar 11 01:53:36 1999 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.33 1998/10/19 07:04:02 jj Exp $ +# $Id: Makefile,v 1.35 1999/01/02 16:45:50 davem Exp $ # sparc64/Makefile # # Makefile for the architecture dependent flags and dependencies on the @@ -46,6 +46,7 @@ else CFLAGS := $(CFLAGS) -m64 -pipe -mno-fpu -mcpu=ultrasparc -mcmodel=medlow \ -ffixed-g4 -fcall-used-g5 -fcall-used-g7 -Wno-sign-compare + AFLAGS += -m64 -mcpu=ultrasparc endif # Uncomment this to get spinlock/rwlock debugging on SMP. diff -ur --new-file old/linux/arch/sparc64/config.in new/linux/arch/sparc64/config.in --- old/linux/arch/sparc64/config.in Thu Jan 14 19:29:28 1999 +++ new/linux/arch/sparc64/config.in Fri Apr 23 04:24:51 1999 @@ -1,8 +1,8 @@ -# $Id: config.in,v 1.58 1998/11/16 04:47:30 davem Exp $ +# $Id: config.in,v 1.66 1999/03/29 05:08:42 davem Exp $ # For a description of the syntax of this configuration file, # see the Configure script. # -mainmenu_name "Linux/SPARC Kernel Configuration" +mainmenu_name "Linux/UltraSPARC Kernel Configuration" mainmenu_option next_comment comment 'Code maturity level options' @@ -24,7 +24,6 @@ define_bool CONFIG_VT y define_bool CONFIG_VT_CONSOLE y -bool 'Support for AP1000 multicomputer' CONFIG_AP1000 bool 'Symmetric multi-processing support' CONFIG_SMP mainmenu_option next_comment @@ -34,28 +33,20 @@ source drivers/video/Config.in endmenu -if [ "$CONFIG_AP1000" = "y" ]; then - define_bool CONFIG_NO_KEYBOARD y - define_bool CONFIG_APFDDI y - define_bool CONFIG_APBLOCK y - define_bool CONFIG_APBIF y - tristate 'OPIU DDV Driver' CONFIG_DDV -else - # Global things across all Sun machines. - define_bool CONFIG_SBUS y - define_bool CONFIG_SBUSCHAR y - define_bool CONFIG_SUN_MOUSE y - define_bool CONFIG_SERIAL y - define_bool CONFIG_SUN_SERIAL y - define_bool CONFIG_SERIAL_CONSOLE y - define_bool CONFIG_SUN_KEYBOARD y - define_bool CONFIG_SUN_CONSOLE y - define_bool CONFIG_SUN_AUXIO y - define_bool CONFIG_SUN_IO y - bool 'PCI support' CONFIG_PCI - source drivers/sbus/char/Config.in - source drivers/sbus/audio/Config.in -fi +# Global things across all Sun machines. +define_bool CONFIG_SBUS y +define_bool CONFIG_SBUSCHAR y +define_bool CONFIG_SUN_MOUSE y +define_bool CONFIG_SERIAL y +define_bool CONFIG_SUN_SERIAL y +define_bool CONFIG_SERIAL_CONSOLE y +define_bool CONFIG_SUN_KEYBOARD y +define_bool CONFIG_SUN_CONSOLE y +define_bool CONFIG_SUN_AUXIO y +define_bool CONFIG_SUN_IO y +bool 'PCI support' CONFIG_PCI +source drivers/sbus/char/Config.in +source drivers/sbus/audio/Config.in tristate 'Openprom tree appears in /proc/openprom (EXPERIMENTAL)' CONFIG_SUN_OPENPROMFS if [ "$CONFIG_PCI" = "y" ]; then @@ -194,6 +185,7 @@ bool ' assume boards are SYMBIOS compatible' CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT fi fi + dep_tristate 'Qlogic ISP SCSI support' CONFIG_SCSI_QLOGIC_ISP $CONFIG_SCSI fi endmenu @@ -221,14 +213,14 @@ fi bool 'Sun LANCE support' CONFIG_SUNLANCE tristate 'Sun Happy Meal 10/100baseT support' CONFIG_HAPPYMEAL + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate 'Sun BigMAC 10/100baseT support' CONFIG_SUNBMAC + fi tristate 'Sun QuadEthernet support' CONFIG_SUNQE tristate 'MyriCOM Gigabit Ethernet support' CONFIG_MYRI_SBUS if [ "$CONFIG_PCI" = "y" ]; then tristate 'Generic DECchip & DIGITAL EtherWORKS PCI/EISA' CONFIG_DE4X5 -# Turned off until updated 3c59x.c driver -# gets approved by Linus... --DAVEM -# -# tristate '3c590/3c900 series (592/595/597) "Vortex/Boomerang" support' CONFIG_VORTEX + tristate '3c590/3c900 series (592/595/597) "Vortex/Boomerang" support' CONFIG_VORTEX fi # bool 'FDDI driver support' CONFIG_FDDI # if [ "$CONFIG_FDDI" = "y" ]; then @@ -236,6 +228,15 @@ fi endmenu fi + +# This one must be before the filesystem configs. -DaveM +mainmenu_option next_comment +comment 'Unix 98 PTY support' +bool 'Unix98 PTY support' CONFIG_UNIX98_PTYS +if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then + int 'Maximum number of Unix98 PTYs in use (0-2048)' CONFIG_UNIX98_PTY_COUNT 256 +fi +endmenu source fs/Config.in diff -ur --new-file old/linux/arch/sparc64/defconfig new/linux/arch/sparc64/defconfig --- old/linux/arch/sparc64/defconfig Fri Dec 18 23:01:48 1998 +++ new/linux/arch/sparc64/defconfig Fri Apr 23 04:24:51 1999 @@ -19,7 +19,6 @@ # CONFIG_VT=y CONFIG_VT_CONSOLE=y -# CONFIG_AP1000 is not set # CONFIG_SMP is not set # @@ -28,7 +27,9 @@ CONFIG_PROM_CONSOLE=y CONFIG_FB=y CONFIG_DUMMY_CONSOLE=y +# CONFIG_FB_PM2 is not set # CONFIG_FB_MATROX is not set +CONFIG_FB_ATY=y CONFIG_FB_SBUS=y CONFIG_FB_CREATOR=y CONFIG_FB_CGSIX=y @@ -71,9 +72,9 @@ # # Linux/SPARC audio subsystem (EXPERIMENTAL) # -# CONFIG_SPARCAUDIO is not set +CONFIG_SPARCAUDIO=y # CONFIG_SPARCAUDIO_AMD7930 is not set -# CONFIG_SPARCAUDIO_CS4231 is not set +CONFIG_SPARCAUDIO_CS4231=y # CONFIG_SPARCAUDIO_DBRI is not set # CONFIG_SPARCAUDIO_DUMMY is not set CONFIG_SUN_OPENPROMFS=m @@ -128,7 +129,6 @@ CONFIG_PACKET=y # CONFIG_NETLINK is not set # CONFIG_FIREWALL is not set -# CONFIG_NET_ALIAS is not set # CONFIG_FILTER is not set CONFIG_UNIX=y CONFIG_INET=y @@ -145,7 +145,6 @@ # (it is safe to leave these untouched) # CONFIG_INET_RARP=m -CONFIG_IP_NOSR=y CONFIG_SKB_LARGE=y CONFIG_IPV6=m # CONFIG_IPV6_EUI64 is not set @@ -166,6 +165,10 @@ # CONFIG_NET_FASTROUTE is not set # CONFIG_NET_HW_FLOWCONTROL is not set # CONFIG_CPU_IS_SLOW is not set + +# +# QoS and/or fair queueing +# # CONFIG_NET_SCHED is not set # @@ -205,6 +208,7 @@ CONFIG_SCSI_NCR53C8XX_SYNC=10 # CONFIG_SCSI_NCR53C8XX_PROFILE is not set # CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set +CONFIG_SCSI_QLOGIC_ISP=y # # Fibre Channel support @@ -215,11 +219,13 @@ # FC4 drivers # CONFIG_FC4_SOC=m +CONFIG_FC4_SOCAL=m # # FC4 targets # CONFIG_SCSI_PLUTO=m +CONFIG_SCSI_FCAL=m # # Network device support @@ -237,29 +243,53 @@ # CONFIG_SLIP_MODE_SLIP6 is not set CONFIG_SUNLANCE=y CONFIG_HAPPYMEAL=y +CONFIG_SUNBMAC=m CONFIG_SUNQE=m CONFIG_MYRI_SBUS=m CONFIG_DE4X5=m +CONFIG_VORTEX=m + +# +# Unix 98 PTY support +# +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 # # Filesystems # # CONFIG_QUOTA is not set -CONFIG_MINIX_FS=m -CONFIG_EXT2_FS=y -CONFIG_ISO9660_FS=m -# CONFIG_JOLIET is not set +CONFIG_AUTOFS_FS=m +# CONFIG_ADFS_FS is not set +CONFIG_AFFS_FS=m +# CONFIG_HFS_FS is not set CONFIG_FAT_FS=m CONFIG_MSDOS_FS=m # CONFIG_UMSDOS_FS is not set CONFIG_VFAT_FS=m +CONFIG_ISO9660_FS=m +# CONFIG_JOLIET is not set +CONFIG_MINIX_FS=m +# CONFIG_NTFS_FS is not set +CONFIG_HPFS_FS=m CONFIG_PROC_FS=y +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +CONFIG_ROMFS_FS=m +CONFIG_EXT2_FS=y +CONFIG_SYSV_FS=m +CONFIG_UFS_FS=m +CONFIG_UFS_FS_WRITE=y + +# +# Network File Systems +# +CONFIG_CODA_FS=m CONFIG_NFS_FS=y CONFIG_NFSD=m # CONFIG_NFSD_SUN is not set CONFIG_SUNRPC=y CONFIG_LOCKD=y -CONFIG_CODA_FS=m CONFIG_SMB_FS=m CONFIG_SMB_WIN95=y CONFIG_NCP_FS=m @@ -269,21 +299,18 @@ # CONFIG_NCPFS_NFS_NS is not set # CONFIG_NCPFS_OS2_NS is not set # CONFIG_NCPFS_MOUNT_SUBDIR is not set -CONFIG_HPFS_FS=m -# CONFIG_NTFS_FS is not set -CONFIG_SYSV_FS=m -CONFIG_AFFS_FS=m -# CONFIG_HFS_FS is not set -CONFIG_ROMFS_FS=m -CONFIG_AUTOFS_FS=m -CONFIG_AMIGA_PARTITION=y -CONFIG_UFS_FS=m +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set + +# +# Partition Types +# CONFIG_BSD_DISKLABEL=y +# CONFIG_MAC_PARTITION is not set CONFIG_SMD_DISKLABEL=y CONFIG_SOLARIS_X86_PARTITION=y -# CONFIG_ADFS_FS is not set -# CONFIG_QNX4FS_FS is not set -# CONFIG_MAC_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +CONFIG_AMIGA_PARTITION=y CONFIG_NLS=y # @@ -314,6 +341,7 @@ # CONFIG_NLS_ISO8859_7 is not set # CONFIG_NLS_ISO8859_8 is not set # CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_15 is not set # CONFIG_NLS_KOI8_R is not set # diff -ur --new-file old/linux/arch/sparc64/kernel/Makefile new/linux/arch/sparc64/kernel/Makefile --- old/linux/arch/sparc64/kernel/Makefile Fri Dec 18 23:01:48 1998 +++ new/linux/arch/sparc64/kernel/Makefile Thu Mar 11 01:53:37 1999 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.41 1998/10/11 06:58:14 davem Exp $ +# $Id: Makefile,v 1.43 1999/01/02 16:45:53 davem Exp $ # Makefile for the linux kernel. # # Note! Dependencies are done automagically by 'make dep', which also @@ -20,7 +20,7 @@ traps.o devices.o auxio.o ioport.o \ irq.o ptrace.o time.o sys_sparc.o signal.o \ unaligned.o sys_sunos32.o sunos_ioctl32.o \ - central.o psycho.o + central.o psycho.o starfire.o OX_OBJS := sparc64_ksyms.o ifdef CONFIG_PCI diff -ur --new-file old/linux/arch/sparc64/kernel/binfmt_aout32.c new/linux/arch/sparc64/kernel/binfmt_aout32.c --- old/linux/arch/sparc64/kernel/binfmt_aout32.c Wed Nov 11 20:50:00 1998 +++ new/linux/arch/sparc64/kernel/binfmt_aout32.c Mon Mar 22 19:06:36 1999 @@ -9,7 +9,6 @@ #include -#include #include #include #include @@ -18,9 +17,10 @@ #include #include #include +#include +#include #include #include -#include #include #include #include @@ -58,14 +58,13 @@ * 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 +while (file->f_op->write(file,(char *)(addr),(nr),&file->f_pos) != (nr)) goto close_coredump #define DUMP_SEEK(offset) \ -if (file.f_op->llseek) { \ - if (file.f_op->llseek(&file,(offset),0) != (offset)) \ +if (file->f_op->llseek) { \ + if (file->f_op->llseek(file,(offset),0) != (offset)) \ goto close_coredump; \ -} else file.f_pos = (offset) +} else file->f_pos = (offset) /* * Routine writes a core dump image in the current directory. @@ -82,7 +81,7 @@ { struct dentry * dentry = NULL; struct inode * inode = NULL; - struct file file; + struct file * file; mm_segment_t fs; int has_dumped = 0; char corefile[6+sizeof(current->comm)]; @@ -106,29 +105,16 @@ #else corefile[4] = '\0'; #endif - dentry = open_namei(corefile,O_CREAT | 2 | O_TRUNC | O_NOFOLLOW, 0600); - if (IS_ERR(dentry)) { - dentry = 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 (!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 (get_write_access(inode)) - goto end_coredump; - file.f_mode = 3; - file.f_flags = 0; - file.f_count = 1; - file.f_dentry = dentry; - file.f_pos = 0; - file.f_reada = 0; - file.f_op = inode->i_op->default_file_ops; - if (file.f_op->open) - if (file.f_op->open(inode,&file)) - goto done_coredump; - if (!file.f_op->write) + goto close_coredump; + if (!file->f_op->write) goto close_coredump; has_dumped = 1; current->flags |= PF_DUMPCORE; @@ -175,13 +161,9 @@ set_fs(KERNEL_DS); DUMP_WRITE(current,sizeof(*current)); close_coredump: - if (file.f_op->release) - file.f_op->release(inode,&file); -done_coredump: - put_write_access(inode); + filp_close(file, NULL); end_coredump: set_fs(fs); - dput(dentry); return has_dumped; } @@ -269,7 +251,6 @@ return -ENOEXEC; } - current->personality = PER_LINUX; fd_offset = N_TXTOFF(ex); /* Check initial limits. This avoids letting people circumvent @@ -288,6 +269,8 @@ return retval; /* OK, This is the point of no return */ + current->personality = PER_LINUX; + current->mm->end_code = ex.a_text + (current->mm->start_code = N_TXTADDR(ex)); current->mm->end_data = ex.a_data + @@ -297,8 +280,7 @@ current->mm->rss = 0; current->mm->mmap = NULL; - current->suid = current->euid = current->fsuid = bprm->e_uid; - current->sgid = current->egid = current->fsgid = bprm->e_gid; + compute_creds(bprm); current->flags &= ~PF_FORKNOEXEC; if (N_MAGIC(ex) == NMAGIC) { /* Fuck me plenty... */ @@ -404,48 +386,44 @@ do_load_aout32_library(int fd) { struct file * file; - struct exec ex; - struct dentry * dentry; struct inode * inode; - unsigned int len; - unsigned int bss; - unsigned int start_addr; + unsigned long bss, start_addr, len; unsigned long error; + int retval; + loff_t offset = 0; + struct exec ex; - file = fcheck(fd); - - if (!file || !file->f_op) - return -EACCES; - - dentry = file->f_dentry; - inode = dentry->d_inode; - - /* Seek into the file */ - if (file->f_op->llseek) { - if ((error = file->f_op->llseek(file, 0, 0)) != 0) - return -ENOEXEC; - } else - file->f_pos = 0; + retval = -EACCES; + file = fget(fd); + if (!file) + goto out; + if (!file->f_op) + goto out_putf; + inode = file->f_dentry->d_inode; + retval = -ENOEXEC; + /* N.B. Save current fs? */ set_fs(KERNEL_DS); - error = file->f_op->read(file, (char *) &ex, sizeof(ex), &file->f_pos); + error = file->f_op->read(file, (char *) &ex, sizeof(ex), &offset); set_fs(USER_DS); if (error != sizeof(ex)) - return -ENOEXEC; + goto out_putf; /* We come in here for the regular a.out style of shared libraries */ if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != QMAGIC) || N_TRSIZE(ex) || N_DRSIZE(ex) || ((ex.a_entry & 0xfff) && N_MAGIC(ex) == ZMAGIC) || inode->i_size < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) { - return -ENOEXEC; + goto out_putf; } + if (N_MAGIC(ex) == ZMAGIC && N_TXTOFF(ex) && (N_TXTOFF(ex) < inode->i_sb->s_blocksize)) { printk("N_TXTOFF < BLOCK_SIZE. Please convert library\n"); - return -ENOEXEC; + goto out_putf; } - if (N_FLAGS(ex)) return -ENOEXEC; + if (N_FLAGS(ex)) + goto out_putf; /* For QMAGIC, the starting address is 0x20 into the page. We mask this off to get the starting address for the page */ @@ -457,18 +435,26 @@ PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE, N_TXTOFF(ex)); + retval = error; if (error != start_addr) - return error; + goto out_putf; + len = PAGE_ALIGN(ex.a_text + ex.a_data); bss = ex.a_text + ex.a_data + ex.a_bss; if (bss > len) { - error = do_mmap(NULL, start_addr + len, bss-len, - PROT_READ|PROT_WRITE|PROT_EXEC, - MAP_PRIVATE|MAP_FIXED, 0); + error = do_mmap(NULL, start_addr + len, bss - len, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_PRIVATE | MAP_FIXED, 0); + retval = error; if (error != start_addr + len) - return error; + goto out_putf; } - return 0; + retval = 0; + +out_putf: + fput(file); +out: + return retval; } static int diff -ur --new-file old/linux/arch/sparc64/kernel/central.c new/linux/arch/sparc64/kernel/central.c --- old/linux/arch/sparc64/kernel/central.c Wed Aug 5 01:03:35 1998 +++ new/linux/arch/sparc64/kernel/central.c Thu Mar 11 01:53:37 1999 @@ -1,4 +1,4 @@ -/* $Id: central.c,v 1.6 1998/05/14 13:35:45 jj Exp $ +/* $Id: central.c,v 1.11 1998/12/14 12:18:16 davem Exp $ * central.c: Central FHC driver for Sunfire/Starfire/Wildfire. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -7,11 +7,17 @@ #include #include #include +#include +#include +#include #include #include struct linux_central *central_bus = NULL; +struct linux_fhc *fhc_list = NULL; + +#define IS_CENTRAL_FHC(__fhc) ((__fhc) == central_bus->child) static inline unsigned long long_align(unsigned long addr) { @@ -22,6 +28,156 @@ extern void prom_central_ranges_init(int cnode, struct linux_central *central); extern void prom_fhc_ranges_init(int fnode, struct linux_fhc *fhc); +static unsigned long probe_other_fhcs(unsigned long memory_start) +{ + struct linux_prom64_registers fpregs[6]; + char namebuf[128]; + int node; + + node = prom_getchild(prom_root_node); + node = prom_searchsiblings(node, "fhc"); + if (node == 0) { + prom_printf("FHC: Cannot find any toplevel firehose controllers.\n"); + prom_halt(); + } + while(node) { + struct linux_fhc *fhc; + int board; + u32 tmp; + + fhc = (struct linux_fhc *)memory_start; + memory_start += sizeof(struct linux_fhc); + memory_start = long_align(memory_start); + + /* Link it into the FHC chain. */ + fhc->next = fhc_list; + fhc_list = fhc; + + /* Toplevel FHCs have no parent. */ + fhc->parent = NULL; + + fhc->prom_node = node; + prom_getstring(node, "name", namebuf, sizeof(namebuf)); + strcpy(fhc->prom_name, namebuf); + prom_fhc_ranges_init(node, fhc); + + /* Non-central FHC's have 64-bit OBP format registers. */ + if(prom_getproperty(node, "reg", + (char *)&fpregs[0], sizeof(fpregs)) == -1) { + prom_printf("FHC: Fatal error, cannot get fhc regs.\n"); + prom_halt(); + } + + /* Only central FHC needs special ranges applied. */ + fhc->fhc_regs.pregs = (struct fhc_internal_regs *) + __va(fpregs[0].phys_addr); + fhc->fhc_regs.ireg = (struct fhc_ign_reg *) + __va(fpregs[1].phys_addr); + fhc->fhc_regs.ffregs = (struct fhc_fanfail_regs *) + __va(fpregs[2].phys_addr); + fhc->fhc_regs.sregs = (struct fhc_system_regs *) + __va(fpregs[3].phys_addr); + fhc->fhc_regs.uregs = (struct fhc_uart_regs *) + __va(fpregs[4].phys_addr); + fhc->fhc_regs.tregs = (struct fhc_tod_regs *) + __va(fpregs[5].phys_addr); + + board = prom_getintdefault(node, "board#", -1); + fhc->board = board; + + tmp = fhc->fhc_regs.pregs->fhc_jtag_ctrl; + if((tmp & FHC_JTAG_CTRL_MENAB) != 0) + fhc->jtag_master = 1; + else + fhc->jtag_master = 0; + + tmp = fhc->fhc_regs.pregs->fhc_id; + printk("FHC(board %d): Version[%x] PartID[%x] Manuf[%x] %s\n", + board, + (tmp & FHC_ID_VERS) >> 28, + (tmp & FHC_ID_PARTID) >> 12, + (tmp & FHC_ID_MANUF) >> 1, + (fhc->jtag_master ? "(JTAG Master)" : "")); + + /* This bit must be set in all non-central FHC's in + * the system. When it is clear, this identifies + * the central board. + */ + fhc->fhc_regs.pregs->fhc_control |= FHC_CONTROL_IXIST; + + /* Look for the next FHC. */ + node = prom_getsibling(node); + if(node == 0) + break; + node = prom_searchsiblings(node, "fhc"); + if(node == 0) + break; + } + + return memory_start; +} + +static void probe_clock_board(struct linux_central *central, + struct linux_fhc *fhc, + int cnode, int fnode) +{ + struct linux_prom_registers cregs[3]; + int clknode, nslots, tmp, nregs; + + clknode = prom_searchsiblings(prom_getchild(fnode), "clock-board"); + if(clknode == 0 || clknode == -1) { + prom_printf("Critical error, central lacks clock-board.\n"); + prom_halt(); + } + nregs = prom_getproperty(clknode, "reg", (char *)&cregs[0], sizeof(cregs)); + if (nregs == -1) { + prom_printf("CENTRAL: Fatal error, cannot map clock-board regs.\n"); + prom_halt(); + } + nregs /= sizeof(struct linux_prom_registers); + prom_apply_fhc_ranges(fhc, &cregs[0], nregs); + prom_apply_central_ranges(central, &cregs[0], nregs); + central->cfreg = (volatile u8 *) + __va((((unsigned long)cregs[0].which_io) << 32) | + (((unsigned long)cregs[0].phys_addr)+0x02)); + central->clkregs = (struct clock_board_regs *) + __va((((unsigned long)cregs[1].which_io) << 32) | + (((unsigned long)cregs[1].phys_addr))); + if(nregs == 2) + central->clkver = NULL; + else + central->clkver = (volatile u8 *) + __va((((unsigned long)cregs[2].which_io) << 32) | + (((unsigned long)cregs[2].phys_addr))); + + tmp = central->clkregs->stat1; + tmp &= 0xc0; + switch(tmp) { + case 0x40: + nslots = 16; + break; + case 0xc0: + nslots = 8; + break; + case 0x80: + if(central->clkver != NULL && + *(central->clkver) != 0) { + if((*(central->clkver) & 0x80) != 0) + nslots = 4; + else + nslots = 5; + break; + } + default: + nslots = 4; + break; + }; + central->slots = nslots; + printk("CENTRAL: Detected %d slot Enterprise system. cfreg[%02x] cver[%02x]\n", + central->slots, *(central->cfreg), + (central->clkver ? *(central->clkver) : 0x00)); +} + unsigned long central_probe(unsigned long memory_start) { struct linux_prom_registers fpregs[6]; @@ -30,9 +186,12 @@ int cnode, fnode, err; cnode = prom_finddevice("/central"); - if(cnode == 0 || cnode == -1) + if(cnode == 0 || cnode == -1) { + extern void starfire_check(void); + + starfire_check(); return memory_start; - printk("CENTRAL: found central PROM node %08x.\n", cnode); + } /* Ok we got one, grab some memory for software state. */ memory_start = long_align(memory_start); @@ -54,7 +213,9 @@ prom_central_ranges_init(cnode, central_bus); /* And then central's FHC. */ - fhc->next = NULL; + fhc->next = fhc_list; + fhc_list = fhc; + fhc->parent = central_bus; fnode = prom_searchsiblings(prom_getchild(cnode), "fhc"); if(fnode == 0 || fnode == -1) { @@ -67,9 +228,9 @@ prom_fhc_ranges_init(fnode, fhc); - /* Finally, map in FHC register set. */ + /* Now, map in FHC register set. */ if (prom_getproperty(fnode, "reg", (char *)&fpregs[0], sizeof(fpregs)) == -1) { - prom_printf("CENTRAL: fatal error, cannot get fhc regs.\n"); + prom_printf("CENTRAL: Fatal error, cannot get fhc regs.\n"); prom_halt(); } prom_apply_central_ranges(central_bus, &fpregs[0], 6); @@ -93,11 +254,144 @@ __va((((unsigned long)fpregs[5].which_io)<<32) | (((unsigned long)fpregs[5].phys_addr))); + /* Obtain board number from board status register, Central's + * FHC lacks "board#" property. + */ + err = fhc->fhc_regs.pregs->fhc_bsr; + fhc->board = (((err >> 16) & 0x01) | + ((err >> 12) & 0x0e)); + + fhc->jtag_master = 0; + + /* Attach the clock board registers for CENTRAL. */ + probe_clock_board(central_bus, fhc, cnode, fnode); + err = fhc->fhc_regs.pregs->fhc_id; - printk("FHC Version[%x] PartID[%x] Manufacturer[%x]\n", + printk("FHC(board %d): Version[%x] PartID[%x] Manuf[%x] (CENTRAL)\n", + fhc->board, ((err & FHC_ID_VERS) >> 28), ((err & FHC_ID_PARTID) >> 12), ((err & FHC_ID_MANUF) >> 1)); - return memory_start; + return probe_other_fhcs(memory_start); +} + +static __inline__ void fhc_ledblink(struct linux_fhc *fhc, int on) +{ + volatile u32 *ctrl = (volatile u32 *) + &fhc->fhc_regs.pregs->fhc_control; + u32 tmp; + + tmp = *ctrl; + + /* NOTE: reverse logic on this bit */ + if (on) + tmp &= ~(FHC_CONTROL_RLED); + else + tmp |= FHC_CONTROL_RLED; + tmp &= ~(FHC_CONTROL_AOFF | FHC_CONTROL_BOFF | FHC_CONTROL_SLINE); + + *ctrl = tmp; + tmp = *ctrl; +} + +static __inline__ void central_ledblink(struct linux_central *central, int on) +{ + volatile u8 *ctrl = (volatile u8 *) ¢ral->clkregs->control; + int tmp; + + tmp = *ctrl; + + /* NOTE: reverse logic on this bit */ + if(on) + tmp &= ~(CLOCK_CTRL_RLED); + else + tmp |= CLOCK_CTRL_RLED; + + *ctrl = tmp; + tmp = *ctrl; +} + +static struct timer_list sftimer; +static int led_state; + +static void sunfire_timer(unsigned long __ignored) +{ + struct linux_fhc *fhc; + + central_ledblink(central_bus, led_state); + for(fhc = fhc_list; fhc != NULL; fhc = fhc->next) + if(! IS_CENTRAL_FHC(fhc)) + fhc_ledblink(fhc, led_state); + led_state = ! led_state; + sftimer.expires = jiffies + (HZ >> 1); + add_timer(&sftimer); +} + +/* After PCI/SBUS busses have been probed, this is called to perform + * final initialization of all FireHose Controllers in the system. + */ +void firetruck_init(void) +{ + struct linux_central *central = central_bus; + struct linux_fhc *fhc; + + /* No central bus, nothing to do. */ + if (central == NULL) + return; + + for(fhc = fhc_list; fhc != NULL; fhc = fhc->next) { + volatile u32 *ctrl = (volatile u32 *) + &fhc->fhc_regs.pregs->fhc_control; + u32 tmp; + + /* Clear all of the interrupt mapping registers + * just in case OBP left them in a foul state. + */ +#define ZAP(REG1, REG2) \ +do { volatile u32 *__iclr = (volatile u32 *)(&(REG1)); \ + volatile u32 *__imap = (volatile u32 *)(&(REG2)); \ + *(__iclr) = 0; \ + (void) *(__iclr); \ + *(__imap) &= ~(0x80000000); \ + (void) *(__imap); \ +} while(0) + + ZAP(fhc->fhc_regs.ffregs->fhc_ff_iclr, + fhc->fhc_regs.ffregs->fhc_ff_imap); + ZAP(fhc->fhc_regs.sregs->fhc_sys_iclr, + fhc->fhc_regs.sregs->fhc_sys_imap); + ZAP(fhc->fhc_regs.uregs->fhc_uart_iclr, + fhc->fhc_regs.uregs->fhc_uart_imap); + ZAP(fhc->fhc_regs.tregs->fhc_tod_iclr, + fhc->fhc_regs.tregs->fhc_tod_imap); + +#undef ZAP + + /* Setup FHC control register. */ + tmp = *ctrl; + + /* All non-central boards have this bit set. */ + if(! IS_CENTRAL_FHC(fhc)) + tmp |= FHC_CONTROL_IXIST; + + /* For all FHCs, clear the firmware synchronization + * line and both low power mode enables. + */ + tmp &= ~(FHC_CONTROL_AOFF | FHC_CONTROL_BOFF | FHC_CONTROL_SLINE); + *ctrl = tmp; + tmp = *ctrl; /* Ensure completion */ + } + + /* OBP leaves it on, turn it off so clock board timer LED + * is in sync with FHC ones. + */ + central->clkregs->control &= ~(CLOCK_CTRL_RLED); + + led_state = 0; + init_timer(&sftimer); + sftimer.data = 0; + sftimer.function = &sunfire_timer; + sftimer.expires = jiffies + (HZ >> 1); + add_timer(&sftimer); } diff -ur --new-file old/linux/arch/sparc64/kernel/cpu.c new/linux/arch/sparc64/kernel/cpu.c --- old/linux/arch/sparc64/kernel/cpu.c Wed Apr 15 02:44:20 1998 +++ new/linux/arch/sparc64/kernel/cpu.c Tue May 11 17:24:31 1999 @@ -49,11 +49,11 @@ #define NSPARCCHIPS (sizeof(linux_sparc_chips)/sizeof(struct cpu_iu_info)) #ifdef __SMP__ -char *sparc_cpu_type[NR_CPUS] = { "cpu-oops", "cpu-oops1", "cpu-oops2", "cpu-oops3" }; -char *sparc_fpu_type[NR_CPUS] = { "fpu-oops", "fpu-oops1", "fpu-oops2", "fpu-oops3" }; +char *sparc_cpu_type[64] = { "cpu-oops", "cpu-oops1", "cpu-oops2", "cpu-oops3" }; +char *sparc_fpu_type[64] = { "fpu-oops", "fpu-oops1", "fpu-oops2", "fpu-oops3" }; #else -char *sparc_cpu_type[NR_CPUS] = { "cpu-oops", }; -char *sparc_fpu_type[NR_CPUS] = { "fpu-oops", }; +char *sparc_cpu_type[64] = { "cpu-oops", }; +char *sparc_fpu_type[64] = { "fpu-oops", }; #endif unsigned int fsr_storage; @@ -65,11 +65,11 @@ long ver, fpu_vers; long fprs; - cpuid = smp_processor_id(); + cpuid = hard_smp_processor_id(); fprs = fprs_read (); fprs_write (FPRS_FEF); - __asm__ __volatile__ ("rdpr %%ver, %0; stx %%fsr, [%1]" : "=r" (ver) : "r" (&fpu_vers)); + __asm__ __volatile__ ("rdpr %%ver, %0; stx %%fsr, [%1]" : "=&r" (ver) : "r" (&fpu_vers)); fprs_write (fprs); manuf = ((ver >> 48)&0xffff); @@ -88,7 +88,7 @@ if(i==NSPARCCHIPS) { printk("DEBUG: manuf = 0x%x impl = 0x%x\n", manuf, impl); - sparc_cpu_type[cpuid] = "Unknow CPU"; + sparc_cpu_type[cpuid] = "Unknown CPU"; } for(i = 0; i #include -struct prom_cpuinfo linux_cpus[NR_CPUS] __initdata = { { 0 } }; -unsigned prom_cpu_nodes[NR_CPUS]; +struct prom_cpuinfo linux_cpus[64] __initdata = { { 0 } }; +unsigned prom_cpu_nodes[64]; int linux_num_cpus = 0; extern void cpu_probe(void); @@ -25,11 +25,12 @@ { char node_str[128]; int nd, prom_node_cpu, thismid; - int cpu_nds[NR_CPUS]; /* One node for each cpu */ + int cpu_nds[64]; /* One node for each cpu */ int cpu_ctr = 0; prom_getstring(prom_root_node, "device_type", node_str, sizeof(node_str)); + prom_printf("Booting Linux...\n"); if(strcmp(node_str, "cpu") == 0) { cpu_nds[0] = prom_root_node; linux_cpus[0].prom_node = prom_root_node; @@ -38,7 +39,7 @@ } else { int scan; scan = prom_getchild(prom_root_node); - prom_printf("root child is %08x\n", (unsigned) scan); + /* prom_printf("root child is %08x\n", (unsigned) scan); */ nd = 0; while((scan = prom_getsibling(scan)) != 0) { prom_getstring(scan, "device_type", node_str, sizeof(node_str)); @@ -49,11 +50,11 @@ (char *) &thismid, sizeof(thismid)); linux_cpus[cpu_ctr].mid = thismid; #ifdef __SMP__ - prom_printf("Found CPU %d (node=%08x,mid=%d)\n", - cpu_ctr, (unsigned) scan, - thismid); - printk("Found CPU %d (node=%08x,mid=%d)\n", - cpu_ctr, (unsigned) scan, thismid); + /* Don't pollute PROM screen with these messages. If the kernel is screwed enough + that console does not start up, then we don't care how many CPUs have been found, + if it starts up, the user can use console=prom to see it. */ + /* prom_printf("Found CPU %d (node=%08x,mid=%d)\n", cpu_ctr, (unsigned) scan, thismid); */ + printk("Found CPU %d (node=%08x,mid=%d)\n", cpu_ctr, (unsigned) scan, thismid); #endif cpu_ctr++; } @@ -72,6 +73,9 @@ prom_cpu_nodes[0] = prom_node_cpu; + mem_start = central_probe(mem_start); + cpu_probe(); - return central_probe(mem_start); + + return mem_start; } diff -ur --new-file old/linux/arch/sparc64/kernel/dtlb_backend.S new/linux/arch/sparc64/kernel/dtlb_backend.S --- old/linux/arch/sparc64/kernel/dtlb_backend.S Sun Oct 4 19:22:43 1998 +++ new/linux/arch/sparc64/kernel/dtlb_backend.S Thu Mar 11 01:53:37 1999 @@ -1,4 +1,4 @@ -/* $Id: dtlb_backend.S,v 1.6 1998/09/24 03:21:32 davem Exp $ +/* $Id: dtlb_backend.S,v 1.7 1998/12/16 04:33:28 davem Exp $ * dtlb_backend.S: Back end to DTLB miss replacement strategy. * This is included directly into the trap table. * @@ -37,28 +37,30 @@ be,pn %xcc, sparc64_vpte_nucleus ! Is it from Nucleus? and %g1, 0xffe, %g1 ! Mask PMD offset bits brnz,pt %g5, sparc64_vpte_continue ! Yep, go like smoke - nop ! Pipe bubble... + add %g1, %g1, %g1 ! Position PMD offset some more srlx %g6, (PGD_SHIFT - 2), %g5 ! Position PGD offset and %g5, 0xffc, %g5 ! Mask PGD offset /* TLB1 ** ICACHE line 3: Quick VPTE miss */ lduwa [%g7 + %g5] ASI_PHYS_USE_EC, %g5! Load PGD - brz,pn %g5, 2f ! Valid? + brz,pn %g5, vpte_noent ! Valid? +sparc64_kpte_continue: + sllx %g5, 11, %g5 ! Shift into place sparc64_vpte_continue: - add %g1, %g1, %g1 ! Position PMD offset once again lduwa [%g5 + %g1] ASI_PHYS_USE_EC, %g5! Load PMD - brz,pn %g5, 2f ! Valid? + sllx %g5, 11, %g5 ! Shift into place + brz,pn %g5, vpte_noent ! Valid? sllx %g2, 62, %g1 ! Put _PAGE_VALID into %g1 or %g5, VPTE_BITS, %g5 ! Prepare VPTE data - or %g5, %g1, %g5 ! ... /* TLB1 ** ICACHE line 4: Quick VPTE miss */ + or %g5, %g1, %g5 ! ... mov TLB_SFSR, %g1 ! Restore %g1 value stxa %g5, [%g0] ASI_DTLB_DATA_IN ! Load VPTE into TLB - membar #Sync ! Synchronize ASI stores stxa %g4, [%g1 + %g1] ASI_DMMU ! Restore previous TAG_ACCESS retry ! Load PTE once again -2: mov TLB_SFSR, %g1 ! Restore %g1 value +vpte_noent: + mov TLB_SFSR, %g1 ! Restore %g1 value stxa %g4, [%g1 + %g1] ASI_DMMU ! Restore previous TAG_ACCESS done ! Slick trick diff -ur --new-file old/linux/arch/sparc64/kernel/dtlb_prot.S new/linux/arch/sparc64/kernel/dtlb_prot.S --- old/linux/arch/sparc64/kernel/dtlb_prot.S Wed Aug 5 01:03:35 1998 +++ new/linux/arch/sparc64/kernel/dtlb_prot.S Thu Mar 11 01:53:37 1999 @@ -1,4 +1,4 @@ -/* $Id: dtlb_prot.S,v 1.17 1998/05/25 16:59:11 davem Exp $ +/* $Id: dtlb_prot.S,v 1.18 1999/03/02 15:42:14 jj Exp $ * dtlb_prot.S: DTLB protection trap strategy. * This is included directly into the trap table. * @@ -45,13 +45,13 @@ mov TLB_TAG_ACCESS, %g4 ! Prepare reload of vaddr bgu,pn %xcc, winfix_trampoline ! Yes, perform winfixup ldxa [%g4] ASI_DMMU, %g5 ! Put tagaccess in %g5 - sethi %hi(1f), %g7 ! Nope, normal fault + ba,pt %xcc, sparc64_realfault_common ! Nope, normal fault /* PROT ** ICACHE line 4: More real fault processing */ - ba,pt %xcc, etrap ! Save state -1: or %g7, %lo(1b), %g7 ! ... - ba,pt %xcc, sparc64_realfault_continue! Now call the fault handler - mov 1, %o2 ! Indicate this was a write + mov 1, %g4 ! Indicate this was a write + nop + nop + nop nop nop nop diff -ur --new-file old/linux/arch/sparc64/kernel/ebus.c new/linux/arch/sparc64/kernel/ebus.c --- old/linux/arch/sparc64/kernel/ebus.c Sun Oct 4 19:22:43 1998 +++ new/linux/arch/sparc64/kernel/ebus.c Tue May 11 17:24:31 1999 @@ -1,4 +1,4 @@ -/* $Id: ebus.c,v 1.33 1998/09/21 05:06:03 jj Exp $ +/* $Id: ebus.c,v 1.36 1999/05/04 03:21:42 davem Exp $ * ebus.c: PCI to EBus bridge device. * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -35,9 +35,6 @@ #ifdef CONFIG_SUN_OPENPROMIO extern int openprom_init(void); #endif -#ifdef CONFIG_SPARCAUDIO -extern int sparcaudio_init(void); -#endif #ifdef CONFIG_SUN_AUXIO extern void auxio_probe(void); #endif @@ -263,6 +260,31 @@ ebus->next = 0; while (ebusnd) { + /* SUNW,pci-qfe uses four empty ebuses on it. + I think we should not consider them here, + as they have half of the properties this + code expects and once we do PCI hot-plug, + we'd have to tweak with the ebus_chain + in the runtime after initialization. -jj */ + if (!prom_getchild (ebusnd)) { + pdev = pci_find_device(PCI_VENDOR_ID_SUN, + PCI_DEVICE_ID_SUN_EBUS, pdev); + if (!pdev) { + if (ebus == ebus_chain) { + ebus_chain = NULL; + printk("ebus: No EBus's found.\n"); +#ifdef PROM_DEBUG + dprintf("ebus: No EBus's found.\n"); +#endif + return; + } + break; + } + + cookie = pdev->sysdata; + ebusnd = cookie->prom_node; + continue; + } printk("ebus%d:", num_ebus); #ifdef PROM_DEBUG dprintf("ebus%d:", num_ebus); @@ -280,6 +302,12 @@ pci_command |= PCI_COMMAND_MASTER; pci_write_config_word(pdev, PCI_COMMAND, pci_command); + /* Set reasonable cache line size and latency timer values. */ + pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64); + + /* NOTE: Cache line size is in 32-bit word units. */ + pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 0x10); + len = prom_getproperty(ebusnd, "reg", (void *)regs, sizeof(regs)); if (len == 0 || len == -1) { @@ -367,9 +395,6 @@ #ifdef CONFIG_SUN_OPENPROMIO openprom_init(); -#endif -#ifdef CONFIG_SPARCAUDIO - sparcaudio_init(); #endif #ifdef CONFIG_SUN_BPP bpp_init(); diff -ur --new-file old/linux/arch/sparc64/kernel/entry.S new/linux/arch/sparc64/kernel/entry.S --- old/linux/arch/sparc64/kernel/entry.S Tue Oct 27 18:52:20 1998 +++ new/linux/arch/sparc64/kernel/entry.S Tue May 11 17:24:31 1999 @@ -1,10 +1,10 @@ -/* $Id: entry.S,v 1.91 1998/10/07 01:27:08 davem Exp $ +/* $Id: entry.S,v 1.103 1999/05/08 03:00:21 davem Exp $ * arch/sparc64/kernel/entry.S: Sparc64 trap low-level entry points. * * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu) * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be) * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx) - * Copyright (C) 1996,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * Copyright (C) 1996,98,99 Jakub Jelinek (jj@sunsite.mff.cuni.cz) */ #include @@ -29,8 +29,17 @@ .text .align 32 + .globl sparc64_vpte_patchme1 + .globl sparc64_vpte_patchme2 +sparc64_vpte_nucleus: +sparc64_vpte_patchme1: + sethi %hi(0), %g5 ! This has to be patched +sparc64_vpte_patchme2: + or %g5, %lo(0), %g5 ! This is patched too + ba,pt %xcc, sparc64_kpte_continue ! Part of dtlb_backend + add %g1, %g1, %g1 ! Finish PMD offset adjustment + /* This is trivial with the new code... */ - .align 32 .globl do_fpdis do_fpdis: ldub [%g6 + AOFF_task_tss + AOFF_thread_fpsaved], %g5 ! Load Group @@ -155,6 +164,39 @@ wr %g0, FPRS_FEF, %fprs ! clean DU/DL bits retry + .globl do_fptrap + .align 32 +do_fptrap: + ldub [%g6 + AOFF_task_tss + AOFF_thread_fpsaved], %g3 + stx %fsr, [%g6 + AOFF_task_tss + AOFF_thread_xfsr] + rd %fprs, %g1 + or %g3, %g1, %g3 + stb %g3, [%g6 + AOFF_task_tss + AOFF_thread_fpsaved] + rd %gsr, %g3 + stb %g3, [%g6 + AOFF_task_tss + AOFF_thread_gsr] + mov SECONDARY_CONTEXT, %g3 + add %g6, AOFF_task_fpregs, %g2 + ldxa [%g3] ASI_DMMU, %g5 + stxa %g0, [%g3] ASI_DMMU + flush %g6 + membar #StoreStore | #LoadStore + andcc %g1, FPRS_DL, %g0 + be,pn %icc, 4f + mov 0x40, %g3 + stda %f0, [%g2] ASI_BLK_S + stda %f16, [%g2 + %g3] ASI_BLK_S + andcc %g1, FPRS_DU, %g0 + be,pn %icc, 5f +4: add %g2, 128, %g2 + stda %f32, [%g2] ASI_BLK_S + stda %f48, [%g2 + %g3] ASI_BLK_S +5: mov SECONDARY_CONTEXT, %g1 + membar #Sync + stxa %g5, [%g1] ASI_DMMU + flush %g6 + ba,pt %xcc, etrap + wr %g0, 0, %fprs + /* The registers for cross calls will be: * * DATA 0: [low 32-bits] Address of function to call, jmp to this @@ -164,69 +206,57 @@ * * With this method we can do most of the cross-call tlb/cache * flushing very quickly. + * + * Current CPU's IRQ worklist table is locked into %g1, + * don't touch. */ - .data - .align 8 - .globl ivec_spurious_cookie -ivec_spurious_cookie: .xword 0 - .text - .align 32 - .globl do_ivec + .align 32 + .globl do_ivec do_ivec: - ldxa [%g0] ASI_INTR_RECEIVE, %g5 - andcc %g5, 0x20, %g0 - be,pn %xcc, do_ivec_return - mov 0x40, %g2 - - /* Load up Interrupt Vector Data 0 register. */ + wr %g0, ASI_UDB_INTR_R, %asi + ldxa [%g0 + 0x40] %asi, %g3 sethi %hi(KERNBASE), %g4 - ldxa [%g2] ASI_UDB_INTR_R, %g3 cmp %g3, %g4 bgeu,pn %xcc, do_ivec_xcall - nop - and %g3, 0x7ff, %g3 - sllx %g3, 3, %g3 - ldx [%g1 + %g3], %g2 - brz,pn %g2, do_ivec_spurious - sethi %hi(0x80000000), %g5 + srlx %g3, 32, %g5 + stxa %g0, [%g0] ASI_INTR_RECEIVE + membar #Sync - or %g2, %g5, %g2 - stx %g2, [%g1 + %g3] + sethi %hi(ivector_table), %g2 + sllx %g3, 5, %g3 + or %g2, %lo(ivector_table), %g2 + add %g2, %g3, %g3 + ldx [%g3 + 0x08], %g2 /* irq_info */ + ldub [%g3 + 0x04], %g4 /* pil */ + brz,pn %g2, do_ivec_spurious + mov 1, %g2 - /* No branches, worse case we don't know about this interrupt - * yet, so we would just write a zero into the softint register - * which is completely harmless. - */ + sllx %g2, %g4, %g2 + sllx %g4, 2, %g4 + lduw [%g1 + %g4], %g5 /* g5 = irq_work(cpu, pil) */ + stw %g5, [%g3 + 0x00] /* bucket->irq_chain = g5 */ + stw %g3, [%g1 + %g4] /* irq_work(cpu, pil) = bucket */ wr %g2, 0x0, %set_softint -do_ivec_return: - stxa %g0, [%g0] ASI_INTR_RECEIVE - membar #Sync retry do_ivec_xcall: - srlx %g3, 32, %g5 - add %g2, 0x10, %g2 + ldxa [%g0 + 0x50] %asi, %g6 + srl %g3, 0, %g3 - ldxa [%g2] ASI_UDB_INTR_R, %g6 - add %g2, 0x10, %g2 - ldxa [%g2] ASI_UDB_INTR_R, %g7 + ldxa [%g0 + 0x60] %asi, %g7 stxa %g0, [%g0] ASI_INTR_RECEIVE membar #Sync jmpl %g3, %g0 nop - do_ivec_spurious: - srl %g3, 3, %g3 - sethi %hi(ivec_spurious_cookie), %g2 - stx %g3, [%g2 + %lo(ivec_spurious_cookie)] - stxa %g0, [%g0] ASI_INTR_RECEIVE - membar #Sync + stw %g3, [%g1 + 0x00] /* irq_work(cpu, 0) = bucket */ rdpr %pstate, %g5 + wrpr %g5, PSTATE_IG | PSTATE_AG, %pstate sethi %hi(109f), %g7 ba,pt %xcc, etrap 109: or %g7, %lo(109b), %g7 - call report_spurious_ivec + call catch_disabled_ivec add %sp, STACK_BIAS + REGWIN_SZ, %o0 ba,pt %xcc, rtrap clr %l6 @@ -337,7 +367,7 @@ or %g1, %lo(irq_action), %g1 ldx [%g1 + (11 << 3)], %g3 ! irqaction[floppy_irq] ldx [%g3 + 0x10], %g4 ! action->mask == ino_bucket ptr - ldx [%g4 + 0x18], %g4 ! bucket->iclr + ldx [%g4 + 0x10], %g4 ! bucket->iclr stw %g0, [%g4] ! SYSIO_ICLR_IDLE membar #Sync ! probably not needed... retry @@ -588,12 +618,20 @@ /* SunOS's execv() call only specifies the argv argument, the * environment settings are the same as the calling processes. */ - .globl sunos_execv + .globl sunos_execv, sys_execve, sys32_execve +sys_execve: + sethi %hi(sparc_execve), %g1 + ba,pt %xcc, execve_merge + or %g1, %lo(sparc_execve), %g1 sunos_execv: - sethi %hi(sparc32_execve), %g1 - stx %g0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I2] - jmpl %g1 + %lo(sparc32_execve), %g0 - add %sp, STACK_BIAS + REGWIN_SZ, %o0 + stx %g0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I2] +sys32_execve: + sethi %hi(sparc32_execve), %g1 + or %g1, %lo(sparc32_execve), %g1 +execve_merge: + flushw + jmpl %g1, %g0 + add %sp, STACK_BIAS + REGWIN_SZ, %o0 .globl sys_pipe, sys_execve, sys_sigpause, sys_nis_syscall .globl sys_sigsuspend, sys_rt_sigsuspend, sys32_rt_sigsuspend @@ -612,14 +650,6 @@ jmpl %g1 + %lo(c_sys_nis_syscall), %g0 nop -sys_execve: sethi %hi(sparc_execve), %g1 - add %sp, STACK_BIAS + REGWIN_SZ, %o0 - jmpl %g1 + %lo(sparc_execve), %g0 - nop -sys32_execve: sethi %hi(sparc32_execve), %g1 - add %sp, STACK_BIAS + REGWIN_SZ, %o0 - jmpl %g1 + %lo(sparc32_execve), %g0 - nop sys_memory_ordering: sethi %hi(sparc_memory_ordering), %g1 add %sp, STACK_BIAS + REGWIN_SZ, %o1 @@ -719,27 +749,31 @@ .globl sys_fork, sys_vfork, sys_clone, sparc_exit .globl ret_from_syscall .align 32 -sys_fork: -sys_vfork: mov SIGCHLD, %o0 - clr %o1 +sys_vfork: /* Under Linux, vfork and fork are just special cases of clone. */ + sethi %hi(0x4000 | 0x0100 | SIGCHLD), %o0 + or %o0, %lo(0x4000 | 0x0100 | SIGCHLD), %o0 + ba,pt %xcc, sys_clone +sys_fork: clr %o1 + mov SIGCHLD, %o0 sys_clone: flushw - mov %o7, %l5 - add %sp, STACK_BIAS + REGWIN_SZ, %o2 movrz %o1, %fp, %o1 - call do_fork - mov %l5, %o7 + nop + ba,pt %xcc, do_fork + add %sp, STACK_BIAS + REGWIN_SZ, %o2 ret_from_syscall: /* Clear SPARC_FLAG_NEWCHILD, switch_to leaves tss.flags in * %o7 for us. Check performance counter stuff too. */ - andn %o7, 0x100, %o7 - sth %o7, [%g6 + AOFF_task_tss + AOFF_thread_flags] #ifdef __SMP__ - sethi %hi(scheduler_lock), %o4 - membar #StoreStore | #LoadStore - stb %g0, [%o4 + %lo(scheduler_lock)] + andn %o7, 0x100, %l0 + mov %g5, %o0 /* 'prev' */ + call schedule_tail + sth %l0, [%g6 + AOFF_task_tss + AOFF_thread_flags] +#else + andn %o7, 0x100, %l0 + sth %l0, [%g6 + AOFF_task_tss + AOFF_thread_flags] #endif - andcc %o7, 0x200, %g0 + andcc %l0, 0x200, %g0 be,pt %icc, 1f nop ldx [%g6 + AOFF_task_tss + AOFF_thread_pcr_reg], %o7 diff -ur --new-file old/linux/arch/sparc64/kernel/head.S new/linux/arch/sparc64/kernel/head.S --- old/linux/arch/sparc64/kernel/head.S Tue Oct 27 18:52:20 1998 +++ new/linux/arch/sparc64/kernel/head.S Fri Apr 23 04:24:51 1999 @@ -1,4 +1,4 @@ -/* $Id: head.S,v 1.54 1998/10/06 20:48:30 ecd Exp $ +/* $Id: head.S,v 1.60 1999/04/12 08:08:21 davem Exp $ * head.S: Initial boot code for the Sparc64 port of Linux. * * Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu) @@ -7,6 +7,7 @@ * Copyright (C) 1997 Miguel de Icaza (miguel@nuclecu.unam.mx) */ +#include #include #include #include @@ -46,7 +47,7 @@ * HdrS version should be incremented. */ .global root_flags, ram_flags, root_dev - .global ramdisk_image, ramdisk_size + .global sparc_ramdisk_image, sparc_ramdisk_size .globl silo_args .ascii "HdrS" @@ -58,9 +59,9 @@ .half 0 ram_flags: .half 0 -ramdisk_image: +sparc_ramdisk_image: .word 0 -ramdisk_size: +sparc_ramdisk_size: .word 0 .xword reboot_command .xword bootstr_len @@ -330,7 +331,7 @@ /* IMPORTANT NOTE: Whenever making changes here, check * trampoline.S as well. -jj */ .globl setup_tba -setup_tba: +setup_tba: /* i0 = is_starfire */ save %sp, -160, %sp rdpr %tba, %g7 @@ -376,9 +377,34 @@ /* Setup Interrupt globals */ wrpr %o1, (PSTATE_IG|PSTATE_IE), %pstate - sethi %hi(ivector_to_mask), %g5 - or %g5, %lo(ivector_to_mask), %g1 /* IVECTOR table */ - mov 0x40, %g2 /* INTR data 0 register */ +#ifndef __SMP__ + sethi %hi(__up_workvec), %g5 + or %g5, %lo(__up_workvec), %g1 +#else + /* By definition of where we are, this is boot_cpu. */ + sethi %hi(cpu_data), %g5 + or %g5, %lo(cpu_data), %g5 + + brz,pt %i0, not_starfire + sethi %hi(0x1fff4000), %g1 + or %g1, %lo(0x1fff4000), %g1 + sllx %g1, 12, %g1 + or %g1, 0xd0, %g1 + lduwa [%g1] ASI_PHYS_BYPASS_EC_E, %g1 + b,pt %xcc, set_worklist + nop + +not_starfire: + ldxa [%g0] ASI_UPA_CONFIG, %g1 + srlx %g1, 17, %g1 + and %g1, 0x1f, %g1 + + /* In theory this is: &(cpu_data[boot_cpu_id].irq_worklists[0]) */ +set_worklist: + sllx %g1, 7, %g1 + add %g5, %g1, %g5 + add %g5, 64, %g1 +#endif /* Kill PROM timer */ wr %g0, 0, %tick_cmpr @@ -407,6 +433,13 @@ .globl empty_bad_page empty_bad_page: .skip 0x2000 + +#ifdef CONFIG_SBUS +/* This is just a hack to fool make depend config.h discovering + strategy: As the .S files below need config.h, but + make depend does not find it for them, we include config.h + in head.S */ +#endif ! 0x0000000000408000 diff -ur --new-file old/linux/arch/sparc64/kernel/ioctl32.c new/linux/arch/sparc64/kernel/ioctl32.c --- old/linux/arch/sparc64/kernel/ioctl32.c Wed Nov 18 18:06:05 1998 +++ new/linux/arch/sparc64/kernel/ioctl32.c Tue May 11 17:24:31 1999 @@ -1,4 +1,4 @@ -/* $Id: ioctl32.c,v 1.55 1998/11/17 07:43:17 davem Exp $ +/* $Id: ioctl32.c,v 1.62 1999/05/01 09:17:44 davem Exp $ * ioctl32.c: Conversion between 32bit and 64bit native ioctls. * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -35,6 +36,7 @@ #include #include #include +#include #include /* Ugly hack. */ @@ -52,6 +54,7 @@ #include #include #include +#include #include @@ -116,6 +119,247 @@ return sys_ioctl(fd, cmd, arg); } +struct video_tuner32 { + s32 tuner; + u8 name[32]; + u32 rangelow, rangehigh; + u32 flags; + u16 mode, signal; +}; + +static int get_video_tuner32(struct video_tuner *kp, struct video_tuner32 *up) +{ + int i; + + if(get_user(kp->tuner, &up->tuner)) + return -EFAULT; + for(i = 0; i < 32; i++) + __get_user(kp->name[i], &up->name[i]); + __get_user(kp->rangelow, &up->rangelow); + __get_user(kp->rangehigh, &up->rangehigh); + __get_user(kp->flags, &up->flags); + __get_user(kp->mode, &up->mode); + __get_user(kp->signal, &up->signal); + return 0; +} + +static int put_video_tuner32(struct video_tuner *kp, struct video_tuner32 *up) +{ + int i; + + if(put_user(kp->tuner, &up->tuner)) + return -EFAULT; + for(i = 0; i < 32; i++) + __put_user(kp->name[i], &up->name[i]); + __put_user(kp->rangelow, &up->rangelow); + __put_user(kp->rangehigh, &up->rangehigh); + __put_user(kp->flags, &up->flags); + __put_user(kp->mode, &up->mode); + __put_user(kp->signal, &up->signal); + return 0; +} + +struct video_buffer32 { + /* void * */ u32 base; + s32 height, width, depth, bytesperline; +}; + +static int get_video_buffer32(struct video_buffer *kp, struct video_buffer32 *up) +{ + u32 tmp; + + if(get_user(tmp, &up->base)) + return -EFAULT; + kp->base = (void *) ((unsigned long)tmp); + __get_user(kp->height, &up->height); + __get_user(kp->width, &up->width); + __get_user(kp->depth, &up->depth); + __get_user(kp->bytesperline, &up->bytesperline); + return 0; +} + +static int put_video_buffer32(struct video_buffer *kp, struct video_buffer32 *up) +{ + u32 tmp = (u32)((unsigned long)kp->base); + + if(put_user(tmp, &up->base)) + return -EFAULT; + __put_user(kp->height, &up->height); + __put_user(kp->width, &up->width); + __put_user(kp->depth, &up->depth); + __put_user(kp->bytesperline, &up->bytesperline); + return 0; +} + +struct video_clip32 { + s32 x, y, width, height; + /* struct video_clip32 * */ u32 next; +}; + +struct video_window32 { + u32 x, y, width, height, chromakey, flags; + /* struct video_clip32 * */ u32 clips; + s32 clipcount; +}; + +static void free_kvideo_clips(struct video_window *kp) +{ + struct video_clip *cp; + + cp = kp->clips; + if(cp != NULL) + kfree(cp); +} + +static int get_video_window32(struct video_window *kp, struct video_window32 *up) +{ + struct video_clip32 *ucp; + struct video_clip *kcp; + int nclips, err, i; + u32 tmp; + + if(get_user(kp->x, &up->x)) + return -EFAULT; + __get_user(kp->y, &up->y); + __get_user(kp->width, &up->width); + __get_user(kp->height, &up->height); + __get_user(kp->chromakey, &up->chromakey); + __get_user(kp->flags, &up->flags); + __get_user(kp->clipcount, &up->clipcount); + __get_user(tmp, &up->clips); + ucp = (struct video_clip32 *)A(tmp); + kp->clips = NULL; + + nclips = kp->clipcount; + if(nclips == 0) + return 0; + + if(ucp == 0) + return -EINVAL; + + /* Peculiar interface... */ + if(nclips < 0) + nclips = VIDEO_CLIPMAP_SIZE; + + kcp = kmalloc(nclips * sizeof(struct video_clip), GFP_KERNEL); + err = -ENOMEM; + if(kcp == NULL) + goto cleanup_and_err; + + kp->clips = kcp; + for(i = 0; i < nclips; i++) { + __get_user(kcp[i].x, &ucp[i].x); + __get_user(kcp[i].y, &ucp[i].y); + __get_user(kcp[i].width, &ucp[i].width); + __get_user(kcp[i].height, &ucp[i].height); + kcp[nclips].next = NULL; + } + + return 0; + +cleanup_and_err: + free_kvideo_clips(kp); + return err; +} + +/* You get back everything except the clips... */ +static int put_video_window32(struct video_window *kp, struct video_window32 *up) +{ + if(put_user(kp->x, &up->x)) + return -EFAULT; + __put_user(kp->y, &up->y); + __put_user(kp->width, &up->width); + __put_user(kp->height, &up->height); + __put_user(kp->chromakey, &up->chromakey); + __put_user(kp->flags, &up->flags); + __put_user(kp->clipcount, &up->clipcount); + return 0; +} + +#define VIDIOCGTUNER32 _IOWR('v',4, struct video_tuner32) +#define VIDIOCSTUNER32 _IOW('v',5, struct video_tuner32) +#define VIDIOCGWIN32 _IOR('v',9, struct video_window32) +#define VIDIOCSWIN32 _IOW('v',10, struct video_window32) +#define VIDIOCGFBUF32 _IOR('v',11, struct video_buffer32) +#define VIDIOCSFBUF32 _IOW('v',12, struct video_buffer32) +#define VIDIOCGFREQ32 _IOR('v',14, u32) +#define VIDIOCSFREQ32 _IOW('v',15, u32) + +static int do_video_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + union { + struct video_tuner vt; + struct video_buffer vb; + struct video_window vw; + unsigned long vx; + } karg; + mm_segment_t old_fs = get_fs(); + void *up = (void *)arg; + int err = 0; + + /* First, convert the command. */ + switch(cmd) { + case VIDIOCGTUNER32: cmd = VIDIOCGTUNER; break; + case VIDIOCSTUNER32: cmd = VIDIOCSTUNER; break; + case VIDIOCGWIN32: cmd = VIDIOCGWIN; break; + case VIDIOCSWIN32: cmd = VIDIOCSWIN; break; + case VIDIOCGFBUF32: cmd = VIDIOCGFBUF; break; + case VIDIOCSFBUF32: cmd = VIDIOCSFBUF; break; + case VIDIOCGFREQ32: cmd = VIDIOCGFREQ; break; + case VIDIOCSFREQ32: cmd = VIDIOCSFREQ; break; + }; + + switch(cmd) { + case VIDIOCSTUNER: + case VIDIOCGTUNER: + err = get_video_tuner32(&karg.vt, up); + break; + + case VIDIOCSWIN: + err = get_video_window32(&karg.vw, up); + break; + + case VIDIOCSFBUF: + err = get_video_buffer32(&karg.vb, up); + break; + + case VIDIOCSFREQ: + err = get_user(karg.vx, (u32 *)up); + break; + }; + if(err) + goto out; + + set_fs(KERNEL_DS); + err = sys_ioctl(fd, cmd, (unsigned long)&karg); + set_fs(old_fs); + + if(cmd == VIDIOCSWIN) + free_kvideo_clips(&karg.vw); + + if(err == 0) { + switch(cmd) { + case VIDIOCGTUNER: + err = put_video_tuner32(&karg.vt, up); + break; + + case VIDIOCGWIN: + err = put_video_window32(&karg.vw, up); + break; + + case VIDIOCGFBUF: + err = put_video_buffer32(&karg.vb, up); + break; + + case VIDIOCGFREQ: + err = put_user(((u32)karg.vx), (u32 *)up); + break; + }; + } +out: + return err; +} + struct timeval32 { int tv_sec; int tv_usec; @@ -253,11 +497,23 @@ case SIOCGPPPSTATS: case SIOCGPPPCSTATS: case SIOCGPPPVER: + case SIOCETHTOOL: if (copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(struct ifreq32))) return -EFAULT; ifr.ifr_data = (__kernel_caddr_t)get_free_page(GFP_KERNEL); if (!ifr.ifr_data) return -EAGAIN; + if(cmd == SIOCETHTOOL) { + u32 data; + + __get_user(data, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_data)); + if(copy_from_user(ifr.ifr_data, + (char *)A(data), + sizeof(struct ethtool_cmd))) { + free_page((unsigned long)ifr.ifr_data); + return -EFAULT; + } + } break; default: if (copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(struct ifreq32))) @@ -280,17 +536,21 @@ case SIOCGIFBRDADDR: case SIOCGIFDSTADDR: case SIOCGIFNETMASK: + case SIOCGIFTXQLEN: if (copy_to_user((struct ifreq32 *)arg, &ifr, sizeof(struct ifreq32))) return -EFAULT; break; case SIOCGPPPSTATS: case SIOCGPPPCSTATS: case SIOCGPPPVER: + case SIOCETHTOOL: { u32 data; int len; __get_user(data, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_data)); + if(cmd == SIOCETHTOOL) + len = sizeof(struct ethtool_cmd); if(cmd == SIOCGPPPVER) len = strlen(PPP_VERSION) + 1; else if(cmd == SIOCGPPPCSTATS) @@ -298,7 +558,9 @@ else len = sizeof(struct ppp_stats); - if (copy_to_user((char *)A(data), ifr.ifr_data, len)) + len = copy_to_user((char *)A(data), ifr.ifr_data, len); + free_page((unsigned long)ifr.ifr_data); + if(len) return -EFAULT; break; } @@ -558,8 +820,7 @@ cmap.transp = kmalloc(cmap.len * sizeof(__u16), GFP_KERNEL); if (!cmap.transp) goto out; - } else - cmap.transp = NULL; + } if (cmd == FBIOGETCMAP) break; @@ -1458,6 +1719,9 @@ case SIOCGPPPSTATS: case SIOCGPPPCSTATS: case SIOCGPPPVER: + case SIOCGIFTXQLEN: + case SIOCSIFTXQLEN: + case SIOCETHTOOL: error = dev_ifsioc(fd, cmd, arg); goto out; @@ -1579,11 +1843,22 @@ error = do_ext2_ioctl(fd, cmd, arg); goto out; + case VIDIOCGTUNER32: + case VIDIOCSTUNER32: + case VIDIOCGWIN32: + case VIDIOCSWIN32: + case VIDIOCGFBUF32: + case VIDIOCSFBUF32: + case VIDIOCGFREQ32: + case VIDIOCSFREQ32: + error = do_video_ioctl(fd, cmd, arg); + goto out; + /* List here exlicitly which ioctl's are known to have * compatable types passed or none at all... */ - /* Bit T */ + /* Big T */ case TCGETA: case TCSETA: case TCSETAW: @@ -1618,6 +1893,8 @@ case TIOCSPGRP: case TIOCGPGRP: case TIOCSCTTY: + case TIOCGPTN: + case TIOCSPTLCK: /* Big F */ case FBIOGTYPE: @@ -1769,6 +2046,33 @@ /* Little v */ case VUIDSFORMAT: case VUIDGFORMAT: + + /* Little v, the video4linux ioctls */ + case VIDIOCGCAP: + case VIDIOCGCHAN: + case VIDIOCSCHAN: + case VIDIOCGPICT: + case VIDIOCSPICT: + case VIDIOCCAPTURE: + case VIDIOCKEY: + case VIDIOCGAUDIO: + case VIDIOCSAUDIO: + case VIDIOCSYNC: + case VIDIOCMCAPTURE: + case VIDIOCGMBUF: + case VIDIOCGUNIT: + case VIDIOCGCAPTURE: + case VIDIOCSCAPTURE: + + /* BTTV specific... */ + case _IOW('v', BASE_VIDIOCPRIVATE+0, char [256]): + case _IOR('v', BASE_VIDIOCPRIVATE+1, char [256]): + case _IOR('v' , BASE_VIDIOCPRIVATE+2, unsigned int): + case _IOW('v' , BASE_VIDIOCPRIVATE+3, char [16]): /* struct bttv_pll_info */ + case _IOR('v' , BASE_VIDIOCPRIVATE+4, int): + case _IOR('v' , BASE_VIDIOCPRIVATE+5, int): + case _IOR('v' , BASE_VIDIOCPRIVATE+6, int): + case _IOR('v' , BASE_VIDIOCPRIVATE+7, int): /* Little p (/dev/rtc, /dev/envctrl, etc.) */ case RTCGET: diff -ur --new-file old/linux/arch/sparc64/kernel/irq.c new/linux/arch/sparc64/kernel/irq.c --- old/linux/arch/sparc64/kernel/irq.c Tue Oct 27 18:52:20 1998 +++ new/linux/arch/sparc64/kernel/irq.c Fri Apr 23 04:24:51 1999 @@ -1,4 +1,4 @@ -/* $Id: irq.c,v 1.66 1998/10/21 15:02:25 ecd Exp $ +/* $Id: irq.c,v 1.76 1999/04/02 14:54:30 davem Exp $ * irq.c: UltraSparc IRQ handling/init/registry. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -41,20 +41,30 @@ #define SA_DMA_SYNC 0x200 #ifdef __SMP__ -void distribute_irqs(void); -static int irqs_have_been_distributed = 0; +static void distribute_irqs(void); #endif -/* UPA nodes send interrupt packet to UltraSparc with first data reg value - * low 5 bits holding the IRQ identifier being delivered. We must translate - * this into a non-vector IRQ so we can set the softint on this cpu. To - * make things even more swift we store the complete mask here. +/* UPA nodes send interrupt packet to UltraSparc with first data reg + * value low 5 (7 on Starfire) bits holding the IRQ identifier being + * delivered. We must translate this into a non-vector IRQ so we can + * set the softint on this cpu. + * + * To make processing these packets efficient and race free we use + * an array of irq buckets below. The interrupt vector handler in + * entry.S feeds incoming packets into per-cpu pil-indexed lists. + * The IVEC handler does not need to act atomically, the PIL dispatch + * code uses CAS to get an atomic snapshot of the list and clear it + * at the same time. */ -#define NUM_HARD_IVECS 2048 -#define NUM_IVECS (NUM_HARD_IVECS + 64) /* For SMP IRQ distribution alg. */ +struct ino_bucket ivector_table[NUM_IVECS] __attribute__ ((aligned (64))); -unsigned long ivector_to_mask[NUM_IVECS]; +#ifndef __SMP__ +unsigned int __up_workvec[16] __attribute__ ((aligned (64))); +#define irq_work(__cpu, __pil) &(__up_workvec[(__pil)]) +#else +#define irq_work(__cpu, __pil) &(cpu_data[(__cpu)].irq_worklists[(__pil)]) +#endif /* This is based upon code in the 32-bit Sparc kernel written mostly by * David Redman (djhr@tadpole.co.uk). @@ -63,30 +73,21 @@ static struct irqaction static_irqaction[MAX_STATIC_ALLOC]; static int static_irq_count = 0; -/* XXX Must be exported so that fast IRQ handlers can get at it... -DaveM */ +/* This is exported so that fast IRQ handlers can get at it... -DaveM */ struct irqaction *irq_action[NR_IRQS+1] = { NULL, NULL, NULL, NULL, NULL, NULL , NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL , NULL, NULL }; -#define IBF_DMA_SYNC 0x01 -#define IBF_PCI 0x02 -#define IBF_ACTIVE 0x04 +/* Only 8-bits are available, be careful. -DaveM */ +#define IBF_DMA_SYNC 0x01 /* DMA synchronization behind PCI bridge needed. */ +#define IBF_PCI 0x02 /* Indicates PSYCHO/SCHIZO PCI interrupt. */ +#define IBF_ACTIVE 0x04 /* This interrupt is active and has a handler. */ +#define IBF_MULTI 0x08 /* On PCI, indicates shared bucket. */ -#define __imap(bucket) ((bucket)->iclr + (bucket)->imap_off) #define __bucket(irq) ((struct ino_bucket *)(unsigned long)(irq)) #define __irq(bucket) ((unsigned int)(unsigned long)(bucket)) -static struct ino_bucket *bucket_base, *buckets, *endbuckets; - -__initfunc(unsigned long irq_init(unsigned long start_mem, unsigned long end_mem)) -{ - start_mem = (start_mem + 15) & ~15; - bucket_base = buckets = (struct ino_bucket *)start_mem; - endbuckets = buckets + 2048; - return (unsigned long)endbuckets; -} - int get_irq_list(char *buf) { int i, len = 0; @@ -104,7 +105,7 @@ #else for (j = 0; j < smp_num_cpus; j++) len += sprintf(buf + len, "%10u ", - kstat.irqs[cpu_logical_map(j)][i]); + kstat.irqs[cpu_logical_map(j)][i]); #endif len += sprintf(buf + len, "%c %s", (action->flags & SA_INTERRUPT) ? '+' : ' ', @@ -224,8 +225,7 @@ 1, /* Power Management */ }; -/* INO number to IMAP register offset for PSYCHO external IRQ's. - */ +/* INO number to IMAP register offset for PSYCHO external IRQ's. */ #define psycho_offset(x) ((unsigned long)(&(((struct psycho_regs *)0)->x))) #define psycho_imap_offset(ino) \ @@ -241,16 +241,27 @@ /* Now these are always passed a true fully specified sun4u INO. */ void enable_irq(unsigned int irq) { + extern int this_is_starfire; struct ino_bucket *bucket = __bucket(irq); - unsigned long tid; unsigned int *imap; + unsigned long tid; - imap = __imap(bucket); - if (!imap) return; + imap = bucket->imap; + if (!imap) + return; - /* We send it to our UPA MID, for SMP this will be different. */ - __asm__ __volatile__("ldxa [%%g0] %1, %0" : "=r" (tid) : "i" (ASI_UPA_CONFIG)); - tid = ((tid & UPA_CONFIG_MID) << 9); + if(this_is_starfire == 0) { + /* We set it to our UPA MID. */ + __asm__ __volatile__("ldxa [%%g0] %1, %0" + : "=r" (tid) + : "i" (ASI_UPA_CONFIG)); + tid = ((tid & UPA_CONFIG_MID) << 9); + } else { + extern unsigned int starfire_translate(unsigned int *imap, + unsigned int upaid); + + tid = (starfire_translate(imap, current->processor) << 26); + } /* NOTE NOTE NOTE, IGN and INO are read-only, IGN is a product * of this SYSIO's preconfigured IGN in the SYSIO Control @@ -269,35 +280,83 @@ struct ino_bucket *bucket = __bucket(irq); unsigned int *imap; - imap = __imap(bucket); - if (!imap) return; - - /* NOTE: We do not want to futz with the IRQ clear registers - * and move the state to IDLE, the SCSI code does call - * disable_irq() to assure atomicity in the queue cmd - * SCSI adapter driver code. Thus we'd lose interrupts. - */ - *imap &= ~(SYSIO_IMAP_VALID); + imap = bucket->imap; + if (imap != NULL) { + /* NOTE: We do not want to futz with the IRQ clear registers + * and move the state to IDLE, the SCSI code does call + * disable_irq() to assure atomicity in the queue cmd + * SCSI adapter driver code. Thus we'd lose interrupts. + */ + *imap &= ~(SYSIO_IMAP_VALID); + } } +/* The timer is the one "weird" interrupt which is generated by + * the CPU %tick register and not by some normal vectored interrupt + * source. To handle this special case, we use this dummy INO bucket. + */ +static struct ino_bucket pil0_dummy_bucket = { + 0, /* irq_chain */ + 0, /* pil */ + 0, /* pending */ + 0, /* flags */ + 0, /* __unused */ + NULL, /* irq_info */ + NULL, /* iclr */ + NULL, /* imap */ +}; + unsigned int build_irq(int pil, int inofixup, unsigned int *iclr, unsigned int *imap) { - if (buckets == endbuckets) - panic("Out of IRQ buckets. Should not happen.\n"); - buckets->pil = pil; - if (pil && (!iclr || !imap)) { - prom_printf("Invalid build_irq %d %d %016lx %016lx\n", pil, inofixup, iclr, imap); + struct ino_bucket *bucket; + int ino; + + if(pil == 0) { + if(iclr != NULL || imap != NULL) { + prom_printf("Invalid dummy bucket for PIL0 (%p:%p)\n", + iclr, imap); + prom_halt(); + } + return __irq(&pil0_dummy_bucket); + } + + /* RULE: Both must be specified in all other cases. */ + if (iclr == NULL || imap == NULL) { + prom_printf("Invalid build_irq %d %d %016lx %016lx\n", + pil, inofixup, iclr, imap); prom_halt(); } - if (imap) - buckets->ino = (*imap & (SYSIO_IMAP_IGN | SYSIO_IMAP_INO)) + inofixup; - else - buckets->ino = 0; - - buckets->iclr = iclr; - buckets->flags = 0; - buckets->imap_off = imap - iclr; - return __irq(buckets++); + + ino = (*imap & (SYSIO_IMAP_IGN | SYSIO_IMAP_INO)) + inofixup; + if(ino > NUM_IVECS) { + prom_printf("Invalid INO %04x (%d:%d:%016lx:%016lx)\n", + ino, pil, inofixup, iclr, imap); + prom_halt(); + } + + /* Ok, looks good, set it up. Don't touch the irq_chain or + * the pending flag. + */ + bucket = &ivector_table[ino]; + if ((bucket->flags & IBF_ACTIVE) || + (bucket->irq_info != NULL)) { + /* This is a gross fatal error if it happens here. */ + prom_printf("IRQ: Trying to reinit INO bucket, fatal error.\n"); + prom_printf("IRQ: Request INO %04x (%d:%d:%016lx:%016lx)\n", + ino, pil, inofixup, iclr, imap); + prom_printf("IRQ: Existing (%d:%016lx:%016lx)\n", + bucket->pil, bucket->iclr, bucket->imap); + prom_printf("IRQ: Cannot continue, halting...\n"); + prom_halt(); + } + bucket->imap = imap; + bucket->iclr = iclr; + bucket->pil = pil; + bucket->flags = 0; + + bucket->irq_info = NULL; + + return __irq(bucket); } unsigned int sbus_build_irq(void *buscookie, unsigned int ino) @@ -382,8 +441,44 @@ if(!(ino & 0x20)) inofixup = ino & 0x03; - bucket = __bucket(build_irq(pil, inofixup, iclr, imap)); - + /* First check for sharing. */ + ino = (*imap & (SYSIO_IMAP_IGN | SYSIO_IMAP_INO)) + inofixup; + if (ino > NUM_IVECS) { + prom_printf("PSYCHO: Invalid INO %04x (%d:%d:%016lx:%016lx)\n", + ino, pil, inofixup, iclr, imap); + prom_halt(); + } + bucket = &ivector_table[ino]; + if(bucket->flags & IBF_ACTIVE) { + void *old_handler = bucket->irq_info; + unsigned long flags; + + if(old_handler == NULL) { + prom_printf("PSYCHO: Active bucket, but no handler.\n"); + prom_halt(); + } + save_and_cli(flags); + if((bucket->flags & IBF_MULTI) == 0) { + void **vector; + + vector = kmalloc(sizeof(void *) * 4, + GFP_KERNEL); + + /* We might have slept. */ + if((bucket->flags & IBF_MULTI) != 0) { + kfree(vector); + } else { + vector[0] = old_handler; + vector[1] = vector[2] = vector[3] = NULL; + bucket->irq_info = vector; + bucket->flags |= IBF_MULTI; + } + } + restore_flags(flags); + } else { + /* Just init the bucket */ + bucket = __bucket(build_irq(pil, inofixup, iclr, imap)); + } if (need_dma_sync) bucket->flags |= IBF_DMA_SYNC; @@ -392,6 +487,20 @@ } #endif +static void atomic_bucket_insert(struct ino_bucket *bucket) +{ + unsigned long pstate; + unsigned int *ent; + + __asm__ __volatile__("rdpr %%pstate, %0" : "=r" (pstate)); + __asm__ __volatile__("wrpr %0, %1, %%pstate" + : : "r" (pstate), "i" (PSTATE_IE)); + ent = irq_work(smp_processor_id(), bucket->pil); + bucket->irq_chain = *ent; + *ent = __irq(bucket); + __asm__ __volatile__("wrpr %0, 0x0, %%pstate" : : "r" (pstate)); +} + int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), unsigned long irqflags, const char *name, void *dev_id) { @@ -400,11 +509,16 @@ unsigned long flags; int pending = 0; - if (irq < 0x400000 || (irq & 0x80000000)) { - prom_printf("request_irq with old style irq %08x %016lx\n", irq, handler); - prom_halt(); - } - + if ((bucket != &pil0_dummy_bucket) && + (bucket < &ivector_table[0] || + bucket >= &ivector_table[NUM_IVECS])) { + unsigned int *caller; + + __asm__ __volatile__("mov %%i7, %0" : "=r" (caller)); + printk(KERN_CRIT "request_irq: Old style IRQ registry attempt " + "from %p, irq %08x.\n", caller, irq); + return -EINVAL; + } if(!handler) return -EINVAL; @@ -429,24 +543,26 @@ } } + save_and_cli(flags); + action = *(bucket->pil + irq_action); if(action) { if((action->flags & SA_SHIRQ) && (irqflags & SA_SHIRQ)) for (tmp = action; tmp->next; tmp = tmp->next) ; - else + else { + restore_flags(flags); return -EBUSY; - + } if((action->flags & SA_INTERRUPT) ^ (irqflags & SA_INTERRUPT)) { printk("Attempt to mix fast and slow interrupts on IRQ%d " "denied\n", bucket->pil); + restore_flags(flags); return -EBUSY; } action = NULL; /* Or else! */ } - save_and_cli(flags); - /* If this is flagged as statically allocated then we use our * private struct which is never freed. */ @@ -466,12 +582,65 @@ return -ENOMEM; } - if (irqflags & SA_IMAP_MASKED) { - pending = ((ivector_to_mask[bucket->ino] & 0x80000000) != 0); - ivector_to_mask[bucket->ino] = (1 << bucket->pil); - if(pending) - ivector_to_mask[bucket->ino] |= 0x80000000; + if ((irqflags & SA_IMAP_MASKED) == 0) { + bucket->irq_info = action; bucket->flags |= IBF_ACTIVE; + } else { + if((bucket->flags & IBF_ACTIVE) != 0) { + void *orig = bucket->irq_info; + void **vector = NULL; + + if((bucket->flags & IBF_PCI) == 0) { + printk("IRQ: Trying to share non-PCI bucket.\n"); + goto free_and_ebusy; + } + if((bucket->flags & IBF_MULTI) == 0) { + vector = kmalloc(sizeof(void *) * 4, GFP_KERNEL); + if(vector == NULL) + goto free_and_enomem; + + /* We might have slept. */ + if ((bucket->flags & IBF_MULTI) != 0) { + int ent; + + kfree(vector); + vector = (void **)bucket->irq_info; + for(ent = 0; ent < 4; ent++) { + if (vector[ent] == NULL) { + vector[ent] = action; + break; + } + } + if (ent == 4) + goto free_and_ebusy; + } else { + vector[0] = orig; + vector[1] = action; + vector[2] = NULL; + vector[3] = NULL; + bucket->irq_info = vector; + bucket->flags |= IBF_MULTI; + } + } else { + int ent; + + vector = (void **)orig; + for(ent = 0; ent < 4; ent++) { + if(vector[ent] == NULL) { + vector[ent] = action; + break; + } + } + if (ent == 4) + goto free_and_ebusy; + } + } else { + bucket->irq_info = action; + bucket->flags |= IBF_ACTIVE; + } + pending = bucket->pending; + if(pending) + bucket->pending = 0; } action->mask = (unsigned long) bucket; @@ -489,15 +658,26 @@ enable_irq(irq); /* We ate the IVEC already, this makes sure it does not get lost. */ - if(pending) + if(pending) { + atomic_bucket_insert(bucket); set_softint(1 << bucket->pil); - + } restore_flags(flags); + #ifdef __SMP__ - if(irqs_have_been_distributed) - distribute_irqs(); + distribute_irqs(); #endif return 0; + +free_and_ebusy: + kfree(action); + restore_flags(flags); + return -EBUSY; + +free_and_enomem: + kfree(action); + restore_flags(flags); + return -ENOMEM; } void free_irq(unsigned int irq, void *dev_id) @@ -507,9 +687,15 @@ unsigned long flags; struct ino_bucket *bucket = __bucket(irq), *bp; - if (irq < 0x400000 || (irq & 0x80000000)) { - prom_printf("free_irq with old style irq %08x\n", irq); - prom_halt(); + if ((bucket != &pil0_dummy_bucket) && + (bucket < &ivector_table[0] || + bucket >= &ivector_table[NUM_IVECS])) { + unsigned int *caller; + + __asm__ __volatile__("mov %%i7, %0" : "=r" (caller)); + printk(KERN_CRIT "free_irq: Old style IRQ removal attempt " + "from %p, irq %08x.\n", caller, irq); + return; } action = *(bucket->pil + irq_action); @@ -545,27 +731,59 @@ *(bucket->pil + irq_action) = action->next; if(action->flags & SA_IMAP_MASKED) { - unsigned int *imap = __imap(bucket); + unsigned int *imap = bucket->imap; + void **vector, *orig; + int ent; + + orig = bucket->irq_info; + vector = (void **)orig; + + if ((bucket->flags & IBF_MULTI) != 0) { + int other = 0; + void *orphan = NULL; + for(ent = 0; ent < 4; ent++) { + if(vector[ent] == action) + vector[ent] = NULL; + else if(vector[ent] != NULL) { + orphan = vector[ent]; + other++; + } + } - /* - * Only free when no other shared irq uses this bucket. - */ - tmp = *(bucket->pil + irq_action); - for( ; tmp; tmp = tmp->next) - if ((struct ino_bucket *)tmp->mask == bucket) + /* Only free when no other shared irq + * uses this bucket. + */ + if(other) { + if (other == 1) { + /* Convert back to non-shared bucket. */ + bucket->irq_info = orphan; + bucket->flags &= ~(IBF_MULTI); + kfree(vector); + } goto out; + } + } else { + bucket->irq_info = NULL; + } - ivector_to_mask[bucket->ino] = 0; - + /* This unique interrupt source is now inactive. */ bucket->flags &= ~IBF_ACTIVE; - for (bp = bucket_base; bp < endbuckets; bp++) - if (__imap(bp) == imap && (bp->flags & IBF_ACTIVE)) + + /* See if any other buckets share this bucket's IMAP + * and are still active. + */ + for(ent = 0; ent < NUM_IVECS; ent++) { + bp = &ivector_table[ent]; + if(bp != bucket && + bp->imap == imap && + (bp->flags & IBF_ACTIVE) != 0) break; - /* - * Only disable when no other sub-irq levels of - * the same imap are active. + } + + /* Only disable when no other sub-irq levels of + * the same IMAP are active. */ - if (bp == endbuckets) + if (ent == NUM_IVECS) disable_irq(irq); } @@ -607,10 +825,10 @@ int cpu = smp_processor_id(); printk("\n%s, CPU %d:\n", str, cpu); - printk("irq: %d [%d %d]\n", + printk("irq: %d [%ld %ld]\n", atomic_read(&global_irq_count), cpu_data[0].irq_count, cpu_data[1].irq_count); - printk("bh: %d [%d %d]\n", + printk("bh: %d [%ld %ld]\n", (spin_is_locked(&global_bh_count) ? 1 : 0), cpu_data[0].bh_count, cpu_data[1].bh_count); } @@ -755,57 +973,56 @@ #endif /* __SMP__ */ -void report_spurious_ivec(struct pt_regs *regs) +void catch_disabled_ivec(struct pt_regs *regs) { - extern unsigned long ivec_spurious_cookie; - -#if 0 - printk("IVEC: Spurious interrupt vector (%016lx) received at (%016lx)\n", - ivec_spurious_cookie, regs->tpc); -#endif + int cpu = smp_processor_id(); + struct ino_bucket *bucket = __bucket(*irq_work(cpu, 0)); /* We can actually see this on Ultra/PCI PCI cards, which are bridges * to other devices. Here a single IMAP enabled potentially multiple * unique interrupt sources (which each do have a unique ICLR register. * * So what we do is just register that the IVEC arrived, when registered - * for real the request_irq() code will check the high bit and signal + * for real the request_irq() code will check the bit and signal * a local CPU interrupt for it. */ - ivector_to_mask[ivec_spurious_cookie] |= (0x80000000); +#if 0 + printk("IVEC: Spurious interrupt vector (%x) received at (%016lx)\n", + bucket - &ivector_table[0], regs->tpc); +#endif + *irq_work(cpu, 0) = 0; + bucket->pending = 1; } -void unexpected_irq(int irq, void *dev_cookie, struct pt_regs *regs) -{ - int i; - struct irqaction *action; - unsigned int cpu_irq; - - cpu_irq = irq & NR_IRQS; - action = *(cpu_irq + irq_action); - - prom_printf("Unexpected IRQ[%d]: ", irq); - prom_printf("PC[%016lx] NPC[%016lx] FP[%016lx]\n", - regs->tpc, regs->tnpc, regs->u_regs[14]); - - if(action) { - prom_printf("Expecting: "); - for(i = 0; i < 16; i++) { - if(action->handler) - prom_printf("[%s:%d:0x%016lx] ", action->name, - i, (unsigned long) action->handler); - } - } - prom_printf("AIEEE\n"); - prom_printf("bogus interrupt received\n"); - prom_cmdline (); -} +/* Tune this... */ +#define FORWARD_VOLUME 12 void handler_irq(int irq, struct pt_regs *regs) { - struct ino_bucket *bucket = NULL; - struct irqaction *action, *act; + struct ino_bucket *bp, *nbp; int cpu = smp_processor_id(); +#ifdef __SMP__ + extern int this_is_starfire; + int should_forward = (this_is_starfire == 0 && + irq < 10 && + current->pid != 0); + unsigned int buddy = 0; + + /* 'cpu' is the MID (ie. UPAID), calculate the MID + * of our buddy. + */ + if(should_forward != 0) { + buddy = cpu_number_map[cpu] + 1; + if (buddy >= NR_CPUS || + (buddy = cpu_logical_map(buddy)) == -1) + buddy = cpu_logical_map(0); + + /* Voo-doo programming. */ + if(cpu_data[buddy].idle_volume < FORWARD_VOLUME) + should_forward = 0; + buddy <<= 26; + } +#endif #ifndef __SMP__ /* @@ -817,30 +1034,55 @@ clear_softint(1 << irq); irq_enter(cpu, irq); - action = *(irq + irq_action); kstat.irqs[cpu][irq]++; - if(!action) { - unexpected_irq(irq, 0, regs); - } else { - act = action; - do { - if(act->flags & SA_IMAP_MASKED) { - bucket = (struct ino_bucket *)act->mask; - if(!(ivector_to_mask[bucket->ino] & 0x80000000)) - continue; + + /* Sliiiick... */ +#ifndef __SMP__ + bp = ((irq != 0) ? + __bucket(xchg32(irq_work(cpu, irq), 0)) : + &pil0_dummy_bucket); +#else + bp = __bucket(xchg32(irq_work(cpu, irq), 0)); +#endif + for( ; bp != NULL; bp = nbp) { + unsigned char flags = bp->flags; + + nbp = __bucket(bp->irq_chain); + if((flags & IBF_ACTIVE) != 0) { + if((flags & IBF_MULTI) == 0) { + struct irqaction *ap = bp->irq_info; + ap->handler(__irq(bp), ap->dev_id, regs); + } else { + void **vector = (void **)bp->irq_info; + int ent; + for(ent = 0; ent < 4; ent++) { + struct irqaction *ap = vector[ent]; + if(ap != NULL) + ap->handler(__irq(bp), ap->dev_id, regs); + } } - act->handler(__irq(bucket), act->dev_id, regs); - } while((act = act->next) != NULL); - act = action; - do { - if(act->flags & SA_IMAP_MASKED) { - bucket = (struct ino_bucket *)act->mask; - if(!(ivector_to_mask[bucket->ino] & 0x80000000)) - continue; - ivector_to_mask[bucket->ino] &= ~(0x80000000); - *(bucket->iclr) = SYSIO_ICLR_IDLE; + /* Only the dummy bucket lacks IMAP/ICLR. */ + if(bp->pil != 0) { +#ifdef __SMP__ + /* Ok, here is what is going on: + * 1) Retargeting IRQs on Starfire is very + * expensive so just forget about it on them. + * 2) Moving around very high priority interrupts + * is a losing game. + * 3) If the current cpu is idle, interrupts are + * useful work, so keep them here. But do not + * pass to our neighbour if he is not very idle. + */ + if (should_forward != 0) { + /* Push it to our buddy. */ + should_forward = 0; + *(bp->imap) = (buddy | SYSIO_IMAP_VALID); + } +#endif + *(bp->iclr) = SYSIO_ICLR_IDLE; } - } while((act = act->next) != NULL); + } else + bp->pending = 1; } irq_exit(cpu, irq); } @@ -856,10 +1098,13 @@ irq_enter(cpu, irq); kstat.irqs[cpu][irq]++; + + *(irq_work(cpu, irq)) = 0; bucket = (struct ino_bucket *)action->mask; + floppy_interrupt(irq, dev_cookie, regs); - ivector_to_mask[bucket->ino] &= ~(0x80000000); *(bucket->iclr) = SYSIO_ICLR_IDLE; + irq_exit(cpu, irq); } #endif @@ -897,11 +1142,21 @@ struct ino_bucket *bucket = __bucket(irq); unsigned long flags; - if (irq < 0x400000 || (irq & 0x80000000)) { - prom_printf("request_irq with old style irq %08x %016lx\n", irq, handler); - prom_halt(); - } + /* No pil0 dummy buckets allowed here. */ + if (bucket < &ivector_table[0] || + bucket >= &ivector_table[NUM_IVECS]) { + unsigned int *caller; + + __asm__ __volatile__("mov %%i7, %0" : "=r" (caller)); + printk(KERN_CRIT "request_fast_irq: Old style IRQ registry attempt " + "from %p, irq %08x.\n", caller, irq); + return -EINVAL; + } + /* Only IMAP style interrupts can be registered as fast. */ + if(bucket->pil == 0) + return -EINVAL; + if(!handler) return -EINVAL; @@ -919,6 +1174,7 @@ printk("request_fast_irq: Trying to register yet already owned.\n"); return -EBUSY; } + save_and_cli(flags); if(irqflags & SA_STATIC_ALLOC) { if(static_irq_count < MAX_STATIC_ALLOC) @@ -936,7 +1192,8 @@ } install_fast_irq(bucket->pil, handler); - ivector_to_mask[bucket->ino] = (1 << bucket->pil); + bucket->irq_info = action; + bucket->flags |= IBF_ACTIVE; action->mask = (unsigned long) bucket; action->handler = handler; @@ -949,9 +1206,9 @@ enable_irq(irq); restore_flags(flags); + #ifdef __SMP__ - if(irqs_have_been_distributed) - distribute_irqs(); + distribute_irqs(); #endif return 0; } @@ -1025,50 +1282,51 @@ } #ifdef __SMP__ -/* Called from smp_commence, when we know how many cpus are in the system - * and can have device IRQ's directed at them. - */ -/* #define SMP_IRQ_VERBOSE */ -void distribute_irqs(void) +static int retarget_one_irq(struct irqaction *p, int goal_cpu) +{ + extern int this_is_starfire; + struct ino_bucket *bucket = __bucket(p->mask); + unsigned int *imap = bucket->imap; + unsigned int tid; + + /* Never change this, it causes problems on Ex000 systems. */ + if (bucket->pil == 12) + return goal_cpu; + + if(this_is_starfire == 0) { + tid = __cpu_logical_map[goal_cpu] << 26; + } else { + extern unsigned int starfire_translate(unsigned int *imap, + unsigned int upaid); + + tid = (starfire_translate(imap, __cpu_logical_map[goal_cpu]) << 26); + } + *imap = SYSIO_IMAP_VALID | (tid & SYSIO_IMAP_TID); + + goal_cpu++; + if(goal_cpu >= NR_CPUS || + __cpu_logical_map[goal_cpu] == -1) + goal_cpu = 0; + return goal_cpu; +} + +/* Called from request_irq. */ +static void distribute_irqs(void) { unsigned long flags; int cpu, level; -#ifdef SMP_IRQ_VERBOSE - printk("SMP: redistributing interrupts...\n"); -#endif save_and_cli(flags); cpu = 0; for(level = 0; level < NR_IRQS; level++) { struct irqaction *p = irq_action[level]; - while(p) { - if(p->flags & SA_IMAP_MASKED) { - struct ino_bucket *bucket = (struct ino_bucket *)p->mask; - unsigned int *imap = __imap(bucket); - unsigned int val; - unsigned long tid = __cpu_logical_map[cpu] << 26; - - val = *imap; - *imap = SYSIO_IMAP_VALID | (tid & SYSIO_IMAP_TID); - -#ifdef SMP_IRQ_VERBOSE - printk("SMP: Redirecting IGN[%x] INO[%x] " - "to cpu %d [%s]\n", - (val & SYSIO_IMAP_IGN) >> 6, - (val & SYSIO_IMAP_INO), cpu, - p->name); -#endif - - cpu++; - if (cpu >= NR_CPUS || __cpu_logical_map[cpu] == -1) - cpu = 0; - } + if(p->flags & SA_IMAP_MASKED) + cpu = retarget_one_irq(p, cpu); p = p->next; } } restore_flags(flags); - irqs_have_been_distributed = 1; } #endif @@ -1146,13 +1404,13 @@ static int called = 0; if (called == 0) { - int i; - called = 1; map_prom_timers(); kill_prom_timer(); - for(i = 0; i < NUM_IVECS; i++) - ivector_to_mask[i] = 0; + memset(&ivector_table[0], 0, sizeof(ivector_table)); +#ifndef __SMP__ + memset(&__up_workvec[0], 0, sizeof(__up_workvec)); +#endif } /* We need to clear any IRQ's pending in the soft interrupt diff -ur --new-file old/linux/arch/sparc64/kernel/itlb_base.S new/linux/arch/sparc64/kernel/itlb_base.S --- old/linux/arch/sparc64/kernel/itlb_base.S Wed Aug 5 01:03:35 1998 +++ new/linux/arch/sparc64/kernel/itlb_base.S Thu Mar 11 01:53:37 1999 @@ -1,4 +1,4 @@ -/* $Id: itlb_base.S,v 1.5 1998/06/15 16:59:32 jj Exp $ +/* $Id: itlb_base.S,v 1.7 1999/03/02 15:42:12 jj Exp $ * itlb_base.S: Front end to ITLB miss replacement strategy. * This is included directly into the trap table. * @@ -15,11 +15,9 @@ * 2) All user instruction misses. * * All real page faults merge their code paths to the - * sparc64_realfault_* labels below. + * sparc64_realfault_common label below. */ - .globl sparc64_vpte_patchme - /* ITLB ** ICACHE line 1: Quick user TLB misses */ ldxa [%g1 + %g1] ASI_IMMU, %g4 ! Get TAG_ACCESS srax %g4, VPTE_SHIFT, %g6 ! Create VPTE offset @@ -42,28 +40,25 @@ /* ITLB ** ICACHE line 3: Real faults */ rdpr %tpc, %g5 ! And load faulting VA + clr %g4 ! It was read sparc64_realfault_common: ! Called by TL0 dtlb_miss too sethi %hi(1f), %g7 ! Save state ba,pt %xcc, etrap ! ... 1: or %g7, %lo(1b), %g7 ! ... - clr %o2 ! It was read -sparc64_realfault_continue: ! Called by dtlb_prot handler + mov %l4, %o2 ! Read/Write/No idea srlx %l5, PAGE_SHIFT, %o1 ! Page align faulting VA add %sp, STACK_BIAS + REGWIN_SZ, %o0! Compute pt_regs arg - call do_sparc64_fault ! Call fault handler /* ITLB ** ICACHE line 4: Call fault processing code */ + call do_sparc64_fault ! Call fault handler sllx %o1, PAGE_SHIFT, %o1 ! Finish page alignment ba,a,pt %xcc, rtrap_clr_l6 ! Restore cpu state + nop winfix_trampoline: rdpr %tpc, %g3 ! Prepare winfixup TNPC or %g3, 0x7c, %g3 ! Compute offset to branch wrpr %g3, %tnpc ! Write it into TNPC done ! Do it to it -sparc64_vpte_nucleus: - ba,pt %xcc, sparc64_vpte_continue ! Part of dtlb_backend -sparc64_vpte_patchme: - sethi %hi(0), %g5 ! This has to be patched #undef TAG_CONTEXT_BITS #undef VPTE_SHIFT diff -ur --new-file old/linux/arch/sparc64/kernel/process.c new/linux/arch/sparc64/kernel/process.c --- old/linux/arch/sparc64/kernel/process.c Tue Oct 27 18:52:20 1998 +++ new/linux/arch/sparc64/kernel/process.c Tue May 11 17:24:32 1999 @@ -1,4 +1,4 @@ -/* $Id: process.c,v 1.82 1998/10/19 21:52:23 davem Exp $ +/* $Id: process.c,v 1.92 1999/05/08 23:04:48 davem Exp $ * arch/sparc64/kernel/process.c * * Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu) @@ -53,11 +53,19 @@ /* endless idle loop with no priority at all */ current->priority = 0; - current->counter = 0; + current->counter = -100; + init_idle(); + for (;;) { - check_pgt_cache(); - run_task_queue(&tq_scheduler); + /* If current->need_resched is zero we should really + * setup for a system wakup event and execute a shutdown + * instruction. + * + * But this requires writing back the contents of the + * L2 cache etc. so implement this later. -DaveM + */ schedule(); + check_pgt_cache(); } return 0; } @@ -67,20 +75,27 @@ /* * the idle loop on a UltraMultiPenguin... */ +#define idle_me_harder() (cpu_data[current->processor].idle_volume += 1) +#define unidle_me() (cpu_data[current->processor].idle_volume = 0) asmlinkage int cpu_idle(void) { current->priority = 0; - while(1) { - struct task_struct *p; + current->counter = -100; + init_idle(); - check_pgt_cache(); - run_task_queue(&tq_scheduler); - current->counter = 0; - if (current->need_resched != 0 || - ((p = init_task.next_run) != NULL && - (p->processor == smp_processor_id() || - (p->tss.flags & SPARC_FLAG_NEWCHILD) != 0))) + while(1) { + if (current->need_resched != 0) { + unidle_me(); schedule(); + check_pgt_cache(); + } + idle_me_harder(); + + /* The store ordering is so that IRQ handlers on + * other cpus see our increasing idleness for the buddy + * redistribution algorithm. -DaveM + */ + membar("#StoreStore | #StoreLoad"); } } @@ -158,12 +173,12 @@ } rw = &r_w; set_fs (old_fs); - printk("l0: %016x l1: %016x l2: %016x l3: %016x\n" - "l4: %016x l5: %016x l6: %016x l7: %016x\n", + printk("l0: %08x l1: %08x l2: %08x l3: %08x " + "l4: %08x l5: %08x l6: %08x l7: %08x\n", rw->locals[0], rw->locals[1], rw->locals[2], rw->locals[3], rw->locals[4], rw->locals[5], rw->locals[6], rw->locals[7]); - printk("i0: %016x i1: %016x i2: %016x i3: %016x\n" - "i4: %016x i5: %016x i6: %016x i7: %016x\n", + printk("i0: %08x i1: %08x i2: %08x i3: %08x " + "i4: %08x i5: %08x i6: %08x i7: %08x\n", rw->ins[0], rw->ins[1], rw->ins[2], rw->ins[3], rw->ins[4], rw->ins[5], rw->ins[6], rw->ins[7]); } @@ -340,13 +355,13 @@ { printk("PSR: %08x PC: %08x NPC: %08x Y: %08x\n", regs->psr, regs->pc, regs->npc, regs->y); - printk("g0: %08x g1: %08x g2: %08x g3: %08x\n", + printk("g0: %08x g1: %08x g2: %08x g3: %08x ", regs->u_regs[0], regs->u_regs[1], regs->u_regs[2], regs->u_regs[3]); printk("g4: %08x g5: %08x g6: %08x g7: %08x\n", regs->u_regs[4], regs->u_regs[5], regs->u_regs[6], regs->u_regs[7]); - printk("o0: %08x o1: %08x o2: %08x o3: %08x\n", + printk("o0: %08x o1: %08x o2: %08x o3: %08x ", regs->u_regs[8], regs->u_regs[9], regs->u_regs[10], regs->u_regs[11]); printk("o4: %08x o5: %08x sp: %08x ret_pc: %08x\n", @@ -427,9 +442,7 @@ /* exec_mmap() set context to NO_CONTEXT, here is * where we grab a new one. */ - current->mm->cpu_vm_mask = 0; activate_context(current); - current->mm->cpu_vm_mask = (1UL<tss.flags & SPARC_FLAG_32BIT) __asm__ __volatile__("stxa %%g0, [%0] %1" @@ -447,6 +460,11 @@ { unsigned long fp, distance, rval; + /* do_fork() grabs the parent semaphore, we must release it + * temporarily so we can build the child clone stack frame + * without deadlocking. + */ + up(¤t->mm->mmap_sem); if(!(current->tss.flags & SPARC_FLAG_32BIT)) { csp += STACK_BIAS; psp += STACK_BIAS; @@ -463,17 +481,20 @@ distance = fp - psp; rval = (csp - distance); if(copy_in_user(rval, psp, distance)) - return 0; - if(current->tss.flags & SPARC_FLAG_32BIT) { + rval = 0; + else if(current->tss.flags & SPARC_FLAG_32BIT) { if(put_user(((u32)csp), &(((struct reg_window32 *)rval)->ins[6]))) - return 0; - return rval; + rval = 0; } else { if(put_user(((u64)csp - STACK_BIAS), &(((struct reg_window *)rval)->ins[6]))) - return 0; - return rval - STACK_BIAS; + rval = 0; + else + rval = rval - STACK_BIAS; } + down(¤t->mm->mmap_sem); + + return rval; } /* Standard stuff. */ @@ -621,6 +642,37 @@ /* Set the second return value for the parent. */ regs->u_regs[UREG_I1] = 0; return 0; +} + +/* + * This is the mechanism for creating a new kernel thread. + * + * NOTE! Only a kernel-only process(ie the swapper or direct descendants + * who haven't done an "execve()") should use this: it will work within + * a system call from a "real" process, but the process memory space will + * not be free'd until both the parent and the child have exited. + */ +pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) +{ + long retval; + + __asm__ __volatile("mov %1, %%g1\n\t" + "mov %2, %%o0\n\t" /* Clone flags. */ + "mov 0, %%o1\n\t" /* usp arg == 0 */ + "t 0x6d\n\t" /* Linux/Sparc clone(). */ + "brz,a,pn %%o1, 1f\n\t" /* Parent, just return. */ + " mov %%o0, %0\n\t" + "jmpl %4, %%o7\n\t" /* Call the function. */ + " mov %5, %%o0\n\t" /* Set arg in delay. */ + "mov %3, %%g1\n\t" + "t 0x6d\n\t" /* Linux/Sparc exit(). */ + /* Notreached by child. */ + "1:" : + "=r" (retval) : + "i" (__NR_clone), "r" (flags | CLONE_VM), + "i" (__NR_exit), "r" (fn), "r" (arg) : + "g1", "o0", "o1", "memory", "cc"); + return retval; } /* diff -ur --new-file old/linux/arch/sparc64/kernel/psycho.c new/linux/arch/sparc64/kernel/psycho.c --- old/linux/arch/sparc64/kernel/psycho.c Mon Nov 16 19:37:28 1998 +++ new/linux/arch/sparc64/kernel/psycho.c Fri Apr 23 04:24:51 1999 @@ -1,8 +1,9 @@ -/* $Id: psycho.c,v 1.66 1998/11/02 22:27:45 davem Exp $ +/* $Id: psycho.c,v 1.85 1999/04/02 14:54:28 davem Exp $ * psycho.c: Ultra/AX U2P PCI controller support. * * Copyright (C) 1997 David S. Miller (davem@caipfs.rutgers.edu) * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) + * Copyright (C) 1999 Jakub Jelinek (jj@ultra.linux.cz) */ #include @@ -29,14 +30,13 @@ #define dprintf printk #endif - unsigned long pci_dvma_offset = 0x00000000UL; unsigned long pci_dvma_mask = 0xffffffffUL; +#define PCI_DVMA_HASH_NONE 0xffffffffffffffffUL unsigned long pci_dvma_v2p_hash[PCI_DVMA_HASHSZ]; unsigned long pci_dvma_p2v_hash[PCI_DVMA_HASHSZ]; - #ifndef CONFIG_PCI int pcibios_present(void) @@ -74,9 +74,12 @@ #include #include +#define PSYCHO_REORDER_ONBOARDFIRST 1 + struct linux_psycho *psycho_root = NULL; int linux_num_psycho = 0; static struct linux_pbm_info *bus2pbm[256]; +static int psycho_reorder __initdata = 0; static int pbm_read_config_byte(struct linux_pbm_info *pbm, unsigned char bus, unsigned char devfn, @@ -112,8 +115,10 @@ pci_dvma_p2v_hash[pci_dvma_ahashfn(dvma_addr)] = vaddr - dvma_addr; } -__initfunc(static void psycho_iommu_init(struct linux_psycho *psycho, int tsbsize)) +static void __init psycho_iommu_init(struct linux_psycho *psycho, int tsbsize) { + extern int this_is_starfire; + extern void *starfire_hookup(int); struct linux_mlist_p1275 *mlist; unsigned long tsbbase; unsigned long control, i, n; @@ -137,37 +142,77 @@ break; } tsbbase = __get_free_pages(GFP_DMA, order); + if (!tsbbase) { + prom_printf("IOMMU: Error, kmalloc(tsb) failed.\n"); + prom_halt(); + } iopte = (unsigned long *)tsbbase; - memset(pci_dvma_v2p_hash, 0, sizeof(pci_dvma_v2p_hash)); - memset(pci_dvma_p2v_hash, 0, sizeof(pci_dvma_p2v_hash)); + /* Initialize to "none" settings. */ + for(i = 0; i < PCI_DVMA_HASHSZ; i++) { + pci_dvma_v2p_hash[i] = PCI_DVMA_HASH_NONE; + pci_dvma_p2v_hash[i] = PCI_DVMA_HASH_NONE; + } n = 0; mlist = *prom_meminfo()->p1275_totphys; while (mlist) { unsigned long paddr = mlist->start_adr; + unsigned long num_bytes = mlist->num_bytes; - for (i = 0; i < (mlist->num_bytes >> 16); i++) { + if(paddr >= (((unsigned long) high_memory) - PAGE_OFFSET)) + goto next; + if((paddr + num_bytes) >= (((unsigned long) high_memory) - PAGE_OFFSET)) + num_bytes = (((unsigned long) high_memory) - PAGE_OFFSET) - paddr; + + /* Align base and length so we map whole hash table sized chunks + * at a time (and therefore full 64K IOMMU pages). + */ + paddr &= ~((1UL << 24UL) - 1); + num_bytes = (num_bytes + ((1UL << 24UL) - 1)) & ~((1UL << 24) - 1); + + /* Move up the base for mappings already created. */ + while(pci_dvma_v2p_hash[pci_dvma_ahashfn(paddr)] != + PCI_DVMA_HASH_NONE) { + paddr += (1UL << 24UL); + num_bytes -= (1UL << 24UL); + if(num_bytes == 0UL) + goto next; + } + + /* Move down the size for tail mappings already created. */ + while(pci_dvma_v2p_hash[pci_dvma_ahashfn(paddr + num_bytes - (1UL << 24UL))] != + PCI_DVMA_HASH_NONE) { + num_bytes -= (1UL << 24UL); + if(num_bytes == 0UL) + goto next; + } + + /* Now map the rest. */ + for (i = 0; i < ((num_bytes + ((1 << 16) - 1)) >> 16); i++) { *iopte = (IOPTE_VALID | IOPTE_64K | IOPTE_CACHE | IOPTE_WRITE); *iopte |= paddr; if (!(n & 0xff)) set_dvma_hash(paddr, (n << 16)); - + if (++n > (tsbsize * 1024)) goto out; paddr += (1 << 16); iopte++; } - + next: mlist = mlist->theres_more; } out: - if (mlist) - printk("WARNING: not all physical memory mapped in IOMMU\n"); + if (mlist) { + prom_printf("WARNING: not all physical memory mapped in IOMMU\n"); + prom_printf("Try booting with mem=xxxM or similar\n"); + prom_halt(); + } psycho->psycho_regs->iommu_tsbbase = __pa(tsbbase); @@ -193,6 +238,12 @@ break; } psycho->psycho_regs->iommu_control = control; + + /* If necessary, hook us up for starfire IRQ translations. */ + if(this_is_starfire) + psycho->starfire_cookie = starfire_hookup(psycho->upa_portid); + else + psycho->starfire_cookie = NULL; } extern void prom_pbm_ranges_init(int node, struct linux_pbm_info *pbm); @@ -201,7 +252,7 @@ /* * Poor man's PCI... */ -__initfunc(void sabre_init(int pnode)) +void __init sabre_init(int pnode) { struct linux_prom64_registers pr_regs[2]; struct linux_psycho *sabre; @@ -213,6 +264,10 @@ int bus; sabre = kmalloc(sizeof(struct linux_psycho), GFP_ATOMIC); + if (!sabre) { + prom_printf("SABRE: Error, kmalloc(sabre) failed.\n"); + prom_halt(); + } portid = prom_getintdefault(pnode, "upa-portid", 0xff); @@ -248,9 +303,11 @@ prom_halt(); } - printk("PCI: Found SABRE, main regs at %p\n", sabre->psycho_regs); + printk("PCI: Found SABRE, main regs at %p CTRL[%016lx]\n", + sabre->psycho_regs, sabre->psycho_regs->control); #ifdef PROM_DEBUG - dprintf("PCI: Found SABRE, main regs at %p\n", sabre->psycho_regs); + dprintf("PCI: Found SABRE, main regs at %p CTRL[%016lx]\n", + sabre->psycho_regs, sabre->psycho_regs->control); #endif ctrl = sabre->psycho_regs->pci_a_control; @@ -382,7 +439,7 @@ return psycho->pci_bus ? 1 : 0; } -__initfunc(void pcibios_init(void)) +void __init pcibios_init(void) { struct linux_prom64_registers pr_regs[3]; struct linux_psycho *psycho; @@ -408,8 +465,6 @@ goto next_pci; } - psycho = kmalloc(sizeof(struct linux_psycho), GFP_ATOMIC); - portid = prom_getintdefault(node, "upa-portid", 0xff); for(search = psycho_root; search; search = search->next) { if(search->upa_portid == portid) { @@ -424,6 +479,11 @@ } } + psycho = kmalloc(sizeof(struct linux_psycho), GFP_ATOMIC); + if (!psycho) { + prom_printf("PSYCHO: Error, kmalloc(psycho) failed.\n"); + prom_halt(); + } memset(psycho, 0, sizeof(*psycho)); psycho->next = psycho_root; @@ -494,8 +554,14 @@ is_pbm_a = ((pr_regs[0].phys_addr & 0x6000) == 0x2000); /* Enable arbitration for all PCI slots. */ - psycho->psycho_regs->pci_a_control |= 0x3f; - psycho->psycho_regs->pci_b_control |= 0x3f; + psycho->psycho_regs->pci_a_control |= PSYCHO_PCICTRL_AEN; + psycho->psycho_regs->pci_b_control |= PSYCHO_PCICTRL_AEN; + + /* Disable DMA write / PIO rd synchronization on both + * PCI bus segments. + */ + psycho->psycho_regs->pci_a_diag |= PSYCHO_PCIDIAG_DDWSYNC; + psycho->psycho_regs->pci_b_diag |= PSYCHO_PCIDIAG_DDWSYNC; other_pbm: if(is_pbm_a) @@ -609,25 +675,28 @@ } -__initfunc(static void -pbm_reconfigure_bridges(struct linux_pbm_info *pbm, unsigned char bus)) +static void __init +pbm_reconfigure_bridges(struct linux_pbm_info *pbm, unsigned char bus) { unsigned int devfn, l, class; unsigned char hdr_type = 0; + int is_multi = 0; for (devfn = 0; devfn < 0xff; ++devfn) { - if (PCI_FUNC(devfn) == 0) { - pbm_read_config_byte(pbm, bus, devfn, - PCI_HEADER_TYPE, &hdr_type); - } else if (!(hdr_type & 0x80)) { + if (PCI_FUNC(devfn) != 0 && is_multi == 0) { /* not a multi-function device */ continue; } + pbm_read_config_byte(pbm, bus, devfn, + PCI_HEADER_TYPE, &hdr_type); + if (PCI_FUNC(devfn) == 0) + is_multi = hdr_type & 0x80; /* Check if there is anything here. */ pbm_read_config_dword(pbm, bus, devfn, PCI_VENDOR_ID, &l); - if (l == 0xffffffff || l == 0x00000000) { - hdr_type = 0; + if (l == 0xffffffff || l == 0x00000000 || + l == 0x0000ffff || l == 0xffff0000) { + is_multi = 0; continue; } @@ -657,7 +726,7 @@ } } -__initfunc(static void pbm_fixup_busno(struct linux_pbm_info *pbm, unsigned char bus)) +static void __init pbm_fixup_busno(struct linux_pbm_info *pbm, unsigned char bus) { unsigned int nbus; @@ -682,8 +751,7 @@ } while (nbus--); } - -__initfunc(static void apb_init(struct linux_psycho *sabre)) +static void __init apb_init(struct linux_psycho *sabre) { struct pci_dev *pdev; unsigned short stmp; @@ -692,21 +760,20 @@ for(pdev = pci_devices; pdev; pdev = pdev->next) { if(pdev->vendor == PCI_VENDOR_ID_SUN && pdev->device == PCI_DEVICE_ID_SUN_SABRE) { - /* Increase latency timer on top level bridge. */ - pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0xf8); + pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 128); break; } } for (pdev = sabre->pci_bus->devices; pdev; pdev = pdev->sibling) { if (pdev->vendor == PCI_VENDOR_ID_SUN && pdev->device == PCI_DEVICE_ID_SUN_SIMBA) { - pci_read_config_word(pdev, PCI_COMMAND, &stmp); stmp |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO; pci_write_config_word(pdev, PCI_COMMAND, stmp); + /* Status register bits are "write 1 to clear". */ pci_write_config_word(pdev, PCI_STATUS, 0xffff); pci_write_config_word(pdev, PCI_SEC_STATUS, 0xffff); @@ -721,28 +788,25 @@ APB_PCI_CTL_HIGH_ARBITER_EN; pci_write_config_dword(pdev, APB_PCI_CONTROL_HIGH, itmp); + /* Systems with SIMBA are usually workstations, so + * we configure to park to SIMBA not to the previous + * bus owner. + */ pci_read_config_dword(pdev, APB_PCI_CONTROL_LOW, &itmp); - itmp = APB_PCI_CTL_LOW_ARB_PARK | - APB_PCI_CTL_LOW_ERRINT_EN | 0x0f; + itmp = APB_PCI_CTL_LOW_ERRINT_EN | 0x0f; pci_write_config_dword(pdev, APB_PCI_CONTROL_LOW, itmp); - /* - * Setup Registers for Guaranteed Completion. + /* 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, APB_PRIMARY_MASTER_RETRY_LIMIT, 0); - pci_write_config_byte(pdev, APB_SECONDARY_MASTER_RETRY_LIMIT, 0); - pci_write_config_byte(pdev, APB_PIO_TARGET_RETRY_LIMIT, 0x80); - pci_write_config_byte(pdev, APB_PIO_TARGET_LATENCY_TIMER, 0); - pci_write_config_byte(pdev, APB_DMA_TARGET_RETRY_LIMIT, 0x80); - pci_write_config_byte(pdev, APB_DMA_TARGET_LATENCY_TIMER, 0); - - /* Increase primary latency timer. */ - pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0xf8); + pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 128); + pci_write_config_byte(pdev, PCI_SEC_LATENCY_TIMER, 128); } } } -__initfunc(static void sabre_probe(struct linux_psycho *sabre)) +static void __init sabre_probe(struct linux_psycho *sabre) { struct pci_bus *pbus = sabre->pci_bus; static unsigned char busno = 0; @@ -764,7 +828,7 @@ } -__initfunc(static void pbm_probe(struct linux_pbm_info *pbm)) +static void __init pbm_probe(struct linux_pbm_info *pbm) { static struct pci_bus *pchain = NULL; struct pci_bus *pbus = &pbm->pci_bus; @@ -803,9 +867,9 @@ } } -__initfunc(static int pdev_to_pnode_sibtraverse(struct linux_pbm_info *pbm, - struct pci_dev *pdev, - int pnode)) +static int __init pdev_to_pnode_sibtraverse(struct linux_pbm_info *pbm, + struct pci_dev *pdev, + int pnode) { struct linux_prom_pci_registers pregs[PROMREG_MAX]; int node; @@ -827,8 +891,8 @@ return 0; } -__initfunc(static void pdev_cookie_fillin(struct linux_pbm_info *pbm, - struct pci_dev *pdev, int pnode)) +static void __init pdev_cookie_fillin(struct linux_pbm_info *pbm, + struct pci_dev *pdev, int pnode) { struct pcidev_cookie *pcp; int node; @@ -846,9 +910,9 @@ #endif } -__initfunc(static void fill_in_pbm_cookies(struct pci_bus *pbus, - struct linux_pbm_info *pbm, - int node)) +static void __init fill_in_pbm_cookies(struct pci_bus *pbus, + struct linux_pbm_info *pbm, + int node) { struct pci_dev *pdev; @@ -868,7 +932,7 @@ } } -__initfunc(static void sabre_cookie_fillin(struct linux_psycho *sabre)) +static void __init sabre_cookie_fillin(struct linux_psycho *sabre) { struct pci_bus *pbus = sabre->pci_bus; @@ -886,9 +950,9 @@ * properties, and recording them in pci_vma's linked in via * PBM->assignments. */ -__initfunc(static int gimme_ebus_assignments(int node, struct linux_prom_pci_registers *aregs)) +static int __init gimme_ebus_assignments(int node, struct linux_prom_pci_registers *aregs) { - struct linux_prom_ebus_ranges erng[PROMREG_MAX]; + struct linux_prom_ebus_ranges erng[PROM_PCIRNG_MAX]; int err, iter; err = prom_getproperty(node, "ranges", (char *)&erng[0], sizeof(erng)); @@ -911,7 +975,7 @@ return err; } -__initfunc(static void assignment_process(struct linux_pbm_info *pbm, int node)) +static void __init assignment_process(struct linux_pbm_info *pbm, int node) { struct linux_prom_pci_registers aregs[PROMREG_MAX]; char pname[256]; @@ -968,7 +1032,7 @@ } } -__initfunc(static void assignment_walk_siblings(struct linux_pbm_info *pbm, int node)) +static void __init assignment_walk_siblings(struct linux_pbm_info *pbm, int node) { while(node) { int child = prom_getchild(node); @@ -1077,12 +1141,12 @@ #endif } -__initfunc(static void fixup_regs(struct pci_dev *pdev, - struct linux_pbm_info *pbm, - struct linux_prom_pci_registers *pregs, - int nregs, - struct linux_prom_pci_registers *assigned, - int numaa)) +static void __init fixup_regs(struct pci_dev *pdev, + struct linux_pbm_info *pbm, + struct linux_prom_pci_registers *pregs, + int nregs, + struct linux_prom_pci_registers *assigned, + int numaa) { int preg, rng; int IO_seen = 0; @@ -1173,12 +1237,13 @@ } if (bsreg == PCI_ROM_ADDRESS) { pdev->rom_address = (unsigned long)__va(pci_addr); - pdev->rom_address |= 1; + pdev->rom_address &= ~1UL; + /* - * Enable access to the ROM. + * Disable access to the ROM. */ pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &rtmp); - pci_write_config_dword(pdev, PCI_ROM_ADDRESS, rtmp | 1); + pci_write_config_dword(pdev, PCI_ROM_ADDRESS, rtmp & ~1); } else pdev->base_address[brindex] = (unsigned long)__va(pci_addr); @@ -1347,7 +1412,7 @@ rtmp = new_base; pci_read_config_dword(pdev, breg, &base); - rtmp |= (base & ~PCI_ROM_ADDRESS_MASK); + rtmp &= ~(base & ~PCI_ROM_ADDRESS_MASK); pci_write_config_dword(pdev, breg, rtmp); /* Apply PBM ranges and update pci_dev. */ @@ -1370,8 +1435,7 @@ "PBM ranges\n"); } pdev->rom_address = (unsigned long)__va(pci_addr); - - pdev->rom_address |= (base & ~PCI_ROM_ADDRESS_MASK); + pdev->rom_address &= ~(base & ~PCI_ROM_ADDRESS_MASK); MEM_seen = 1; } rom_address_done: @@ -1415,7 +1479,7 @@ #define imap_offset(__member) \ ((unsigned long)(&(((struct psycho_regs *)0)->__member))) -__initfunc(static unsigned long psycho_pcislot_imap_offset(unsigned long ino)) +static unsigned long __init psycho_pcislot_imap_offset(unsigned long ino) { unsigned int bus, slot; @@ -1431,11 +1495,8 @@ case 2: return imap_offset(imap_a_slot2); case 3: - return imap_offset(imap_a_slot3); default: - prom_printf("pcislot_imap: IMPOSSIBLE [%d:%d]\n", - bus, slot); - prom_halt(); + return imap_offset(imap_a_slot3); } } else { switch(slot) { @@ -1446,19 +1507,16 @@ case 2: return imap_offset(imap_b_slot2); case 3: - return imap_offset(imap_b_slot3); default: - prom_printf("pcislot_imap: IMPOSSIBLE [%d:%d]\n", - bus, slot); - prom_halt(); + return imap_offset(imap_b_slot3); } } } /* Exported for EBUS probing layer. */ -__initfunc(unsigned int psycho_irq_build(struct linux_pbm_info *pbm, - struct pci_dev *pdev, - unsigned int ino)) +unsigned int __init psycho_irq_build(struct linux_pbm_info *pbm, + struct pci_dev *pdev, + unsigned int ino) { unsigned long imap_off; int need_dma_sync = 0; @@ -1533,6 +1591,36 @@ imap_off = imap_offset(imap_ser); break; + case 0x2c: + /* Onboard Timer 0 */ + imap_off = imap_offset(imap_tim0); + break; + + case 0x2d: + /* Onboard Timer 1 */ + imap_off = imap_offset(imap_tim1); + break; + + case 0x2e: + /* Psycho UE Interrupt */ + imap_off = imap_offset(imap_ue); + break; + + case 0x2f: + /* Psycho CE Interrupt */ + imap_off = imap_offset(imap_ce); + break; + + case 0x30: + /* Psycho PCI A Error Interrupt */ + imap_off = imap_offset(imap_a_err); + break; + + case 0x31: + /* Psycho PCI B Error Interrupt */ + imap_off = imap_offset(imap_b_err); + break; + case 0x32: /* Power Management */ imap_off = imap_offset(imap_pmgmt); @@ -1554,37 +1642,78 @@ return psycho_build_irq(pbm->parent, imap_off, ino, need_dma_sync); } -__initfunc(static int pbm_intmap_match(struct linux_pbm_info *pbm, - struct pci_dev *pdev, - struct linux_prom_pci_registers *preg, - unsigned int *interrupt)) +static int __init pbm_intmap_match(struct linux_pbm_info *pbm, + struct pci_dev *pdev, + struct linux_prom_pci_registers *preg, + unsigned int *interrupt) { struct linux_prom_pci_registers ppreg; unsigned int hi, mid, lo, irq; int i; - if (!pbm->num_pbm_intmap) +#ifdef FIXUP_IRQ_DEBUG + dprintf("pbm_intmap_match: "); +#endif + if (!pbm->num_pbm_intmap) { +#ifdef FIXUP_IRQ_DEBUG + dprintf("No intmap UPA[%x:%c]\n", + pbm->parent->upa_portid, + (pbm == &pbm->parent->pbm_A) ? 'A' : 'B'); +#endif return 0; - + } /* * Underneath a bridge, use register of parent bridge. */ if (pdev->bus->number != pbm->pci_first_busno) { - struct pcidev_cookie *pcp = pdev->bus->self->sysdata; - int node; + struct pcidev_cookie *pcp; + int node, offset; + char prom_name[64]; - if (!pcp) +#ifdef FIXUP_IRQ_DEBUG + dprintf("UnderBridge, "); +#endif + pcp = pdev->bus->self->sysdata; + if (!pcp) { +#ifdef FIXUP_IRQ_DEBUG + dprintf("No bus PCP\n"); +#endif goto out; - + } node = pcp->prom_node; i = prom_getproperty(node, "reg", (char*)&ppreg, sizeof(ppreg)); - if(i == 0 || i == -1) + if(i == 0 || i == -1) { +#ifdef FIXUP_IRQ_DEBUG + dprintf("No reg property.\n"); +#endif goto out; + } + /* + * Did PROM know better and assign an interrupt different + * to #INTA to the device? - We test here for presence of + * FCODE on the card, in this case we assume PROM has set + * correct 'interrupts' property, unless it is quadhme. + */ + pcp = pdev->sysdata; + if (!pcp) { +#ifdef FIXUP_IRQ_DEBUG + dprintf("No dev PCP\n"); +#endif + goto out; + } + node = pcp->prom_node; - /* Use low slot number bits of child as IRQ line. */ - *interrupt = ((pdev->devfn >> 3) & 3) + 1; - + offset = prom_getint(node, "fcode-rom-offset"); + prom_getstring(node, "name", prom_name, sizeof(prom_name)); + if (offset == -1 || + !strcmp(prom_name, "SUNW,qfe") || + !strcmp(prom_name, "qfe")) { + /* + * No, use low slot number bits of child as IRQ line. + */ + *interrupt = ((*interrupt - 1 + PCI_SLOT(pdev->devfn)) & 3) + 1; + } preg = &ppreg; } @@ -1618,13 +1747,12 @@ prom_halt(); } -__initfunc(static void fixup_irq(struct pci_dev *pdev, - struct linux_pbm_info *pbm, - struct linux_prom_pci_registers *preg, - int node)) +static void __init fixup_irq(struct pci_dev *pdev, + struct linux_pbm_info *pbm, + struct linux_prom_pci_registers *preg, + int node) { unsigned int prom_irq, portid = pbm->parent->upa_portid; - unsigned char pci_irq_line = pdev->irq; int err; #ifdef FIXUP_IRQ_DEBUG @@ -1668,7 +1796,25 @@ unsigned int bus, slot, line; bus = (pbm == &pbm->parent->pbm_B) ? (1 << 4) : 0; - line = (pci_irq_line) & 3; + + /* Use the given interrupt property value as the line if it + * is non-zero and legal. Legal encodings are INTA=1, INTB=2, + * INTC=3, INTD=4 as per PCI OBP binding spec version 2.1 -DaveM + */ + if(prom_irq > 0 && prom_irq < 5) { + line = ((prom_irq - 1) & 3); + } else { + unsigned char pci_irq_line; + + /* The generic PCI probing layer will read the + * interrupt line into pdev->irq if the interrupt + * pin is non-zero, so we have to explicitly fetch + * the pin here to be certain (the interrupt line is + * typically left at zero by OBP). + */ + pci_read_config_byte(pdev, PCI_INTERRUPT_PIN, &pci_irq_line); + line = ((pci_irq_line - 1) & 3); + } /* Slot determination is only slightly complex. Handle * the easy case first. @@ -1721,11 +1867,11 @@ #endif } -__initfunc(static void fixup_doit(struct pci_dev *pdev, - struct linux_pbm_info *pbm, - struct linux_prom_pci_registers *pregs, - int nregs, - int node)) +static void __init fixup_doit(struct pci_dev *pdev, + struct linux_pbm_info *pbm, + struct linux_prom_pci_registers *pregs, + int nregs, + int node) { struct linux_prom_pci_registers assigned[PROMREG_MAX]; int numaa, err; @@ -1745,9 +1891,9 @@ fixup_irq(pdev, pbm, &pregs[0], node); } -__initfunc(static void fixup_pci_dev(struct pci_dev *pdev, - struct pci_bus *pbus, - struct linux_pbm_info *pbm)) +static void __init fixup_pci_dev(struct pci_dev *pdev, + struct pci_bus *pbus, + struct linux_pbm_info *pbm) { struct linux_prom_pci_registers pregs[PROMREG_MAX]; struct pcidev_cookie *pcp = pdev->sysdata; @@ -1762,8 +1908,12 @@ cmd |= PCI_COMMAND_MASTER; pci_write_config_word(pdev, PCI_COMMAND, cmd); - /* Now, set cache line size to 64-bytes. */ - pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 64); + /* Now, set cache line size to 64-bytes. + * NOTE: Cache line size is in 32-bit word units. + */ + pci_write_config_byte(pdev, + PCI_CACHE_LINE_SIZE, + (64 / sizeof(u32))); } /* Ignore if this is one of the PBM's, EBUS, or a @@ -1808,7 +1958,7 @@ } } -__initfunc(static void fixup_pci_bus(struct pci_bus *pbus, struct linux_pbm_info *pbm)) +static void __init fixup_pci_bus(struct pci_bus *pbus, struct linux_pbm_info *pbm) { struct pci_dev *pdev; @@ -1819,7 +1969,7 @@ fixup_pci_bus(pbus, pbm); } -__initfunc(static void fixup_addr_irq(struct linux_pbm_info *pbm)) +static void __init fixup_addr_irq(struct linux_pbm_info *pbm) { struct pci_bus *pbus = &pbm->pci_bus; @@ -1832,7 +1982,7 @@ /* Walk all PCI devices probes, fixing up base registers and IRQ registers. * We use OBP for most of this work. */ -__initfunc(static void psycho_final_fixup(struct linux_psycho *psycho)) +static void __init psycho_final_fixup(struct linux_psycho *psycho) { /* Second, fixup base address registers and IRQ lines... */ if (psycho->pbm_A.parent) @@ -1841,7 +1991,33 @@ fixup_addr_irq(&psycho->pbm_B); } -__initfunc(void pcibios_fixup(void)) +/* Reorder the pci_dev chain, so that onboard devices come first + and then come the pluggable cards. */ +void __init psycho_reorder_devs(void) +{ + struct pci_dev **pci_onboard = &pci_devices; + struct pci_dev **pci_tail = &pci_devices; + struct pci_dev *pdev = pci_devices, *pci_other = NULL; + + while (pdev) { + if (pdev->irq && (__irq_ino(pdev->irq) & 0x20)) { + if (pci_other) { + *pci_onboard = pdev; + pci_onboard = &pdev->next; + pdev = pdev->next; + *pci_onboard = pci_other; + *pci_tail = pdev; + continue; + } else + pci_onboard = &pdev->next; + } else if (!pci_other) + pci_other = pdev; + pci_tail = &pdev->next; + pdev = pdev->next; + } +} + +void __init pcibios_fixup(void) { struct linux_psycho *psycho; @@ -1861,9 +2037,9 @@ for (psycho = psycho_root; psycho; psycho = psycho->next) { /* Probe bus on builtin PCI. */ - if (apb_present(psycho)) + if (apb_present(psycho)) { sabre_probe(psycho); - else { + } else { /* Probe busses under PBM B. */ pbm_probe(&psycho->pbm_B); @@ -1896,6 +2072,9 @@ psycho_final_fixup(psycho); } + if (psycho_reorder & PSYCHO_REORDER_ONBOARDFIRST) + psycho_reorder_devs(); + return ebus_init(); } @@ -2418,12 +2597,20 @@ return err; } -__initfunc(void pcibios_fixup_bus(struct pci_bus *bus)) +void __init pcibios_fixup_bus(struct pci_bus *bus) { } -__initfunc(char *pcibios_setup(char *str)) +char * __init pcibios_setup(char *str) { + if (!strcmp(str, "onboardfirst")) { + psycho_reorder |= PSYCHO_REORDER_ONBOARDFIRST; + return NULL; + } + if (!strcmp(str, "noreorder")) { + psycho_reorder = 0; + return NULL; + } return str; } diff -ur --new-file old/linux/arch/sparc64/kernel/ptrace.c new/linux/arch/sparc64/kernel/ptrace.c --- old/linux/arch/sparc64/kernel/ptrace.c Tue Oct 27 18:52:20 1998 +++ new/linux/arch/sparc64/kernel/ptrace.c Thu Mar 25 00:10:28 1999 @@ -591,6 +591,8 @@ if (((current->personality & PER_BSD) && (request == PTRACE_SUNATTACH)) || (!(current->personality & PER_BSD) && (request == PTRACE_ATTACH))) { + unsigned long flags; + if(child == current) { /* Try this under SunOS/Solaris, bwa haha * You'll never be able to kill the process. ;-) @@ -602,8 +604,9 @@ (current->uid != child->euid) || (current->uid != child->uid) || (current->gid != child->egid) || - (current->gid != child->gid)) && - !capable(CAP_SYS_PTRACE)) { + (current->gid != child->sgid) || + (!cap_issubset(child->cap_permitted, current->cap_permitted)) || + (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE)) { pt_error_return(regs, EPERM); goto out; } @@ -613,15 +616,13 @@ goto out; } child->flags |= PF_PTRACED; + write_lock_irqsave(&tasklist_lock, flags); if(child->p_pptr != current) { - unsigned long flags; - - write_lock_irqsave(&tasklist_lock, flags); REMOVE_LINKS(child); child->p_pptr = current; SET_LINKS(child); - write_unlock_irqrestore(&tasklist_lock, flags); } + write_unlock_irqrestore(&tasklist_lock, flags); send_sig(SIGSTOP, child, 1); pt_succ_return(regs, 0); goto out; @@ -670,14 +671,18 @@ pt_error_return(regs, EINVAL); goto out; } + down(&child->mm->mmap_sem); res = read_int(child, addr, &x); + up(&child->mm->mmap_sem); tmp = x; } else { if(addr & (sizeof(unsigned long) - 1)) { pt_error_return(regs, EINVAL); goto out; } + down(&child->mm->mmap_sem); res = read_long(child, addr, &tmp); + up(&child->mm->mmap_sem); } if (res < 0) { pt_error_return(regs, -res); @@ -709,13 +714,17 @@ pt_error_return(regs, EINVAL); goto out; } + down(&child->mm->mmap_sem); res = write_int(child, addr, data); + up(&child->mm->mmap_sem); } else { if(addr & (sizeof(unsigned long) - 1)) { pt_error_return(regs, EINVAL); goto out; } + down(&child->mm->mmap_sem); res = write_long(child, addr, data); + up(&child->mm->mmap_sem); } if(res < 0) pt_error_return(regs, -res); @@ -944,12 +953,15 @@ unsigned long page; while(len) { + down(&child->mm->mmap_sem); vma = find_extend_vma(child, src); if (!vma) { + up(&child->mm->mmap_sem); pt_error_return(regs, EIO); goto flush_and_out; } pgtable = get_page (child, vma, src, 0); + up(&child->mm->mmap_sem); if (src & ~PAGE_MASK) { curlen = PAGE_SIZE - (src & ~PAGE_MASK); if (curlen > len) curlen = len; @@ -988,12 +1000,15 @@ unsigned long page; while(len) { + down(&child->mm->mmap_sem); vma = find_extend_vma(child, dest); if (!vma) { + up(&child->mm->mmap_sem); pt_error_return(regs, EIO); goto flush_and_out; } pgtable = get_page (child, vma, dest, 1); + up(&child->mm->mmap_sem); if (dest & ~PAGE_MASK) { curlen = PAGE_SIZE - (dest & ~PAGE_MASK); if (curlen > len) curlen = len; diff -ur --new-file old/linux/arch/sparc64/kernel/setup.c new/linux/arch/sparc64/kernel/setup.c --- old/linux/arch/sparc64/kernel/setup.c Tue Oct 27 18:52:20 1998 +++ new/linux/arch/sparc64/kernel/setup.c Fri Apr 23 04:24:51 1999 @@ -1,4 +1,4 @@ -/* $Id: setup.c,v 1.37 1998/10/14 15:49:09 ecd Exp $ +/* $Id: setup.c,v 1.43 1999/04/12 08:08:24 davem Exp $ * linux/arch/sparc64/kernel/setup.c * * Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu) @@ -277,6 +277,22 @@ #endif static unsigned long memory_size = 0; +#ifdef PROM_DEBUG_CONSOLE +static struct console prom_debug_console = { + "debug", + prom_console_write, + NULL, + NULL, + NULL, + NULL, + NULL, + CON_PRINTBUFFER, + -1, + 0, + NULL +}; +#endif + /* XXX Implement this at some point... */ void kernel_enter_debugger(void) { @@ -397,13 +413,12 @@ extern int prom_probe_memory(void); extern unsigned long start, end; extern void panic_setup(char *, int *); -extern unsigned long sun_serial_setup(unsigned long); extern unsigned short root_flags; extern unsigned short root_dev; extern unsigned short ram_flags; -extern unsigned int ramdisk_image; -extern unsigned int ramdisk_size; +extern unsigned int sparc_ramdisk_image; +extern unsigned int sparc_ramdisk_size; #define RAMDISK_IMAGE_START_MASK 0x07FF #define RAMDISK_PROMPT_FLAG 0x8000 #define RAMDISK_LOAD_FLAG 0x4000 @@ -430,6 +445,10 @@ *cmdline_p = prom_getbootargs(); strcpy(saved_command_line, *cmdline_p); +#ifdef PROM_DEBUG_CONSOLE + register_console(&prom_debug_console); +#endif + printk("ARCH: SUN4U\n"); #ifdef CONFIG_DUMMY_CONSOLE @@ -489,13 +508,13 @@ rd_doload = ((ram_flags & RAMDISK_LOAD_FLAG) != 0); #endif #ifdef CONFIG_BLK_DEV_INITRD - if (ramdisk_image) { + if (sparc_ramdisk_image) { unsigned long start = 0; - if (ramdisk_image >= (unsigned long)&end - 2 * PAGE_SIZE) - ramdisk_image -= KERNBASE; - initrd_start = ramdisk_image + phys_base + PAGE_OFFSET; - initrd_end = initrd_start + ramdisk_size; + if (sparc_ramdisk_image >= (unsigned long)&end - 2 * PAGE_SIZE) + sparc_ramdisk_image -= KERNBASE; + initrd_start = sparc_ramdisk_image + phys_base + PAGE_OFFSET; + initrd_end = initrd_start + sparc_ramdisk_size; if (initrd_end > *memory_end_p) { printk(KERN_CRIT "initrd extends beyond end of memory " "(0x%016lx > 0x%016lx)\ndisabling initrd\n", @@ -503,10 +522,10 @@ initrd_start = 0; } if (initrd_start) - start = ramdisk_image + KERNBASE; + start = sparc_ramdisk_image + KERNBASE; if (start >= *memory_start_p && start < *memory_start_p + 2 * PAGE_SIZE) { initrd_below_start_ok = 1; - *memory_start_p = PAGE_ALIGN (start + ramdisk_size); + *memory_start_p = PAGE_ALIGN (start + sparc_ramdisk_size); } } #endif @@ -531,7 +550,7 @@ ic_servaddr = sv; if (gw) ic_gateway = gw; - ic_bootp_flag = ic_rarp_flag = 0; + ic_proto_enabled = 0; } } #endif @@ -566,7 +585,6 @@ serial_console = 2; break; } - *memory_start_p = sun_serial_setup(*memory_start_p); /* set this up ASAP */ #else serial_console = 0; #endif diff -ur --new-file old/linux/arch/sparc64/kernel/smp.c new/linux/arch/sparc64/kernel/smp.c --- old/linux/arch/sparc64/kernel/smp.c Tue Oct 27 18:52:20 1998 +++ new/linux/arch/sparc64/kernel/smp.c Tue May 11 17:24:32 1999 @@ -5,6 +5,8 @@ #include #include +#include +#include #include #include #include @@ -34,24 +36,23 @@ extern void calibrate_delay(void); extern unsigned prom_cpu_nodes[]; -volatile int smp_processors_ready = 0; -unsigned long cpu_present_map = 0; -int smp_num_cpus = 1; -int smp_threads_ready = 0; +struct cpuinfo_sparc cpu_data[NR_CPUS] __attribute__ ((aligned (64))); -struct cpuinfo_sparc cpu_data[NR_CPUS] __attribute__ ((aligned (64))); +volatile int cpu_number_map[NR_CPUS] __attribute__ ((aligned (64))); +volatile int __cpu_logical_map[NR_CPUS] __attribute__ ((aligned (64))); -/* Please don't make this initdata!!! --DaveM */ +/* Please don't make this stuff initdata!!! --DaveM */ static unsigned char boot_cpu_id = 0; - static int smp_activated = 0; -volatile int cpu_number_map[NR_CPUS]; -volatile int __cpu_logical_map[NR_CPUS]; - /* Kernel spinlock */ spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED; +volatile int smp_processors_ready = 0; +unsigned long cpu_present_map = 0; +int smp_num_cpus = 1; +int smp_threads_ready = 0; + __initfunc(void smp_setup(char *str, int *ints)) { /* XXX implement me XXX */ @@ -84,6 +85,8 @@ __initfunc(void smp_store_cpu_info(int id)) { + int i; + cpu_data[id].irq_count = 0; cpu_data[id].bh_count = 0; /* multiplier and counter set by @@ -94,16 +97,18 @@ cpu_data[id].pte_cache = NULL; cpu_data[id].pgdcache_size = 0; cpu_data[id].pgd_cache = NULL; -} + cpu_data[id].idle_volume = 1; -extern void distribute_irqs(void); + for(i = 0; i < 16; i++) + cpu_data[id].irq_worklists[i] = 0; +} __initfunc(void smp_commence(void)) { - distribute_irqs(); } static void smp_setup_percpu_timer(void); +static void smp_tune_scheduling(void); static volatile unsigned long callin_flag = 0; @@ -173,10 +178,16 @@ panic("SMP bolixed\n"); } -extern struct prom_cpuinfo linux_cpus[NR_CPUS]; +extern struct prom_cpuinfo linux_cpus[64]; extern unsigned long smp_trampoline; +/* The OBP cpu startup callback truncates the 3rd arg cookie to + * 32-bits (I think) so to be safe we have it read the pointer + * contained here so we work on >4GB machines. -DaveM + */ +static struct task_struct *cpu_new_task = NULL; + __initfunc(void smp_boot_cpus(void)) { int cpucount = 0, i; @@ -184,6 +195,8 @@ printk("Entering UltraSMPenguin Mode...\n"); __sti(); smp_store_cpu_info(boot_cpu_id); + smp_tune_scheduling(); + init_idle(); if(linux_num_cpus == 1) return; @@ -194,21 +207,25 @@ if(cpu_present_map & (1UL << i)) { unsigned long entry = (unsigned long)(&smp_trampoline); + unsigned long cookie = (unsigned long)(&cpu_new_task); struct task_struct *p; int timeout; int no; extern unsigned long phys_base; entry += phys_base - KERNBASE; + cookie += phys_base - KERNBASE; kernel_thread(start_secondary, NULL, CLONE_PID); p = task[++cpucount]; p->processor = i; + p->has_cpu = 1; /* we schedule the first task manually */ callin_flag = 0; for (no = 0; no < linux_num_cpus; no++) if (linux_cpus[no].mid == i) break; + cpu_new_task = p; prom_startcpu(linux_cpus[no].prom_node, - entry, ((unsigned long)p)); + entry, cookie); for(timeout = 0; timeout < 5000000; timeout++) { if(callin_flag) break; @@ -216,8 +233,8 @@ } if(callin_flag) { cpu_number_map[i] = cpucount; - prom_cpu_nodes[i] = linux_cpus[no].prom_node; __cpu_logical_map[cpucount] = i; + prom_cpu_nodes[i] = linux_cpus[no].prom_node; } else { cpucount--; printk("Processor %d is stuck.\n", i); @@ -228,6 +245,7 @@ cpu_number_map[i] = -1; } } + cpu_new_task = NULL; if(cpucount == 0) { printk("Error: only one processor found.\n"); cpu_present_map = (1UL << smp_processor_id()); @@ -249,17 +267,6 @@ membar("#StoreStore | #StoreLoad"); } -/* We don't even need to do anything, the only generic message pass done - * anymore is to stop all cpus during a panic(). When the user drops to - * the PROM prompt, the firmware will send the other cpu's it's MONDO - * vector anyways, so doing anything special here is pointless. - * - * This whole thing should go away anyways... - */ -void smp_message_pass(int target, int msg, unsigned long data, int wait) -{ -} - /* #define XCALL_DEBUG */ static inline void xcall_deliver(u64 data0, u64 data1, u64 data2, u64 pstate, unsigned long cpu) @@ -342,6 +349,17 @@ extern unsigned long xcall_tlbcachesync; extern unsigned long xcall_flush_cache_all; extern unsigned long xcall_report_regs; +extern unsigned long xcall_receive_signal; + +void smp_receive_signal(int cpu) +{ + if(smp_processors_ready && + (cpu_present_map & (1UL<cpu_vm_mask is a bit mask of which cpus an address + * space has (potentially) executed on, this is the heuristic + * we use to avoid doing cross calls. + * + * 2) TLB context numbers are shared globally across all processors + * in the system, this allows us to play several games to avoid + * cross calls. + * + * One invariant is that when a cpu switches to a process, and + * that processes tsk->mm->cpu_vm_mask does not have the current + * cpu's bit set, that tlb context is flushed locally. + * + * If the address space is non-shared (ie. mm->count == 1) we avoid + * cross calls when we want to flush the currently running process's + * tlb state. This is done by clearing all cpu bits except the current + * processor's in current->mm->cpu_vm_mask and performing the flush + * locally only. This will force any subsequent cpus which run this + * task to flush the context from the local tlb if the process migrates + * to another cpu (again). + * + * 3) For shared address spaces (threads) and swapping we bite the + * bullet for most cases and perform the cross call. + * + * The performance gain from "optimizing" away the cross call for threads is + * questionable (in theory the big win for threads is the massive sharing of + * address space state across processors). + * + * For the swapping case the locking is difficult to get right, we'd have to + * enforce strict ordered access to mm->cpu_vm_mask via a spinlock for example. + * Then again one could argue that when you are swapping, the cost of a cross + * call won't even show up on the performance radar. But in any case we do get + * rid of the cross-call when the task has a dead context or the task has only + * ever run on the local cpu. */ -static void smp_cross_call_avoidance(struct mm_struct *mm) -{ - u32 ctx; - - spin_lock(&scheduler_lock); - get_new_mmu_context(mm); - mm->cpu_vm_mask = (1UL << smp_processor_id()); - current->tss.ctx = ctx = mm->context & 0x3ff; - spitfire_set_secondary_context(ctx); - __asm__ __volatile__("flush %g6"); - spitfire_flush_dtlb_secondary_context(); - spitfire_flush_itlb_secondary_context(); - __asm__ __volatile__("flush %g6"); - if(!segment_eq(current->tss.current_ds,USER_DS)) { - /* Rarely happens. */ - current->tss.ctx = 0; - spitfire_set_secondary_context(0); - __asm__ __volatile__("flush %g6"); - } - spin_unlock(&scheduler_lock); -} - void smp_flush_tlb_mm(struct mm_struct *mm) { u32 ctx = mm->context & 0x3ff; if(mm == current->mm && atomic_read(&mm->count) == 1) { - if(mm->cpu_vm_mask == (1UL << smp_processor_id())) - goto local_flush_and_out; - return smp_cross_call_avoidance(mm); + if(mm->cpu_vm_mask != (1UL << smp_processor_id())) + mm->cpu_vm_mask = (1UL << smp_processor_id()); + goto local_flush_and_out; } smp_cross_call(&xcall_flush_tlb_mm, ctx, 0, 0); @@ -410,9 +442,9 @@ start &= PAGE_MASK; end &= PAGE_MASK; if(mm == current->mm && atomic_read(&mm->count) == 1) { - if(mm->cpu_vm_mask == (1UL << smp_processor_id())) - goto local_flush_and_out; - return smp_cross_call_avoidance(mm); + if(mm->cpu_vm_mask != (1UL << smp_processor_id())) + mm->cpu_vm_mask = (1UL << smp_processor_id()); + goto local_flush_and_out; } smp_cross_call(&xcall_flush_tlb_range, ctx, start, end); @@ -426,22 +458,26 @@ page &= PAGE_MASK; if(mm == current->mm && atomic_read(&mm->count) == 1) { - if(mm->cpu_vm_mask == (1UL << smp_processor_id())) - goto local_flush_and_out; - return smp_cross_call_avoidance(mm); - } -#if 0 /* XXX Disabled until further notice... */ - else if(atomic_read(&mm->count) == 1) { + if(mm->cpu_vm_mask != (1UL << smp_processor_id())) + mm->cpu_vm_mask = (1UL << smp_processor_id()); + goto local_flush_and_out; + } else { /* Try to handle two special cases to avoid cross calls * in common scenerios where we are swapping process * pages out. */ - if((mm->context ^ tlb_context_cache) & CTX_VERSION_MASK) + if(((mm->context ^ tlb_context_cache) & CTX_VERSION_MASK) || + (mm->cpu_vm_mask == 0)) { + /* A dead context cannot ever become "alive" until + * a task switch is done to it. + */ return; /* It's dead, nothing to do. */ - if(mm->cpu_vm_mask == (1UL << smp_processor_id())) - goto local_flush_and_out; + } + if(mm->cpu_vm_mask == (1UL << smp_processor_id())) { + __flush_tlb_page(ctx, page, SECONDARY_CONTEXT); + return; /* Only local flush is necessary. */ + } } -#endif smp_cross_call(&xcall_flush_tlb_page, ctx, page, 0); local_flush_and_out: @@ -642,6 +678,100 @@ __cpu_logical_map[0] = boot_cpu_id; current->processor = boot_cpu_id; prof_counter(boot_cpu_id) = prof_multiplier(boot_cpu_id) = 1; +} + +static inline unsigned long find_flush_base(unsigned long size) +{ + struct page *p = mem_map; + unsigned long found, base; + + size = PAGE_ALIGN(size); + found = size; + base = page_address(p); + while(found != 0) { + /* Failure. */ + if(p >= (mem_map + max_mapnr)) + return 0UL; + if(PageSkip(p)) { + p = p->next_hash; + base = page_address(p); + found = size; + } else { + found -= PAGE_SIZE; + p++; + } + } + return base; +} + +cycles_t cacheflush_time; + +__initfunc(static void smp_tune_scheduling (void)) +{ + unsigned long flush_base, flags, *p; + unsigned int ecache_size; + cycles_t tick1, tick2, raw; + + /* Approximate heuristic for SMP scheduling. It is an + * estimation of the time it takes to flush the L2 cache + * on the local processor. + * + * The ia32 chooses to use the L1 cache flush time instead, + * and I consider this complete nonsense. The Ultra can service + * a miss to the L1 with a hit to the L2 in 7 or 8 cycles, and + * L2 misses are what create extra bus traffic (ie. the "cost" + * of moving a process from one cpu to another). + */ + printk("SMP: Calibrating ecache flush... "); + ecache_size = prom_getintdefault(linux_cpus[0].prom_node, + "ecache-size", (512 *1024)); + flush_base = find_flush_base(ecache_size << 1); + + if(flush_base != 0UL) { + __save_and_cli(flags); + + /* Scan twice the size once just to get the TLB entries + * loaded and make sure the second scan measures pure misses. + */ + for(p = (unsigned long *)flush_base; + ((unsigned long)p) < (flush_base + (ecache_size<<1)); + p += (64 / sizeof(unsigned long))) + *((volatile unsigned long *)p); + + /* Now the real measurement. */ + __asm__ __volatile__(" + b,pt %%xcc, 1f + rd %%tick, %0 + + .align 64 +1: ldx [%2 + 0x000], %%g1 + ldx [%2 + 0x040], %%g2 + ldx [%2 + 0x080], %%g3 + ldx [%2 + 0x0c0], %%g5 + add %2, 0x100, %2 + cmp %2, %4 + bne,pt %%xcc, 1b + nop + + rd %%tick, %1" + : "=&r" (tick1), "=&r" (tick2), "=&r" (flush_base) + : "2" (flush_base), "r" (flush_base + ecache_size) + : "g1", "g2", "g3", "g5"); + + __restore_flags(flags); + + raw = (tick2 - tick1); + + /* Dampen it a little, considering two processes + * sharing the cache and fitting. + */ + cacheflush_time = (raw - (raw >> 2)); + } else + cacheflush_time = ((ecache_size << 2) + + (ecache_size << 1)); + + printk("Using heuristic of %d cycles.\n", + (int) cacheflush_time); } int __init setup_profiling_timer(unsigned int multiplier) diff -ur --new-file old/linux/arch/sparc64/kernel/sparc64_ksyms.c new/linux/arch/sparc64/kernel/sparc64_ksyms.c --- old/linux/arch/sparc64/kernel/sparc64_ksyms.c Mon Nov 16 19:37:28 1998 +++ new/linux/arch/sparc64/kernel/sparc64_ksyms.c Tue May 11 17:24:32 1999 @@ -1,8 +1,9 @@ -/* $Id: sparc64_ksyms.c,v 1.49 1998/10/28 08:11:28 jj Exp $ +/* $Id: sparc64_ksyms.c,v 1.58 1999/05/08 03:00:31 davem Exp $ * arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be) + * Copyright (C) 1999 Jakub Jelinek (jj@ultra.linux.cz) */ /* Tell string.h we don't want memcpy etc. as cpp defines */ @@ -52,8 +53,9 @@ short revents; }; -extern unsigned prom_cpu_nodes[NR_CPUS]; +extern unsigned prom_cpu_nodes[64]; extern void die_if_kernel(char *str, struct pt_regs *regs); +extern pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); extern unsigned long sunos_mmap(unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long); void _sigpause_common (unsigned int set, struct pt_regs *); @@ -88,7 +90,6 @@ extern void dump_thread(struct pt_regs *, struct user *); #ifdef __SMP__ -extern spinlock_t scheduler_lock; extern spinlock_t kernel_flag; extern int smp_num_cpus; #ifdef SPIN_LOCK_DEBUG @@ -102,6 +103,8 @@ #endif #endif +extern unsigned long phys_base; + /* One thing to note is that the way the symbols of the mul/div * support routines are named is a mess, they all start with * a '.' which makes it a bitch to export, here is the trick: @@ -116,7 +119,6 @@ /* used by various drivers */ #ifdef __SMP__ /* Kernel wide locking */ -EXPORT_SYMBOL(scheduler_lock); EXPORT_SYMBOL(kernel_flag); /* Software-IRQ BH locking */ @@ -155,6 +157,8 @@ EXPORT_SYMBOL(local_irq_count); EXPORT_SYMBOL(local_bh_count); #endif + +EXPORT_SYMBOL(ivector_table); EXPORT_SYMBOL(enable_irq); EXPORT_SYMBOL(disable_irq); @@ -171,6 +175,7 @@ EXPORT_SYMBOL(mmu_release_scsi_one); EXPORT_SYMBOL(mmu_release_scsi_sgl); #if CONFIG_SBUS +EXPORT_SYMBOL(mmu_set_sbus64); EXPORT_SYMBOL(SBus_chain); EXPORT_SYMBOL(dma_chain); #endif @@ -199,6 +204,9 @@ /* math-emu wants this */ EXPORT_SYMBOL(die_if_kernel); +/* Kernel thread creation. */ +EXPORT_SYMBOL(kernel_thread); + /* prom symbols */ EXPORT_SYMBOL(idprom); EXPORT_SYMBOL(prom_root_node); @@ -214,6 +222,7 @@ EXPORT_SYMBOL(saved_command_line); EXPORT_SYMBOL(prom_getname); EXPORT_SYMBOL(prom_feval); +EXPORT_SYMBOL(prom_getbool); EXPORT_SYMBOL(prom_getstring); EXPORT_SYMBOL(prom_apply_sbus_ranges); EXPORT_SYMBOL(prom_getint); @@ -257,7 +266,6 @@ EXPORT_SYMBOL(prom_cpu_nodes); EXPORT_SYMBOL(sys_ioctl); EXPORT_SYMBOL(sys32_ioctl); -EXPORT_SYMBOL(get_unmapped_area); EXPORT_SYMBOL(move_addr_to_kernel); EXPORT_SYMBOL(move_addr_to_user); #endif @@ -280,6 +288,10 @@ EXPORT_SYMBOL(__copy_from_user); EXPORT_SYMBOL(__strncpy_from_user); EXPORT_SYMBOL(__bzero_noasi); + +/* Various address conversion macros use this. */ +EXPORT_SYMBOL(phys_base); +EXPORT_SYMBOL(sparc64_valid_addr_bitmap); /* No version information on this, heavily used in inline asm, * and will always be 'void __ret_efault(void)'. diff -ur --new-file old/linux/arch/sparc64/kernel/starfire.c new/linux/arch/sparc64/kernel/starfire.c --- old/linux/arch/sparc64/kernel/starfire.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/sparc64/kernel/starfire.c Thu Mar 11 01:53:37 1999 @@ -0,0 +1,121 @@ +/* $Id: starfire.c,v 1.2 1998/12/09 18:53:11 davem Exp $ + * starfire.c: Starfire/E10000 support. + * + * Copyright (C) 1998 David S. Miller (davem@dm.cobaltmicro.com) + */ + +#include +#include + +#include +#include +#include + +/* A few places around the kernel check this to see if + * they need to call us to do things in a Starfire specific + * way. + */ +int this_is_starfire = 0; + +void starfire_check(void) +{ + int ssnode = prom_finddevice("/ssp-serial"); + + if(ssnode != 0 && ssnode != -1) { + int i; + + this_is_starfire = 1; + + /* Now must fixup cpu MIDs. OBP gave us a logical + * linear cpuid number, not the real upaid. + */ + for(i = 0; i < linux_num_cpus; i++) { + unsigned int mid = linux_cpus[i].mid; + + mid = (((mid & 0x3c) << 1) | + ((mid & 0x40) >> 4) | + (mid & 0x3)); + + linux_cpus[i].mid = mid; + } + } +} + +int starfire_hard_smp_processor_id(void) +{ + return *((unsigned int *) __va(0x1fff40000d0)); +} + +/* Each Starfire board has 32 registers which perform translation + * and delivery of traditional interrupt packets into the extended + * Starfire hardware format. Essentially UPAID's now have 2 more + * bits than in all previous Sun5 systems. + */ +struct starfire_irqinfo { + unsigned int *imap_slots[32]; + unsigned int *tregs[32]; + struct starfire_irqinfo *next; + int upaid, hwmid; +}; + +static struct starfire_irqinfo *sflist = NULL; + +/* Beam me up Scott(McNeil)y... */ +void *starfire_hookup(int upaid) +{ + struct starfire_irqinfo *p; + unsigned long treg_base, hwmid, i; + + p = kmalloc(sizeof(*p), GFP_KERNEL); + if(!p) { + prom_printf("starfire_hookup: No memory, this is insane.\n"); + prom_halt(); + } + treg_base = 0x100fc000000UL; + hwmid = ((upaid & 0x3c) << 1) | + ((upaid & 0x40) >> 4) | + (upaid & 0x3); + p->hwmid = hwmid; + treg_base += (hwmid << 33UL); + treg_base += 0x200UL; + for(i = 0; i < 32; i++) { + p->imap_slots[i] = NULL; + p->tregs[i] = __va(treg_base + (i * 0x10)); + } + p->upaid = upaid; + p->next = sflist; + sflist = p; + + return (void *) p; +} + +unsigned int starfire_translate(unsigned int *imap, + unsigned int upaid) +{ + struct starfire_irqinfo *p; + unsigned int bus_hwmid; + unsigned int i; + + bus_hwmid = (((unsigned long)imap) >> 33) & 0x7f; + for(p = sflist; p != NULL; p = p->next) + if(p->hwmid == bus_hwmid) + break; + if(p == NULL) { + prom_printf("XFIRE: Cannot find irqinfo for imap %016lx\n", + ((unsigned long)imap)); + prom_halt(); + } + for(i = 0; i < 32; i++) { + if(p->imap_slots[i] == imap || + p->imap_slots[i] == NULL) + break; + } + if(i == 32) { + printk("starfire_translate: Are you kidding me?\n"); + panic("Lucy in the sky...."); + } + p->imap_slots[i] = imap; + *(p->tregs[i]) = upaid; + + return i; +} diff -ur --new-file old/linux/arch/sparc64/kernel/sys_sparc.c new/linux/arch/sparc64/kernel/sys_sparc.c --- old/linux/arch/sparc64/kernel/sys_sparc.c Tue Oct 27 18:52:20 1998 +++ new/linux/arch/sparc64/kernel/sys_sparc.c Thu Mar 11 01:53:37 1999 @@ -1,4 +1,4 @@ -/* $Id: sys_sparc.c,v 1.25 1998/10/21 03:21:15 davem Exp $ +/* $Id: sys_sparc.c,v 1.26 1999/01/07 19:07:01 jj Exp $ * linux/arch/sparc64/kernel/sys_sparc.c * * This file contains various random system calls that @@ -27,6 +27,8 @@ #include #include +/* #define DEBUG_UNIMP_SYSCALL */ + /* XXX Make this per-binary type, this way we can detect the type of * XXX a binary. Every Sparc executable calls this very early on. */ @@ -200,11 +202,14 @@ c_sys_nis_syscall (struct pt_regs *regs) { static int count=0; + + /* Don't make the system unusable, if someone goes stuck */ + if (count++ > 5) return -ENOSYS; lock_kernel(); - if (++count <= 20) { /* Don't make the system unusable, if someone goes stuck */ - printk ("Unimplemented SPARC system call %ld\n",regs->u_regs[1]); - show_regs (regs); - } + printk ("Unimplemented SPARC system call %ld\n",regs->u_regs[1]); +#ifdef DEBUG_UNIMP_SYSCALL + show_regs (regs); +#endif unlock_kernel(); return -ENOSYS; } diff -ur --new-file old/linux/arch/sparc64/kernel/sys_sparc32.c new/linux/arch/sparc64/kernel/sys_sparc32.c --- old/linux/arch/sparc64/kernel/sys_sparc32.c Mon Nov 16 19:37:28 1998 +++ new/linux/arch/sparc64/kernel/sys_sparc32.c Thu Mar 11 01:53:37 1999 @@ -1,4 +1,4 @@ -/* $Id: sys_sparc32.c,v 1.100 1998/11/08 11:14:00 davem Exp $ +/* $Id: sys_sparc32.c,v 1.107 1999/03/05 13:21:02 davem Exp $ * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls. * * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -43,6 +43,7 @@ #include #include #include +#include #include #include @@ -50,6 +51,8 @@ #include #include +#include + /* Use this to get at 32-bit user passed pointers. */ /* Things to consider: the low-level assembly stub does srl x, 0, x for first four arguments, so if you have @@ -74,15 +77,6 @@ __ret; \ }) -static inline char * get_page(void) -{ - char * res; - res = (char *)__get_free_page(GFP_KERNEL); - return res; -} - -#define putname32 putname - /* In order to reduce some races, while at the same time doing additional * checking and hopefully speeding things up, we copy filenames to the * kernel data space before using them.. @@ -109,13 +103,13 @@ char *tmp, *result; result = ERR_PTR(-ENOMEM); - tmp = get_page(); + tmp = (char *)__get_free_page(GFP_KERNEL); if (tmp) { int retval = do_getname32(filename, tmp); result = tmp; if (retval < 0) { - putname32(tmp); + putname(tmp); result = ERR_PTR(retval); } } @@ -243,7 +237,10 @@ err = -EFAULT; if (get_user (pad, (u32 *)uptr)) goto out; - fourth.__pad = (void *)A(pad); + if(third == SETVAL) + fourth.val = (int)pad; + else + fourth.__pad = (void *)A(pad); if (IPCOP_MASK (third) & (IPCOP_MASK (IPC_INFO) | IPCOP_MASK (SEM_INFO) | IPCOP_MASK (GETVAL) | IPCOP_MASK (GETPID) | IPCOP_MASK (GETNCNT) | IPCOP_MASK (GETZCNT) | @@ -652,7 +649,7 @@ set_fs (KERNEL_DS); err = sys_quotactl(cmd, (const char *)spec, id, (caddr_t)&d); set_fs (old_fs); - putname32 (spec); + putname (spec); if (cmds == Q_GETQUOTA) { __kernel_time_t b = d.dqb_btime, i = d.dqb_itime; ((struct dqblk32 *)&d)->dqb_itime = i; @@ -696,7 +693,7 @@ set_fs (KERNEL_DS); ret = sys_statfs((const char *)pth, &s); set_fs (old_fs); - putname32 (pth); + putname (pth); if (put_statfs(buf, &s)) return -EFAULT; } @@ -744,7 +741,7 @@ set_fs (KERNEL_DS); ret = sys_utime(filenam, &t); set_fs (old_fs); - putname32 (filenam); + putname (filenam); } return ret; } @@ -796,8 +793,9 @@ } inode = file->f_dentry->d_inode; - retval = locks_verify_area((type == VERIFY_READ) ? - FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE, + /* VERIFY_WRITE actually means a read, as we write to user space */ + retval = locks_verify_area((type == VERIFY_WRITE + ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE), inode, file, file->f_pos, tot_len); if (retval) { if (iov != iovstack) @@ -1106,13 +1104,17 @@ __put_user(*fdset, ufdset); } +#define MAX_SELECT_SECONDS \ + ((unsigned long) (MAX_SCHEDULE_TIMEOUT / HZ)-1) + asmlinkage int sys32_select(int n, u32 *inp, u32 *outp, u32 *exp, u32 tvp_x) { - fd_set_buffer *fds; + fd_set_bits fds; struct timeval32 *tvp = (struct timeval32 *)AA(tvp_x); + char *bits; unsigned long nn; long timeout; - int ret; + int ret, size; timeout = MAX_SCHEDULE_TIMEOUT; if (tvp) { @@ -1123,30 +1125,47 @@ || (ret = __get_user(usec, &tvp->tv_usec))) goto out_nofds; - timeout = (usec + 1000000/HZ - 1) / (1000000/HZ); - timeout += sec * HZ; + ret = -EINVAL; + if(sec < 0 || usec < 0) + goto out_nofds; + + if ((unsigned long) sec < MAX_SELECT_SECONDS) { + timeout = (usec + 1000000/HZ - 1) / (1000000/HZ); + timeout += sec * (unsigned long) HZ; + } } + ret = -EINVAL; + if (n < 0 || n > KFDS_NR) + goto out_nofds; + + /* + * We need 6 bitmaps (in/out/ex for both incoming and outgoing), + * since we used fdset we need to allocate memory in units of + * long-words. + */ ret = -ENOMEM; - fds = (fd_set_buffer *) __get_free_page(GFP_KERNEL); - if (!fds) + size = FDS_BYTES(n); + bits = kmalloc(6 * size, GFP_KERNEL); + if (!bits) goto out_nofds; - ret = -EINVAL; - if (n < 0) - goto out; - if (n > KFDS_NR) - n = KFDS_NR; + fds.in = (unsigned long *) bits; + fds.out = (unsigned long *) (bits + size); + fds.ex = (unsigned long *) (bits + 2*size); + fds.res_in = (unsigned long *) (bits + 3*size); + fds.res_out = (unsigned long *) (bits + 4*size); + fds.res_ex = (unsigned long *) (bits + 5*size); nn = (n + 8*sizeof(u32) - 1) / (8*sizeof(u32)); - if ((ret = get_fd_set32(nn, fds->in, inp)) || - (ret = get_fd_set32(nn, fds->out, outp)) || - (ret = get_fd_set32(nn, fds->ex, exp))) + if ((ret = get_fd_set32(nn, fds.in, inp)) || + (ret = get_fd_set32(nn, fds.out, outp)) || + (ret = get_fd_set32(nn, fds.ex, exp))) goto out; - zero_fd_set(n, fds->res_in); - zero_fd_set(n, fds->res_out); - zero_fd_set(n, fds->res_ex); + zero_fd_set(n, fds.res_in); + zero_fd_set(n, fds.res_out); + zero_fd_set(n, fds.res_ex); - ret = do_select(n, fds, &timeout); + ret = do_select(n, &fds, &timeout); if (tvp && !(current->personality & STICKY_TIMEOUTS)) { time_t sec = 0, usec = 0; @@ -1168,12 +1187,12 @@ ret = 0; } - set_fd_set32(nn, inp, fds->res_in); - set_fd_set32(nn, outp, fds->res_out); - set_fd_set32(nn, exp, fds->res_ex); + set_fd_set32(nn, inp, fds.res_in); + set_fd_set32(nn, outp, fds.res_out); + set_fd_set32(nn, exp, fds.res_ex); out: - free_page ((unsigned long)fds); + kfree(bits); out_nofds: return ret; } @@ -1213,7 +1232,7 @@ set_fs (KERNEL_DS); ret = sys_newstat(filenam, &s); set_fs (old_fs); - putname32 (filenam); + putname (filenam); if (putstat (statbuf, &s)) return -EFAULT; } @@ -1235,7 +1254,7 @@ set_fs (KERNEL_DS); ret = sys_newlstat(filenam, &s); set_fs (old_fs); - putname32 (filenam); + putname (filenam); if (putstat (statbuf, &s)) return -EFAULT; } @@ -2010,74 +2029,6 @@ return ret; } -struct timex32 { - unsigned int modes; - s32 offset; - s32 freq; - s32 maxerror; - s32 esterror; - int status; - s32 constant; - s32 precision; - s32 tolerance; - struct timeval32 time; - s32 tick; - s32 ppsfreq; - s32 jitter; - int shift; - s32 stabil; - s32 jitcnt; - s32 calcnt; - s32 errcnt; - s32 stbcnt; - int :32; int :32; int :32; int :32; - int :32; int :32; int :32; int :32; - int :32; int :32; int :32; int :32; -}; - -extern int do_adjtimex(struct timex *); - -asmlinkage int sys32_adjtimex(struct timex32 *txc_p) -{ - struct timex t; - int ret; - - ret = get_user (t.modes, &txc_p->modes); - ret |= __get_user (t.offset, &txc_p->offset); - ret |= __get_user (t.freq, &txc_p->freq); - ret |= __get_user (t.maxerror, &txc_p->maxerror); - ret |= __get_user (t.esterror, &txc_p->esterror); - ret |= __get_user (t.status, &txc_p->status); - ret |= __get_user (t.constant, &txc_p->constant); - ret |= __get_user (t.tick, &txc_p->tick); - ret |= __get_user (t.shift, &txc_p->shift); - if (ret || (ret = do_adjtimex(&t))) - return ret; - ret = __put_user (t.modes, &txc_p->modes); - ret |= __put_user (t.offset, &txc_p->offset); - ret |= __put_user (t.freq, &txc_p->freq); - ret |= __put_user (t.maxerror, &txc_p->maxerror); - ret |= __put_user (t.esterror, &txc_p->esterror); - ret |= __put_user (t.status, &txc_p->status); - ret |= __put_user (t.constant, &txc_p->constant); - ret |= __put_user (t.precision, &txc_p->precision); - ret |= __put_user (t.tolerance, &txc_p->tolerance); - ret |= __put_user (t.time.tv_sec, &txc_p->time.tv_sec); - ret |= __put_user (t.time.tv_usec, &txc_p->time.tv_usec); - ret |= __put_user (t.tick, &txc_p->tick); - ret |= __put_user (t.ppsfreq, &txc_p->ppsfreq); - ret |= __put_user (t.jitter, &txc_p->jitter); - ret |= __put_user (t.shift, &txc_p->shift); - ret |= __put_user (t.stabil, &txc_p->stabil); - ret |= __put_user (t.jitcnt, &txc_p->jitcnt); - ret |= __put_user (t.calcnt, &txc_p->calcnt); - ret |= __put_user (t.errcnt, &txc_p->errcnt); - ret |= __put_user (t.stbcnt, &txc_p->stbcnt); - if (!ret) - ret = time_state; - return ret; -} - /* XXX This really belongs in some header file... -DaveM */ #define MAX_SOCK_ADDR 128 /* 108 for Unix domain - 16 for IP, 16 for IPX, @@ -2131,9 +2082,44 @@ __kernel_size_t32 cmsg_len; int cmsg_level; int cmsg_type; - unsigned char cmsg_data[0]; }; +/* Bleech... */ +#define __CMSG32_NXTHDR(ctl, len, cmsg, cmsglen) __cmsg32_nxthdr((ctl),(len),(cmsg),(cmsglen)) +#define CMSG32_NXTHDR(mhdr, cmsg, cmsglen) cmsg32_nxthdr((mhdr), (cmsg), (cmsglen)) + +#define CMSG32_ALIGN(len) ( ((len)+sizeof(int)-1) & ~(sizeof(int)-1) ) + +#define CMSG32_DATA(cmsg) ((void *)((char *)(cmsg) + CMSG32_ALIGN(sizeof(struct cmsghdr32)))) +#define CMSG32_SPACE(len) (CMSG32_ALIGN(sizeof(struct cmsghdr32)) + CMSG32_ALIGN(len)) +#define CMSG32_LEN(len) (CMSG32_ALIGN(sizeof(struct cmsghdr32)) + (len)) + +#define __CMSG32_FIRSTHDR(ctl,len) ((len) >= sizeof(struct cmsghdr32) ? \ + (struct cmsghdr32 *)(ctl) : \ + (struct cmsghdr32 *)NULL) +#define CMSG32_FIRSTHDR(msg) __CMSG32_FIRSTHDR((msg)->msg_control, (msg)->msg_controllen) + +__inline__ struct cmsghdr32 *__cmsg32_nxthdr(void *__ctl, __kernel_size_t __size, + struct cmsghdr32 *__cmsg, int __cmsg_len) +{ + struct cmsghdr32 * __ptr; + + __ptr = (struct cmsghdr32 *)(((unsigned char *) __cmsg) + + CMSG32_ALIGN(__cmsg_len)); + if ((unsigned long)((char*)(__ptr+1) - (char *) __ctl) > __size) + return NULL; + + return __ptr; +} + +__inline__ struct cmsghdr32 *cmsg32_nxthdr (struct msghdr *__msg, + struct cmsghdr32 *__cmsg, + int __cmsg_len) +{ + return __cmsg32_nxthdr(__msg->msg_control, __msg->msg_controllen, + __cmsg, __cmsg_len); +} + static inline int iov_from_user32_to_kern(struct iovec *kiov, struct iovec32 *uiov32, int niov) @@ -2175,6 +2161,7 @@ kmsg->msg_control = (void *)A(tmp3); err = get_user(kmsg->msg_namelen, &umsg->msg_namelen); + err |= get_user(kmsg->msg_iovlen, &umsg->msg_iovlen); err |= get_user(kmsg->msg_controllen, &umsg->msg_controllen); err |= get_user(kmsg->msg_flags, &umsg->msg_flags); @@ -2217,6 +2204,165 @@ return tot_len; } +/* There is a lot of hair here because the alignment rules (and + * thus placement) of cmsg headers and length are different for + * 32-bit apps. -DaveM + */ +static int cmsghdr_from_user32_to_kern(struct msghdr *kmsg, + unsigned char *stackbuf, int stackbuf_size) +{ + struct cmsghdr32 *ucmsg; + struct cmsghdr *kcmsg, *kcmsg_base; + __kernel_size_t32 ucmlen; + __kernel_size_t kcmlen, tmp; + + kcmlen = 0; + kcmsg_base = kcmsg = (struct cmsghdr *)stackbuf; + ucmsg = CMSG32_FIRSTHDR(kmsg); + while(ucmsg != NULL) { + if(get_user(ucmlen, &ucmsg->cmsg_len)) + return -EFAULT; + + /* Catch bogons. */ + if(CMSG32_ALIGN(ucmlen) < + CMSG32_ALIGN(sizeof(struct cmsghdr32))) + return -EINVAL; + if((unsigned long)(((char *)ucmsg - (char *)kmsg->msg_control) + + ucmlen) > kmsg->msg_controllen) + return -EINVAL; + + tmp = ((ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))) + + CMSG_ALIGN(sizeof(struct cmsghdr))); + kcmlen += tmp; + ucmsg = CMSG32_NXTHDR(kmsg, ucmsg, ucmlen); + } + if(kcmlen == 0) + return -EINVAL; + + /* The kcmlen holds the 64-bit version of the control length. + * It may not be modified as we do not stick it into the kmsg + * until we have successfully copied over all of the data + * from the user. + */ + if(kcmlen > stackbuf_size) + kcmsg_base = kcmsg = kmalloc(kcmlen, GFP_KERNEL); + if(kcmsg == NULL) + return -ENOBUFS; + + /* Now copy them over neatly. */ + memset(kcmsg, 0, kcmlen); + ucmsg = CMSG32_FIRSTHDR(kmsg); + while(ucmsg != NULL) { + __get_user(ucmlen, &ucmsg->cmsg_len); + tmp = ((ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))) + + CMSG_ALIGN(sizeof(struct cmsghdr))); + kcmsg->cmsg_len = tmp; + __get_user(kcmsg->cmsg_level, &ucmsg->cmsg_level); + __get_user(kcmsg->cmsg_type, &ucmsg->cmsg_type); + + /* Copy over the data. */ + if(copy_from_user(CMSG_DATA(kcmsg), + CMSG32_DATA(ucmsg), + (ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))))) + goto out_free_efault; + + /* Advance. */ + kcmsg = (struct cmsghdr *)((char *)kcmsg + CMSG_ALIGN(tmp)); + ucmsg = CMSG32_NXTHDR(kmsg, ucmsg, ucmlen); + } + + /* Ok, looks like we made it. Hook it up and return success. */ + kmsg->msg_control = kcmsg_base; + kmsg->msg_controllen = kcmlen; + return 0; + +out_free_efault: + if(kcmsg_base != (struct cmsghdr *)stackbuf) + kfree(kcmsg_base); + return -EFAULT; +} + +static void put_cmsg32(struct msghdr *kmsg, int level, int type, + int len, void *data) +{ + struct cmsghdr32 *cm = (struct cmsghdr32 *) kmsg->msg_control; + struct cmsghdr32 cmhdr; + int cmlen = CMSG32_LEN(len); + + if(cm == NULL || kmsg->msg_controllen < sizeof(*cm)) { + kmsg->msg_flags |= MSG_CTRUNC; + return; + } + + if(kmsg->msg_controllen < cmlen) { + kmsg->msg_flags |= MSG_CTRUNC; + cmlen = kmsg->msg_controllen; + } + cmhdr.cmsg_level = level; + cmhdr.cmsg_type = type; + cmhdr.cmsg_len = cmlen; + + if(copy_to_user(cm, &cmhdr, sizeof cmhdr)) + return; + if(copy_to_user(CMSG32_DATA(cm), data, cmlen - sizeof(struct cmsghdr32))) + return; + cmlen = CMSG32_SPACE(len); + kmsg->msg_control += cmlen; + kmsg->msg_controllen -= cmlen; +} + +static void scm_detach_fds32(struct msghdr *kmsg, struct scm_cookie *scm) +{ + struct cmsghdr32 *cm = (struct cmsghdr32 *) kmsg->msg_control; + int fdmax = (kmsg->msg_controllen - sizeof(struct cmsghdr32)) / sizeof(int); + int fdnum = scm->fp->count; + struct file **fp = scm->fp->fp; + int *cmfptr; + int err = 0, i; + + if (fdnum < fdmax) + fdmax = fdnum; + + for (i = 0, cmfptr = (int *) CMSG32_DATA(cm); i < fdmax; i++, cmfptr++) { + int new_fd; + err = get_unused_fd(); + if (err < 0) + break; + new_fd = err; + err = put_user(new_fd, cmfptr); + if (err) { + put_unused_fd(new_fd); + break; + } + /* Bump the usage count and install the file. */ + fp[i]->f_count++; + current->files->fd[new_fd] = fp[i]; + } + + if (i > 0) { + int cmlen = CMSG32_LEN(i * sizeof(int)); + if (!err) + err = put_user(SOL_SOCKET, &cm->cmsg_level); + if (!err) + err = put_user(SCM_RIGHTS, &cm->cmsg_type); + if (!err) + err = put_user(cmlen, &cm->cmsg_len); + if (!err) { + cmlen = CMSG32_SPACE(i * sizeof(int)); + kmsg->msg_control += cmlen; + kmsg->msg_controllen -= cmlen; + } + } + if (i < fdnum) + kmsg->msg_flags |= MSG_CTRUNC; + + /* + * All of the files that fit in the message have had their + * usage counts incremented, so we just free the list. + */ + __scm_destroy(scm); +} + asmlinkage int sys32_sendmsg(int fd, struct msghdr32 *user_msg, unsigned user_flags) { struct socket *sock; @@ -2237,25 +2383,10 @@ total_len = err; if(kern_msg.msg_controllen) { - struct cmsghdr32 *ucmsg = (struct cmsghdr32 *)kern_msg.msg_control; - unsigned long *kcmsg; - __kernel_size_t32 cmlen; - - if(kern_msg.msg_controllen > sizeof(ctl) && - kern_msg.msg_controllen <= 256) { - err = -ENOBUFS; - ctl_buf = kmalloc(kern_msg.msg_controllen, GFP_KERNEL); - if(!ctl_buf) - goto out_freeiov; - } - __get_user(cmlen, &ucmsg->cmsg_len); - kcmsg = (unsigned long *) ctl_buf; - *kcmsg++ = (unsigned long)cmlen; - err = -EFAULT; - if(copy_from_user(kcmsg, &ucmsg->cmsg_level, - kern_msg.msg_controllen - sizeof(__kernel_size_t32))) - goto out_freectl; - kern_msg.msg_control = ctl_buf; + err = cmsghdr_from_user32_to_kern(&kern_msg, ctl, sizeof(ctl)); + if(err) + goto out_freeiov; + ctl_buf = kern_msg.msg_control; } kern_msg.msg_flags = user_flags; @@ -2269,7 +2400,6 @@ } unlock_kernel(); -out_freectl: /* N.B. Use kfree here, as kern_msg.msg_controllen might change? */ if(ctl_buf != ctl) kfree(ctl_buf); @@ -2310,26 +2440,43 @@ lock_kernel(); sock = sockfd_lookup(fd, &err); if (sock != NULL) { + struct scm_cookie scm; + if (sock->file->f_flags & O_NONBLOCK) user_flags |= MSG_DONTWAIT; - err = sock_recvmsg(sock, &kern_msg, total_len, user_flags); - if(err >= 0) + memset(&scm, 0, sizeof(scm)); + err = sock->ops->recvmsg(sock, &kern_msg, total_len, + user_flags, &scm); + if(err >= 0) { len = err; + if(!kern_msg.msg_control) { + if(sock->passcred || scm.fp) + kern_msg.msg_flags |= MSG_CTRUNC; + if(scm.fp) + __scm_destroy(&scm); + } else { + /* Wheee... */ + if(sock->passcred) + put_cmsg32(&kern_msg, + SOL_SOCKET, SCM_CREDENTIALS, + sizeof(scm.creds), &scm.creds); + if(scm.fp != NULL) + scm_detach_fds32(&kern_msg, &scm); + } + } sockfd_put(sock); } unlock_kernel(); if(uaddr != NULL && err >= 0) err = move_addr_to_user(addr, kern_msg.msg_namelen, uaddr, uaddr_len); - if(err >= 0) { - err = __put_user(kern_msg.msg_flags, &user_msg->msg_flags); - if(!err) { - /* XXX Convert cmsg back into userspace 32-bit format... */ - err = __put_user((unsigned long)kern_msg.msg_control - cmsg_ptr, - &user_msg->msg_controllen); - } + if(cmsg_ptr != 0 && err >= 0) { + u32 ucmsg_ptr = ((u32)(unsigned long)kern_msg.msg_control); + err = __put_user(ucmsg_ptr, &user_msg->msg_control); + err |= __put_user(kern_msg.msg_controllen, &user_msg->msg_controllen); } - + if(err >= 0) + err = __put_user(kern_msg.msg_flags, &user_msg->msg_flags); if(kern_msg.msg_iov != iov) kfree(kern_msg.msg_iov); out: @@ -2653,7 +2800,7 @@ error = do_execve32(filename, (u32 *)AA((u32)regs->u_regs[base + UREG_I1]), (u32 *)AA((u32)regs->u_regs[base + UREG_I2]), regs); - putname32(filename); + putname(filename); if(!error) { fprs_write(0); @@ -2943,8 +3090,10 @@ info.addr = (unsigned long)mod; info.size = mod->size; info.flags = mod->flags; - info.usecount = (mod_member_present(mod, can_unload) - && mod->can_unload ? -1 : mod->usecount); + info.usecount = + ((mod_member_present(mod, can_unload) + && mod->can_unload) + ? -1 : atomic_read(&mod->uc.usecount)); if (copy_to_user(buf, &info, sizeof(struct module_info32))) return -EFAULT; @@ -3452,7 +3601,7 @@ ret = sys_utimes(kfilename, &ktvs[0]); set_fs(old_fs); - putname32(kfilename); + putname(kfilename); } return ret; } @@ -3575,5 +3724,78 @@ if (!ret && offset && put_user(of, offset)) return -EFAULT; + return ret; +} + +/* Handle adjtimex compatability. */ + +struct timex32 { + u32 modes; + s32 offset, freq, maxerror, esterror; + s32 status, constant, precision, tolerance; + struct timeval32 time; + s32 tick; + s32 ppsfreq, jitter, shift, stabil; + s32 jitcnt, calcnt, errcnt, stbcnt; + s32 :32; s32 :32; s32 :32; s32 :32; + s32 :32; s32 :32; s32 :32; s32 :32; + s32 :32; s32 :32; s32 :32; s32 :32; +}; + +extern int do_adjtimex(struct timex *); + +asmlinkage int sys32_adjtimex(struct timex32 *utp) +{ + struct timex txc; + int ret; + + memset(&txc, 0, sizeof(struct timex)); + + if(get_user(txc.modes, &utp->modes) || + __get_user(txc.offset, &utp->offset) || + __get_user(txc.freq, &utp->freq) || + __get_user(txc.maxerror, &utp->maxerror) || + __get_user(txc.esterror, &utp->esterror) || + __get_user(txc.status, &utp->status) || + __get_user(txc.constant, &utp->constant) || + __get_user(txc.precision, &utp->precision) || + __get_user(txc.tolerance, &utp->tolerance) || + __get_user(txc.time.tv_sec, &utp->time.tv_sec) || + __get_user(txc.time.tv_usec, &utp->time.tv_usec) || + __get_user(txc.tick, &utp->tick) || + __get_user(txc.ppsfreq, &utp->ppsfreq) || + __get_user(txc.jitter, &utp->jitter) || + __get_user(txc.shift, &utp->shift) || + __get_user(txc.stabil, &utp->stabil) || + __get_user(txc.jitcnt, &utp->jitcnt) || + __get_user(txc.calcnt, &utp->calcnt) || + __get_user(txc.errcnt, &utp->errcnt) || + __get_user(txc.stbcnt, &utp->stbcnt)) + return -EFAULT; + + ret = do_adjtimex(&txc); + + if(put_user(txc.modes, &utp->modes) || + __put_user(txc.offset, &utp->offset) || + __put_user(txc.freq, &utp->freq) || + __put_user(txc.maxerror, &utp->maxerror) || + __put_user(txc.esterror, &utp->esterror) || + __put_user(txc.status, &utp->status) || + __put_user(txc.constant, &utp->constant) || + __put_user(txc.precision, &utp->precision) || + __put_user(txc.tolerance, &utp->tolerance) || + __put_user(txc.time.tv_sec, &utp->time.tv_sec) || + __put_user(txc.time.tv_usec, &utp->time.tv_usec) || + __put_user(txc.tick, &utp->tick) || + __put_user(txc.ppsfreq, &utp->ppsfreq) || + __put_user(txc.jitter, &utp->jitter) || + __put_user(txc.shift, &utp->shift) || + __put_user(txc.stabil, &utp->stabil) || + __put_user(txc.jitcnt, &utp->jitcnt) || + __put_user(txc.calcnt, &utp->calcnt) || + __put_user(txc.errcnt, &utp->errcnt) || + __put_user(txc.stbcnt, &utp->stbcnt)) + ret = -EFAULT; + return ret; } diff -ur --new-file old/linux/arch/sparc64/kernel/systbls.S new/linux/arch/sparc64/kernel/systbls.S --- old/linux/arch/sparc64/kernel/systbls.S Tue Oct 27 18:52:20 1998 +++ new/linux/arch/sparc64/kernel/systbls.S Fri Apr 23 04:24:51 1999 @@ -1,4 +1,4 @@ -/* $Id: systbls.S,v 1.50 1998/10/07 01:27:27 davem Exp $ +/* $Id: systbls.S,v 1.53 1999/04/07 17:14:11 davem Exp $ * systbls.S: System call entry point tables for OS compatibility. * The native Linux system call table lives here also. * @@ -26,7 +26,7 @@ /*30*/ .word sys32_utime, sys_nis_syscall, sys_nis_syscall, sys_access, sys_nice .word sys_nis_syscall, sys_sync, sys_kill, sys32_newstat, sys32_sendfile /*40*/ .word sys32_newlstat, sys_dup, sys_pipe, sys32_times, sys_nis_syscall - .word sys_nis_syscall, sys_setgid, sys_getgid, sys_signal, sys_geteuid + .word sys_umount, sys_setgid, sys_getgid, sys_signal, sys_geteuid /*50*/ .word sys_getegid, sys_acct, sys_nis_syscall, sys_nis_syscall, sys32_ioctl .word sys_reboot, sys_nis_syscall, sys_symlink, sys_readlink, sys32_execve /*60*/ .word sys_umask, sys_chroot, sys32_newfstat, sys_nis_syscall, sys_getpagesize @@ -48,7 +48,7 @@ /*140*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_getrlimit .word sys32_setrlimit, sys_nis_syscall, sys32_prctl, sys32_pciconfig_read, sys32_pciconfig_write /*150*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_nis_syscall - .word sys_nis_syscall, sys_nis_syscall, sys32_statfs, sys32_fstatfs, sys_umount + .word sys_nis_syscall, sys_nis_syscall, sys32_statfs, sys32_fstatfs, sys_oldumount /*160*/ .word sys_nis_syscall, sys_nis_syscall, sys_getdomainname, sys_setdomainname, sys_nis_syscall .word sys32_quotactl, sys_nis_syscall, sys32_mount, sys_ustat, sys_nis_syscall /*170*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_getdents @@ -85,7 +85,7 @@ /*30*/ .word sys_utime, sys_nis_syscall, sys_nis_syscall, sys_access, sys_nice .word sys_nis_syscall, sys_sync, sys_kill, sys_newstat, sys_sendfile /*40*/ .word sys_newlstat, sys_dup, sys_pipe, sys_times, sys_nis_syscall - .word sys_nis_syscall, sys_setgid, sys_getgid, sys_signal, sys_geteuid + .word sys_umount, sys_setgid, sys_getgid, sys_signal, sys_geteuid /*50*/ .word sys_getegid, sys_acct, sys_memory_ordering, sys_nis_syscall, sys_ioctl .word sys_reboot, sys_nis_syscall, sys_symlink, sys_readlink, sys_execve /*60*/ .word sys_umask, sys_chroot, sys_newfstat, sys_nis_syscall, sys_getpagesize @@ -107,7 +107,7 @@ /*140*/ .word sys_nis_syscall, sys_getpeername, sys_nis_syscall, sys_nis_syscall, sys_getrlimit .word sys_setrlimit, sys_nis_syscall, sys_prctl, sys_pciconfig_read, sys_pciconfig_write /*150*/ .word sys_getsockname, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_nis_syscall - .word sys_nis_syscall, sys_nis_syscall, sys_statfs, sys_fstatfs, sys_umount + .word sys_nis_syscall, sys_nis_syscall, sys_statfs, sys_fstatfs, sys_oldumount /*160*/ .word sys_nis_syscall, sys_nis_syscall, sys_getdomainname, sys_setdomainname, sys_utrap_install .word sys_quotactl, sys_nis_syscall, sys_mount, sys_ustat, sys_nis_syscall /*170*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getdents @@ -188,7 +188,7 @@ /*150*/ .word sys_getsockname, sunos_nosys, sunos_nosys .word sys_poll, sunos_nosys, sunos_nosys .word sunos_getdirentries, sys32_statfs, sys32_fstatfs - .word sys_umount, sunos_nosys, sunos_nosys + .word sys_oldumount, sunos_nosys, sunos_nosys .word sys_getdomainname, sys_setdomainname .word sunos_nosys, sys32_quotactl, sunos_nosys .word sunos_mount, sys_ustat, sunos_semsys diff -ur --new-file old/linux/arch/sparc64/kernel/time.c new/linux/arch/sparc64/kernel/time.c --- old/linux/arch/sparc64/kernel/time.c Tue Jan 19 19:19:54 1999 +++ new/linux/arch/sparc64/kernel/time.c Tue Mar 16 01:10:43 1999 @@ -1,4 +1,4 @@ -/* $Id: time.c,v 1.16 1998/09/05 17:25:28 jj Exp $ +/* $Id: time.c,v 1.20 1999/03/15 22:13:40 davem Exp $ * time.c: UltraSparc timer and TOD clock support. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -31,6 +31,8 @@ #include #include +extern rwlock_t xtime_lock; + struct mostek48t02 *mstk48t02_regs = 0; static struct mostek48t08 *mstk48t08_regs = 0; static struct mostek48t59 *mstk48t59_regs = 0; @@ -69,6 +71,8 @@ { unsigned long ticks; + write_lock(&xtime_lock); + do { do_timer(regs); @@ -82,11 +86,15 @@ } while (ticks >= timer_tick_compare); timer_check_rtc(); + + write_unlock(&xtime_lock); } #ifdef __SMP__ void timer_tick_interrupt(struct pt_regs *regs) { + write_lock(&xtime_lock); + do_timer(regs); /* @@ -99,6 +107,8 @@ : "r" (timer_tick_offset)); timer_check_rtc(); + + write_unlock(&xtime_lock); } #endif @@ -256,13 +266,17 @@ node = prom_getchild(busnd); while(1) { - prom_getstring(node, "model", model, sizeof(model)); + if (!node) + model[0] = 0; + else + prom_getstring(node, "model", model, sizeof(model)); if(strcmp(model, "mk48t02") && strcmp(model, "mk48t08") && strcmp(model, "mk48t59")) { - node = prom_getsibling(node); + if (node) + node = prom_getsibling(node); #ifdef CONFIG_PCI - if ((node == 0) && ebus) { + while ((node == 0) && ebus) { ebus = ebus->next; if (ebus) { busnd = ebus->prom_node; @@ -397,6 +411,9 @@ return ticks / timer_ticks_per_usec; } +/* This need not obtain the xtime_lock as it is coded in + * an implicitly SMP safe way already. + */ void do_gettimeofday(struct timeval *tv) { /* Load doubles must be used on xtime so that what we get @@ -450,7 +467,7 @@ void do_settimeofday(struct timeval *tv) { - cli(); + write_lock_irq(&xtime_lock); tv->tv_usec -= do_gettimeoffset(); if(tv->tv_usec < 0) { @@ -461,10 +478,10 @@ xtime = *tv; time_adjust = 0; /* stop active adjtime() */ time_status |= STA_UNSYNC; - time_state = TIME_ERROR; /* p. 24, (a) */ time_maxerror = NTP_PHASE_LIMIT; time_esterror = NTP_PHASE_LIMIT; - sti(); + + write_unlock_irq(&xtime_lock); } static int set_rtc_mmss(unsigned long nowtime) diff -ur --new-file old/linux/arch/sparc64/kernel/trampoline.S new/linux/arch/sparc64/kernel/trampoline.S --- old/linux/arch/sparc64/kernel/trampoline.S Tue Oct 27 18:52:20 1998 +++ new/linux/arch/sparc64/kernel/trampoline.S Thu Mar 11 01:53:37 1999 @@ -1,4 +1,4 @@ -/* $Id: trampoline.S,v 1.6 1998/10/11 06:58:23 davem Exp $ +/* $Id: trampoline.S,v 1.8 1998/12/09 21:01:15 davem Exp $ * trampoline.S: Jump start slave processors on sparc64. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -34,8 +34,8 @@ sllx %g4, 32, %g4 /* XXX Buggy PROM... */ - srl %o0, 0, %g6 - add %g6, %g4, %g6 + srl %o0, 0, %o0 + ldx [%o0], %g6 sethi %uhi(_PAGE_VALID | _PAGE_SZ4MB), %g5 sllx %g5, 32, %g5 @@ -197,10 +197,18 @@ #undef KERN_LOWBITS #undef VPTE_BASE + /* Setup interrupt globals, we are always SMP. */ wrpr %o1, (PSTATE_IG | PSTATE_IE), %pstate - sethi %hi(ivector_to_mask), %g5 - or %g5, %lo(ivector_to_mask), %g1 - mov 0x40, %g2 + + /* Get our UPA MID. */ + lduw [%o2 + AOFF_task_processor], %g1 + sethi %hi(cpu_data), %g5 + or %g5, %lo(cpu_data), %g5 + + /* In theory this is: &(cpu_data[this_upamid].irq_worklists[0]) */ + sllx %g1, 7, %g1 + add %g5, %g1, %g1 + add %g1, 64, %g1 wrpr %g0, 0, %wstate or %o1, PSTATE_IE, %o1 diff -ur --new-file old/linux/arch/sparc64/kernel/traps.c new/linux/arch/sparc64/kernel/traps.c --- old/linux/arch/sparc64/kernel/traps.c Tue Oct 27 18:52:20 1998 +++ new/linux/arch/sparc64/kernel/traps.c Fri Apr 23 04:24:51 1999 @@ -1,8 +1,8 @@ -/* $Id: traps.c,v 1.55 1998/10/11 06:58:22 davem Exp $ +/* $Id: traps.c,v 1.58 1999/03/29 12:38:10 jj Exp $ * arch/sparc64/kernel/traps.c * * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu) - * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * Copyright (C) 1997,1999 Jakub Jelinek (jj@sunsite.mff.cuni.cz) */ /* @@ -406,8 +406,6 @@ void do_fpieee(struct pt_regs *regs) { #ifdef DEBUG_FPU - save_and_clear_fpu(); - printk("fpieee %016lx\n", current->tss.xfsr[0]); #endif do_fpe_common(regs); @@ -420,7 +418,6 @@ struct fpustate *f = FPUSTATE; int ret = 0; - save_and_clear_fpu(); switch ((current->tss.xfsr[0] & 0x1c000)) { case (2 << 14): /* unfinished_FPop */ case (3 << 14): /* unimplemented_FPop */ @@ -428,7 +425,7 @@ break; } if (ret) return; -#ifdef DEBUG_FPU +#ifdef DEBUG_FPU printk("fpother %016lx\n", current->tss.xfsr[0]); #endif do_fpe_common(regs); @@ -462,6 +459,9 @@ void die_if_kernel(char *str, struct pt_regs *regs) { + extern void __show_regs(struct pt_regs * regs); + extern void smp_report_regs(void); + /* Amuse the user. */ printk( " \\|/ ____ \\|/\n" @@ -471,7 +471,7 @@ printk("%s(%d): %s\n", current->comm, current->pid, str); __asm__ __volatile__("flushw"); - show_regs(regs); + __show_regs(regs); { struct reg_window *rw = (struct reg_window *) (regs->u_regs[UREG_FP] + STACK_BIAS); @@ -491,6 +491,10 @@ printk("Instruction DUMP:"); instruction_dump ((unsigned int *) regs->tpc); } +#ifdef __SMP__ + smp_report_regs(); +#endif + lock_kernel(); /* Or else! */ if(regs->tstate & TSTATE_PRIV) do_exit(SIGKILL); @@ -498,7 +502,7 @@ } extern int handle_popc(u32 insn, struct pt_regs *regs); -extern int handle_ldq_stq(u32 insn, struct pt_regs *regs); +extern int handle_ldf_stq(u32 insn, struct pt_regs *regs); void do_illegal_instruction(struct pt_regs *regs) { @@ -515,7 +519,7 @@ if (handle_popc(insn, regs)) return; } else if ((insn & 0xc1580000) == 0xc1100000) /* LDQ/STQ */ { - if (handle_ldq_stq(insn, regs)) + if (handle_ldf_stq(insn, regs)) return; } } diff -ur --new-file old/linux/arch/sparc64/kernel/ttable.S new/linux/arch/sparc64/kernel/ttable.S --- old/linux/arch/sparc64/kernel/ttable.S Sun Oct 4 19:22:43 1998 +++ new/linux/arch/sparc64/kernel/ttable.S Fri Apr 23 04:24:51 1999 @@ -1,4 +1,4 @@ -/* $Id: ttable.S,v 1.27 1998/09/25 01:09:10 davem Exp $ +/* $Id: ttable.S,v 1.28 1999/03/29 12:38:10 jj Exp $ * ttable.S: Sparc V9 Trap Table(s) with SpitFire extensions. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -21,8 +21,8 @@ tl0_resv018: BTRAP(0x18) BTRAP(0x19) BTRAP(0x1a) BTRAP(0x1b) BTRAP(0x1c) BTRAP(0x1d) tl0_resv01e: BTRAP(0x1e) BTRAP(0x1f) tl0_fpdis: TRAP_NOSAVE(do_fpdis) -tl0_fpieee: TRAP(do_fpieee) -tl0_fpother: TRAP(do_fpother) +tl0_fpieee: TRAP_SAVEFPU(do_fpieee) +tl0_fpother: TRAP_SAVEFPU(do_fpother) tl0_tof: TRAP(do_tof) tl0_cwin: CLEAN_WINDOW tl0_div0: TRAP(do_div0) diff -ur --new-file old/linux/arch/sparc64/kernel/unaligned.c new/linux/arch/sparc64/kernel/unaligned.c --- old/linux/arch/sparc64/kernel/unaligned.c Tue Oct 27 18:52:20 1998 +++ new/linux/arch/sparc64/kernel/unaligned.c Fri Apr 23 04:24:51 1999 @@ -1,4 +1,4 @@ -/* $Id: unaligned.c,v 1.13 1998/10/07 22:43:13 davem Exp $ +/* $Id: unaligned.c,v 1.15 1999/04/03 11:36:21 anton Exp $ * unaligned.c: Unaligned load/store trap handling with special * cases for the kernel to do them more quickly. * @@ -374,7 +374,6 @@ enum direction dir = decode_direction(insn); int size = decode_access_size(insn); - lock_kernel(); if(!ok_for_kernel(insn) || dir == both) { printk("Unsupported unaligned load/store trap for kernel at <%016lx>.\n", regs->tpc); @@ -423,7 +422,6 @@ } advance(regs); } - unlock_kernel(); } static char popc_helper[] = { @@ -470,7 +468,7 @@ extern void do_privact(struct pt_regs *regs); extern void data_access_exception(struct pt_regs *regs); -int handle_ldq_stq(u32 insn, struct pt_regs *regs) +int handle_ldf_stq(u32 insn, struct pt_regs *regs) { unsigned long addr = compute_effective_address(regs, insn, 0); int freg = ((insn >> 25) & 0x1e) | ((insn >> 20) & 0x20); @@ -522,8 +520,10 @@ return 1; } } else { - /* LDQ */ - u32 first, second, third, fourth; + /* LDF, LDDF, LDQF */ + u32 data[4] __attribute__ ((aligned(8))); + int size, i; + int err; if (asi < 0x80) { do_privact(regs); @@ -532,25 +532,35 @@ data_access_exception(regs); return 1; } - if (get_user (first, (u32 *)addr) || - __get_user (second, (u32 *)(addr + 4)) || - __get_user (third, (u32 *)(addr + 8)) || - __get_user (fourth, (u32 *)(addr + 12))) { - if (asi & 0x2) /* NF */ { - first = 0; second = 0; third = 0; fourth = 0; - } else { - data_access_exception(regs); - return 1; - } + switch (insn & 0x180000) { + case 0x000000: size = 1; break; + case 0x100000: size = 4; break; + default: size = 2; break; + } + for (i = 0; i < size; i++) + data[i] = 0; + + err = get_user (data[0], (u32 *)addr); + if (!err) { + for (i = 1; i < size; i++) + err |= __get_user (data[i], (u32 *)(addr + 4*i)); + } + if (err && !(asi & 0x2 /* NF */)) { + data_access_exception(regs); + return 1; } if (asi & 0x8) /* Little */ { - u32 tmp = le32_to_cpup(&first); - - first = le32_to_cpup(&fourth); - fourth = tmp; - tmp = le32_to_cpup(&second); - second = le32_to_cpup(&third); - third = tmp; + u64 tmp; + + switch (size) { + case 1: data[0] = le32_to_cpup(data + 0); break; + default:*(u64 *)(data + 0) = le64_to_cpup((u64 *)(data + 0)); + break; + case 4: tmp = le64_to_cpup((u64 *)(data + 0)); + *(u64 *)(data + 0) = le64_to_cpup((u64 *)(data + 2)); + *(u64 *)(data + 2) = tmp; + break; + } } if (!(current->tss.fpsaved[0] & FPRS_FEF)) { current->tss.fpsaved[0] = FPRS_FEF; @@ -562,14 +572,25 @@ else memset(f->regs+32, 0, 32*sizeof(u32)); } - f->regs[freg] = first; - f->regs[freg+1] = second; - f->regs[freg+2] = third; - f->regs[freg+3] = fourth; + memcpy(f->regs + freg, data, size * 4); current->tss.fpsaved[0] |= flag; } advance(regs); return 1; +} + +void handle_ld_nf(u32 insn, struct pt_regs *regs) +{ + int rd = ((insn >> 25) & 0x1f); + int from_kernel = (regs->tstate & TSTATE_PRIV) != 0; + unsigned long *reg; + + maybe_flush_windows(0, 0, rd, from_kernel); + reg = fetch_reg_addr(rd, regs); + if ((insn & 0x780000) == 0x180000) + reg[1] = 0; + reg[0] = 0; + advance(regs); } void handle_lddfmna(struct pt_regs *regs, unsigned long sfar, unsigned long sfsr) diff -ur --new-file old/linux/arch/sparc64/math-emu/fabsq.c new/linux/arch/sparc64/math-emu/fabsq.c --- old/linux/arch/sparc64/math-emu/fabsq.c Wed Apr 15 02:44:21 1998 +++ new/linux/arch/sparc64/math-emu/fabsq.c Thu Mar 11 01:53:37 1999 @@ -2,5 +2,5 @@ { rd[0] = rs2[0] & 0x7fffffffffffffffUL; rd[1] = rs2[1]; - return 1; + return 0; } diff -ur --new-file old/linux/arch/sparc64/math-emu/faddd.c new/linux/arch/sparc64/math-emu/faddd.c --- old/linux/arch/sparc64/math-emu/faddd.c Tue Jan 13 00:15:44 1998 +++ new/linux/arch/sparc64/math-emu/faddd.c Thu Mar 11 01:53:37 1999 @@ -8,6 +8,5 @@ __FP_UNPACK_D(A, rs1); __FP_UNPACK_D(B, rs2); FP_ADD_D(R, A, B); - __FP_PACK_D(rd, R); - return 1; + return __FP_PACK_D(rd, R); } diff -ur --new-file old/linux/arch/sparc64/math-emu/faddq.c new/linux/arch/sparc64/math-emu/faddq.c --- old/linux/arch/sparc64/math-emu/faddq.c Tue Jan 13 00:15:44 1998 +++ new/linux/arch/sparc64/math-emu/faddq.c Thu Mar 11 01:53:37 1999 @@ -8,6 +8,5 @@ __FP_UNPACK_Q(A, rs1); __FP_UNPACK_Q(B, rs2); FP_ADD_Q(R, A, B); - __FP_PACK_Q(rd, R); - return 1; + return __FP_PACK_Q(rd, R); } diff -ur --new-file old/linux/arch/sparc64/math-emu/fadds.c new/linux/arch/sparc64/math-emu/fadds.c --- old/linux/arch/sparc64/math-emu/fadds.c Tue Jan 13 00:15:44 1998 +++ new/linux/arch/sparc64/math-emu/fadds.c Thu Mar 11 01:53:37 1999 @@ -8,6 +8,5 @@ __FP_UNPACK_S(A, rs1); __FP_UNPACK_S(B, rs2); FP_ADD_S(R, A, B); - __FP_PACK_S(rd, R); - return 1; + return __FP_PACK_S(rd, R); } diff -ur --new-file old/linux/arch/sparc64/math-emu/fcmpeq.c new/linux/arch/sparc64/math-emu/fcmpeq.c --- old/linux/arch/sparc64/math-emu/fcmpeq.c Wed Apr 15 02:44:21 1998 +++ new/linux/arch/sparc64/math-emu/fcmpeq.c Thu Mar 11 01:53:37 1999 @@ -21,5 +21,5 @@ case 3: fsr &= ~0x3000000000UL; fsr |= (ret << 36); break; } *(unsigned long *)rd = fsr; - return 1; + return 0; } diff -ur --new-file old/linux/arch/sparc64/math-emu/fcmpq.c new/linux/arch/sparc64/math-emu/fcmpq.c --- old/linux/arch/sparc64/math-emu/fcmpq.c Wed Apr 15 02:44:21 1998 +++ new/linux/arch/sparc64/math-emu/fcmpq.c Thu Mar 11 01:53:37 1999 @@ -21,5 +21,5 @@ case 3: fsr &= ~0x3000000000UL; fsr |= (ret << 36); break; } *(unsigned long *)rd = fsr; - return 1; + return 0; } diff -ur --new-file old/linux/arch/sparc64/math-emu/fdivd.c new/linux/arch/sparc64/math-emu/fdivd.c --- old/linux/arch/sparc64/math-emu/fdivd.c Tue Jan 13 00:15:44 1998 +++ new/linux/arch/sparc64/math-emu/fdivd.c Thu Mar 11 01:53:37 1999 @@ -4,10 +4,16 @@ int FDIVD(void *rd, void *rs2, void *rs1) { FP_DECL_D(A); FP_DECL_D(B); FP_DECL_D(R); + int ret = 0; __FP_UNPACK_D(A, rs1); __FP_UNPACK_D(B, rs2); + if(B_c == FP_CLS_ZERO && + A_c != FP_CLS_ZERO) { + ret |= EFLAG_DIVZERO; + if(__FPU_TRAP_P(EFLAG_DIVZERO)) + return ret; + } FP_DIV_D(R, A, B); - __FP_PACK_D(rd, R); - return 1; + return (ret | __FP_PACK_D(rd, R)); } diff -ur --new-file old/linux/arch/sparc64/math-emu/fdivq.c new/linux/arch/sparc64/math-emu/fdivq.c --- old/linux/arch/sparc64/math-emu/fdivq.c Tue Jan 13 00:15:44 1998 +++ new/linux/arch/sparc64/math-emu/fdivq.c Thu Mar 11 01:53:37 1999 @@ -4,10 +4,16 @@ int FDIVQ(void *rd, void *rs2, void *rs1) { FP_DECL_Q(A); FP_DECL_Q(B); FP_DECL_Q(R); + int ret; __FP_UNPACK_Q(A, rs1); __FP_UNPACK_Q(B, rs2); + if(B_c == FP_CLS_ZERO && + A_c != FP_CLS_ZERO) { + ret |= EFLAG_DIVZERO; + if(__FPU_TRAP_P(EFLAG_DIVZERO)) + return ret; + } FP_DIV_Q(R, A, B); - __FP_PACK_Q(rd, R); - return 1; + return (ret | __FP_PACK_Q(rd, R)); } diff -ur --new-file old/linux/arch/sparc64/math-emu/fdivs.c new/linux/arch/sparc64/math-emu/fdivs.c --- old/linux/arch/sparc64/math-emu/fdivs.c Tue Jan 13 00:15:44 1998 +++ new/linux/arch/sparc64/math-emu/fdivs.c Thu Mar 11 01:53:37 1999 @@ -4,10 +4,17 @@ int FDIVS(void *rd, void *rs2, void *rs1) { FP_DECL_S(A); FP_DECL_S(B); FP_DECL_S(R); + int ret = 0; __FP_UNPACK_S(A, rs1); __FP_UNPACK_S(B, rs2); + if(B_c == FP_CLS_ZERO && + A_c != FP_CLS_ZERO) { + ret |= EFLAG_DIVZERO; + if(__FPU_TRAP_P(EFLAG_DIVZERO)) + return ret; + } FP_DIV_S(R, A, B); - __FP_PACK_S(rd, R); - return 1; + return (ret | __FP_PACK_S(rd, R)); } + diff -ur --new-file old/linux/arch/sparc64/math-emu/fdmulq.c new/linux/arch/sparc64/math-emu/fdmulq.c --- old/linux/arch/sparc64/math-emu/fdmulq.c Tue Jan 13 00:15:44 1998 +++ new/linux/arch/sparc64/math-emu/fdmulq.c Thu Mar 11 01:53:37 1999 @@ -11,6 +11,5 @@ __FP_UNPACK_D(IN, rs2); FP_CONV(Q,D,2,1,B,IN); FP_MUL_Q(R, A, B); - __FP_PACK_Q(rd, R); - return 1; + return __FP_PACK_Q(rd, R); } diff -ur --new-file old/linux/arch/sparc64/math-emu/fdtoi.c new/linux/arch/sparc64/math-emu/fdtoi.c --- old/linux/arch/sparc64/math-emu/fdtoi.c Tue Jan 13 00:15:44 1998 +++ new/linux/arch/sparc64/math-emu/fdtoi.c Thu Mar 11 01:53:37 1999 @@ -9,5 +9,5 @@ __FP_UNPACK_D(A, rs2); FP_TO_INT_D(r, A, 32, 1); *rd = r; - return 1; + return 0; } diff -ur --new-file old/linux/arch/sparc64/math-emu/fdtoq.c new/linux/arch/sparc64/math-emu/fdtoq.c --- old/linux/arch/sparc64/math-emu/fdtoq.c Tue Jan 13 00:15:44 1998 +++ new/linux/arch/sparc64/math-emu/fdtoq.c Thu Mar 11 01:53:37 1999 @@ -8,6 +8,5 @@ __FP_UNPACK_D(A, rs2); FP_CONV(Q,D,2,1,R,A); - __FP_PACK_Q(rd, R); - return 1; + return __FP_PACK_Q(rd, R); } diff -ur --new-file old/linux/arch/sparc64/math-emu/fdtos.c new/linux/arch/sparc64/math-emu/fdtos.c --- old/linux/arch/sparc64/math-emu/fdtos.c Tue Jan 13 00:15:44 1998 +++ new/linux/arch/sparc64/math-emu/fdtos.c Thu Mar 11 01:53:37 1999 @@ -8,6 +8,5 @@ __FP_UNPACK_D(A, rs2); FP_CONV(S,D,1,1,R,A); - __FP_PACK_S(rd, R); - return 1; + return __FP_PACK_S(rd, R); } diff -ur --new-file old/linux/arch/sparc64/math-emu/fdtox.c new/linux/arch/sparc64/math-emu/fdtox.c --- old/linux/arch/sparc64/math-emu/fdtox.c Tue Jan 13 00:15:44 1998 +++ new/linux/arch/sparc64/math-emu/fdtox.c Thu Mar 11 01:53:37 1999 @@ -9,5 +9,5 @@ __FP_UNPACK_D(A, rs2); FP_TO_INT_D(r, A, 64, 1); *rd = r; - return 1; + return 0; } diff -ur --new-file old/linux/arch/sparc64/math-emu/fitoq.c new/linux/arch/sparc64/math-emu/fitoq.c --- old/linux/arch/sparc64/math-emu/fitoq.c Tue Jan 13 00:15:44 1998 +++ new/linux/arch/sparc64/math-emu/fitoq.c Thu Mar 11 01:53:37 1999 @@ -7,6 +7,5 @@ int a = *(int *)rs2; FP_FROM_INT_Q(R, a, 32, int); - __FP_PACK_Q(rd, R); - return 1; + return __FP_PACK_Q(rd, R); } diff -ur --new-file old/linux/arch/sparc64/math-emu/fmuld.c new/linux/arch/sparc64/math-emu/fmuld.c --- old/linux/arch/sparc64/math-emu/fmuld.c Tue Jan 13 00:15:44 1998 +++ new/linux/arch/sparc64/math-emu/fmuld.c Thu Mar 11 01:53:37 1999 @@ -8,6 +8,5 @@ __FP_UNPACK_D(A, rs1); __FP_UNPACK_D(B, rs2); FP_MUL_D(R, A, B); - __FP_PACK_D(rd, R); - return 1; + return __FP_PACK_D(rd, R); } diff -ur --new-file old/linux/arch/sparc64/math-emu/fmulq.c new/linux/arch/sparc64/math-emu/fmulq.c --- old/linux/arch/sparc64/math-emu/fmulq.c Tue Jan 13 00:15:44 1998 +++ new/linux/arch/sparc64/math-emu/fmulq.c Thu Mar 11 01:53:37 1999 @@ -8,6 +8,5 @@ __FP_UNPACK_Q(A, rs1); __FP_UNPACK_Q(B, rs2); FP_MUL_Q(R, A, B); - __FP_PACK_Q(rd, R); - return 1; + return __FP_PACK_Q(rd, R); } diff -ur --new-file old/linux/arch/sparc64/math-emu/fmuls.c new/linux/arch/sparc64/math-emu/fmuls.c --- old/linux/arch/sparc64/math-emu/fmuls.c Tue Jan 13 00:15:44 1998 +++ new/linux/arch/sparc64/math-emu/fmuls.c Thu Mar 11 01:53:37 1999 @@ -8,6 +8,5 @@ __FP_UNPACK_S(A, rs1); __FP_UNPACK_S(B, rs2); FP_MUL_S(R, A, B); - __FP_PACK_S(rd, R); - return 1; + return __FP_PACK_S(rd, R); } diff -ur --new-file old/linux/arch/sparc64/math-emu/fnegq.c new/linux/arch/sparc64/math-emu/fnegq.c --- old/linux/arch/sparc64/math-emu/fnegq.c Wed Apr 15 02:44:21 1998 +++ new/linux/arch/sparc64/math-emu/fnegq.c Thu Mar 11 01:53:37 1999 @@ -2,6 +2,6 @@ { rd[0] = rs2[0] ^ 0x8000000000000000UL; rd[1] = rs2[1]; - return 1; + return 0; } diff -ur --new-file old/linux/arch/sparc64/math-emu/fqtod.c new/linux/arch/sparc64/math-emu/fqtod.c --- old/linux/arch/sparc64/math-emu/fqtod.c Tue Jan 13 00:15:44 1998 +++ new/linux/arch/sparc64/math-emu/fqtod.c Thu Mar 11 01:53:37 1999 @@ -8,6 +8,5 @@ __FP_UNPACK_Q(A, rs2); FP_CONV(D,Q,1,2,R,A); - __FP_PACK_D(rd, R); - return 1; + return __FP_PACK_D(rd, R); } diff -ur --new-file old/linux/arch/sparc64/math-emu/fqtoi.c new/linux/arch/sparc64/math-emu/fqtoi.c --- old/linux/arch/sparc64/math-emu/fqtoi.c Tue Jan 13 00:15:44 1998 +++ new/linux/arch/sparc64/math-emu/fqtoi.c Thu Mar 11 01:53:37 1999 @@ -9,5 +9,5 @@ __FP_UNPACK_Q(A, rs2); FP_TO_INT_Q(r, A, 32, 1); *rd = r; - return 1; + return 0; } diff -ur --new-file old/linux/arch/sparc64/math-emu/fqtos.c new/linux/arch/sparc64/math-emu/fqtos.c --- old/linux/arch/sparc64/math-emu/fqtos.c Tue Jan 13 00:15:44 1998 +++ new/linux/arch/sparc64/math-emu/fqtos.c Thu Mar 11 01:53:37 1999 @@ -8,6 +8,5 @@ __FP_UNPACK_Q(A, rs2); FP_CONV(S,Q,1,2,R,A); - __FP_PACK_S(rd, R); - return 1; + return __FP_PACK_S(rd, R); } diff -ur --new-file old/linux/arch/sparc64/math-emu/fqtox.c new/linux/arch/sparc64/math-emu/fqtox.c --- old/linux/arch/sparc64/math-emu/fqtox.c Tue Jan 13 00:15:44 1998 +++ new/linux/arch/sparc64/math-emu/fqtox.c Thu Mar 11 01:53:37 1999 @@ -9,5 +9,5 @@ __FP_UNPACK_Q(A, rs2); FP_TO_INT_Q(r, A, 64, 1); *rd = r; - return 1; + return 0; } diff -ur --new-file old/linux/arch/sparc64/math-emu/fsmuld.c new/linux/arch/sparc64/math-emu/fsmuld.c --- old/linux/arch/sparc64/math-emu/fsmuld.c Tue Jan 13 00:15:44 1998 +++ new/linux/arch/sparc64/math-emu/fsmuld.c Thu Mar 11 01:53:37 1999 @@ -11,6 +11,5 @@ __FP_UNPACK_S(IN, rs2); FP_CONV(D,S,1,1,B,IN); FP_MUL_D(R, A, B); - __FP_PACK_D(rd, R); - return 1; + return __FP_PACK_D(rd, R); } diff -ur --new-file old/linux/arch/sparc64/math-emu/fsqrtd.c new/linux/arch/sparc64/math-emu/fsqrtd.c --- old/linux/arch/sparc64/math-emu/fsqrtd.c Tue Jan 13 00:15:44 1998 +++ new/linux/arch/sparc64/math-emu/fsqrtd.c Thu Mar 11 01:53:37 1999 @@ -7,6 +7,5 @@ __FP_UNPACK_D(A, rs2); FP_SQRT_D(R, A); - __FP_PACK_D(rd, R); - return 1; + return __FP_PACK_D(rd, R); } diff -ur --new-file old/linux/arch/sparc64/math-emu/fsqrtq.c new/linux/arch/sparc64/math-emu/fsqrtq.c --- old/linux/arch/sparc64/math-emu/fsqrtq.c Tue Jan 13 00:15:44 1998 +++ new/linux/arch/sparc64/math-emu/fsqrtq.c Thu Mar 11 01:53:37 1999 @@ -7,6 +7,5 @@ __FP_UNPACK_Q(A, rs2); FP_SQRT_Q(R, A); - __FP_PACK_Q(rd, R); - return 1; + return __FP_PACK_Q(rd, R); } diff -ur --new-file old/linux/arch/sparc64/math-emu/fsqrts.c new/linux/arch/sparc64/math-emu/fsqrts.c --- old/linux/arch/sparc64/math-emu/fsqrts.c Tue Jan 13 00:15:44 1998 +++ new/linux/arch/sparc64/math-emu/fsqrts.c Thu Mar 11 01:53:37 1999 @@ -7,6 +7,5 @@ __FP_UNPACK_S(A, rs2); FP_SQRT_S(R, A); - __FP_PACK_S(rd, R); - return 1; + return __FP_PACK_S(rd, R); } diff -ur --new-file old/linux/arch/sparc64/math-emu/fstod.c new/linux/arch/sparc64/math-emu/fstod.c --- old/linux/arch/sparc64/math-emu/fstod.c Tue Jan 13 00:15:44 1998 +++ new/linux/arch/sparc64/math-emu/fstod.c Thu Mar 11 01:53:37 1999 @@ -8,6 +8,5 @@ __FP_UNPACK_S(A, rs2); FP_CONV(D,S,1,1,R,A); - __FP_PACK_D(rd, R); - return 1; + return __FP_PACK_D(rd, R); } diff -ur --new-file old/linux/arch/sparc64/math-emu/fstoi.c new/linux/arch/sparc64/math-emu/fstoi.c --- old/linux/arch/sparc64/math-emu/fstoi.c Tue Jan 13 00:15:44 1998 +++ new/linux/arch/sparc64/math-emu/fstoi.c Thu Mar 11 01:53:37 1999 @@ -9,5 +9,5 @@ __FP_UNPACK_S(A, rs2); FP_TO_INT_S(r, A, 32, 1); *rd = r; - return 1; + return 0; } diff -ur --new-file old/linux/arch/sparc64/math-emu/fstoq.c new/linux/arch/sparc64/math-emu/fstoq.c --- old/linux/arch/sparc64/math-emu/fstoq.c Tue Jan 13 00:15:44 1998 +++ new/linux/arch/sparc64/math-emu/fstoq.c Thu Mar 11 01:53:37 1999 @@ -8,6 +8,5 @@ __FP_UNPACK_S(A, rs2); FP_CONV(Q,S,2,1,R,A); - __FP_PACK_Q(rd, R); - return 1; + return __FP_PACK_Q(rd, R); } diff -ur --new-file old/linux/arch/sparc64/math-emu/fstox.c new/linux/arch/sparc64/math-emu/fstox.c --- old/linux/arch/sparc64/math-emu/fstox.c Tue Jan 13 00:15:44 1998 +++ new/linux/arch/sparc64/math-emu/fstox.c Thu Mar 11 01:53:37 1999 @@ -9,5 +9,5 @@ __FP_UNPACK_S(A, rs2); FP_TO_INT_S(r, A, 64, 1); *rd = r; - return 1; + return 0; } diff -ur --new-file old/linux/arch/sparc64/math-emu/fsubd.c new/linux/arch/sparc64/math-emu/fsubd.c --- old/linux/arch/sparc64/math-emu/fsubd.c Tue Jan 13 00:15:44 1998 +++ new/linux/arch/sparc64/math-emu/fsubd.c Thu Mar 11 01:53:37 1999 @@ -10,6 +10,5 @@ if (B_c != FP_CLS_NAN) B_s ^= 1; FP_ADD_D(R, A, B); - __FP_PACK_D(rd, R); - return 1; + return __FP_PACK_D(rd, R); } diff -ur --new-file old/linux/arch/sparc64/math-emu/fsubq.c new/linux/arch/sparc64/math-emu/fsubq.c --- old/linux/arch/sparc64/math-emu/fsubq.c Tue Jan 13 00:15:44 1998 +++ new/linux/arch/sparc64/math-emu/fsubq.c Thu Mar 11 01:53:37 1999 @@ -10,6 +10,5 @@ if (B_c != FP_CLS_NAN) B_s ^= 1; FP_ADD_Q(R, A, B); - __FP_PACK_Q(rd, R); - return 1; + return __FP_PACK_Q(rd, R); } diff -ur --new-file old/linux/arch/sparc64/math-emu/fsubs.c new/linux/arch/sparc64/math-emu/fsubs.c --- old/linux/arch/sparc64/math-emu/fsubs.c Tue Jan 13 00:15:44 1998 +++ new/linux/arch/sparc64/math-emu/fsubs.c Thu Mar 11 01:53:37 1999 @@ -10,6 +10,5 @@ if (B_c != FP_CLS_NAN) B_s ^= 1; FP_ADD_S(R, A, B); - __FP_PACK_S(rd, R); - return 1; + return __FP_PACK_S(rd, R); } diff -ur --new-file old/linux/arch/sparc64/math-emu/fxtoq.c new/linux/arch/sparc64/math-emu/fxtoq.c --- old/linux/arch/sparc64/math-emu/fxtoq.c Tue Jan 13 00:15:44 1998 +++ new/linux/arch/sparc64/math-emu/fxtoq.c Thu Mar 11 01:53:37 1999 @@ -7,6 +7,5 @@ long a = *(long *)rs2; FP_FROM_INT_Q(R, a, 64, long); - __FP_PACK_Q(rd, R); - return 1; + return __FP_PACK_Q(rd, R); } diff -ur --new-file old/linux/arch/sparc64/math-emu/math.c new/linux/arch/sparc64/math-emu/math.c --- old/linux/arch/sparc64/math-emu/math.c Wed Aug 5 01:03:35 1998 +++ new/linux/arch/sparc64/math-emu/math.c Thu Mar 11 01:53:37 1999 @@ -1,7 +1,8 @@ -/* $Id: math.c,v 1.5 1998/06/12 14:54:27 jj Exp $ +/* $Id: math.c,v 1.7 1999/02/10 14:16:26 davem Exp $ * arch/sparc64/math-emu/math.c * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * Copyright (C) 1999 David S. Miller (davem@redhat.com) * * Emulation routines originate from soft-fp package, which is part * of glibc and has appropriate copyrights in it. @@ -14,6 +15,8 @@ #include #include +#include "soft-fp.h" + #define FLOATFUNC(x) extern int x(void *,void *,void *); FLOATFUNC(FMOVQ) @@ -54,6 +57,91 @@ FLOATFUNC(FSTOI) FLOATFUNC(FDTOI) +#define FSR_TEM_SHIFT 23UL +#define FSR_TEM_MASK (0x1fUL << FSR_TEM_SHIFT) +#define FSR_AEXC_SHIFT 5UL +#define FSR_AEXC_MASK (0x1fUL << FSR_AEXC_SHIFT) +#define FSR_CEXC_SHIFT 0UL +#define FSR_CEXC_MASK (0x1fUL << FSR_CEXC_SHIFT) + +/* All routines returning an exception to raise should detect + * such exceptions _before_ rounding to be consistant with + * the behavior of the hardware in the implemented cases + * (and thus with the recommendations in the V9 architecture + * manual). + * + * We return 0 if a SIGFPE should be sent, 1 otherwise. + */ +static int record_exception(struct pt_regs *regs, int eflag) +{ + u64 fsr = current->tss.xfsr[0]; + int would_trap; + + /* Determine if this exception would have generated a trap. */ + would_trap = (fsr & ((long)eflag << FSR_TEM_SHIFT)) != 0UL; + + /* If trapping, we only want to signal one bit. */ + if(would_trap != 0) { + eflag &= ((fsr & FSR_TEM_MASK) >> FSR_TEM_SHIFT); + if((eflag & (eflag - 1)) != 0) { + if(eflag & EFLAG_INVALID) + eflag = EFLAG_INVALID; + else if(eflag & EFLAG_DIVZERO) + eflag = EFLAG_DIVZERO; + else if(eflag & EFLAG_INEXACT) + eflag = EFLAG_INEXACT; + } + } + + /* Set CEXC, here are the rules: + * + * 1) In general all FPU ops will set one and only one + * bit in the CEXC field, this is always the case + * when the IEEE exception trap is enabled in TEM. + * + * 2) As a special case, if an overflow or underflow + * is being signalled, AND the trap is not enabled + * in TEM, then the inexact field shall also be set. + */ + fsr &= ~(FSR_CEXC_MASK); + if(would_trap || + (eflag & (EFLAG_OVERFLOW | EFLAG_UNDERFLOW)) == 0) { + fsr |= ((long)eflag << FSR_CEXC_SHIFT); + } else { + fsr |= (((long)eflag << FSR_CEXC_SHIFT) | + (EFLAG_INEXACT << FSR_CEXC_SHIFT)); + } + + /* Set the AEXC field, rules are: + * + * 1) If a trap would not be generated, the + * CEXC just generated is OR'd into the + * existing value of AEXC. + * + * 2) When a trap is generated, AEXC is cleared. + */ + if(would_trap == 0) + fsr |= ((long)eflag << FSR_AEXC_SHIFT); + else + fsr &= ~(FSR_AEXC_MASK); + + /* If trapping, indicate fault trap type IEEE. */ + if(would_trap != 0) + fsr |= (1UL << 14); + + current->tss.xfsr[0] = fsr; + + /* If we will not trap, advance the program counter over + * the instruction being handled. + */ + if(would_trap == 0) { + regs->tpc = regs->tnpc; + regs->tnpc += 4; + } + + return (would_trap ? 0 : 1); +} + int do_mathemu(struct pt_regs *regs, struct fpustate *f) { unsigned long pc = regs->tpc; @@ -175,7 +263,12 @@ current->tss.fpsaved[0] |= flags; break; } - func(rd, rs2, rs1); + flags = func(rd, rs2, rs1); + if(flags != 0) + return record_exception(regs, flags); + + /* Success and no exceptions detected. */ + current->tss.xfsr[0] &= ~(FSR_CEXC_MASK); regs->tpc = regs->tnpc; regs->tnpc += 4; return 1; diff -ur --new-file old/linux/arch/sparc64/math-emu/op-2.h new/linux/arch/sparc64/math-emu/op-2.h --- old/linux/arch/sparc64/math-emu/op-2.h Wed Apr 15 02:44:21 1998 +++ new/linux/arch/sparc64/math-emu/op-2.h Thu Mar 11 01:53:37 1999 @@ -190,14 +190,14 @@ \ __FP_FRAC_ADD_4(_FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2), \ _FP_FRAC_WORD_4(_z,1),_FP_FRAC_WORD_4(_z,0), \ + 0, _b_f1, _b_f0, 0, \ _FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2), \ - _FP_FRAC_WORD_4(_z,1),_FP_FRAC_WORD_4(_z,0), \ - 0, _b_f1, _b_f0, 0); \ + _FP_FRAC_WORD_4(_z,1),_FP_FRAC_WORD_4(_z,0)); \ __FP_FRAC_ADD_4(_FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2), \ _FP_FRAC_WORD_4(_z,1),_FP_FRAC_WORD_4(_z,0), \ + 0, _c_f1, _c_f0, 0, \ _FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2), \ - _FP_FRAC_WORD_4(_z,1),_FP_FRAC_WORD_4(_z,0), \ - 0, _c_f1, _c_f0, 0); \ + _FP_FRAC_WORD_4(_z,1),_FP_FRAC_WORD_4(_z,0)); \ \ /* Normalize since we know where the msb of the multiplicands \ were (bit B), we know that the msb of the of the product is \ diff -ur --new-file old/linux/arch/sparc64/math-emu/op-common.h new/linux/arch/sparc64/math-emu/op-common.h --- old/linux/arch/sparc64/math-emu/op-common.h Wed Aug 5 01:03:35 1998 +++ new/linux/arch/sparc64/math-emu/op-common.h Thu Mar 11 01:53:37 1999 @@ -53,14 +53,14 @@ */ #define _FP_PACK_CANONICAL(fs, wc, X) \ -do { \ +({int __ret = 0; \ switch (X##_c) \ { \ case FP_CLS_NORMAL: \ X##_e += _FP_EXPBIAS_##fs; \ if (X##_e > 0) \ { \ - _FP_ROUND(wc, X); \ + __ret |= _FP_ROUND(wc, X); \ if (_FP_FRAC_OVERP_##wc(fs, X)) \ { \ _FP_FRAC_SRL_##wc(X, (_FP_WORKBITS+1)); \ @@ -73,6 +73,7 @@ /* overflow to infinity */ \ X##_e = _FP_EXPMAX_##fs; \ _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc); \ + __ret |= EFLAG_OVERFLOW; \ } \ } \ else \ @@ -82,7 +83,7 @@ if (X##_e <= _FP_WFRACBITS_##fs) \ { \ _FP_FRAC_SRS_##wc(X, X##_e, _FP_WFRACBITS_##fs); \ - _FP_ROUND(wc, X); \ + __ret |= _FP_ROUND(wc, X); \ _FP_FRAC_SLL_##wc(X, 1); \ if (_FP_FRAC_OVERP_##wc(fs, X)) \ { \ @@ -93,6 +94,7 @@ { \ X##_e = 0; \ _FP_FRAC_SRL_##wc(X, _FP_WORKBITS+1); \ + __ret |= EFLAG_UNDERFLOW; \ } \ } \ else \ @@ -100,6 +102,7 @@ /* underflow to zero */ \ X##_e = 0; \ _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc); \ + __ret |= EFLAG_UNDERFLOW; \ } \ } \ break; \ @@ -125,7 +128,8 @@ _FP_FRAC_HIGH_##wc(X) |= _FP_QNANBIT_##fs; \ break; \ } \ -} while (0) + __ret; \ +}) /* @@ -424,11 +428,19 @@ } \ else \ { \ - /* Force -0 -> +0 */ \ - if (!X##_e && _FP_FRAC_ZEROP_##wc(X)) X##_s = 0; \ - if (!Y##_e && _FP_FRAC_ZEROP_##wc(Y)) X##_s = 0; \ + int __is_zero_x; \ + int __is_zero_y; \ + \ + __is_zero_x = (!X##_e && _FP_FRAC_ZEROP_##wc(X)) ? 1 : 0; \ + __is_zero_y = (!Y##_e && _FP_FRAC_ZEROP_##wc(Y)) ? 1 : 0; \ \ - if (X##_s != Y##_s) \ + if (__is_zero_x && __is_zero_y) \ + ret = 0; \ + else if (__is_zero_x) \ + ret = Y##_s ? 1 : -1; \ + else if (__is_zero_y) \ + ret = X##_s ? -1 : 1; \ + else if (X##_s != Y##_s) \ ret = X##_s ? -1 : 1; \ else if (X##_e > Y##_e) \ ret = X##_s ? -1 : 1; \ diff -ur --new-file old/linux/arch/sparc64/math-emu/sfp-machine.h new/linux/arch/sparc64/math-emu/sfp-machine.h --- old/linux/arch/sparc64/math-emu/sfp-machine.h Tue Jan 13 00:15:44 1998 +++ new/linux/arch/sparc64/math-emu/sfp-machine.h Wed Mar 17 06:52:06 1999 @@ -52,16 +52,6 @@ X##_s = _flo->bits.sign; \ } while (0) -#define __FP_PACK_RAW_1(fs, val, X) \ - do { \ - union _FP_UNION_##fs *_flo = \ - (union _FP_UNION_##fs *)val; \ - \ - _flo->bits.frac = X##_f; \ - _flo->bits.exp = X##_e; \ - _flo->bits.sign = X##_s; \ - } while (0) - #define __FP_UNPACK_RAW_2(fs, X, val) \ do { \ union _FP_UNION_##fs *_flo = \ @@ -73,52 +63,79 @@ X##_s = _flo->bits.sign; \ } while (0) -#define __FP_PACK_RAW_2(fs, val, X) \ - do { \ - union _FP_UNION_##fs *_flo = \ - (union _FP_UNION_##fs *)val; \ - \ - _flo->bits.frac0 = X##_f0; \ - _flo->bits.frac1 = X##_f1; \ - _flo->bits.exp = X##_e; \ - _flo->bits.sign = X##_s; \ - } while (0) - #define __FP_UNPACK_S(X,val) \ do { \ __FP_UNPACK_RAW_1(S,X,val); \ _FP_UNPACK_CANONICAL(S,1,X); \ } while (0) -#define __FP_PACK_S(val,X) \ - do { \ - _FP_PACK_CANONICAL(S,1,X); \ - __FP_PACK_RAW_1(S,val,X); \ - } while (0) - #define __FP_UNPACK_D(X,val) \ do { \ __FP_UNPACK_RAW_1(D,X,val); \ _FP_UNPACK_CANONICAL(D,1,X); \ } while (0) -#define __FP_PACK_D(val,X) \ - do { \ - _FP_PACK_CANONICAL(D,1,X); \ - __FP_PACK_RAW_1(D,val,X); \ - } while (0) - #define __FP_UNPACK_Q(X,val) \ do { \ __FP_UNPACK_RAW_2(Q,X,val); \ _FP_UNPACK_CANONICAL(Q,2,X); \ } while (0) -#define __FP_PACK_Q(val,X) \ - do { \ - _FP_PACK_CANONICAL(Q,2,X); \ - __FP_PACK_RAW_2(Q,val,X); \ +#define __FP_PACK_RAW_1(fs, val, X) \ + do { \ + union _FP_UNION_##fs *_flo = \ + (union _FP_UNION_##fs *)val; \ + \ + _flo->bits.frac = X##_f; \ + _flo->bits.exp = X##_e; \ + _flo->bits.sign = X##_s; \ } while (0) + +#define __FP_PACK_RAW_2(fs, val, X) \ + do { \ + union _FP_UNION_##fs *_flo = \ + (union _FP_UNION_##fs *)val; \ + \ + _flo->bits.frac0 = X##_f0; \ + _flo->bits.frac1 = X##_f1; \ + _flo->bits.exp = X##_e; \ + _flo->bits.sign = X##_s; \ + } while (0) + +#include +#include + +/* We only actually write to the destination register + * if exceptions signalled (if any) will not trap. + */ +#define __FPU_TEM \ + (((current->tss.xfsr[0])>>23)&0x1f) +#define __FPU_TRAP_P(bits) \ + ((__FPU_TEM & (bits)) != 0) + +#define __FP_PACK_S(val,X) \ +({ int __exc = _FP_PACK_CANONICAL(S,1,X); \ + if(!__exc || !__FPU_TRAP_P(__exc)) \ + __FP_PACK_RAW_1(S,val,X); \ + __exc; \ +}) + +#define __FP_PACK_D(val,X) \ +({ int __exc = _FP_PACK_CANONICAL(D,1,X); \ + if(!__exc || !__FPU_TRAP_P(__exc)) \ + __FP_PACK_RAW_1(D,val,X); \ + __exc; \ +}) + +#define __FP_PACK_Q(val,X) \ +({ int __exc = _FP_PACK_CANONICAL(Q,2,X); \ + if(!__exc || !__FPU_TRAP_P(__exc)) \ + __FP_PACK_RAW_2(Q,val,X); \ + __exc; \ +}) + +/* Obtain the current rounding mode. */ +#define FP_ROUNDMODE ((current->tss.xfsr[0] >> 30) & 0x3) #include #include @@ -153,28 +170,24 @@ #define umul_ppmm(wh, wl, u, v) \ do { \ - long tmp1 = 0, tmp2 = 0, tmp3 = 0; \ __asm__ ("mulx %2,%3,%1 - srlx %2,32,%4 - srl %3,0,%5 - mulx %4,%5,%6 - srlx %3,32,%4 - srl %2,0,%5 - mulx %4,%5,%5 - srlx %2,32,%4 - add %5,%6,%6 - srlx %3,32,%5 - mulx %4,%5,%4 - srlx %6,32,%5 - add %4,%5,%0" \ + srlx %2,32,%%g1 + srl %3,0,%%g2 + mulx %%g1,%%g2,%%g3 + srlx %3,32,%%g1 + srl %2,0,%%g2 + mulx %%g1,%%g2,%%g2 + srlx %2,32,%%g1 + add %%g2,%%g3,%%g3 + srlx %3,32,%%g2 + mulx %%g1,%%g2,%%g1 + srlx %%g3,32,%%g2 + add %%g1,%%g2,%0" \ : "=r" ((UDItype)(wh)), \ "=&r" ((UDItype)(wl)) \ : "r" ((UDItype)(u)), \ - "r" ((UDItype)(v)), \ - "r" ((UDItype)(tmp1)), \ - "r" ((UDItype)(tmp2)), \ - "r" ((UDItype)(tmp3)) \ - : "cc"); \ + "r" ((UDItype)(v)) \ + : "g1", "g2", "g3", "cc"); \ } while (0) #define udiv_qrnnd(q, r, n1, n0, d) \ @@ -223,3 +236,10 @@ #else #define __BYTE_ORDER __LITTLE_ENDIAN #endif + +/* Exception flags. */ +#define EFLAG_INVALID (1 << 4) +#define EFLAG_OVERFLOW (1 << 3) +#define EFLAG_UNDERFLOW (1 << 2) +#define EFLAG_DIVZERO (1 << 1) +#define EFLAG_INEXACT (1 << 0) diff -ur --new-file old/linux/arch/sparc64/math-emu/soft-fp.h new/linux/arch/sparc64/math-emu/soft-fp.h --- old/linux/arch/sparc64/math-emu/soft-fp.h Tue Jan 13 00:15:44 1998 +++ new/linux/arch/sparc64/math-emu/soft-fp.h Thu Mar 11 01:53:37 1999 @@ -14,45 +14,56 @@ # define FP_RND_ZERO 1 # define FP_RND_PINF 2 # define FP_RND_MINF 3 +#ifndef FP_ROUNDMODE # define FP_ROUNDMODE FP_RND_NEAREST #endif +#endif #define _FP_ROUND_NEAREST(wc, X) \ - do { \ +({ int __ret = EFLAG_INEXACT; \ if ((_FP_FRAC_LOW_##wc(X) & 15) != _FP_WORK_ROUND) \ _FP_FRAC_ADDI_##wc(X, _FP_WORK_ROUND); \ - } while(0) + else __ret = 0; \ + __ret; \ +}) -#define _FP_ROUND_ZERO(wc, X) +#define _FP_ROUND_ZERO(wc, X) 0 /* XXX */ #define _FP_ROUND_PINF(wc, X) \ - do { \ +({ int __ret = EFLAG_INEXACT; \ if (!X##_s && (_FP_FRAC_LOW_##wc(X) & 7)) \ _FP_FRAC_ADDI_##wc(X, _FP_WORK_LSB); \ - } while (0) + else __ret = 0; \ + __ret; \ +}) #define _FP_ROUND_MINF(wc, X) \ - do { \ +({ int __ret = EFLAG_INEXACT; \ if (X##_s && (_FP_FRAC_LOW_##wc(X) & 7)) \ _FP_FRAC_ADDI_##wc(X, _FP_WORK_LSB); \ - } while (0) + else __ret = 0; \ + __ret; \ +}) #define _FP_ROUND(wc, X) \ +({ int __ret = 0; \ switch (FP_ROUNDMODE) \ { \ case FP_RND_NEAREST: \ - _FP_ROUND_NEAREST(wc,X); \ + __ret |= _FP_ROUND_NEAREST(wc,X); \ break; \ case FP_RND_ZERO: \ - _FP_ROUND_ZERO(wc,X); \ + __ret |= _FP_ROUND_ZERO(wc,X); \ break; \ case FP_RND_PINF: \ - _FP_ROUND_PINF(wc,X); \ + __ret |= _FP_ROUND_PINF(wc,X); \ break; \ case FP_RND_MINF: \ - _FP_ROUND_MINF(wc,X); \ + __ret |= _FP_ROUND_MINF(wc,X); \ break; \ - } + }; \ + __ret; \ +}) #define FP_CLS_NORMAL 0 #define FP_CLS_ZERO 1 diff -ur --new-file old/linux/arch/sparc64/mm/fault.c new/linux/arch/sparc64/mm/fault.c --- old/linux/arch/sparc64/mm/fault.c Mon Nov 16 19:37:28 1998 +++ new/linux/arch/sparc64/mm/fault.c Wed Mar 17 06:52:06 1999 @@ -1,8 +1,8 @@ -/* $Id: fault.c,v 1.26 1998/11/08 11:14:03 davem Exp $ +/* $Id: fault.c,v 1.34 1999/03/16 12:12:28 jj Exp $ * arch/sparc64/mm/fault.c: Page fault handlers for the 64-bit Sparc. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) - * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) */ #include @@ -14,6 +14,8 @@ #include #include #include +#include +#include #include #include @@ -26,7 +28,7 @@ extern struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS]; /* Nice, simple, prom library does all the sweating for us. ;) */ -unsigned long prom_probe_memory (void) +unsigned long __init prom_probe_memory (void) { register struct linux_mlist_p1275 *mlist; register unsigned long bytes, base_paddr, tally; @@ -35,7 +37,7 @@ i = 0; mlist = *prom_meminfo()->p1275_available; bytes = tally = mlist->num_bytes; - base_paddr = (unsigned int) mlist->start_adr; + base_paddr = mlist->start_adr; sp_banks[0].base_addr = base_paddr; sp_banks[0].num_bytes = bytes; @@ -55,12 +57,12 @@ break; } - sp_banks[i].base_addr = (unsigned long) mlist->start_adr; + sp_banks[i].base_addr = mlist->start_adr; sp_banks[i].num_bytes = mlist->num_bytes; } i++; - sp_banks[i].base_addr = 0xdeadbeef; + sp_banks[i].base_addr = 0xdeadbeefbeefdeadUL; sp_banks[i].num_bytes = 0; /* Now mask all bank sizes on a page boundary, it is all we can @@ -72,26 +74,12 @@ return tally; } -/* Traverse the memory lists in the prom to see how much physical we - * have. - */ -unsigned long -probe_memory(void) -{ - unsigned long total; - - total = prom_probe_memory(); - - /* Oh man, much nicer, keep the dirt in promlib. */ - return total; -} - void unhandled_fault(unsigned long address, struct task_struct *tsk, struct pt_regs *regs) { if((unsigned long) address < PAGE_SIZE) { printk(KERN_ALERT "Unable to handle kernel NULL " - "pointer dereference"); + "pointer dereference\n"); } else { printk(KERN_ALERT "Unable to handle kernel paging request " "at virtual address %016lx\n", (unsigned long)address); @@ -100,22 +88,74 @@ (unsigned long) tsk->mm->context); printk(KERN_ALERT "tsk->mm->pgd = %016lx\n", (unsigned long) tsk->mm->pgd); - lock_kernel(); die_if_kernel("Oops", regs); - unlock_kernel(); } /* #define DEBUG_EXCEPTIONS */ /* #define DEBUG_LOCKUPS */ +/* #define INSN_VPTE_LOOKUP */ + +static inline u32 get_user_insn(unsigned long tpc) +{ + u32 insn; +#ifndef INSN_VPTE_LOOKUP + pgd_t *pgdp = pgd_offset(current->mm, tpc); + pmd_t *pmdp; + pte_t *ptep; + + if(pgd_none(*pgdp)) + return 0; + pmdp = pmd_offset(pgdp, tpc); + if(pmd_none(*pmdp)) + return 0; + ptep = pte_offset(pmdp, tpc); + if(!pte_present(*ptep)) + return 0; + insn = *(unsigned int *)(pte_page(*ptep) + (tpc & ~PAGE_MASK)); +#else + register unsigned long pte asm("l1"); + + /* So that we don't pollute TLB, we read the instruction + * using PHYS bypass. For that, we of course need + * to know its page table entry. Do this by simulating + * dtlb_miss handler. -jj */ + pte = ((((long)tpc) >> (PAGE_SHIFT-3)) & ~7); + asm volatile (" + rdpr %%pstate, %%l0 + wrpr %%l0, %2, %%pstate + wrpr %%g0, 1, %%tl + mov %%l1, %%g6 + ldxa [%%g3 + %%l1] %3, %%g5 + mov %%g5, %%l1 + wrpr %%g0, 0, %%tl + wrpr %%l0, 0, %%pstate + " : "=r" (pte) : "0" (pte), "i" (PSTATE_MG|PSTATE_IE), "i" (ASI_S) : "l0"); + + if ((long)pte >= 0) return 0; + + pte = (pte & _PAGE_PADDR) + (tpc & ~PAGE_MASK); + asm ("lduwa [%1] %2, %0" : "=r" (insn) : "r" (pte), "i" (ASI_PHYS_USE_EC)); +#endif + + return insn; +} + asmlinkage void do_sparc64_fault(struct pt_regs *regs, unsigned long address, int write) { struct mm_struct *mm = current->mm; struct vm_area_struct *vma; + unsigned int insn = 0; #ifdef DEBUG_LOCKUPS static unsigned long lastaddr, lastpc; static int lastwrite, lockcnt; #endif + /* + * If we're in an interrupt or have no user + * context, we must not take the fault.. + */ + if (in_interrupt() || mm == &init_mm) + goto do_kernel_fault; down(&mm->mmap_sem); #ifdef DEBUG_LOCKUPS @@ -135,6 +175,21 @@ vma = find_vma(mm, address); if(!vma) goto bad_area; +#ifndef INSN_VPTE_LOOKUP + write &= 0xf; +#else + if (write & 0x10) { + write = 0; + if((vma->vm_flags & VM_WRITE)) { + if (regs->tstate & TSTATE_PRIV) + insn = *(unsigned int *)regs->tpc; + else + insn = get_user_insn(regs->tpc); + if ((insn & 0xc0200000) == 0xc0200000 && (insn & 0x1780000) != 0x1680000) + write = 1; + } + } +#endif if(vma->vm_start <= address) goto good_area; if(!(vma->vm_flags & VM_GROWSDOWN)) @@ -168,16 +223,44 @@ do_kernel_fault: { - unsigned long g2 = regs->u_regs[UREG_G2]; + unsigned long g2; + unsigned char asi = ASI_P; + + if (!insn) { + if (regs->tstate & TSTATE_PRIV) + insn = *(unsigned int *)regs->tpc; + else + insn = get_user_insn(regs->tpc); + } + if (write != 1 && (insn & 0xc0800000) == 0xc0800000) { + if (insn & 0x2000) + asi = (regs->tstate >> 24); + else + asi = (insn >> 5); + if ((asi & 0xf2) == 0x82) { + /* This was a non-faulting load. Just clear the + destination register(s) and continue with the next + instruction. -jj */ + if (insn & 0x1000000) { + extern int handle_ldf_stq(u32, struct pt_regs *); + + handle_ldf_stq(insn, regs); + } else { + extern int handle_ld_nf(u32, struct pt_regs *); + + handle_ld_nf(insn, regs); + } + return; + } + } + + g2 = regs->u_regs[UREG_G2]; /* Is this in ex_table? */ if (regs->tstate & TSTATE_PRIV) { - unsigned char asi = ASI_P; - unsigned int insn; unsigned long fixup; - - insn = *(unsigned int *)regs->tpc; - if ((insn & 0xc0800000) == 0xc0800000) { + + if (asi == ASI_P && (insn & 0xc0800000) == 0xc0800000) { if (insn & 0x2000) asi = (regs->tstate >> 24); else diff -ur --new-file old/linux/arch/sparc64/mm/generic.c new/linux/arch/sparc64/mm/generic.c --- old/linux/arch/sparc64/mm/generic.c Mon Nov 16 19:37:28 1998 +++ new/linux/arch/sparc64/mm/generic.c Tue Mar 16 01:10:43 1999 @@ -1,4 +1,4 @@ -/* $Id: generic.c,v 1.3 1998/10/27 23:28:07 davem Exp $ +/* $Id: generic.c,v 1.8 1999/03/12 06:51:50 davem Exp $ * generic.c: Generic Sparc mm routines that are not dependent upon * MMU type but are Sparc specific. * @@ -56,6 +56,10 @@ * * They use a pgprot that sets PAGE_IO and does not check the * mem_map table as this is independent of normal memory. + * + * As a special hack if the lowest bit of offset is set the + * side-effect bit will be turned off. This is used as a + * performance improvement on FFB/AFB. -DaveM */ static inline void io_remap_pte_range(pte_t * pte, unsigned long address, unsigned long size, unsigned long offset, pgprot_t prot, int space) @@ -71,23 +75,32 @@ pte_t entry; unsigned long curend = address + PAGE_SIZE; - entry = mk_pte_io(offset, prot, space); - offset += PAGE_SIZE; + entry = mk_pte_io((offset & ~(0x1UL)), prot, space); if (!(address & 0xffff)) { - if (!(address & 0x3fffff) && !(offset & 0x3fffff) && end >= address + 0x400000) { - entry = mk_pte_io(offset, __pgprot(pgprot_val (prot) | _PAGE_SZ4MB), space); + if (!(address & 0x3fffff) && !(offset & 0x3ffffe) && end >= address + 0x400000) { + entry = mk_pte_io((offset & ~(0x1UL)), + __pgprot(pgprot_val (prot) | _PAGE_SZ4MB), + space); curend = address + 0x400000; - offset += 0x400000 - PAGE_SIZE; - } else if (!(address & 0x7ffff) && !(offset & 0x7ffff) && end >= address + 0x80000) { - entry = mk_pte_io(offset, __pgprot(pgprot_val (prot) | _PAGE_SZ512K), space); + offset += 0x400000; + } else if (!(address & 0x7ffff) && !(offset & 0x7fffe) && end >= address + 0x80000) { + entry = mk_pte_io((offset & ~(0x1UL)), + __pgprot(pgprot_val (prot) | _PAGE_SZ512K), + space); curend = address + 0x80000; - offset += 0x80000 - PAGE_SIZE; - } else if (!(offset & 0xffff) && end >= address + 0x10000) { - entry = mk_pte_io(offset, __pgprot(pgprot_val (prot) | _PAGE_SZ64K), space); + offset += 0x80000; + } else if (!(offset & 0xfffe) && end >= address + 0x10000) { + entry = mk_pte_io((offset & ~(0x1UL)), + __pgprot(pgprot_val (prot) | _PAGE_SZ64K), + space); curend = address + 0x10000; - offset += 0x10000 - PAGE_SIZE; + offset += 0x10000; } - } + } else + offset += PAGE_SIZE; + + if (offset & 0x1UL) + pte_val(entry) &= ~(_PAGE_E); do { oldpage = *pte; pte_clear(pte); diff -ur --new-file old/linux/arch/sparc64/mm/init.c new/linux/arch/sparc64/mm/init.c --- old/linux/arch/sparc64/mm/init.c Tue Oct 27 18:52:21 1998 +++ new/linux/arch/sparc64/mm/init.c Tue May 11 17:24:32 1999 @@ -1,8 +1,8 @@ -/* $Id: init.c,v 1.103 1998/10/20 03:09:12 jj Exp $ +/* $Id: init.c,v 1.127 1999/05/08 03:00:38 davem Exp $ * arch/sparc64/mm/init.c * - * Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu) - * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * Copyright (C) 1996-1999 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1997-1999 Jakub Jelinek (jj@sunsite.mff.cuni.cz) */ #include @@ -23,6 +23,7 @@ #include #include #include +#include /* Turn this off if you suspect some place in some physical memory hole might get into page tables (something would be broken very much). */ @@ -34,6 +35,8 @@ struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS]; +unsigned long *sparc64_valid_addr_bitmap; + /* Ugly, but necessary... -DaveM */ unsigned long phys_base; @@ -69,7 +72,7 @@ page->next_hash = NULL; page->pprev_hash = NULL; pgd_cache_size -= 2; - free_page(PAGE_OFFSET + (page->map_nr << PAGE_SHIFT)); + __free_page(page); freed++; if (page2) page = page2->next_hash; @@ -139,9 +142,9 @@ printk("%d reserved pages\n",reserved); printk("%d pages shared\n",shared); printk("%d pages swap cached\n",cached); - printk("%ld pages in page table cache\n",pgtable_cache_size); + printk("%d pages in page table cache\n",pgtable_cache_size); #ifndef __SMP__ - printk("%ld entries in page dir cache\n",pgd_cache_size); + printk("%d entries in page dir cache\n",pgd_cache_size); #endif show_buffers(); #ifdef CONFIG_NET @@ -160,27 +163,31 @@ static unsigned long dvmaiobase = 0; static unsigned long dvmaiosz __initdata = 0; -/* #define E3000_DEBUG */ - __initfunc(void dvmaio_init(void)) { - int i; + long i; if (!dvmaiobase) { for (i = 0; sp_banks[i].num_bytes != 0; i++) if (sp_banks[i].base_addr + sp_banks[i].num_bytes > dvmaiobase) dvmaiobase = sp_banks[i].base_addr + sp_banks[i].num_bytes; + + /* We map directly phys_base to phys_base+(4GB-DVMAIO_SIZE). */ + dvmaiobase -= phys_base; + dvmaiobase = (dvmaiobase + DVMAIO_SIZE + 0x400000 - 1) & ~(0x400000 - 1); for (i = 0; i < 6; i++) - if (dvmaiobase <= ((1024 * 64 * 1024) << i)) + if (dvmaiobase <= ((1024L * 64 * 1024) << i)) break; - dvmaiobase = ((1024 * 64 * 1024) << i) - DVMAIO_SIZE; + dvmaiobase = ((1024L * 64 * 1024) << i) - DVMAIO_SIZE; dvmaiosz = i; } } __initfunc(void iommu_init(int iommu_node, struct linux_sbus *sbus)) { + extern int this_is_starfire; + extern void *starfire_hookup(int); struct iommu_struct *iommu; struct sysio_regs *sregs; struct linux_prom64_registers rprop; @@ -191,10 +198,6 @@ int err, i, j; dvmaio_init(); -#ifdef E3000_DEBUG - prom_printf("\niommu_init: [%x:%p] ", - iommu_node, sbus); -#endif err = prom_getproperty(iommu_node, "reg", (char *)&rprop, sizeof(rprop)); if(err == -1) { @@ -203,19 +206,16 @@ } sregs = (struct sysio_regs *) __va(rprop.phys_addr); -#ifdef E3000_DEBUG - prom_printf("sregs[%p]\n"); -#endif if(!sregs) { prom_printf("iommu_init: Fatal error, sysio regs not mapped\n"); prom_halt(); } iommu = kmalloc(sizeof(struct iommu_struct), GFP_ATOMIC); - -#ifdef E3000_DEBUG - prom_printf("iommu_init: iommu[%p] ", iommu); -#endif + if (!iommu) { + prom_printf("iommu_init: Fatal error, kmalloc(iommu) failed\n"); + prom_halt(); + } spin_lock_init(&iommu->iommu_lock); iommu->sysio_regs = sregs; @@ -224,14 +224,19 @@ control = sregs->iommu_control; impl = (control & IOMMU_CTRL_IMPL) >> 60; vers = (control & IOMMU_CTRL_VERS) >> 56; -#ifdef E3000_DEBUG - prom_printf("sreg_control[%08x]\n", control); - prom_printf("IOMMU: IMPL[%x] VERS[%x] SYSIO mapped at %016lx\n", - (unsigned int) impl, (unsigned int)vers, (unsigned long) sregs); -#endif printk("IOMMU(SBUS): IMPL[%x] VERS[%x] SYSIO mapped at %016lx\n", (unsigned int) impl, (unsigned int)vers, (unsigned long) sregs); + /* Streaming buffer is unreliable on VERS 0 of SYSIO, + * although such parts were never shipped in production + * Sun hardware, I check just to be robust. --DaveM + */ + vers = ((sregs->control & SYSIO_CONTROL_VER) >> 56); + if (vers == 0) + iommu->strbuf_enabled = 0; + else + iommu->strbuf_enabled = 1; + control &= ~(IOMMU_CTRL_TSBSZ); control |= ((IOMMU_TSBSZ_2K * dvmaiosz) | IOMMU_CTRL_TBWSZ | IOMMU_CTRL_ENAB); @@ -281,9 +286,14 @@ /* Setup aliased mappings... */ for(i = 0; i < (dvmaiobase >> 16); i++) { - *iopte = (IOPTE_VALID | IOPTE_64K | IOPTE_STBUF | - IOPTE_CACHE | IOPTE_WRITE); - *iopte |= (i << 16); + unsigned long val = ((((unsigned long)i) << 16UL) + phys_base); + + val |= IOPTE_VALID | IOPTE_64K | IOPTE_WRITE; + if (iommu->strbuf_enabled) + val |= IOPTE_STBUF; + else + val |= IOPTE_CACHE; + *iopte = val; iopte++; } @@ -291,38 +301,34 @@ for( ; i < ((dvmaiobase + DVMAIO_SIZE) >> 16); i++) *iopte++ = 0; -#ifdef E3000_DEBUG - prom_printf("IOMMU: pte's mapped, enabling IOMMU... "); -#endif sregs->iommu_tsbbase = __pa(tsbbase); sregs->iommu_control = control; -#ifdef E3000_DEBUG - prom_printf("done\n"); -#endif /* Get the streaming buffer going. */ control = sregs->sbuf_control; impl = (control & SYSIO_SBUFCTRL_IMPL) >> 60; vers = (control & SYSIO_SBUFCTRL_REV) >> 56; -#ifdef E3000_DEBUG - prom_printf("IOMMU: enabling streaming buffer, control[%08x]... ", - control); -#endif - printk("IOMMU: Streaming Buffer IMPL[%x] REV[%x] ", + printk("IOMMU: Streaming Buffer IMPL[%x] REV[%x] ... ", (unsigned int)impl, (unsigned int)vers); - iommu->sbuf_flushflag_va = kmalloc(sizeof(unsigned long), GFP_DMA); - printk("FlushFLAG[%016lx] ... ", (iommu->sbuf_flushflag_pa = __pa(iommu->sbuf_flushflag_va))); - *(iommu->sbuf_flushflag_va) = 0; - - sregs->sbuf_control = (control | SYSIO_SBUFCTRL_SB_EN); + iommu->flushflag = 0; -#ifdef E3000_DEBUG - prom_printf("done, returning\n"); -#endif - printk("ENABLED\n"); + if (iommu->strbuf_enabled != 0) { + sregs->sbuf_control = (control | SYSIO_SBUFCTRL_SB_EN); + printk("ENABLED\n"); + } else { + sregs->sbuf_control = (control & ~(SYSIO_SBUFCTRL_SB_EN)); + printk("DISABLED\n"); + } /* Finally enable DVMA arbitration for all devices, just in case. */ sregs->sbus_control |= SYSIO_SBCNTRL_AEN; + + /* If necessary, hook us up for starfire IRQ translations. */ + sbus->upaid = prom_getintdefault(sbus->prom_node, "upa-portid", -1); + if(this_is_starfire) + sbus->starfire_cookie = starfire_hookup(sbus->upaid); + else + sbus->starfire_cookie = NULL; } void mmu_map_dma_area(unsigned long addr, int len, __u32 *dvma_addr, @@ -397,19 +403,35 @@ __u32 mmu_get_scsi_one(char *vaddr, unsigned long len, struct linux_sbus *sbus) { - __u32 sbus_addr = (__u32) __pa(vaddr); + struct iommu_struct *iommu = sbus->iommu; + struct sysio_regs *sregs = iommu->sysio_regs; + unsigned long start = (unsigned long) vaddr; + unsigned long end = PAGE_ALIGN(start + len); + unsigned long flags, tmp; + volatile u64 *sbctrl = (volatile u64 *) &sregs->sbus_control; + + start &= PAGE_MASK; + if (end > MAX_DMA_ADDRESS) { + printk("mmu_get_scsi_one: Bogus DMA buffer address [%016lx:%d]\n", + (unsigned long) vaddr, (int)len); + panic("DMA address too large, tell DaveM"); + } + + if (iommu->strbuf_enabled) { + spin_lock_irqsave(&iommu->iommu_lock, flags); + iommu->flushflag = 0; + while(start < end) { + sregs->sbuf_pflush = start; + start += PAGE_SIZE; + } + sregs->sbuf_fsync = __pa(&(iommu->flushflag)); + tmp = *sbctrl; + while(iommu->flushflag == 0) + membar("#LoadLoad"); + spin_unlock_irqrestore(&iommu->iommu_lock, flags); + } -#ifndef DEBUG_IOMMU - return sbus_addr; -#else - if((sbus_addr < dvmaiobase) && - ((sbus_addr + len) < dvmaiobase)) - return sbus_addr; - - /* "can't happen"... GFP_DMA assures this. */ - panic("Very high scsi_one mappings should never happen."); - return (__u32)0; -#endif + return sbus_dvma_addr(vaddr); } void mmu_release_scsi_one(u32 vaddr, unsigned long len, struct linux_sbus *sbus) @@ -418,43 +440,89 @@ struct sysio_regs *sregs = iommu->sysio_regs; unsigned long start = (unsigned long) vaddr; unsigned long end = PAGE_ALIGN(start + len); - unsigned long flags; - unsigned int *sync_word; + unsigned long flags, tmp; + volatile u64 *sbctrl = (volatile u64 *) &sregs->sbus_control; start &= PAGE_MASK; - spin_lock_irqsave(&iommu->iommu_lock, flags); + if (iommu->strbuf_enabled) { + spin_lock_irqsave(&iommu->iommu_lock, flags); - while(start < end) { - sregs->sbuf_pflush = start; - start += PAGE_SIZE; - } - sync_word = iommu->sbuf_flushflag_va; - sregs->sbuf_fsync = iommu->sbuf_flushflag_pa; - membar("#StoreLoad | #MemIssue"); - while((*sync_word & 0x1) == 0) - membar("#LoadLoad"); - *sync_word = 0; + /* 1) Clear the flush flag word */ + iommu->flushflag = 0; - spin_unlock_irqrestore(&iommu->iommu_lock, flags); + /* 2) Tell the streaming buffer which entries + * we want flushed. + */ + while(start < end) { + sregs->sbuf_pflush = start; + start += PAGE_SIZE; + } + + /* 3) Initiate flush sequence. */ + sregs->sbuf_fsync = __pa(&(iommu->flushflag)); + + /* 4) Guarentee completion of all previous writes + * by reading SYSIO's SBUS control register. + */ + tmp = *sbctrl; + + /* 5) Wait for flush flag to get set. */ + while(iommu->flushflag == 0) + membar("#LoadLoad"); + + spin_unlock_irqrestore(&iommu->iommu_lock, flags); + } } void mmu_get_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus) { - while(sz >= 0) { - __u32 page = (__u32) __pa(((unsigned long) sg[sz].addr)); -#ifndef DEBUG_IOMMU - sg[sz].dvma_addr = page; -#else - if((page < dvmaiobase) && - (page + sg[sz].len) < dvmaiobase) { - sg[sz].dvma_addr = page; - } else { - /* "can't happen"... GFP_DMA assures this. */ - panic("scsi_sgl high mappings should never happen."); + struct iommu_struct *iommu = sbus->iommu; + struct sysio_regs *sregs = iommu->sysio_regs; + unsigned long flags, tmp; + volatile u64 *sbctrl = (volatile u64 *) &sregs->sbus_control; + + if (iommu->strbuf_enabled) { + spin_lock_irqsave(&iommu->iommu_lock, flags); + iommu->flushflag = 0; + + while(sz >= 0) { + unsigned long start = (unsigned long)sg[sz].addr; + unsigned long end = PAGE_ALIGN(start + sg[sz].len); + + if (end > MAX_DMA_ADDRESS) { + printk("mmu_get_scsi_sgl: Bogus DMA buffer address " + "[%016lx:%d]\n", start, (int) sg[sz].len); + panic("DMA address too large, tell DaveM"); + } + + sg[sz--].dvma_addr = sbus_dvma_addr(start); + start &= PAGE_MASK; + while(start < end) { + sregs->sbuf_pflush = start; + start += PAGE_SIZE; + } + } + + sregs->sbuf_fsync = __pa(&(iommu->flushflag)); + tmp = *sbctrl; + while(iommu->flushflag == 0) + membar("#LoadLoad"); + spin_unlock_irqrestore(&iommu->iommu_lock, flags); + } else { + /* Just verify the addresses and fill in the + * dvma_addr fields in this case. + */ + while(sz >= 0) { + unsigned long start = (unsigned long)sg[sz].addr; + unsigned long end = PAGE_ALIGN(start + sg[sz].len); + if (end > MAX_DMA_ADDRESS) { + printk("mmu_get_scsi_sgl: Bogus DMA buffer address " + "[%016lx:%d]\n", start, (int) sg[sz].len); + panic("DMA address too large, tell DaveM"); + } + sg[sz--].dvma_addr = sbus_dvma_addr(start); } -#endif - sz--; } } @@ -462,30 +530,98 @@ { struct iommu_struct *iommu = sbus->iommu; struct sysio_regs *sregs = iommu->sysio_regs; - unsigned long flags; - unsigned int *sync_word; + volatile u64 *sbctrl = (volatile u64 *) &sregs->sbus_control; + unsigned long flags, tmp; - spin_lock_irqsave(&iommu->iommu_lock, flags); + if (iommu->strbuf_enabled) { + spin_lock_irqsave(&iommu->iommu_lock, flags); - while(sz >= 0) { - unsigned long start = sg[sz].dvma_addr; - unsigned long end = PAGE_ALIGN(start + sg[sz].len); + /* 1) Clear the flush flag word */ + iommu->flushflag = 0; - start &= PAGE_MASK; - while(start < end) { - sregs->sbuf_pflush = start; - start += PAGE_SIZE; + /* 2) Tell the streaming buffer which entries + * we want flushed. + */ + while(sz >= 0) { + unsigned long start = sg[sz].dvma_addr; + unsigned long end = PAGE_ALIGN(start + sg[sz].len); + + start &= PAGE_MASK; + while(start < end) { + sregs->sbuf_pflush = start; + start += PAGE_SIZE; + } + sz--; } - sz--; + + /* 3) Initiate flush sequence. */ + sregs->sbuf_fsync = __pa(&(iommu->flushflag)); + + /* 4) Guarentee completion of previous writes + * by reading SYSIO's SBUS control register. + */ + tmp = *sbctrl; + + /* 5) Wait for flush flag to get set. */ + while(iommu->flushflag == 0) + membar("#LoadLoad"); + + spin_unlock_irqrestore(&iommu->iommu_lock, flags); } - sync_word = iommu->sbuf_flushflag_va; - sregs->sbuf_fsync = iommu->sbuf_flushflag_pa; - membar("#StoreLoad | #MemIssue"); - while((*sync_word & 0x1) == 0) - membar("#LoadLoad"); - *sync_word = 0; +} - spin_unlock_irqrestore(&iommu->iommu_lock, flags); +void mmu_set_sbus64(struct linux_sbus_device *sdev, int bursts) +{ + struct linux_sbus *sbus = sdev->my_bus; + struct sysio_regs *sregs = sbus->iommu->sysio_regs; + int slot = sdev->slot; + u64 *cfg, tmp; + + switch(slot) { + case 0: + cfg = &sregs->sbus_s0cfg; + break; + case 1: + cfg = &sregs->sbus_s1cfg; + break; + case 2: + cfg = &sregs->sbus_s2cfg; + break; + case 3: + cfg = &sregs->sbus_s3cfg; + break; + + case 13: + cfg = &sregs->sbus_s4cfg; + break; + case 14: + cfg = &sregs->sbus_s5cfg; + break; + case 15: + cfg = &sregs->sbus_s6cfg; + break; + + default: + return; + }; + + /* ETM already enabled? If so, we're done. */ + tmp = *cfg; + if ((tmp & SYSIO_SBSCFG_ETM) != 0) + return; + + /* Set burst bits. */ + if (bursts & DMA_BURST8) + tmp |= SYSIO_SBSCFG_BA8; + if (bursts & DMA_BURST16) + tmp |= SYSIO_SBSCFG_BA16; + if (bursts & DMA_BURST32) + tmp |= SYSIO_SBSCFG_BA32; + if (bursts & DMA_BURST64) + tmp |= SYSIO_SBSCFG_BA64; + + /* Finally turn on ETM and set register. */ + *cfg = (tmp | SYSIO_SBSCFG_ETM); } int mmu_info(char *buf) @@ -562,16 +698,9 @@ */ static void __flush_nucleus_vptes(void) { - unsigned long pstate; unsigned long prom_reserved_base = 0xfffffffc00000000UL; int i; - __asm__ __volatile__("flushw\n\t" - "rdpr %%pstate, %0\n\t" - "wrpr %0, %1, %%pstate" - : "=r" (pstate) - : "i" (PSTATE_IE)); - /* Only DTLB must be checked for VPTE entries. */ for(i = 0; i < 63; i++) { unsigned long tag = spitfire_get_dtlb_tag(i); @@ -586,8 +715,6 @@ membar("#Sync"); } } - __asm__ __volatile__("wrpr %0, 0, %%pstate" - : : "r" (pstate)); } static int prom_ditlb_set = 0; @@ -600,10 +727,19 @@ void prom_world(int enter) { + unsigned long pstate; int i; if (!prom_ditlb_set) return; + + /* Make sure the following runs atomically. */ + __asm__ __volatile__("flushw\n\t" + "rdpr %%pstate, %0\n\t" + "wrpr %0, %1, %%pstate" + : "=r" (pstate) + : "i" (PSTATE_IE)); + if (enter) { /* Kick out nucleus VPTEs. */ __flush_nucleus_vptes(); @@ -648,6 +784,8 @@ } } } + __asm__ __volatile__("wrpr %0, 0, %%pstate" + : : "r" (pstate)); } void inherit_locked_prom_mappings(int save_p) @@ -680,7 +818,7 @@ unsigned long data; data = spitfire_get_dtlb_data(i); - if(data & _PAGE_L) { + if((data & (_PAGE_L|_PAGE_VALID)) == (_PAGE_L|_PAGE_VALID)) { unsigned long tag = spitfire_get_dtlb_tag(i); if(save_p) { @@ -703,7 +841,7 @@ unsigned long data; data = spitfire_get_itlb_data(i); - if(data & _PAGE_L) { + if((data & (_PAGE_L|_PAGE_VALID)) == (_PAGE_L|_PAGE_VALID)) { unsigned long tag = spitfire_get_itlb_tag(i); if(save_p) { @@ -811,8 +949,7 @@ #define CTX_BMAP_SLOTS (1UL << (CTX_VERSION_SHIFT - 6)) unsigned long mmu_context_bmap[CTX_BMAP_SLOTS]; -/* We are always protected by scheduler_lock under SMP. - * Caller does TLB context flushing on local CPU if necessary. +/* Caller does TLB context flushing on local CPU if necessary. * * We must be careful about boundary cases so that we never * let the user have CTX 0 (nucleus) or we ever use a CTX @@ -867,15 +1004,11 @@ struct pgtable_cache_struct pgt_quicklists; #endif -/* XXX Add __GFP_HIGH to these calls to "fool" page allocator - * XXX so we don't go to swap so quickly... then do the same - * XXX for get_user_page as well -DaveM - */ pmd_t *get_pmd_slow(pgd_t *pgd, unsigned long offset) { pmd_t *pmd; - pmd = (pmd_t *) __get_free_page(GFP_DMA|GFP_KERNEL); + pmd = (pmd_t *) __get_free_page(GFP_KERNEL); if(pmd) { memset(pmd, 0, PAGE_SIZE); pgd_set(pgd, pmd); @@ -888,7 +1021,7 @@ { pte_t *pte; - pte = (pte_t *) __get_free_page(GFP_DMA|GFP_KERNEL); + pte = (pte_t *) __get_free_page(GFP_KERNEL); if(pte) { memset(pte, 0, PAGE_SIZE); pmd_set(pmd, pte); @@ -993,15 +1126,16 @@ /* paging_init() sets up the page tables */ extern unsigned long free_area_init(unsigned long, unsigned long); +extern unsigned long sun_serial_setup(unsigned long); __initfunc(unsigned long paging_init(unsigned long start_mem, unsigned long end_mem)) { - extern void setup_tba(void); extern pmd_t swapper_pmd_dir[1024]; - extern unsigned long irq_init(unsigned long start_mem, unsigned long end_mem); - extern unsigned int sparc64_vpte_patchme[1]; + extern unsigned int sparc64_vpte_patchme1[1]; + extern unsigned int sparc64_vpte_patchme2[1]; unsigned long alias_base = phys_base + PAGE_OFFSET; + unsigned long second_alias_page = 0; unsigned long pt; unsigned long flags; unsigned long shift = alias_base - ((unsigned long)&empty_zero_page); @@ -1026,6 +1160,21 @@ : "r" (TLB_TAG_ACCESS), "r" (alias_base), "r" (pt), "i" (ASI_DMMU), "i" (ASI_DTLB_DATA_ACCESS), "r" (61 << 3) : "memory"); + if (start_mem >= KERNBASE + 0x340000) { + second_alias_page = alias_base + 0x400000; + __asm__ __volatile__(" + stxa %1, [%0] %3 + stxa %2, [%5] %4 + membar #Sync + flush %%g6 + nop + nop + nop" + : /* No outputs */ + : "r" (TLB_TAG_ACCESS), "r" (second_alias_page), "r" (pt + 0x400000), + "i" (ASI_DMMU), "i" (ASI_DTLB_DATA_ACCESS), "r" (60 << 3) + : "memory"); + } __restore_flags(flags); /* Now set kernel pgd to upper alias so physical page computations @@ -1038,22 +1187,40 @@ /* Now can init the kernel/bad page tables. */ pgd_set(&swapper_pg_dir[0], swapper_pmd_dir + (shift / sizeof(pgd_t))); - sparc64_vpte_patchme[0] |= (init_mm.pgd[0] >> 10); + sparc64_vpte_patchme1[0] |= (init_mm.pgd[0] >> 10); + sparc64_vpte_patchme2[0] |= (init_mm.pgd[0] & 0x3ff); + flushi((long)&sparc64_vpte_patchme1[0]); - start_mem = irq_init(start_mem, end_mem); - /* We use mempool to create page tables, therefore adjust it up * such that __pa() macros etc. work. */ mempool = PAGE_ALIGN(start_mem) + shift; + +#ifdef CONFIG_SUN_SERIAL + /* This does not logically belong here, but is the first place + we can initialize it at, so that we work in the PAGE_OFFSET+ + address space. */ + mempool = sun_serial_setup(mempool); +#endif /* Allocate 64M for dynamic DVMA mapping area. */ allocate_ptable_skeleton(DVMA_VADDR, DVMA_VADDR + 0x4000000); inherit_prom_mappings(); - - /* Ok, we can use our TLB miss and window trap handlers safely. */ - setup_tba(); + /* Ok, we can use our TLB miss and window trap handlers safely. + * We need to do a quick peek here to see if we are on StarFire + * or not, so setup_tba can setup the IRQ globals correctly (it + * needs to get the hard smp processor id correctly). + */ + { + extern void setup_tba(int); + int is_starfire = prom_finddevice("/ssp-serial"); + if(is_starfire != 0 && is_starfire != -1) + is_starfire = 1; + else + is_starfire = 0; + setup_tba(is_starfire); + } /* Really paranoid. */ flushi((long)&empty_zero_page); @@ -1064,6 +1231,8 @@ */ /* We only created DTLB mapping of this stuff. */ spitfire_flush_dtlb_nucleus_page(alias_base); + if (second_alias_page) + spitfire_flush_dtlb_nucleus_page(second_alias_page); membar("#Sync"); /* Paranoid */ @@ -1079,10 +1248,6 @@ return device_scan (PAGE_ALIGN (start_mem)); } -/* XXX Add also PG_Hole flag, set it in the page structs here, - * XXX remove FREE_UNUSED_MEM_MAP code, and the nfsd file handle - * problems will all be gone. -DaveM - */ __initfunc(static void taint_real_pages(unsigned long start_mem, unsigned long end_mem)) { unsigned long tmp = 0, paddr, endaddr; @@ -1096,14 +1261,24 @@ if (!sp_banks[tmp].num_bytes) { mem_map[paddr>>PAGE_SHIFT].flags |= (1<>PAGE_SHIFT].next_hash = mem_map + (phys_base >> PAGE_SHIFT); + mem_map[(paddr>>PAGE_SHIFT)+1UL].flags |= (1<>PAGE_SHIFT)+1UL].next_hash = mem_map + (phys_base >> PAGE_SHIFT); return; } if (sp_banks[tmp].base_addr > paddr) { - /* Making a one or two pages PG_skip holes is not necessary */ - if (sp_banks[tmp].base_addr - paddr > 2 * PAGE_SIZE) { + /* Making a one or two pages PG_skip holes + * is not necessary. We add one more because + * we must set the PG_skip flag on the first + * two mem_map[] entries for the hole. Go and + * see the mm/filemap.c:shrink_mmap() loop for + * details. -DaveM + */ + if (sp_banks[tmp].base_addr - paddr > 3 * PAGE_SIZE) { mem_map[paddr>>PAGE_SHIFT].flags |= (1<>PAGE_SHIFT].next_hash = mem_map + (sp_banks[tmp].base_addr >> PAGE_SHIFT); + mem_map[(paddr>>PAGE_SHIFT)+1UL].flags |= (1<>PAGE_SHIFT)+1UL].next_hash = mem_map + (sp_banks[tmp].base_addr >> PAGE_SHIFT); } paddr = sp_banks[tmp].base_addr; } @@ -1111,7 +1286,8 @@ endaddr = sp_banks[tmp].base_addr + sp_banks[tmp].num_bytes; while (paddr < endaddr) { mem_map[paddr>>PAGE_SHIFT].flags &= ~(1<= dvmaiobase) + set_bit(paddr >> 22, sparc64_valid_addr_bitmap); + if (paddr >= (MAX_DMA_ADDRESS - PAGE_OFFSET)) mem_map[paddr>>PAGE_SHIFT].flags &= ~(1<> ((22 - PAGE_SHIFT) + 6); + i += 1; + memset(sparc64_valid_addr_bitmap, 0, i << 3); + start_mem += i << 3; start_mem = PAGE_ALIGN(start_mem); num_physpages = 0; @@ -1138,6 +1320,8 @@ if (phys_base) { mem_map[0].flags |= (1<> PAGE_SHIFT); + mem_map[1].flags |= (1<> PAGE_SHIFT); } addr = PAGE_OFFSET + phys_base; @@ -1148,6 +1332,7 @@ else #endif mem_map[MAP_NR(addr)].flags |= (1<> 22, sparc64_valid_addr_bitmap); addr += PAGE_SIZE; } @@ -1159,6 +1344,9 @@ if (PageSkip(page)) { unsigned long low, high; + /* See taint_real_pages() for why this is done. -DaveM */ + page++; + low = PAGE_ALIGN((unsigned long)(page+1)); if (page->next_hash < page) high = ((unsigned long)end) & PAGE_MASK; @@ -1255,7 +1443,7 @@ val->totalram = 0; val->sharedram = 0; - val->freeram = nr_free_pages << PAGE_SHIFT; + val->freeram = ((unsigned long)nr_free_pages) << PAGE_SHIFT; val->bufferram = buffermem; for (page = mem_map, end = mem_map + max_mapnr; page < end; page++) { diff -ur --new-file old/linux/arch/sparc64/mm/ultra.S new/linux/arch/sparc64/mm/ultra.S --- old/linux/arch/sparc64/mm/ultra.S Mon Nov 16 19:37:28 1998 +++ new/linux/arch/sparc64/mm/ultra.S Sun Mar 28 19:07:47 1999 @@ -1,4 +1,4 @@ -/* $Id: ultra.S,v 1.31 1998/11/07 06:39:21 davem Exp $ +/* $Id: ultra.S,v 1.32 1999/03/28 08:39:34 davem Exp $ * ultra.S: Don't expand these all over the place... * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -260,6 +260,21 @@ nop b,pt %xcc, rtrap clr %l6 + + .globl xcall_receive_signal +xcall_receive_signal: + rdpr %pstate, %g2 + wrpr %g2, PSTATE_IG | PSTATE_AG, %pstate + rdpr %tstate, %g1 + andcc %g1, TSTATE_PRIV, %g0 + /* If we did not trap from user space, just ignore. */ + bne,pn %xcc, 99f + sethi %hi(109f), %g7 + b,pt %xcc, etrap +109: or %g7, %lo(109b), %g7 + b,pt %xcc, rtrap + clr %l6 +99: retry /* These two are not performance critical... */ .globl xcall_flush_tlb_all diff -ur --new-file old/linux/arch/sparc64/prom/memory.c new/linux/arch/sparc64/prom/memory.c --- old/linux/arch/sparc64/prom/memory.c Mon Mar 17 23:54:24 1997 +++ new/linux/arch/sparc64/prom/memory.c Thu Mar 11 01:53:37 1999 @@ -1,4 +1,4 @@ -/* $Id: memory.c,v 1.3 1997/03/04 16:27:10 jj Exp $ +/* $Id: memory.c,v 1.4 1998/11/25 10:04:06 jj Exp $ * memory.c: Prom routine for acquiring various bits of information * about RAM on the machine, both virtual and physical. * @@ -41,8 +41,8 @@ prom_sortmemlist(struct linux_mlist_p1275 *thislist)) { int swapi = 0; - int i, mitr, tmpsize; - unsigned long tmpaddr; + int i, mitr; + unsigned long tmpaddr, tmpsize; unsigned long lowest; for(i=0; thislist[i].theres_more != 0; i++) { @@ -79,7 +79,7 @@ prom_phys_avail[iter].start_adr = prom_reg_memlist[iter].phys_addr; prom_phys_avail[iter].num_bytes = - (unsigned long) prom_reg_memlist[iter].reg_size; + prom_reg_memlist[iter].reg_size; prom_phys_avail[iter].theres_more = &prom_phys_avail[iter+1]; } @@ -93,7 +93,7 @@ prom_phys_total[iter].start_adr = prom_reg_memlist[iter].phys_addr; prom_phys_total[iter].num_bytes = - (unsigned long) prom_reg_memlist[iter].reg_size; + prom_reg_memlist[iter].reg_size; prom_phys_total[iter].theres_more = &prom_phys_total[iter+1]; } @@ -112,7 +112,7 @@ prom_prom_taken[iter].start_adr = prom_reg_memlist[iter].phys_addr; prom_prom_taken[iter].num_bytes = - (unsigned long) prom_reg_memlist[iter].reg_size; + prom_reg_memlist[iter].reg_size; prom_prom_taken[iter].theres_more = &prom_phys_total[iter+1]; } @@ -130,7 +130,7 @@ prom_prom_taken[iter].start_adr; } prom_prom_taken[iter-1].num_bytes = - ((unsigned long)-1) - (unsigned long) prom_prom_taken[iter-1].start_adr; + -1UL - prom_prom_taken[iter-1].start_adr; /* Sort the other two lists. */ prom_sortmemlist(prom_phys_total); diff -ur --new-file old/linux/arch/sparc64/prom/misc.c new/linux/arch/sparc64/prom/misc.c --- old/linux/arch/sparc64/prom/misc.c Tue Oct 27 18:52:21 1998 +++ new/linux/arch/sparc64/prom/misc.c Thu Mar 11 01:53:37 1999 @@ -1,4 +1,4 @@ -/* $Id: misc.c,v 1.13 1998/10/13 14:03:49 davem Exp $ +/* $Id: misc.c,v 1.14 1998/12/18 10:01:59 davem Exp $ * misc.c: Miscellaneous prom functions that don't belong * anywhere else. * @@ -122,9 +122,123 @@ p1275_cmd("SUNW,set-trap-table", P1275_INOUT(1, 0), tba); } +/* This is only used internally below. */ +static int prom_get_mmu_ihandle(void) +{ + int node; + int ret; + + node = prom_finddevice("/chosen"); + ret = prom_getint(node, "mmu"); + if(ret == -1 || ret == 0) { + prom_printf("PROMLIB: Fatal error, cannot get mmu ihandle.\n"); + prom_halt(); + } + return ret; +} + +/* Load explicit I/D TLB entries. */ +long prom_itlb_load(unsigned long index, + unsigned long tte_data, + unsigned long vaddr) +{ + return p1275_cmd("call-method", + (P1275_ARG(0, P1275_ARG_IN_BUF) | P1275_INOUT(5, 1)), + "SUNW,itlb-load", + prom_get_mmu_ihandle(), + /* And then our actual args are pushed backwards. */ + vaddr, + tte_data, + index); +} + +long prom_dtlb_load(unsigned long index, + unsigned long tte_data, + unsigned long vaddr) +{ + return p1275_cmd("call-method", + (P1275_ARG(0, P1275_ARG_IN_BUF) | P1275_INOUT(5, 1)), + "SUNW,dtlb-load", + prom_get_mmu_ihandle(), + /* And then our actual args are pushed backwards. */ + vaddr, + tte_data, + index); +} + +/* Set aside physical memory which is not touched or modified + * across soft resets. + */ +unsigned long prom_retain(char *name, + unsigned long pa_low, unsigned long pa_high, + long size, long align) +{ + /* XXX I don't think we return multiple values correctly. + * XXX OBP supposedly returns pa_low/pa_high here, how does + * XXX it work? + */ + + /* If align is zero, the pa_low/pa_high args are passed, + * else they are not. + */ + if(align == 0) + return p1275_cmd("SUNW,retain", + (P1275_ARG(0, P1275_ARG_IN_BUF) | P1275_INOUT(5, 2)), + name, pa_low, pa_high, size, align); + else + return p1275_cmd("SUNW,retain", + (P1275_ARG(0, P1275_ARG_IN_BUF) | P1275_INOUT(3, 2)), + name, size, align); +} + +/* Get "Unumber" string for the SIMM at the given + * memory address. Usually this will be of the form + * "Uxxxx" where xxxx is a decimal number which is + * etched into the motherboard next to the SIMM slot + * in question. + */ +int prom_getunumber(unsigned long phys_lo, unsigned long phys_hi, + char *buf, int buflen) +{ + return p1275_cmd("SUNW,get-unumber", + (P1275_ARG(2, P1275_ARG_OUT_BUF) | P1275_INOUT(4, 1)), + phys_lo, phys_hi, buf, buflen); +} + +/* Power management extensions. */ +void prom_sleepself(void) +{ + p1275_cmd("SUNW,sleep-self", P1275_INOUT(0, 0)); +} + +int prom_sleepsystem(void) +{ + return p1275_cmd("SUNW,sleep-system", P1275_INOUT(0, 1)); +} + +int prom_wakeupsystem(void) +{ + return p1275_cmd("SUNW,wakeup-system", P1275_INOUT(0, 1)); +} + #ifdef __SMP__ void prom_startcpu(int cpunode, unsigned long pc, unsigned long o0) { p1275_cmd("SUNW,start-cpu", P1275_INOUT(3, 0), cpunode, pc, o0); +} + +void prom_stopself(void) +{ + p1275_cmd("SUNW,stop-self", P1275_INOUT(0, 0)); +} + +void prom_idleself(void) +{ + p1275_cmd("SUNW,idle-self", P1275_INOUT(0, 0)); +} + +void prom_resumecpu(int cpunode) +{ + p1275_cmd("SUNW,resume-cpu", P1275_INOUT(1, 0), cpunode); } #endif diff -ur --new-file old/linux/arch/sparc64/solaris/fs.c new/linux/arch/sparc64/solaris/fs.c --- old/linux/arch/sparc64/solaris/fs.c Mon Nov 16 19:37:28 1998 +++ new/linux/arch/sparc64/solaris/fs.c Thu Mar 11 01:53:37 1999 @@ -1,4 +1,4 @@ -/* $Id: fs.c,v 1.11 1998/10/28 08:12:04 jj Exp $ +/* $Id: fs.c,v 1.12 1999/01/02 16:46:06 davem Exp $ * fs.c: fs related syscall emulation for Solaris * * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -21,7 +22,6 @@ #include "conv.h" extern char * getname32(u32 filename); -#define putname32 putname #define R4_DEV(DEV) ((DEV & 0xff) | ((DEV & 0xff00) << 10)) #define R4_MAJOR(DEV) (((DEV) >> 18) & 0x3fff) @@ -138,7 +138,7 @@ set_fs (KERNEL_DS); ret = sys_newstat(filenam, &s); set_fs (old_fs); - putname32 (filenam); + putname (filenam); if (putstat ((struct sol_stat *)A(statbuf), &s)) return -EFAULT; } @@ -166,7 +166,7 @@ set_fs (KERNEL_DS); ret = sys_newstat(filenam, &s); set_fs (old_fs); - putname32 (filenam); + putname (filenam); if (putstat64 ((struct sol_stat64 *)A(statbuf), &s)) return -EFAULT; } @@ -188,7 +188,7 @@ set_fs (KERNEL_DS); ret = sys_newlstat(filenam, &s); set_fs (old_fs); - putname32 (filenam); + putname (filenam); if (putstat ((struct sol_stat *)A(statbuf), &s)) return -EFAULT; } @@ -215,7 +215,7 @@ set_fs (KERNEL_DS); ret = sys_newlstat(filenam, &s); set_fs (old_fs); - putname32 (filenam); + putname (filenam); if (putstat64 ((struct sol_stat64 *)A(statbuf), &s)) return -EFAULT; } diff -ur --new-file old/linux/arch/sparc64/solaris/systbl.S new/linux/arch/sparc64/solaris/systbl.S --- old/linux/arch/sparc64/solaris/systbl.S Mon Nov 16 19:37:28 1998 +++ new/linux/arch/sparc64/solaris/systbl.S Thu Mar 11 01:53:37 1999 @@ -1,4 +1,4 @@ -/* $Id: systbl.S,v 1.7 1998/10/28 08:11:49 jj Exp $ +/* $Id: systbl.S,v 1.8 1999/02/11 18:34:02 davem Exp $ * systbl.S: System call entry point table for Solaris compatibility. * * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -72,7 +72,7 @@ .word CHAIN(dup) /* dup d 41 */ .word CHAIN(pipe) /* pipe 42 */ .word CHAIN(times) /* times p 43 */ - .word CHAIN(profil) /* prof xxxx 44 */ + .word 44 /*CHAIN(profil)*/ /* prof xxxx 44 */ .word solaris_unimplemented /* lock/plock 45 */ .word CHAIN(setgid) /* setgid d 46 */ .word solaris_getgid /* getgid 47 */ diff -ur --new-file old/linux/drivers/Makefile new/linux/drivers/Makefile --- old/linux/drivers/Makefile Thu Jun 3 02:11:11 1999 +++ new/linux/drivers/Makefile Thu Jun 3 02:12:04 1999 @@ -10,7 +10,7 @@ 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 atm + macintosh video dio zorro fc4 usb atm ifdef CONFIG_DIO SUB_DIRS += dio @@ -43,6 +43,15 @@ SUB_DIRS += macintosh MOD_SUB_DIRS += macintosh endif + +ifeq ($(CONFIG_USB),y) +SUB_DIRS += usb +MOD_SUB_DIRS += usb +else + ifeq ($(CONFIG_USB),m) + MOD_SUB_DIRS += usb + endif +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 -ur --new-file old/linux/drivers/acorn/char/keyb_ps2.c new/linux/drivers/acorn/char/keyb_ps2.c --- old/linux/drivers/acorn/char/keyb_ps2.c Thu Dec 17 18:07:45 1998 +++ new/linux/drivers/acorn/char/keyb_ps2.c Mon Apr 26 22:31:49 1999 @@ -221,11 +221,6 @@ }; #endif -int ps2kbd_pretranslate(unsigned char scancode) -{ - return 1; -} - int ps2kbd_translate(unsigned char scancode, unsigned char *keycode_p, char *uf_p) { *uf_p = scancode & 0200; @@ -235,7 +230,7 @@ static void ps2kbd_key(unsigned int keycode, unsigned int up_flag) { - handle_scancode(keycode + (up_flag ? 0x80 : 0)); + handle_scancode(keycode, !up_flag); } static inline void ps2kbd_sendbyte(unsigned char val) diff -ur --new-file old/linux/drivers/ap1000/apfddi.c new/linux/drivers/ap1000/apfddi.c --- old/linux/drivers/ap1000/apfddi.c Fri May 8 09:47:24 1998 +++ new/linux/drivers/ap1000/apfddi.c Thu Mar 11 01:51:35 1999 @@ -30,7 +30,6 @@ #include #include -#include #include #include #include diff -ur --new-file old/linux/drivers/ap1000/ringbuf.c new/linux/drivers/ap1000/ringbuf.c --- old/linux/drivers/ap1000/ringbuf.c Mon Aug 24 22:14:10 1998 +++ new/linux/drivers/ap1000/ringbuf.c Thu Mar 11 01:51:35 1999 @@ -22,7 +22,6 @@ #include #include #include -#include #include #include diff -ur --new-file old/linux/drivers/block/Config.in new/linux/drivers/block/Config.in --- old/linux/drivers/block/Config.in Tue Dec 29 20:21:49 1998 +++ new/linux/drivers/block/Config.in Thu Apr 29 21:53:48 1999 @@ -51,13 +51,15 @@ bool ' Winbond SL82c105 support' CONFIG_BLK_DEV_SL82C105 fi fi - if [ "$CONFIG_PMAC" = "y" ]; then - define_bool CONFIG_BLK_DEV_IDE_PMAC y - bool ' PowerMac IDE DMA support' CONFIG_BLK_DEV_IDEDMA_PMAC - if [ "$CONFIG_BLK_DEV_IDEDMA_PMAC" = "y" ]; then - define_bool CONFIG_BLK_DEV_IDEDMA y - bool ' Use DMA by default' CONFIG_PMAC_IDEDMA_AUTO - fi + if [ "$CONFIG_PMAC" = "y" -o "$CONFIG_ALL_PPC" = "y" ]; then + bool ' Builtin PowerMac IDE support' CONFIG_BLK_DEV_IDE_PMAC + if [ "$CONFIG_BLK_DEV_IDE_PMAC" != "n" ]; then + bool ' PowerMac IDE DMA support' CONFIG_BLK_DEV_IDEDMA_PMAC + if [ "$CONFIG_BLK_DEV_IDEDMA_PMAC" = "y" ]; then + define_bool CONFIG_BLK_DEV_IDEDMA y + bool ' Use DMA by default' CONFIG_PMAC_IDEDMA_AUTO + fi + fi fi bool ' Other IDE chipset support' CONFIG_IDE_CHIPSETS if [ "$CONFIG_IDE_CHIPSETS" = "y" ]; then diff -ur --new-file old/linux/drivers/block/Makefile new/linux/drivers/block/Makefile --- old/linux/drivers/block/Makefile Wed Sep 16 22:25:56 1998 +++ new/linux/drivers/block/Makefile Tue Apr 13 01:18:27 1999 @@ -220,6 +220,10 @@ ifeq ($(CONFIG_BLK_DEV_PS2),y) L_OBJS += ps2esdi.o +else + ifeq ($(CONFIG_BLK_DEV_PS2),m) + M_OBJS += ps2esdi.o + endif endif ifeq ($(CONFIG_BLK_DEV_XD),y) diff -ur --new-file old/linux/drivers/block/cmd646.c new/linux/drivers/block/cmd646.c --- old/linux/drivers/block/cmd646.c Wed Aug 5 01:56:37 1998 +++ new/linux/drivers/block/cmd646.c Tue Mar 16 01:11:29 1999 @@ -1,4 +1,4 @@ -/* $Id: cmd646.c,v 1.10 1998/08/03 15:28:42 davem Exp $ +/* $Id: cmd646.c,v 1.11 1998/12/13 08:36:54 davem Exp $ * cmd646.c: Enable interrupts at initialization time on Ultra/PCI machines. * Note, this driver is not used at all on other systems because * there the "BIOS" has done all of the following already. @@ -219,8 +219,11 @@ hwif->chipset = ide_cmd646; - /* Set a good latency timer value. */ - (void) pci_write_config_byte(dev, PCI_LATENCY_TIMER, 240); + /* Set a good latency timer and cache line size value. */ + (void) pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64); +#ifdef __sparc_v9__ + (void) pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 0x10); +#endif /* Setup interrupts. */ (void) pci_read_config_byte(dev, 0x71, &mrdmode); diff -ur --new-file old/linux/drivers/block/floppy.c new/linux/drivers/block/floppy.c --- old/linux/drivers/block/floppy.c Sun Jan 10 18:59:59 1999 +++ new/linux/drivers/block/floppy.c Fri Mar 26 22:29:14 1999 @@ -3592,7 +3592,7 @@ /* read drive info out of physical CMOS */ drive=0; if (!UDP->cmos) - UDP->cmos= FLOPPY0_TYPE; + UDP->cmos = FLOPPY0_TYPE; drive=1; if (!UDP->cmos && FLOPPY1_TYPE) UDP->cmos = FLOPPY1_TYPE; @@ -3601,26 +3601,31 @@ /* additional physical CMOS drive detection should go here */ for (drive=0; drive < N_DRIVE; drive++){ - if (UDP->cmos >= 16) - UDP->cmos = 0; - if (UDP->cmos >= 0 && UDP->cmos <= NUMBER(default_drive_params)) - memcpy((char *) UDP, - (char *) (&default_drive_params[(int)UDP->cmos].params), - sizeof(struct floppy_drive_params)); - if (UDP->cmos){ - if (first) - printk(KERN_INFO "Floppy drive(s): "); - else - printk(", "); - first=0; - if (UDP->cmos > 0){ + unsigned int type = UDP->cmos; + struct floppy_drive_params *params; + const char *name = NULL; + static char temparea[32]; + + if (type < NUMBER(default_drive_params)) { + params = &default_drive_params[type].params; + if (type) { + name = default_drive_params[type].name; allowed_drive_mask |= 1 << drive; - printk("fd%d is %s", drive, - default_drive_params[(int)UDP->cmos].name); - } else - printk("fd%d is unknown type %d",drive, - UDP->cmos); + } + } else { + params = &default_drive_params[0].params; + sprintf(temparea, "unknown type %d (usb?)", type); + name = temparea; + } + if (name) { + const char * prepend = ","; + if (first) { + prepend = KERN_INFO "Floppy drive(s):"; + first = 0; + } + printk("%s fd%d is %s", prepend, drive, name); } + *UDP = *params; } if (!first) printk("\n"); @@ -4020,11 +4025,6 @@ } if (current_drive >= 4 && !FDC2) FDC2 = 0x370; - if (ints[2] <= 0 || - (ints[2] >= NUMBER(default_drive_params) && ints[2] != 16)){ - DPRINT("bad CMOS code %d\n", ints[2]); - return; - } DP->cmos = ints[2]; DPRINT("setting CMOS code to %d\n", ints[2]); } diff -ur --new-file old/linux/drivers/block/genhd.c new/linux/drivers/block/genhd.c --- old/linux/drivers/block/genhd.c Thu Jun 3 02:11:12 1999 +++ new/linux/drivers/block/genhd.c Thu Jun 3 02:12:05 1999 @@ -131,6 +131,14 @@ SYS_IND(p) == LINUX_EXTENDED_PARTITION); } +static int sector_partition_scale(kdev_t dev) +{ + if (hardsect_size[MAJOR(dev)] != NULL) + return (hardsect_size[MAJOR(dev)][MINOR(dev)]/512); + else + return (1); +} + static unsigned int get_ptable_blocksize(kdev_t dev) { int ret = 1024; @@ -150,6 +158,7 @@ * 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: @@ -197,6 +206,7 @@ struct partition *p; unsigned long first_sector, first_size, this_sector, this_size; int mask = (1 << hd->minor_shift) - 1; + int sector_size = sector_partition_scale(dev); int i; first_sector = hd->part[MINOR(dev)].start_sect; @@ -234,22 +244,22 @@ * First process the data partition(s) */ for (i=0; i<4; i++, p++) { - if (!NR_SECTS(p) || is_extended_partition(p)) - continue; + if (!NR_SECTS(p) || is_extended_partition(p)) + continue; - /* Check the 3rd and 4th entries - - these sometimes contain random garbage */ - if (i >= 2 - && START_SECT(p) + NR_SECTS(p) > this_size - && (this_sector + START_SECT(p) < first_sector || - this_sector + START_SECT(p) + NR_SECTS(p) > - first_sector + first_size)) - continue; - - add_partition(hd, current_minor, this_sector+START_SECT(p), NR_SECTS(p)); - current_minor++; - if ((current_minor & mask) == 0) - goto done; + /* Check the 3rd and 4th entries - + these sometimes contain random garbage */ + if (i >= 2 + && START_SECT(p) + NR_SECTS(p) > this_size + && (this_sector + START_SECT(p) < first_sector || + this_sector + START_SECT(p) + NR_SECTS(p) > + first_sector + first_size)) + continue; + + add_partition(hd, current_minor, this_sector+START_SECT(p)*sector_size, NR_SECTS(p)*sector_size); + current_minor++; + if ((current_minor & mask) == 0) + goto done; } /* * Next, process the (first) extended partition, if present. @@ -263,20 +273,21 @@ */ p -= 4; for (i=0; i<4; i++, p++) - if(NR_SECTS(p) && is_extended_partition(p)) - break; + if(NR_SECTS(p) && is_extended_partition(p)) + break; if (i == 4) - goto done; /* nothing left to do */ + goto done; /* nothing left to do */ - hd->part[current_minor].nr_sects = NR_SECTS(p); - hd->part[current_minor].start_sect = first_sector + START_SECT(p); - this_sector = first_sector + START_SECT(p); + hd->part[current_minor].nr_sects = NR_SECTS(p) * sector_size; /* JSt */ + hd->part[current_minor].start_sect = first_sector + START_SECT(p) * sector_size; + this_sector = first_sector + START_SECT(p) * sector_size; dev = MKDEV(hd->major, current_minor); brelse(bh); } done: brelse(bh); } + #ifdef CONFIG_SOLARIS_X86_PARTITION static void solaris_x86_partition(struct gendisk *hd, kdev_t dev, long offset) { @@ -318,11 +329,13 @@ #endif #ifdef CONFIG_BSD_DISKLABEL -static void check_and_add_bsd_partition(struct gendisk *hd, struct bsd_partition *bsd_p) +static void check_and_add_bsd_partition(struct gendisk *hd, + struct bsd_partition *bsd_p, kdev_t dev) { struct hd_struct *lin_p; /* check relative position of partitions. */ - for (lin_p = hd->part + 1; lin_p - hd->part < current_minor; lin_p++) { + for (lin_p = hd->part + 1 + MINOR(dev); + lin_p - hd->part - MINOR(dev) < current_minor; lin_p++) { /* no relationship -> try again */ if (lin_p->start_sect + lin_p->nr_sects <= bsd_p->p_offset || lin_p->start_sect >= bsd_p->p_offset + bsd_p->p_size) @@ -384,7 +397,7 @@ break; if (p->p_fstype != BSD_FS_UNUSED) - check_and_add_bsd_partition(hd, p); + check_and_add_bsd_partition(hd, p, dev); } brelse(bh); @@ -437,6 +450,7 @@ struct partition *p; unsigned char *data; int mask = (1 << hd->minor_shift) - 1; + int sector_size = sector_partition_scale(dev); #ifdef CONFIG_BSD_DISKLABEL /* no bsd disklabel as a default */ kdev_t bsd_kdev = 0; @@ -539,7 +553,7 @@ for (i=1 ; i<=4 ; minor++,i++,p++) { if (!NR_SECTS(p)) continue; - add_partition(hd, minor, first_sector+START_SECT(p), NR_SECTS(p)); + add_partition(hd, minor, first_sector+START_SECT(p)*sector_size, NR_SECTS(p)*sector_size); if (is_extended_partition(p)) { printk(" <"); /* @@ -763,11 +777,14 @@ #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; struct buffer_head *bh; struct sgi_disklabel { int magic_mushroom; /* Big fat spliff... */ @@ -791,21 +808,24 @@ struct sgi_partition *p; #define SGI_LABEL_MAGIC 0x0be5a941 - if(!(bh = bread(dev, 0, 1024))) { + if(!(bh = bread(dev, 0, get_ptable_blocksize(dev)))) { printk("Dev %s: unable to read partition table\n", kdevname(dev)); return -1; } label = (struct sgi_disklabel *) bh->b_data; p = &label->partitions[0]; - if(label->magic_mushroom != SGI_LABEL_MAGIC) { + magic = label->magic_mushroom; + if(be32_to_cpu(magic) != SGI_LABEL_MAGIC) { printk("Dev %s SGI disklabel: bad magic %08x\n", - kdevname(dev), label->magic_mushroom); + kdevname(dev), magic); brelse(bh); return 0; } ui = ((unsigned int *) (label + 1)) - 1; - for(csum = 0; ui >= ((unsigned int *) label);) - csum += *ui--; + for(csum = 0; ui >= ((unsigned int *) label);) { + cs = *ui--; + csum += be32_to_cpu(cs); + } if(csum) { printk("Dev %s SGI disklabel: csum bad, label corrupted\n", kdevname(dev)); @@ -818,9 +838,11 @@ * current_minor. */ for(i = 0; i < 16; i++, p++) { - if(!(p->num_blocks)) + blocks = be32_to_cpu(p->num_blocks); + start = be32_to_cpu(p->first_block); + if(!blocks) continue; - add_partition(hd, current_minor, p->first_block, p->num_blocks); + add_partition(hd, current_minor, start, blocks); current_minor++; } printk("\n"); @@ -854,12 +876,20 @@ int nr_sects; int blk; int part, res; + int old_blocksize; + int blocksize; - set_blocksize(dev,512); + old_blocksize = get_ptable_blocksize(dev); + if (hardsect_size[MAJOR(dev)] != NULL) + blocksize = hardsect_size[MAJOR(dev)][MINOR(dev)]; + else + blocksize = 512; + + set_blocksize(dev,blocksize); res = 0; for (blk = 0; blk < RDB_ALLOCATION_LIMIT; blk++) { - if(!(bh = bread(dev,blk,512))) { + if(!(bh = bread(dev,blk,blocksize))) { printk("Dev %s: unable to read RDB block %d\n", kdevname(dev),blk); goto rdb_done; @@ -867,16 +897,25 @@ if (*(u32 *)bh->b_data == htonl(IDNAME_RIGIDDISK)) { rdb = (struct RigidDiskBlock *)bh->b_data; if (checksum_block((u32 *)bh->b_data,htonl(rdb->rdb_SummedLongs) & 0x7F)) { - printk("Dev %s: RDB in block %d has bad checksum\n", - kdevname(dev),blk); - brelse(bh); - continue; + /* Try again with 0xdc..0xdf zeroed, Windows might have + * trashed it. + */ + *(u32 *)(&bh->b_data[0xdc]) = 0; + if (checksum_block((u32 *)bh->b_data, + htonl(rdb->rdb_SummedLongs) & 0x7F)) { + brelse(bh); + printk("Dev %s: RDB in block %d has bad checksum\n", + kdevname(dev),blk); + continue; + } + printk("Warning: Trashed word at 0xd0 in block %d " + "ignored in checksum calculation\n",blk); } printk(" RDSK"); blk = htonl(rdb->rdb_PartitionList); brelse(bh); for (part = 1; blk > 0 && part <= 16; part++) { - if (!(bh = bread(dev,blk,512))) { + if (!(bh = bread(dev,blk,blocksize))) { printk("Dev %s: unable to read partition block %d\n", kdevname(dev),blk); goto rdb_done; @@ -909,7 +948,7 @@ } rdb_done: - set_blocksize(dev,BLOCK_SIZE); + set_blocksize(dev,old_blocksize); return res; } #endif /* CONFIG_AMIGA_PARTITION */ @@ -1090,7 +1129,7 @@ partsect = extensect = pi->st; while (1) { - xbh = bread (dev, partsect / 2, 1024); + xbh = bread (dev, partsect / 2, get_ptable_blocksize(dev)); if (!xbh) { printk (" block %ld read failed\n", partsect); diff -ur --new-file old/linux/drivers/block/hd.c new/linux/drivers/block/hd.c --- old/linux/drivers/block/hd.c Thu Jan 14 19:31:41 1999 +++ new/linux/drivers/block/hd.c Thu Feb 25 01:27:53 1999 @@ -744,11 +744,12 @@ */ - if ((cmos_disks = CMOS_READ(0x12)) & 0xf0) + if ((cmos_disks = CMOS_READ(0x12)) & 0xf0) { if (cmos_disks & 0x0f) NR_HD = 2; else NR_HD = 1; + } } #endif /* __i386__ */ for (drive=0 ; drive < NR_HD ; drive++) { diff -ur --new-file old/linux/drivers/block/ide-cd.c new/linux/drivers/block/ide-cd.c --- old/linux/drivers/block/ide-cd.c Tue Jan 19 20:10:07 1999 +++ new/linux/drivers/block/ide-cd.c Tue Apr 13 01:18:26 1999 @@ -33,6 +33,7 @@ * boot * -Integrate DVD-ROM support in driver. Thanks to Merete Gotsæd-Petersen * of Pioneer Denmark for providing me with a drive for testing. + * -Implement Features and Profiles. * * * ---------------------------------- @@ -230,9 +231,23 @@ * 4.52 Jan 19, 1999 -- Jens Axboe * - Detect DVD-ROM/RAM drives * + * 4.53 Feb 22, 1999 - Include other model Samsung and one Goldstar + * drive in transfer size limit. + * - Fix the I/O error when doing eject without a medium + * loaded on some drives. + * - CDROMREADMODE2 is now implemented through + * CDROMREADRAW, since many drives don't support + * MODE2 (even though ATAPI 2.6 says they must). + * - Added ignore parameter to ide-cd (as a module), eg + * insmod ide-cd ignore='hda hdb' + * Useful when using ide-cd in conjunction with + * ide-scsi. TODO: non-modular way of doing the + * same. + * + * *************************************************************************/ -#define IDECD_VERSION "4.52" +#define IDECD_VERSION "4.53" #include #include @@ -252,7 +267,6 @@ #include "ide.h" #include "ide-cd.h" - /**************************************************************************** * Generic packet command support and error handling routines. */ @@ -1527,6 +1541,10 @@ CDROM_CONFIG_FLAGS (drive)->no_doorlock = 1; stat = 0; } + + /* no medium, that's alright. */ + if (stat != 0 && reqbuf->sense_key == NOT_READY && reqbuf->asc == 0x3a) + stat = 0; if (stat == 0) CDROM_STATE_FLAGS (drive)->door_locked = lockflag; @@ -1806,7 +1824,6 @@ return cdrom_queue_packet_command (drive, &pc); } - /* ATAPI cdrom drives are free to select the speed you request or any slower rate :-( Requesting too fast a speed will _not_ produce an error. */ static int @@ -2092,22 +2109,17 @@ if (cmd == CDROMREADMODE1) { blocksize = CD_FRAMESIZE; format = 2; - } else if (cmd == CDROMREADMODE2) { - blocksize = CD_FRAMESIZE_RAW0; - format = 3; - } else { + } else { /* for RAW and MODE2. */ blocksize = CD_FRAMESIZE_RAW; format = 0; } - stat = verify_area (VERIFY_WRITE, (char *)arg, blocksize); - if (stat) return stat; + + copy_from_user_ret(&msf, (void *)arg, sizeof (msf), -EFAULT); - copy_from_user (&msf, (void *)arg, sizeof (msf)); + lba = msf_to_lba(msf.cdmsf_min0, + msf.cdmsf_sec0, + msf.cdmsf_frame0); - lba = msf_to_lba (msf.cdmsf_min0, - msf.cdmsf_sec0, - msf.cdmsf_frame0); - /* Make sure the TOC is up to date. */ stat = cdrom_read_toc (drive, NULL); if (stat) return stat; @@ -2117,14 +2129,21 @@ if (lba < 0 || lba >= toc->capacity) return -EINVAL; - buf = (char *) kmalloc (CD_FRAMESIZE_RAW, GFP_KERNEL); + buf = (char *) kmalloc (blocksize, GFP_KERNEL); if (buf == NULL) return -ENOMEM; stat = cdrom_read_block (drive, format, lba, 1, buf, blocksize, NULL); - if (stat == 0) - copy_to_user ((char *)arg, buf, blocksize); + + if (stat == 0) { + if (cmd == CDROMREADMODE2) { + /* For Mode2, skip the Sync, Header, and Subheader */ + copy_to_user_ret((char *)arg, buf+16, CD_FRAMESIZE_RAW0, -EFAULT); + } else { + copy_to_user_ret((char *)arg, buf, blocksize, -EFAULT); + } + } kfree (buf); return stat; @@ -2486,14 +2505,12 @@ static int ide_cdrom_reset (struct cdrom_device_info *cdi) { - ide_drive_t *drive = (ide_drive_t*) cdi->handle; struct request req; ide_init_drive_cmd (&req); req.cmd = RESET_DRIVE_COMMAND; return ide_do_drive_cmd (drive, &req, ide_wait); - } @@ -2501,9 +2518,10 @@ int ide_cdrom_tray_move (struct cdrom_device_info *cdi, int position) { ide_drive_t *drive = (ide_drive_t*) cdi->handle; + struct atapi_request_sense rq; if (position) { - int stat = cdrom_lockdoor (drive, 0, NULL); + int stat = cdrom_lockdoor (drive, 0, &rq); if (stat) return stat; } @@ -2980,12 +2998,14 @@ CDROM_CONFIG_FLAGS (drive)->no_eject = 1; CDROM_CONFIG_FLAGS (drive)->supp_disc_present = 0; - /* limit transfer size per interrupt. currently only one Samsung - drive needs this. */ + /* limit transfer size per interrupt. */ CDROM_CONFIG_FLAGS (drive)->limit_nframes = 0; - if (drive->id != NULL) - if (strcmp (drive->id->model, "SAMSUNG CD-ROM SCR-2432") == 0) + if (drive->id != NULL) { + if (!strcmp(drive->id->model, "SAMSUNG CD-ROM SCR-2430")) CDROM_CONFIG_FLAGS (drive)->limit_nframes = 1; + else if (!strcmp(drive->id->model, "SAMSUNG CD-ROM SCR-2432")) + CDROM_CONFIG_FLAGS (drive)->limit_nframes = 1; + } #if ! STANDARD_ATAPI /* by default Sanyo 3 CD changer support is turned off and @@ -3155,7 +3175,13 @@ NULL }; +/* options */ +char *ignore = NULL; + #ifdef MODULE +MODULE_PARM(ignore, "s"); +MODULE_DESCRIPTION("ATAPI CD-ROM Driver"); + int init_module (void) { return ide_cdrom_init(); @@ -3183,6 +3209,12 @@ MOD_INC_USE_COUNT; while ((drive = ide_scan_devices (ide_cdrom, ide_cdrom_driver.name, NULL, failed++)) != NULL) { + /* skip drives that we were told to ignore */ + if (ignore != NULL) + if (strstr(ignore, drive->name)) { + printk("ide-cd: ignoring drive %s\n", drive->name); + continue; + } info = (struct cdrom_info *) kmalloc (sizeof (struct cdrom_info), GFP_KERNEL); if (info == NULL) { printk ("%s: Can't allocate a cdrom structure\n", drive->name); diff -ur --new-file old/linux/drivers/block/ide-cd.h new/linux/drivers/block/ide-cd.h --- old/linux/drivers/block/ide-cd.h Thu Jan 28 21:41:20 1999 +++ new/linux/drivers/block/ide-cd.h Tue May 11 19:35:45 1999 @@ -85,6 +85,9 @@ #define MECHANISM_STATUS 0xbd #define READ_CD 0xbe +/* DVD Opcodes */ +#define DVD_GET_PERFORMANCE 0xac + /* Page codes for mode sense/set */ @@ -331,13 +334,13 @@ #if defined(__BIG_ENDIAN_BITFIELD) __u8 reserved3 : 2; - /* Drive can fake writes */ - __u8 test_write : 1; - __u8 reserved3a : 1; - /* Drive can write DVD-R discs */ - __u8 dvd_r_write : 1; /* Drive can write DVD-RAM discs */ __u8 dvd_ram_write : 1; + /* Drive can write DVD-R discs */ + __u8 dvd_r_write : 1; + __u8 reserved3a : 1; + /* Drive can fake writes */ + __u8 test_write : 1; /* Drive can write to CD-R/W (CD-E) discs (orange book, part III) */ __u8 cd_rw_write : 1; /* reserved in 1.2 */ /* Drive supports write to CD-R discs (orange book, part II) */ @@ -347,20 +350,20 @@ __u8 cd_r_write : 1; /* reserved in 1.2 */ /* Drive can write to CD-R/W (CD-E) discs (orange book, part III) */ __u8 cd_rw_write : 1; /* reserved in 1.2 */ - /* Drive can write DVD-RAM discs */ - __u8 dvd_ram_write : 1; - /* Drive can write DVD-R discs */ - __u8 dvd_r_write : 1; - __u8 reserved3a : 1; /* Drive can fake writes */ __u8 test_write : 1; + __u8 reserved3a : 1; + /* Drive can write DVD-R discs */ + __u8 dvd_r_write : 1; + /* Drive can write DVD-RAM discs */ + __u8 dvd_ram_write : 1; __u8 reserved3 : 2; #else #error "Please fix " #endif #if defined(__BIG_ENDIAN_BITFIELD) - __u8 reserved4 : 4; + __u8 reserved4 : 1; /* Drive can read multisession discs. */ __u8 multisession : 1; /* Drive can read mode 2, form 2 data. */ @@ -562,7 +565,7 @@ /* Sector buffer. If a read request wants only the first part of a cdrom block, we cache the rest of the block here, - in the expectation that that data is going to be wanted soon. + in the expectation that the data is going to be wanted soon. SECTOR_BUFFERED is the number of the first buffered sector, and NSECTORS_BUFFERED is the number of sectors in the buffer. Before the buffer is allocated, we should have @@ -656,6 +659,7 @@ { PLAY_CD, "Play CD" }, { MECHANISM_STATUS, "Mechanism Status" }, { READ_CD, "Read CD" }, + { DVD_GET_PERFORMANCE, "Get Performance" }, }; @@ -776,7 +780,8 @@ { 0x6400, "Illegal mode for this track or incompatible medium" }, - { 0xb900, "Play operation oborted (sic)" }, + /* Following error is misspelled in ATAPI 2.6 */ + { 0xb900, "Play operation oborted [sic]" }, { 0xbf00, "Loss of streaming" }, }; diff -ur --new-file old/linux/drivers/block/ide-disk.c new/linux/drivers/block/ide-disk.c --- old/linux/drivers/block/ide-disk.c Fri Jan 15 07:58:47 1999 +++ new/linux/drivers/block/ide-disk.c Thu Mar 11 02:49:43 1999 @@ -101,20 +101,6 @@ id->cyls = lba_sects / (16 * 63); /* correct cyls */ return 1; /* lba_capacity is our only option */ } - /* - * This is a split test for drives less than 8 Gig only. - * Drives less than 8GB sometimes declare that they have 15 heads. - * This is an accounting trick (0-15) == (1-16), just an initial - * zero point difference. - */ - if ((id->lba_capacity < 16514064) && (lba_sects > chs_sects) && - ((id->heads == 15) || (id->heads == 16)) && (id->sectors == 63)) { - if (id->heads == 15) - id->cyls = lba_sects / (15 * 63); /* correct cyls */ - if (id->heads == 16) - id->cyls = lba_sects / (16 * 63); /* correct cyls */ - return 1; /* lba_capacity is our only option */ - } /* perform a rough sanity check on lba_sects: within 10% is "okay" */ if ((lba_sects - chs_sects) < _10_percent) { return 1; /* lba_capacity is good */ @@ -684,10 +670,15 @@ if (id == NULL) return; - /* check for removable disks (eg. SYQUEST), ignore 'WD' drives */ - if (id->config & (1<<7)) { /* removable disk ? */ + /* + * CompactFlash cards and their brethern look just like hard drives + * to us, but they are removable and don't have a doorlock mechanism. + */ + if (drive->removable && !drive_is_flashcard(drive)) { + /* + * Removable disks (eg. SYQUEST); ignore 'WD' drives + */ if (id->model[0] != 'W' || id->model[1] != 'D') { - drive->removable = 1; drive->doorlocking = 1; } } @@ -818,12 +809,6 @@ MOD_INC_USE_COUNT; while ((drive = ide_scan_devices (ide_disk, idedisk_driver.name, NULL, failed++)) != NULL) { - - /* SunDisk drives: ignore "second" drive; can mess up non-Sun systems! FIXME */ - struct hd_driveid *id = drive->id; - if (id && id->model[0] == 'S' && id->model[1] == 'u' && drive->select.b.unit) - continue; - if (ide_register_subdriver (drive, &idedisk_driver, IDE_SUBDRIVER_VERSION)) { printk (KERN_ERR "ide-disk: %s: Failed to register the driver with ide.c\n", drive->name); continue; diff -ur --new-file old/linux/drivers/block/ide-dma.c new/linux/drivers/block/ide-dma.c --- old/linux/drivers/block/ide-dma.c Mon Jan 18 03:23:01 1999 +++ new/linux/drivers/block/ide-dma.c Tue May 11 23:58:46 1999 @@ -425,7 +425,7 @@ } else { dma_base = dev->base_address[4] & PCI_BASE_ADDRESS_IO_MASK; if (!dma_base || dma_base == PCI_BASE_ADDRESS_IO_MASK) { - printk("%s: dma_base is invalid (0x%04lx, BIOS problem), please report to \n", name, dma_base); + printk("%s: dma_base is invalid (0x%04lx)\n", name, dma_base); dma_base = 0; } } diff -ur --new-file old/linux/drivers/block/ide-pmac.c new/linux/drivers/block/ide-pmac.c --- old/linux/drivers/block/ide-pmac.c Sun Nov 15 19:51:46 1998 +++ new/linux/drivers/block/ide-pmac.c Thu Mar 11 06:48:46 1999 @@ -20,13 +20,19 @@ #include #include #include +#include #include #include #include #include #include #include +#ifdef CONFIG_PMAC_PBOOK +#include +#include +#endif #include "ide.h" +#include "ide_modes.h" ide_ioreg_t pmac_ide_regbase[MAX_HWIFS]; int pmac_ide_irq[MAX_HWIFS]; @@ -41,6 +47,13 @@ static int pmac_ide_build_dmatable(ide_drive_t *drive, int wr); #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */ +#ifdef CONFIG_PMAC_PBOOK +static int idepmac_notify(struct notifier_block *, unsigned long, void *); +struct notifier_block idepmac_sleep_notifier = { + idepmac_notify +}; +#endif /* CONFIG_PMAC_PBOOK */ + /* * N.B. this can't be an initfunc, because the media-bay task can * call ide_[un]register at any time. @@ -74,6 +87,23 @@ } } +void pmac_ide_tuneproc(ide_drive_t *drive, byte pio) +{ + ide_pio_data_t d; + + if (_machine != _MACH_Pmac) + return; + pio = ide_get_best_pio_mode(drive, pio, 4, &d); + switch (pio) { + case 4: + out_le32((unsigned *)(IDE_DATA_REG + 0x200), 0x211025); + break; + default: + out_le32((unsigned *)(IDE_DATA_REG + 0x200), 0x2f8526); + break; + } +} + __initfunc(void pmac_ide_probe(void)) { @@ -145,9 +175,10 @@ pmac_ide_init_hwif_ports(hwif->io_ports, base, &hwif->irq); hwif->chipset = ide_generic; hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET]; + hwif->tuneproc = pmac_ide_tuneproc; #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC - if (np->n_addrs >= 2 && np->n_intrs >= 2) { + if (np->n_addrs >= 2) { /* has a DBDMA controller channel */ pmac_ide_setup_dma(np, hwif); } @@ -156,6 +187,10 @@ ++i; } pmac_ide_count = i; + +#ifdef CONFIG_PMAC_PBOOK + notifier_chain_register(&sleep_notifier_list, &idepmac_sleep_notifier); +#endif /* CONFIG_PMAC_PBOOK */ } #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC @@ -311,5 +346,32 @@ } return 0; } - #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */ + +#ifdef CONFIG_PMAC_PBOOK +static int idepmac_notify(struct notifier_block *this, + unsigned long code, void *p) +{ + int i, timeout; + + switch (code) { + case PBOOK_SLEEP: + /* do anything here?? */ + break; + case PBOOK_WAKE: + /* wait for the controller(s) to become ready */ + timeout = 5000; + for (i = 0; i < pmac_ide_count; ++i) { + unsigned long base = pmac_ide_regbase[i]; + if (check_media_bay_by_base(base, MB_CD) == -EINVAL) + continue; + while ((inb(base + 0x70) & BUSY_STAT) && timeout) { + mdelay(1); + --timeout; + } + } + break; + } + return NOTIFY_DONE; +} +#endif /* CONFIG_PMAC_PBOOK */ diff -ur --new-file old/linux/drivers/block/ide-probe.c new/linux/drivers/block/ide-probe.c --- old/linux/drivers/block/ide-probe.c Tue Jan 5 00:07:27 1999 +++ new/linux/drivers/block/ide-probe.c Mon Mar 22 21:44:18 1999 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/ide-probe.c Version 1.03 Dec 5, 1997 + * linux/drivers/block/ide-probe.c Version 1.04 March 10, 1999 * * Copyright (C) 1994-1998 Linus Torvalds & authors (see below) */ @@ -17,6 +17,7 @@ * Version 1.02 increase WAIT_PIDENTIFY to avoid CD-ROM locking at boot * by Andrea Arcangeli * Version 1.03 fix for (hwif->chipset == ide_4drives) + * Version 1.04 fixed buggy treatments of known flash memory cards */ #undef REALLY_SLOW_IO /* most systems can safely undef this */ @@ -84,16 +85,6 @@ drive->present = 1; /* - * Prevent long system lockup probing later for non-existant - * slave drive if the hwif is actually a Kodak CompactFlash card. - */ - if (!strcmp(id->model, "KODAK ATA_FLASH")) { - ide_drive_t *mate = &HWIF(drive)->drives[1^drive->select.b.unit]; - mate->present = 0; - mate->noprobe = 1; - } - - /* * Check for an ATAPI device */ if (cmd == WIN_PIDENTIFY) { @@ -124,6 +115,10 @@ case ide_tape: printk ("TAPE"); break; + case ide_optical: + printk ("OPTICAL"); + drive->removable = 1; + break; default: printk("UNKNOWN (type %d)", type); break; @@ -133,6 +128,20 @@ return; } + /* + * Not an ATAPI device: looks like a "regular" hard disk + */ + if (id->config & (1<<7)) + drive->removable = 1; + /* + * Prevent long system lockup probing later for non-existant + * slave drive if the hwif is actually a flash memory card of some variety: + */ + if (drive_is_flashcard(drive)) { + ide_drive_t *mate = &HWIF(drive)->drives[1^drive->select.b.unit]; + mate->present = 0; + mate->noprobe = 1; + } drive->media = ide_disk; printk("ATA DISK drive\n"); return; @@ -720,17 +729,39 @@ } if (register_blkdev (hwif->major, hwif->name, ide_fops)) { printk("%s: UNABLE TO GET MAJOR NUMBER %d\n", hwif->name, hwif->major); - } else if (init_irq (hwif)) { - printk("%s: UNABLE TO GET IRQ %d\n", hwif->name, hwif->irq); - (void) unregister_blkdev (hwif->major, hwif->name); - } else { - init_gendisk(hwif); - blk_dev[hwif->major].data = hwif; - blk_dev[hwif->major].request_fn = rfn; - blk_dev[hwif->major].queue = ide_get_queue; - read_ahead[hwif->major] = 8; /* (4kB) */ - hwif->present = 1; /* success */ + return (hwif->present = 0); + } + + if (init_irq (hwif)) { + int i = hwif->irq; + /* + * It failed to initialise. Find the default IRQ for + * this port and try that. + */ + if (!(hwif->irq = ide_default_irq(hwif->io_ports[IDE_DATA_OFFSET]))) + { + printk("%s: Disabled unable to get IRQ %d.\n", hwif->name, i); + (void) unregister_blkdev (hwif->major, hwif->name); + return (hwif->present = 0); + } + if(init_irq (hwif)) + { + printk("%s: probed IRQ %d and default IRQ %d failed.\n", + hwif->name, i, hwif->irq); + (void) unregister_blkdev (hwif->major, hwif->name); + return (hwif->present = 0); + } + printk("%s: probed IRQ %d failed, using default.\n", + hwif->name, hwif->irq); } + + init_gendisk(hwif); + blk_dev[hwif->major].data = hwif; + blk_dev[hwif->major].request_fn = rfn; + blk_dev[hwif->major].queue = ide_get_queue; + read_ahead[hwif->major] = 8; /* (4kB) */ + hwif->present = 1; /* success */ + #if (DEBUG_SPINLOCK > 0) { static int done = 0; diff -ur --new-file old/linux/drivers/block/ide.c new/linux/drivers/block/ide.c --- old/linux/drivers/block/ide.c Fri Jan 15 23:36:20 1999 +++ new/linux/drivers/block/ide.c Wed May 12 22:19:32 1999 @@ -254,6 +254,33 @@ } /* + * CompactFlash cards and their brethern pretend to be removable hard disks, except: + * (1) they never have a slave unit, and + * (2) they don't have doorlock mechanisms. + * This test catches them, and is invoked elsewhere when setting appropriate config bits. + * + * FIXME: This treatment is probably applicable for *all* PCMCIA (PC CARD) devices, + * so in linux 2.3.x we should change this to just treat all PCMCIA drives this way, + * and get rid of the model-name tests below (too big of an interface change for 2.2.x). + * At that time, we might also consider parameterizing the timeouts and retries, + * since these are MUCH faster than mechanical drives. -M.Lord + */ +int drive_is_flashcard (ide_drive_t *drive) +{ + struct hd_driveid *id = drive->id; + + if (drive->removable && id != NULL) { + if (!strncmp(id->model, "KODAK ATA_FLASH", 15) /* Kodak */ + || !strncmp(id->model, "Hitachi CV", 10) /* Hitachi */ + || !strncmp(id->model, "SunDisk SDCFB", 13)) /* SunDisk */ + { + return 1; /* yes, it is a flash memory card */ + } + } + return 0; /* no, it is not a flash memory card */ +} + +/* * ide_system_bus_speed() returns what we think is the system VESA/PCI * bus speed (in MHz). This is used for calculating interface PIO timings. * The default is 40 for known PCI systems, 50 otherwise. @@ -786,7 +813,7 @@ ide_end_drive_cmd(drive, stat, err); return; } - if (stat & BUSY_STAT) { /* other bits are useless when BUSY */ + if (stat & BUSY_STAT || ((stat & WRERR_STAT) && !drive->nowerr)) { /* other bits are useless when BUSY */ rq->errors |= ERROR_RESET; } else { if (drive->media == ide_disk && (stat & ERR_STAT)) { @@ -1669,6 +1696,7 @@ ide_hwgroup_t *hwgroup; int irq_count = 0, unit, i; unsigned long flags; + unsigned int p, minor; if (index >= MAX_HWIFS) return; @@ -1687,6 +1715,24 @@ goto abort; } hwif->present = 0; + + /* + * All clear? Then blow away the buffer cache + */ + sti(); + for (unit = 0; unit < MAX_DRIVES; ++unit) { + drive = &hwif->drives[unit]; + minor = drive->select.b.unit << PARTN_BITS; + for (p = 0; p < (1<part[p].nr_sects > 0) { + kdev_t devp = MKDEV(hwif->major, minor+p); + struct super_block * sb = get_super(devp); + if (sb) invalidate_inodes(sb); + invalidate_buffers (devp); + } + } + } + cli(); hwgroup = hwif->hwgroup; /* @@ -2068,6 +2114,12 @@ (unsigned long *) &loc->start)) return -EFAULT; return 0; } + case BLKSSZGET: + /* Block size of media */ + return put_user(blksize_size[HWIF(drive)->major] + [minor&PARTN_MASK], + (int *)arg); + case BLKFLSBUF: if (!capable(CAP_SYS_ADMIN)) return -EACCES; fsync_dev(inode->i_rdev); @@ -2957,6 +3009,7 @@ /* * Probe module */ +EXPORT_SYMBOL(drive_is_flashcard); EXPORT_SYMBOL(ide_timer_expiry); EXPORT_SYMBOL(ide_intr); EXPORT_SYMBOL(ide_geninit); diff -ur --new-file old/linux/drivers/block/ide.h new/linux/drivers/block/ide.h --- old/linux/drivers/block/ide.h Thu Jan 28 21:41:26 1999 +++ new/linux/drivers/block/ide.h Tue May 11 19:35:52 1999 @@ -182,6 +182,7 @@ #define ide_scsi 0x21 #define ide_disk 0x20 +#define ide_optical 0x7 #define ide_cdrom 0x5 #define ide_tape 0x1 #define ide_floppy 0x0 @@ -672,6 +673,13 @@ * ide_get_queue() returns the queue which corresponds to a given device. */ struct request **ide_get_queue (kdev_t dev); + +/* + * CompactFlash cards and their brethern pretend to be removable hard disks, + * but they never have a slave unit, and they don't have doorlock mechanisms. + * This test catches them, and is invoked elsewhere when setting appropriate config bits. + */ +int drive_is_flashcard (ide_drive_t *drive); int ide_spin_wait_hwgroup(ide_drive_t *drive, unsigned long *flags); void ide_timer_expiry (unsigned long data); diff -ur --new-file old/linux/drivers/block/ide_modes.h new/linux/drivers/block/ide_modes.h --- old/linux/drivers/block/ide_modes.h Thu Jan 28 21:41:20 1999 +++ new/linux/drivers/block/ide_modes.h Tue May 11 19:35:44 1999 @@ -15,7 +15,7 @@ * breaking the fragile cmd640.c support. */ -#if defined(CONFIG_BLK_DEV_CMD640) || defined(CONFIG_IDE_CHIPSETS) || defined(CONFIG_BLK_DEV_OPTI621) +#if defined(CONFIG_BLK_DEV_CMD640) || defined(CONFIG_IDE_CHIPSETS) || defined(CONFIG_BLK_DEV_OPTI621) || defined(CONFIG_BLK_DEV_IDE_PMAC) /* * Standard (generic) timings for PIO modes, from ATA2 specification. diff -ur --new-file old/linux/drivers/block/ll_rw_blk.c new/linux/drivers/block/ll_rw_blk.c --- old/linux/drivers/block/ll_rw_blk.c Mon Dec 28 20:19:19 1998 +++ new/linux/drivers/block/ll_rw_blk.c Fri Mar 12 08:20:14 1999 @@ -392,8 +392,10 @@ lock_buffer(bh); - if (blk_size[major]) - if (blk_size[major][MINOR(bh->b_rdev)] < (sector + count)>>1) { + 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., @@ -406,6 +408,7 @@ blk_size[major][MINOR(bh->b_rdev)]); goto end_io; } + } rw_ahead = 0; /* normal case; gets changed below for READA/WRITEA */ switch (rw) { diff -ur --new-file old/linux/drivers/block/nbd.c new/linux/drivers/block/nbd.c --- old/linux/drivers/block/nbd.c Wed Dec 16 22:38:18 1998 +++ new/linux/drivers/block/nbd.c Wed Mar 10 01:58:05 1999 @@ -17,6 +17,7 @@ * 97-4-11 Making protocol independent of endianity etc. * 97-9-13 Cosmetic changes * 98-5-13 Attempt to make 64-bit-clean on 64-bit machines + * 99-1-11 Attempt to make 64-bit-clean on 32-bit machines * * possible FIXME: make set_sock / set_blksize / set_size / do_it one syscall * why not: would need verify_area and friends, would share yet another @@ -45,8 +46,9 @@ #define LO_MAGIC 0x68797548 static int nbd_blksizes[MAX_NBD]; +static int nbd_blksize_bits[MAX_NBD]; static int nbd_sizes[MAX_NBD]; -static int nbd_bytesizes[MAX_NBD]; +static u64 nbd_bytesizes[MAX_NBD]; static struct nbd_device nbd_dev[MAX_NBD]; @@ -149,7 +151,7 @@ DEBUG("NBD: sending control, "); request.magic = htonl(NBD_REQUEST_MAGIC); request.type = htonl(req->cmd); - request.from = cpu_to_be64( (u64) req->sector * (u64) 512); + request.from = cpu_to_be64( (u64) req->sector << 9); request.len = htonl(req->current_nr_sectors << 9); memcpy(request.handle, &req, sizeof(req)); @@ -340,7 +342,7 @@ unsigned int cmd, unsigned long arg) { struct nbd_device *lo; - int dev, error; + int dev, error, temp; /* Anyone capable of this syscall can do *real bad* things */ @@ -355,6 +357,7 @@ lo = &nbd_dev[dev]; switch (cmd) { case NBD_CLEAR_SOCK: + nbd_clear_que(lo); if (lo->head || lo->tail) { printk(KERN_ERR "nbd: Some requests are in progress -> can not turn off.\n"); return -EBUSY; @@ -380,14 +383,25 @@ } return error; case NBD_SET_BLKSIZE: - if ((arg & 511) || (arg > PAGE_SIZE)) + if ((arg & (arg-1)) || (arg < 512) || (arg > PAGE_SIZE)) return -EINVAL; nbd_blksizes[dev] = arg; - nbd_sizes[dev] = arg/nbd_blksizes[dev]; + temp = arg >> 9; + nbd_blksize_bits[dev] = 9; + while (temp > 1) { + nbd_blksize_bits[dev]++; + temp >>= 1; + } + nbd_sizes[dev] = nbd_bytesizes[dev] >> nbd_blksize_bits[dev]; + nbd_bytesizes[dev] = nbd_sizes[dev] << nbd_blksize_bits[dev]; return 0; case NBD_SET_SIZE: - nbd_bytesizes[dev] = arg; - nbd_sizes[dev] = arg/nbd_blksizes[dev]; + nbd_sizes[dev] = arg >> nbd_blksize_bits[dev]; + nbd_bytesizes[dev] = nbd_sizes[dev] << nbd_blksize_bits[dev]; + return 0; + case NBD_SET_SIZE_BLOCKS: + nbd_sizes[dev] = arg; + nbd_bytesizes[dev] = arg << nbd_blksize_bits[dev]; return 0; case NBD_DO_IT: if (!lo->file) @@ -404,7 +418,7 @@ return 0; #endif case BLKGETSIZE: - return put_user(nbd_bytesizes[dev]/512, (long *) arg); + return put_user(nbd_bytesizes[dev] >> 9, (long *) arg); } return -EINVAL; } @@ -420,6 +434,7 @@ if (dev >= MAX_NBD) return -ENODEV; fsync_dev(inode->i_rdev); + invalidate_buffers(inode->i_rdev); lo = &nbd_dev[dev]; if (lo->refcnt <= 0) printk(KERN_ALERT "nbd_release: refcount(%d) <= 0\n", lo->refcnt); @@ -478,8 +493,9 @@ nbd_dev[i].magic = LO_MAGIC; nbd_dev[i].flags = 0; nbd_blksizes[i] = 1024; - nbd_bytesizes[i] = 0x7fffffff; - nbd_sizes[i] = nbd_bytesizes[i]/nbd_blksizes[i]; + nbd_blksize_bits[i] = 10; + nbd_bytesizes[i] = 0x7ffffc00; /* 2GB */ + nbd_sizes[i] = nbd_bytesizes[i] >> nbd_blksize_bits[i]; } return 0; } diff -ur --new-file old/linux/drivers/block/ns87415.c new/linux/drivers/block/ns87415.c --- old/linux/drivers/block/ns87415.c Mon Nov 16 19:37:28 1998 +++ new/linux/drivers/block/ns87415.c Tue Mar 16 01:11:29 1999 @@ -95,6 +95,12 @@ byte stat; #endif + /* Set a good latency timer and cache line size value. */ + (void) pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64); +#ifdef __sparc_v9__ + (void) pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 0x10); +#endif + /* * We cannot probe for IRQ: both ports share common IRQ on INTA. * Also, leave IRQ masked during drive probing, to prevent infinite diff -ur --new-file old/linux/drivers/block/rd.c new/linux/drivers/block/rd.c --- old/linux/drivers/block/rd.c Mon Aug 24 22:47:39 1998 +++ new/linux/drivers/block/rd.c Thu Apr 29 20:53:41 1999 @@ -33,11 +33,13 @@ * * Added initrd: Werner Almesberger & Hans Lermen, Feb '96 * -* 4/25/96 : Made RAM disk size a parameter (default is now 4 MB) + * 4/25/96 : Made RAM disk size a parameter (default is now 4 MB) * - Chad Page * * Add support for fs images split across >1 disk, Paul Gortmaker, Mar '98 * + * Make block size and block size shift for RAM disks a global macro + * and set blk_size for -ENOSPC, Werner Fink , Apr '99 */ #include @@ -47,6 +49,7 @@ #include #include #include +#include #include #include #include @@ -70,6 +73,15 @@ #define MAJOR_NR RAMDISK_MAJOR #include +/* + * We use a block size of 512 bytes in comparision to BLOCK_SIZE + * defined in include/linux/blk.h. This because of the finer + * granularity for filling up a RAM disk. + */ +#define RDBLK_SIZE_BITS 9 +#define RDBLK_SIZE (1<rq_dev); @@ -132,14 +149,20 @@ goto repeat; } - offset = CURRENT->sector << 9; - len = CURRENT->current_nr_sectors << 9; + offset = CURRENT->sector << RDBLK_SIZE_BITS; + len = CURRENT->current_nr_sectors << RDBLK_SIZE_BITS; if ((offset + len) > rd_length[minor]) { end_request(0); goto repeat; } + if ((CURRENT->cmd != READ) && (CURRENT->cmd != WRITE)) { + printk(KERN_INFO "RAMDISK: bad command: %d\n", CURRENT->cmd); + end_request(0); + goto repeat; + } + /* * If we're reading, fill the buffer with 0's. This is okay since * we're using protected buffers which should never get freed... @@ -158,28 +181,31 @@ static int rd_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - int err; - + unsigned int minor; + if (!inode || !inode->i_rdev) return -EINVAL; + minor = MINOR(inode->i_rdev); + switch (cmd) { case BLKFLSBUF: if (!capable(CAP_SYS_ADMIN)) return -EACCES; invalidate_buffers(inode->i_rdev); break; + case BLKGETSIZE: /* Return device size */ if (!arg) return -EINVAL; - err = verify_area(VERIFY_WRITE, (long *) arg, - sizeof(long)); - if (err) - return err; - put_user(rd_length[MINOR(inode->i_rdev)] / 512, - (long *) arg); - return 0; - + return put_user(rd_length[minor] >> RDBLK_SIZE_BITS, (long *) arg); + + case BLKSSZGET: /* Block size of media */ + if (!arg) return -EINVAL; + return put_user(rd_blocksizes[minor], (int *)arg); + + RO_IOCTLS(inode->i_rdev, arg); + default: - break; + return -EINVAL; }; return 0; @@ -267,7 +293,7 @@ rd_open, /* open */ NULL, /* flush */ rd_release, /* module needs to decrement use count */ - block_fsync /* fsync */ + block_fsync /* fsync */ }; /* This is the registration and initialization section of the RAM disk driver */ @@ -283,11 +309,16 @@ blk_dev[MAJOR_NR].request_fn = &rd_request; for (i = 0; i < NUM_RAMDISKS; i++) { - rd_length[i] = (rd_size * 1024); - rd_blocksizes[i] = 1024; + /* rd_size is given in kB */ + rd_length[i] = (rd_size << BLOCK_SIZE_BITS); + rd_hardsec[i] = RDBLK_SIZE; + rd_blocksizes[i] = BLOCK_SIZE; + rd_kbsize[i] = (rd_length[i] >> BLOCK_SIZE_BITS); } - blksize_size[MAJOR_NR] = rd_blocksizes; + hardsect_size[MAJOR_NR] = rd_hardsec; /* Size of the RAM disk blocks */ + blksize_size[MAJOR_NR] = rd_blocksizes; /* Avoid set_blocksize() check */ + blk_size[MAJOR_NR] = rd_kbsize; /* Size of the RAM disk in kB */ printk("RAM disk driver initialized: %d RAM disks of %dK size\n", NUM_RAMDISKS, rd_size); @@ -299,6 +330,9 @@ #ifdef MODULE +MODULE_PARM (rd_size, "1i"); +MODULE_PARM_DESC(rd_size, "Size of each RAM disk."); + int init_module(void) { int error = rd_init(); @@ -429,7 +463,7 @@ /* * This routine loads in the RAM disk image. */ -__initfunc(static void rd_load_image(kdev_t device,int offset)) +__initfunc(static void rd_load_image(kdev_t device, int offset, int unit)) { struct inode inode, out_inode; struct file infile, outfile; @@ -442,7 +476,7 @@ unsigned short devblocks = 0; char rotator[4] = { '|' , '/' , '-' , '\\' }; - ram_device = MKDEV(MAJOR_NR, 0); + ram_device = MKDEV(MAJOR_NR, unit); memset(&infile, 0, sizeof(infile)); memset(&inode, 0, sizeof(inode)); @@ -482,9 +516,9 @@ goto done; } - if (nblocks > (rd_length[0] >> BLOCK_SIZE_BITS)) { + if (nblocks > (rd_length[unit] >> RDBLK_SIZE_BITS)) { printk("RAMDISK: image too big! (%d/%d blocks)\n", - nblocks, rd_length[0] >> BLOCK_SIZE_BITS); + nblocks, rd_length[unit] >> RDBLK_SIZE_BITS); goto done; } @@ -540,7 +574,7 @@ successful_load: invalidate_buffers(device); - ROOT_DEV = MKDEV(MAJOR_NR,0); + ROOT_DEV = MKDEV(MAJOR_NR, unit); done: if (infile.f_op->release) @@ -549,12 +583,21 @@ } -__initfunc(void rd_load(void)) +__initfunc(static void rd_load_disk(int n)) { +#ifdef CONFIG_BLK_DEV_INITRD + extern kdev_t real_root_dev; +#endif + if (rd_doload == 0) return; - - if (MAJOR(ROOT_DEV) != FLOPPY_MAJOR) return; + + if (MAJOR(ROOT_DEV) != FLOPPY_MAJOR +#ifdef CONFIG_BLK_DEV_INITRD + && MAJOR(real_root_dev) != FLOPPY_MAJOR +#endif + ) + return; if (rd_prompt) { #ifdef CONFIG_BLK_DEV_FD @@ -565,15 +608,24 @@ wait_for_keypress(); } - rd_load_image(ROOT_DEV,rd_image_start); + rd_load_image(ROOT_DEV,rd_image_start, n); } +__initfunc(void rd_load(void)) +{ + rd_load_disk(0); +} + +__initfunc(void rd_load_secondary(void)) +{ + rd_load_disk(1); +} #ifdef CONFIG_BLK_DEV_INITRD __initfunc(void initrd_load(void)) { - rd_load_image(MKDEV(MAJOR_NR, INITRD_MINOR),0); + rd_load_image(MKDEV(MAJOR_NR, INITRD_MINOR),0,0); } #endif @@ -697,7 +749,14 @@ crd_load(struct file * fp, struct file *outfp)) { int result; - + + insize = 0; /* valid bytes in inbuf */ + inptr = 0; /* index of next byte to be processed in inbuf */ + outcnt = 0; /* bytes in output buffer */ + exit_code = 0; + bytes_out = 0; + crc = (ulg)0xffffffffL; /* shift register contents */ + crd_infp = fp; crd_outfp = outfp; inbuf = kmalloc(INBUFSIZ, GFP_KERNEL); diff -ur --new-file old/linux/drivers/block/sl82c105.c new/linux/drivers/block/sl82c105.c --- old/linux/drivers/block/sl82c105.c Sun Nov 15 19:51:46 1998 +++ new/linux/drivers/block/sl82c105.c Thu Mar 11 06:48:46 1999 @@ -1,3 +1,4 @@ +#include #include #include #include @@ -19,7 +20,6 @@ struct pci_dev *dev = hwif->pci_dev; unsigned short t16; unsigned int t32; - pci_read_config_word(dev, PCI_COMMAND, &t16); printk("SL82C105 command word: %x\n",t16); t16 |= PCI_COMMAND_IO; @@ -28,7 +28,9 @@ pci_read_config_dword(dev, 0x44, &t32); printk("IDE timing: %08x, resetting to PIO0 timing\n",t32); pci_write_config_dword(dev, 0x44, 0x03e4); +#ifndef CONFIG_MBX pci_read_config_dword(dev, 0x40, &t32); printk("IDE control/status register: %08x\n",t32); pci_write_config_dword(dev, 0x40, 0x10ff08a1); +#endif /* CONFIG_MBX */ } diff -ur --new-file old/linux/drivers/block/swim3.c new/linux/drivers/block/swim3.c --- old/linux/drivers/block/swim3.c Sun Nov 15 19:51:46 1998 +++ new/linux/drivers/block/swim3.c Thu Mar 11 06:48:46 1999 @@ -10,6 +10,12 @@ * 2 of the License, or (at your option) any later version. */ +/* + * TODO: + * handle 2 drives + * handle GCR disks + */ + #include #include #include @@ -52,18 +58,18 @@ */ struct swim3 { REG(data); - REG(usecs); /* counts down at 1MHz */ + REG(timer); /* counts down at 1MHz */ REG(error); REG(mode); REG(select); /* controls CA0, CA1, CA2 and LSTRB signals */ - REG(reg5); + REG(setup); REG(control); /* writing bits clears them */ REG(status); /* writing bits sets them in control */ REG(intr); REG(nseek); /* # tracks to seek */ REG(ctrack); /* current track number */ REG(csect); /* current sector number */ - REG(ssize); /* sector size code?? */ + REG(gap3); /* size of gap 3 in track format */ REG(sector); /* sector # to read or write */ REG(nsect); /* # sectors to read or write */ REG(intr_enable); @@ -78,21 +84,46 @@ /* Bits in control register */ #define DO_SEEK 0x80 +#define FORMAT 0x40 #define SELECT 0x20 #define WRITE_SECTORS 0x10 -#define SCAN_TRACK 0x08 +#define DO_ACTION 0x08 +#define DRIVE2_ENABLE 0x04 #define DRIVE_ENABLE 0x02 #define INTR_ENABLE 0x01 /* Bits in status register */ +#define FIFO_1BYTE 0x80 +#define FIFO_2BYTE 0x40 +#define ERROR 0x20 #define DATA 0x08 +#define RDDATA 0x04 +#define INTR_PENDING 0x02 +#define MARK_BYTE 0x01 /* Bits in intr and intr_enable registers */ -#define ERROR 0x20 +#define ERROR_INTR 0x20 #define DATA_CHANGED 0x10 #define TRANSFER_DONE 0x08 #define SEEN_SECTOR 0x04 #define SEEK_DONE 0x02 +#define TIMER_DONE 0x01 + +/* Bits in error register */ +#define ERR_DATA_CRC 0x80 +#define ERR_ADDR_CRC 0x40 +#define ERR_OVERRUN 0x04 +#define ERR_UNDERRUN 0x01 + +/* Bits in setup register */ +#define S_SW_RESET 0x80 +#define S_GCR_WRITE 0x40 +#define S_IBM_DRIVE 0x20 +#define S_TEST_MODE 0x10 +#define S_FCLK_DIV2 0x08 +#define S_GCR 0x04 +#define S_COPY_PROT 0x02 +#define S_INV_WDATA 0x01 /* Select values for swim3_action */ #define SEEK_POSITIVE 0 @@ -100,14 +131,18 @@ #define STEP 1 #define MOTOR_ON 2 #define MOTOR_OFF 6 +#define INDEX 3 #define EJECT 7 +#define SETMFM 9 +#define SETGCR 13 /* Select values for swim3_select and swim3_readbit */ #define STEP_DIR 0 #define STEPPING 1 #define MOTOR_ON 2 -#define RELAX 3 +#define RELAX 3 /* also eject in progress */ #define READ_DATA_0 4 +#define TWOMEG_DRIVE 5 #define SINGLE_SIDED 6 #define DRIVE_PRESENT 7 #define DISK_IN 8 @@ -115,7 +150,25 @@ #define TRACK_ZERO 10 #define TACHO 11 #define READ_DATA_1 12 +#define MFM_MODE 13 #define SEEK_COMPLETE 14 +#define ONEMEG_MEDIA 15 + +/* Definitions of values used in writing and formatting */ +#define DATA_ESCAPE 0x99 +#define GCR_SYNC_EXC 0x3f +#define GCR_SYNC_CONV 0x80 +#define GCR_FIRST_MARK 0xd5 +#define GCR_SECOND_MARK 0xaa +#define GCR_ADDR_MARK "\xd5\xaa\x00" +#define GCR_DATA_MARK "\xd5\xaa\x0b" +#define GCR_SLIP_BYTE "\x27\xaa" +#define GCR_SELF_SYNC "\x3f\xbf\x1e\x34\x3c\x3f" + +#define DATA_99 "\x99\x99" +#define MFM_ADDR_MARK "\x99\xa1\x99\xa1\x99\xa1\x99\xfe" +#define MFM_INDEX_MARK "\x99\xc2\x99\xc2\x99\xc2\x99\xfc" +#define MFM_GAP_LEN 12 struct floppy_state { enum swim_state state; @@ -153,7 +206,7 @@ 0x4e4e, 0x4e4e, 0x4e4e, 0x4e4e, 0x4e4e, /* gap field */ 0, 0, 0, 0, 0, 0, /* sync field */ 0x99a1, 0x99a1, 0x99a1, 0x99fb, /* data address mark */ - 0x990f /* init CRC generator */ + 0x990f /* no escape for 512 bytes */ }; static unsigned short write_postamble[] = { @@ -217,11 +270,11 @@ volatile struct swim3 *sw = fs->swim3; swim3_select(fs, action); - udelay(10); - sw->select |= LSTRB; eieio(); - udelay(20); - sw->select &= ~LSTRB; eieio(); - udelay(10); + udelay(1); + out_8(&sw->select, sw->select | LSTRB); + udelay(2); + out_8(&sw->select, sw->select & ~LSTRB); + udelay(1); out_8(&sw->select, RELAX); } @@ -328,9 +381,9 @@ swim3_select(fs, READ_DATA_0); xx = sw->intr; /* clear SEEN_SECTOR bit */ - out_8(&sw->control_bis, SCAN_TRACK); + out_8(&sw->control_bis, DO_ACTION); /* enable intr when track found */ - out_8(&sw->intr_enable, ERROR | SEEN_SECTOR); + out_8(&sw->intr_enable, ERROR_INTR | SEEN_SECTOR); set_timeout(fs, HZ, scan_timeout); /* enable timeout */ } @@ -349,7 +402,7 @@ swim3_select(fs, STEP); out_8(&sw->control_bis, DO_SEEK); /* enable intr when seek finished */ - out_8(&sw->intr_enable, ERROR | SEEK_DONE); + out_8(&sw->intr_enable, ERROR_INTR | SEEK_DONE); set_timeout(fs, HZ/2, seek_timeout); /* enable timeout */ } @@ -384,7 +437,7 @@ swim3_select(fs, fs->head? READ_DATA_1: READ_DATA_0); out_8(&sw->sector, fs->req_sector); out_8(&sw->nsect, n); - out_8(&sw->ssize, 0); + out_8(&sw->gap3, 0); st_le32(&dr->cmdptr, virt_to_bus(cp)); if (CURRENT->cmd == WRITE) { /* Set up 3 dma commands: write preamble, data, postamble */ @@ -400,9 +453,9 @@ out_le16(&cp->command, DBDMA_STOP); out_le32(&dr->control, (RUN << 16) | RUN); out_8(&sw->control_bis, - (CURRENT->cmd == WRITE? WRITE_SECTORS: 0) | SCAN_TRACK); + (CURRENT->cmd == WRITE? WRITE_SECTORS: 0) | DO_ACTION); /* enable intr when transfer complete */ - out_8(&sw->intr_enable, ERROR | TRANSFER_DONE); + out_8(&sw->intr_enable, ERROR_INTR | TRANSFER_DONE); set_timeout(fs, 2*HZ, xfer_timeout); /* enable timeout */ } @@ -445,7 +498,7 @@ /* wait for SEEK_COMPLETE to become true */ swim3_select(fs, SEEK_COMPLETE); udelay(10); - out_8(&sw->intr_enable, ERROR | DATA_CHANGED); + out_8(&sw->intr_enable, ERROR_INTR | DATA_CHANGED); in_8(&sw->intr); /* clear DATA_CHANGED */ if (in_8(&sw->status) & DATA) { /* seek_complete is not yet true */ @@ -487,7 +540,7 @@ volatile struct swim3 *sw = fs->swim3; fs->timeout_pending = 0; - out_8(&sw->control_bic, SCAN_TRACK); + out_8(&sw->control_bic, DO_ACTION); out_8(&sw->select, RELAX); out_8(&sw->intr_enable, 0); fs->cur_cyl = -1; @@ -537,7 +590,7 @@ fs->timeout_pending = 0; st_le32(&dr->control, RUN << 16); out_8(&sw->intr_enable, 0); - out_8(&sw->control_bic, WRITE_SECTORS | SCAN_TRACK); + out_8(&sw->control_bic, WRITE_SECTORS | DO_ACTION); out_8(&sw->select, RELAX); if (CURRENT->cmd == WRITE) ++cp; @@ -568,13 +621,13 @@ #if 0 printk("swim3 intr state=%d intr=%x err=%x\n", fs->state, intr, err); #endif - if ((intr & ERROR) && fs->state != do_transfer) + if ((intr & ERROR_INTR) && fs->state != do_transfer) printk(KERN_ERR "swim3_interrupt, state=%d, cmd=%x, intr=%x, err=%x\n", fs->state, CURRENT->cmd, intr, err); switch (fs->state) { case locating: if (intr & SEEN_SECTOR) { - out_8(&sw->control_bic, SCAN_TRACK); + out_8(&sw->control_bic, DO_ACTION); out_8(&sw->select, RELAX); out_8(&sw->intr_enable, 0); del_timer(&fs->timeout); @@ -622,13 +675,13 @@ act(fs); break; case do_transfer: - if ((intr & (ERROR | TRANSFER_DONE)) == 0) + if ((intr & (ERROR_INTR | TRANSFER_DONE)) == 0) break; dr = fs->dma; cp = fs->dma_cmd; st_le32(&dr->control, RUN << 16); out_8(&sw->intr_enable, 0); - out_8(&sw->control_bic, WRITE_SECTORS | SCAN_TRACK); + out_8(&sw->control_bic, WRITE_SECTORS | DO_ACTION); out_8(&sw->select, RELAX); del_timer(&fs->timeout); fs->timeout_pending = 0; @@ -636,7 +689,7 @@ ++cp; stat = ld_le16(&cp->xfer_status); resid = ld_le16(&cp->res_count); - if (intr & ERROR) { + if (intr & ERROR_INTR) { n = fs->scount - 1 - resid / 512; if (n > 0) { CURRENT->sector += n; @@ -800,6 +853,8 @@ if (devnum >= floppy_count) return -ENODEV; + if (filp == 0) + return -EIO; fs = &floppy_states[devnum]; sw = fs->swim3; @@ -809,7 +864,7 @@ return -ENXIO; out_8(&sw->mode, 0x95); out_8(&sw->control_bic, 0xff); - out_8(&sw->reg5, 0x28); + out_8(&sw->setup, S_IBM_DRIVE | S_FCLK_DIV2); udelay(10); out_8(&sw->intr_enable, 0); out_8(&sw->control_bis, DRIVE_ENABLE | INTR_ENABLE); @@ -834,14 +889,14 @@ } else if (fs->ref_count == -1 || filp->f_flags & O_EXCL) return -EBUSY; - if (err == 0 && filp && (filp->f_flags & O_NDELAY) == 0 + if (err == 0 && (filp->f_flags & O_NDELAY) == 0 && (filp->f_mode & 3)) { check_disk_change(inode->i_rdev); if (fs->ejected) err = -ENXIO; } - if (err == 0 && filp && (filp->f_flags & (O_WRONLY | O_RDWR))) { + if (err == 0 && (filp->f_mode & 2)) { if (fs->write_prot < 0) fs->write_prot = swim3_readbit(fs, WRITE_PROT); if (fs->write_prot) @@ -977,10 +1032,14 @@ if (devnum >= floppy_count) return -ENODEV; - + check_disk_change(inode->i_rdev); fs = &floppy_states[devnum]; if (fs->ejected) return -ENXIO; + if (fs->write_prot < 0) + fs->write_prot = swim3_readbit(fs, WRITE_PROT); + if (fs->write_prot) + return -EROFS; return block_write(filp, buf, count, ppos); } diff -ur --new-file old/linux/drivers/cdrom/Config.in new/linux/drivers/cdrom/Config.in --- old/linux/drivers/cdrom/Config.in Sun Dec 28 21:05:45 1997 +++ new/linux/drivers/cdrom/Config.in Tue Apr 13 01:18:28 1999 @@ -14,6 +14,10 @@ fi fi tristate 'Mitsumi (standard) [no XA/Multisession] CDROM support' CONFIG_MCD +if [ "$CONFIG_MCD" != "n" ]; then + int 'MCD IRQ' CONFIG_MCD_IRQ 11 + hex 'MCD I/O base' CONFIG_MCD_BASE 300 +fi tristate 'Mitsumi [XA/MultiSession] CDROM support' CONFIG_MCDX tristate 'Optics Storage DOLPHIN 8000AT CDROM support' CONFIG_OPTCD tristate 'Philips/LMS CM206 CDROM support' CONFIG_CM206 diff -ur --new-file old/linux/drivers/cdrom/cdrom.c new/linux/drivers/cdrom/cdrom.c --- old/linux/drivers/cdrom/cdrom.c Tue Jan 19 02:33:01 1999 +++ new/linux/drivers/cdrom/cdrom.c Thu Apr 29 20:53:41 1999 @@ -24,8 +24,9 @@ -- Change the CDROMREADMODE1, CDROMREADMODE2, CDROMREADAUDIO, and CDROMREADRAW ioctls so they go through the Uniform CD-ROM driver. - - + + -- Sync options and capability flags. + Revision History @@ -97,17 +98,38 @@ cdi->options in various ioctl. -- Added version to proc entry. - 2.52 Jan 16, 1998 - Jens Axboe + 2.52 Jan 16, 1999 - Jens Axboe -- Fixed an error in open_for_data where we would sometimes not return the correct error value. Thanks Huba Gaspar . -- Fixed module usage count - usage was based on /proc/sys/dev instead of /proc/sys/dev/cdrom. This could lead to an oops when other - modules had entries in dev. + modules had entries in dev. Feb 02 - real bug was in sysctl.c where + dev would be removed even though it was used. cdrom.c just illuminated + that bug. + + 2.53 Feb 22, 1999 - Jens Axboe + -- Fixup of several ioctl calls, in particular CDROM_SET_OPTIONS has + been "rewritten" because capabilities and options aren't in sync. They + should be... + -- Added CDROM_LOCKDOOR ioctl. Locks the door and keeps it that way. + -- Added CDROM_RESET ioctl. + -- Added CDROM_DEBUG ioctl. Enable debug messages on-the-fly. + -- Added CDROM_GET_CAPABILITY ioctl. This relieves userspace programs + from parsing /proc/sys/dev/cdrom/info. + + 2.54 Mar 15, 1999 - Jens Axboe + -- Check capability mask from low level driver when counting tracks as + per suggestion from Corey J. Scotts . + + 2.55 Apr 25, 1999 - Jens Axboe + -- autoclose was mistakenly checked against CDC_OPEN_TRAY instead of + CDC_CLOSE_TRAY. + -- proc info didn't mask against capabilities mask. -------------------------------------------------------------------------*/ -#define REVISION "Revision: 2.52" -#define VERSION "Id: cdrom.c 2.52 1999/01/16" +#define REVISION "Revision: 2.55" +#define VERSION "Id: cdrom.c 2.55 1999/04/25" /* I use an error-log mask to give fine grain control over the type of messages dumped to the system logs. The available masks include: */ @@ -144,6 +166,8 @@ /* used to tell the module to turn on full debugging messages */ static int debug = 0; +/* used to keep tray locked at all times */ +static int keeplocked = 0; /* default compatibility mode */ static int autoclose=1; static int autoeject=0; @@ -164,13 +188,11 @@ #endif /* These are used to simplify getting data in from and back to user land */ -#define IOCTL_IN(arg, type, in) { \ - if ( copy_from_user(&in, (type *) arg, sizeof in) ) \ - return -EFAULT; } - -#define IOCTL_OUT(arg, type, out) { \ - if ( copy_to_user((type *) arg, &out, sizeof out) ) \ - return -EFAULT; } +#define IOCTL_IN(arg, type, in) \ + copy_from_user_ret(&in, (type *) arg, sizeof in, -EFAULT) + +#define IOCTL_OUT(arg, type, out) \ + copy_to_user_ret((type *) arg, &out, sizeof out, -EFAULT) #define FM_WRITE 0x2 /* file mode write bit */ @@ -251,7 +273,7 @@ cdo->n_minors = 0; cdi->options = CDO_USE_FFLAGS; - if (autoclose==1 && cdo->capability & ~cdi->mask & CDC_OPEN_TRAY) + if (autoclose==1 && cdo->capability & ~cdi->mask & CDC_CLOSE_TRAY) cdi->options |= (int) CDO_AUTO_CLOSE; if (autoeject==1 && cdo->capability & ~cdi->mask & CDC_OPEN_TRAY) cdi->options |= (int) CDO_AUTO_EJECT; @@ -328,7 +350,7 @@ if (fp->f_mode & FM_WRITE) return -EROFS; purpose = purpose || !(cdi->options & CDO_USE_FFLAGS); - if (cdi->use_count || purpose) + if (purpose) ret = cdi->ops->open(cdi, purpose); else ret = open_for_data(cdi); @@ -517,10 +539,10 @@ if (cdi->use_count == 0) cdinfo(CD_CLOSE, "Use count for \"/dev/%s\" now zero\n", cdi->name); if (cdi->use_count == 0 && /* last process that closes dev*/ - cdo->capability & CDC_LOCK) { + cdo->capability & CDC_LOCK && !keeplocked) { cdinfo(CD_CLOSE, "Unlocking door!\n"); cdo->lock_door(cdi, 0); - } + } opened_for_data = !(cdi->options & CDO_USE_FFLAGS) || !(fp && fp->f_flags & O_NONBLOCK); cdo->release(cdi); @@ -588,14 +610,17 @@ tracks->xa=0; tracks->error=0; cdinfo(CD_COUNT_TRACKS, "entering cdrom_count_tracks\n"); - if (!(cdi->ops->capability & CDC_PLAY_AUDIO)) { + if (!(cdi->ops->capability & ~cdi->mask & CDC_PLAY_AUDIO)) { tracks->error=CDS_NO_INFO; return; } /* Grab the TOC header so we can see how many tracks there are */ - ret=cdi->ops->audio_ioctl(cdi, CDROMREADTOCHDR, &header); + ret = cdi->ops->audio_ioctl(cdi, CDROMREADTOCHDR, &header); if (ret) { - tracks->error=(ret == -ENOMEDIUM) ? CDS_NO_DISC : CDS_NO_INFO; + if (ret == -ENOMEDIUM) + tracks->error = CDS_NO_DISC; + else + tracks->error = CDS_NO_INFO; return; } /* check what type of tracks are on this disc */ @@ -716,18 +741,18 @@ cdinfo(CD_DO_IOCTL, "entering CDROMEJECT\n"); if (!(cdo->capability & ~cdi->mask & CDC_OPEN_TRAY)) return -ENOSYS; - if (cdi->use_count != 1) + if (cdi->use_count != 1 || keeplocked) return -EBUSY; - if (cdo->capability & ~cdi->mask & CDC_LOCK) { + if (cdo->capability & ~cdi->mask & CDC_LOCK) if ((ret=cdo->lock_door(cdi, 0))) return ret; - } + return cdo->tray_move(cdi, 1); } case CDROMCLOSETRAY: cdinfo(CD_DO_IOCTL, "entering CDROMCLOSETRAY\n"); - if (!(cdo->capability & ~cdi->mask & CDC_OPEN_TRAY)) + if (!(cdo->capability & ~cdi->mask & CDC_CLOSE_TRAY)) return -ENOSYS; return cdo->tray_move(cdi, 0); @@ -735,6 +760,8 @@ cdinfo(CD_DO_IOCTL, "entering CDROMEJECT_SW\n"); if (!(cdo->capability & ~cdi->mask & CDC_OPEN_TRAY)) return -ENOSYS; + if (keeplocked) + return -EBUSY; cdi->options &= ~(CDO_AUTO_CLOSE | CDO_AUTO_EJECT); if (arg) cdi->options |= CDO_AUTO_CLOSE | CDO_AUTO_EJECT; @@ -755,8 +782,23 @@ case CDROM_SET_OPTIONS: cdinfo(CD_DO_IOCTL, "entering CDROM_SET_OPTIONS\n"); - if (cdo->capability & arg & ~cdi->mask) - return -ENOSYS; + /* options need to be in sync with capability. too late for + that, so we have to check each one separately... */ + switch (arg) { + case CDO_USE_FFLAGS: + case CDO_CHECK_TYPE: + break; + case CDO_LOCK: + if (!(cdo->capability & ~cdi->mask & CDC_LOCK)) + return -ENOSYS; + break; + case 0: + return cdi->options; + /* default is basically CDO_[AUTO_CLOSE|AUTO_EJECT] */ + default: + if (!(cdo->capability & ~cdi->mask & arg)) + return -ENOSYS; + } cdi->options |= (int) arg; return cdi->options; @@ -783,6 +825,36 @@ return cdo->select_disc(cdi, arg); } + case CDROMRESET: { + cdinfo(CD_DO_IOCTL, "entering CDROM_RESET\n"); + if (!(cdo->capability & ~cdi->mask & CDC_RESET)) + return -ENOSYS; + return cdo->reset(cdi); + } + + case CDROM_LOCKDOOR: { + cdinfo(CD_DO_IOCTL, "%socking door.\n",arg?"L":"Unl"); + if (!(cdo->capability & ~cdi->mask & CDC_LOCK)) { + return -EDRIVE_CANT_DO_THIS; + } else { + keeplocked = arg ? 1 : 0; + return cdo->lock_door(cdi, arg); + } + } + + case CDROM_DEBUG: { + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + cdinfo(CD_DO_IOCTL, "%sabling debug.\n",arg?"En":"Dis"); + debug = arg ? 1 : 0; + return debug; + } + + case CDROM_GET_CAPABILITY: { + cdinfo(CD_DO_IOCTL, "entering CDROM_GET_CAPABILITY\n"); + return cdo->capability; + } + /* The following function is implemented, although very few audio * discs give Universal Product Code information, which should just be * the Medium Catalog Number on the box. Note, that the way the code @@ -1030,27 +1102,27 @@ pos += sprintf(cdrom_drive_info+pos, "\nCan close tray:\t"); for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) pos += sprintf(cdrom_drive_info+pos, "\t%d", - ((cdi->ops->capability & CDC_CLOSE_TRAY)!=0)); + ((cdi->ops->capability & ~cdi->mask & CDC_CLOSE_TRAY)!=0)); pos += sprintf(cdrom_drive_info+pos, "\nCan open tray:\t"); for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) pos += sprintf(cdrom_drive_info+pos, "\t%d", - ((cdi->ops->capability & CDC_OPEN_TRAY)!=0)); + ((cdi->ops->capability & ~cdi->mask & CDC_OPEN_TRAY)!=0)); pos += sprintf(cdrom_drive_info+pos, "\nCan lock tray:\t"); for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) pos += sprintf(cdrom_drive_info+pos, "\t%d", - ((cdi->ops->capability & CDC_LOCK)!=0)); + ((cdi->ops->capability & ~cdi->mask & CDC_LOCK)!=0)); pos += sprintf(cdrom_drive_info+pos, "\nCan change speed:"); for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) pos += sprintf(cdrom_drive_info+pos, "\t%d", - ((cdi->ops->capability & CDC_SELECT_SPEED)!=0)); + ((cdi->ops->capability & ~cdi->mask & CDC_SELECT_SPEED)!=0)); pos += sprintf(cdrom_drive_info+pos, "\nCan select disk:"); for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) pos += sprintf(cdrom_drive_info+pos, "\t%d", - ((cdi->ops->capability & CDC_SELECT_DISC)!=0)); + ((cdi->ops->capability & ~cdi->mask & CDC_SELECT_DISC)!=0)); pos += sprintf(cdrom_drive_info+pos, "\nCan read multisession:"); for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) @@ -1070,7 +1142,7 @@ pos += sprintf(cdrom_drive_info+pos, "\nCan play audio:\t"); for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) pos += sprintf(cdrom_drive_info+pos, "\t%d", - ((cdi->ops->capability & CDC_PLAY_AUDIO)!=0)); + ((cdi->ops->capability & ~cdi->mask & CDC_PLAY_AUDIO)!=0)); strcpy(cdrom_drive_info+pos,"\n\n"); *lenp=pos+3; @@ -1123,7 +1195,7 @@ return; cdrom_sysctl_header = register_sysctl_table(cdrom_root_table, 1); - cdrom_root_table->de->fill_inode = &cdrom_procfs_modcount; + cdrom_root_table->child->de->fill_inode = &cdrom_procfs_modcount; initialized = 1; } diff -ur --new-file old/linux/drivers/cdrom/cm206.c new/linux/drivers/cdrom/cm206.c --- old/linux/drivers/cdrom/cm206.c Mon Sep 14 20:34:01 1998 +++ new/linux/drivers/cdrom/cm206.c Thu Mar 11 02:01:57 1999 @@ -186,7 +186,6 @@ #include #include #include -#include /* #include */ diff -ur --new-file old/linux/drivers/cdrom/mcd.c new/linux/drivers/cdrom/mcd.c --- old/linux/drivers/cdrom/mcd.c Wed Nov 4 21:09:43 1998 +++ new/linux/drivers/cdrom/mcd.c Tue Apr 13 01:18:28 1999 @@ -67,6 +67,7 @@ a CD. November 1997 -- ported to the Uniform CD-ROM driver by Erik Andersen. + March 1999 -- made io base and irq CONFIG_ options (Tigran Aivazian). */ #include @@ -83,6 +84,7 @@ #include #include #include +#include /* #define REALLY_SLOW_IO */ #include @@ -155,8 +157,8 @@ int mitsumi_bug_93_wait = 0; #endif /* WORK_AROUND_MITSUMI_BUG_93 */ -static short mcd_port = MCD_BASE_ADDR; /* used as "mcd" by "insmod" */ -static int mcd_irq = MCD_INTR_NR; /* must directly follow mcd_port */ +static short mcd_port = CONFIG_MCD_BASE; /* used as "mcd" by "insmod" */ +static int mcd_irq = CONFIG_MCD_IRQ; /* must directly follow mcd_port */ MODULE_PARM(mcd, "1-2i"); static int McdTimeout, McdTries; diff -ur --new-file old/linux/drivers/cdrom/mcd.h new/linux/drivers/cdrom/mcd.h --- old/linux/drivers/cdrom/mcd.h Tue Dec 2 20:41:44 1997 +++ new/linux/drivers/cdrom/mcd.h Tue Apr 13 01:18:28 1999 @@ -21,20 +21,6 @@ * */ -/* *** change this to set the I/O port address */ -#define MCD_BASE_ADDR 0x300 - -/* *** change this to set the interrupt number */ -#define MCD_INTR_NR 11 - -/* *** make the following line uncommented, if you're sure, - * *** all configuration is done */ - -/* #define I_WAS_HERE */ - - - - /* Increase this if you get lots of timeouts */ #define MCD_STATUS_DELAY 1000 @@ -121,8 +107,3 @@ struct msf trackTime; struct msf diskTime; }; - -#ifndef I_WAS_HERE -#warning You have not edited mcd.h -#warning Perhaps irq and i/o settings are wrong. -#endif diff -ur --new-file old/linux/drivers/cdrom/mcdx.h new/linux/drivers/cdrom/mcdx.h --- old/linux/drivers/cdrom/mcdx.h Wed Jan 20 19:20:16 1999 +++ new/linux/drivers/cdrom/mcdx.h Thu Apr 29 20:53:41 1999 @@ -176,8 +176,10 @@ #define MCDX_ST_DRV 0x00ff /* mask to query the drive status */ #ifndef I_WAS_HERE +#ifndef MODULE #warning You have not edited mcdx.h #warning Perhaps irq and i/o settings are wrong. +#endif #endif /* ex:set ts=4 sw=4: */ diff -ur --new-file old/linux/drivers/cdrom/optcd.c new/linux/drivers/cdrom/optcd.c --- old/linux/drivers/cdrom/optcd.c Mon Aug 24 22:14:10 1998 +++ new/linux/drivers/cdrom/optcd.c Sun Apr 25 02:49:37 1999 @@ -100,6 +100,10 @@ #else #define DEBUG(x) #endif + +static int blksize = 2048; +static int hsecsize = 2048; + /* Drive hardware/firmware characteristics Identifiers in accordance with Optics Storage documentation */ @@ -2061,6 +2065,8 @@ return -EIO; } + hardsect_size[MAJOR_NR] = &hsecsize; + blksize_size[MAJOR_NR] = &blksize; blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; read_ahead[MAJOR_NR] = 4; request_region(optcd_port, 4, "optcd"); diff -ur --new-file old/linux/drivers/cdrom/sjcd.c new/linux/drivers/cdrom/sjcd.c --- old/linux/drivers/cdrom/sjcd.c Sun Dec 20 13:36:47 1998 +++ new/linux/drivers/cdrom/sjcd.c Tue Apr 13 01:18:32 1999 @@ -45,11 +45,14 @@ * Allow only to set io base address on command line: sjcd= * Changes to Documentation/cdrom/sjcd * Added cleanup after any error in the initialisation. + * 1.7 Added code to set the sector size tables to prevent the bug present in + * the previous version of this driver. Coded added by Anthony Barbachan + * from bugfix tip originally suggested by Alan Cox. * */ #define SJCD_VERSION_MAJOR 1 -#define SJCD_VERSION_MINOR 6 +#define SJCD_VERSION_MINOR 7 #ifdef MODULE #include @@ -1437,6 +1440,9 @@ NULL /* revalidate */ }; +static int blksize = 2048; +static int secsize = 2048; + /* * Following stuff is intended for initialization of the cdrom. It * first looks for presence of device. If the device is present, it @@ -1460,6 +1466,9 @@ #if defined( SJCD_TRACE ) printk("SJCD: sjcd=0x%x: ", sjcd_base); #endif + + hardsect_size[MAJOR_NR] = &secsize; + blksize_size[MAJOR_NR] = &blksize; if( register_blkdev( MAJOR_NR, "sjcd", &sjcd_fops ) != 0 ){ printk( "SJCD: Unable to get major %d for Sanyo CD-ROM\n", MAJOR_NR ); diff -ur --new-file old/linux/drivers/char/Config.in new/linux/drivers/char/Config.in --- old/linux/drivers/char/Config.in Sun Dec 27 19:48:46 1998 +++ new/linux/drivers/char/Config.in Fri May 7 20:05:30 1999 @@ -42,6 +42,8 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then dep_tristate 'Multi-Tech multiport card support' CONFIG_ISI m fi + dep_tristate 'Microgate SyncLink card support' CONFIG_SYNCLINK m + dep_tristate 'HDLC line discipline support' CONFIG_N_HDLC m fi bool 'Unix98 PTY support' CONFIG_UNIX98_PTYS if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then @@ -121,6 +123,7 @@ if [ "$CONFIG_RADIO_AZTECH" = "y" ]; then hex ' Aztech/Packard Bell I/O port (0x350 or 0x358)' CONFIG_RADIO_AZTECH_PORT 350 fi + dep_tristate 'ADS Cadet AM/FM Tuner' CONFIG_RADIO_CADET $CONFIG_VIDEO_DEV dep_tristate 'Miro PCM20 Radio' CONFIG_RADIO_MIROPCM20 $CONFIG_VIDEO_DEV dep_tristate 'GemTek Radio Card support' CONFIG_RADIO_GEMTEK $CONFIG_VIDEO_DEV if [ "$CONFIG_RADIO_GEMTEK" = "y" ]; then @@ -134,11 +137,24 @@ dep_tristate 'Colour QuickCam Video For Linux (EXPERIMENTAL)' CONFIG_VIDEO_CQCAM $CONFIG_VIDEO_DEV $CONFIG_PARPORT fi dep_tristate 'Mediavision Pro Movie Studio Video For Linux' CONFIG_VIDEO_PMS $CONFIG_VIDEO_DEV + if [ "$CONFIG_PMAC" = "y" ]; then + dep_tristate 'PlanB Video-In on PowerMac' CONFIG_VIDEO_PLANB $CONFIG_VIDEO_DEV + fi dep_tristate 'SAA5249 Teletext processor' CONFIG_VIDEO_SAA5249 $CONFIG_VIDEO_DEV dep_tristate 'SF16FMI Radio' CONFIG_RADIO_SF16FMI $CONFIG_VIDEO_DEV if [ "$CONFIG_RADIO_SF16FMI" = "y" ]; then hex ' SF16FMI I/O port (0x284 or 0x384)' CONFIG_RADIO_SF16FMI_PORT 284 fi + 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 + bool ' Support for /proc/radio-typhoon' CONFIG_RADIO_TYPHOON_PROC_FS + fi + fi + if [ "$CONFIG_RADIO_TYPHOON" = "y" ]; then + hex ' Typhoon I/O port (0x316 or 0x336)' CONFIG_RADIO_TYPHOON_PORT 316 + int ' Typhoon frequency set when muting the device (kHz)' CONFIG_RADIO_TYPHOON_MUTEFREQ 87500 + fi dep_tristate 'Zoltrix Radio' CONFIG_RADIO_ZOLTRIX $CONFIG_VIDEO_DEV if [ "$CONFIG_RADIO_ZOLTRIX" = "y" ]; then hex ' ZOLTRIX I/O port (0x20c or 0x30c)' CONFIG_RADIO_ZOLTRIX_PORT 20c @@ -155,6 +171,8 @@ source drivers/char/joystick/Config.in fi endmenu + +tristate 'Double Talk PC internal speech card support' CONFIG_DTLK mainmenu_option next_comment comment 'Ftape, the floppy tape device driver' diff -ur --new-file old/linux/drivers/char/Makefile new/linux/drivers/char/Makefile --- old/linux/drivers/char/Makefile Sun Dec 27 19:49:06 1998 +++ new/linux/drivers/char/Makefile Fri May 7 20:05:30 1999 @@ -42,14 +42,20 @@ ifndef CONFIG_SUN_KEYBOARD ifdef CONFIG_VT -L_OBJS += keyboard.o +LX_OBJS += keyboard.o endif -ifneq ($(ARCH),m68k) -L_OBJS += pc_keyb.o defkeymap.o + ifneq ($(ARCH),m68k) + L_OBJS += pc_keyb.o defkeymap.o + endif +else +ifdef CONFIG_PCI +L_OBJS += defkeymap.o +LX_OBJS += keyboard.o endif -ifdef CONFIG_MAGIC_SYSRQ -L_OBJS += sysrq.o endif + +ifdef CONFIG_MAGIC_SYSRQ +LX_OBJS += sysrq.o endif ifeq ($(CONFIG_ATARI_DSP56K),y) @@ -134,6 +140,14 @@ endif endif +ifeq ($(CONFIG_SYNCLINK),m) + M_OBJS += synclink.o +endif + +ifeq ($(CONFIG_N_HDLC),m) + M_OBJS += n_hdlc.o +endif + ifeq ($(CONFIG_SPECIALIX),y) L_OBJS += specialix.o else @@ -176,6 +190,14 @@ endif endif +ifeq ($(CONFIG_DTLK),y) +L_OBJS += dtlk.o +else + ifeq ($(CONFIG_DTLK),m) + M_OBJS += dtlk.o + endif +endif + ifeq ($(CONFIG_MS_BUSMOUSE),y) L_OBJS += msbusmouse.o else @@ -261,12 +283,12 @@ endif ifeq ($(CONFIG_NVRAM),y) - ifeq ($(CONFIG_PMAC)$(CONFIG_CHRP),) + ifeq ($(CONFIG_PPC),) L_OBJS += nvram.o endif else ifeq ($(CONFIG_NVRAM),m) - ifeq ($(CONFIG_PMAC)$(CONFIG_CHRP),) + ifeq ($(CONFIG_PPC),) M_OBJS += nvram.o endif endif @@ -332,6 +354,14 @@ endif endif +ifeq ($(CONFIG_VIDEO_PLANB),y) +L_OBJS += planb.o +else + ifeq ($(CONFIG_VIDEO_PLANB),m) + M_OBJS += planb.o + endif +endif + ifeq ($(CONFIG_RADIO_AZTECH),y) L_OBJS += radio-aztech.o else @@ -364,6 +394,14 @@ endif endif +ifeq ($(CONFIG_RADIO_TYPHOON),y) +L_OBJS += radio-typhoon.o +else + ifeq ($(CONFIG_RADIO_TYPHOON),m) + M_OBJS += radio-typhoon.o + endif +endif + ifeq ($(CONFIG_RADIO_ZOLTRIX),y) L_OBJS += radio-zoltrix.o else @@ -372,6 +410,14 @@ endif endif +ifeq ($(CONFIG_RADIO_CADET),y) +L_OBJS += radio-cadet.o +else + ifeq ($(CONFIG_RADIO_CADET),m) + M_OBJS += radio-cadet.o + endif +endif + ifeq ($(CONFIG_RADIO_MIROPCM20),y) L_OBJS += radio-miropcm20.o else @@ -430,6 +476,7 @@ ALL_SUB_DIRS += hfmodem MOD_SUB_DIRS += hfmodem endif + endif include $(TOPDIR)/Rules.make diff -ur --new-file old/linux/drivers/char/README.epca new/linux/drivers/char/README.epca --- old/linux/drivers/char/README.epca Thu Jan 7 17:46:59 1999 +++ new/linux/drivers/char/README.epca Tue Mar 16 23:21:35 1999 @@ -504,3 +504,14 @@ Files affected : epca.c Release version : 1.1.1 (BETA) ----------------------------------------------------------------------- +Programmer : Daniel Taylor +Date : March 11, 1999 +Description (Verbose) : Updated driver: + 1. Simultaneous data and modem change events were + resulting in the modem change events not being + recognized. Fixed. + 2. Modified pc_info device name to work better + with devfs. +Files affected : epca.c +Release version : 1.3.0-K +----------------------------------------------------------------------- diff -ur --new-file old/linux/drivers/char/adbmouse.c new/linux/drivers/char/adbmouse.c --- old/linux/drivers/char/adbmouse.c Sun Nov 15 19:51:46 1998 +++ new/linux/drivers/char/adbmouse.c Thu Apr 29 21:53:48 1999 @@ -113,7 +113,7 @@ * on a logitech mouseman, the right and mid buttons sometimes behave * strangely until they both have been pressed after booting. */ /* data valid only if extended mouse format ! */ - if (nb == 4) + if (nb >= 4) buttons = (buttons&6) | (buf[3] & 0x80 ? 1 : 0); /* 1+3 unchanged */ add_mouse_randomness(((~buttons&7) << 16) + ((buf[2]&0x7f) << 8) + (buf[1]&0x7f)); diff -ur --new-file old/linux/drivers/char/amikeyb.c new/linux/drivers/char/amikeyb.c --- old/linux/drivers/char/amikeyb.c Thu Jul 30 20:17:11 1998 +++ new/linux/drivers/char/amikeyb.c Mon Apr 26 22:25:54 1999 @@ -188,7 +188,7 @@ amikeyb_rep_timer.expires = jiffies + key_repeat_rate; amikeyb_rep_timer.prev = amikeyb_rep_timer.next = NULL; add_timer(&amikeyb_rep_timer); - handle_scancode(rep_scancode); + handle_scancode(rep_scancode, 1); restore_flags(flags); } @@ -243,8 +243,8 @@ if (keycode == AMIKEY_CAPS) { /* if the key is CAPS, fake a press/release. */ - handle_scancode(AMIKEY_CAPS); - handle_scancode(BREAK_MASK | AMIKEY_CAPS); + handle_scancode(AMIKEY_CAPS, 1); + handle_scancode(AMIKEY_CAPS, 0); } else if (keycode < 0x78) { /* handle repeat */ if (break_flag) { @@ -257,7 +257,7 @@ amikeyb_rep_timer.prev = amikeyb_rep_timer.next = NULL; add_timer(&amikeyb_rep_timer); } - handle_scancode(scancode); + handle_scancode(scancode, !break_flag); } else switch (keycode) { case 0x78: diff -ur --new-file old/linux/drivers/char/bttv.c new/linux/drivers/char/bttv.c --- old/linux/drivers/char/bttv.c Mon Jan 25 06:54:35 1999 +++ new/linux/drivers/char/bttv.c Sun Apr 25 02:49:37 1999 @@ -120,6 +120,7 @@ #define I2C_TIMING (0x7<<4) #define I2C_DELAY 10 + #define I2C_SET(CTRL,DATA) \ { btwrite((CTRL<<1)|(DATA), BT848_I2C); udelay(I2C_DELAY); } #define I2C_GET() (btread(BT848_I2C)&1) @@ -244,6 +245,7 @@ { struct bttv *btv = (struct bttv*)bus->data; btwrite((ctrl<<1)|data, BT848_I2C); + btread(BT848_I2C); /* flush buffers */ udelay(I2C_DELAY); } @@ -537,6 +539,10 @@ { 3, 4, 0, 2, 15, { 2, 3, 1, 1}, { 13, 14, 11, 7, 0, 0}, 0}, /* Aimslab VHX */ { 3, 1, 0, 2, 7, { 2, 3, 1, 1}, { 0, 1, 2, 3, 4}}, + /* Zoltrix TV-Max */ + { 3, 1, 0, 2,15, { 2, 3, 1, 1}, { 0, 0, 0, 0, 0}}, + /* Pixelview PlayTV (bt878) */ + { 3, 4, 0, 2, 0x01e000, { 2, 0, 1, 1}, {0x01c000, 0, 0x018000, 0x014000, 0x002000, 0 }}, }; #define TVCARDS (sizeof(tvcards)/sizeof(tvcard)) @@ -1554,12 +1560,33 @@ static void bttv_close(struct video_device *dev) { struct bttv *btv=(struct bttv *)dev; - + btv->user--; audio(btv, AUDIO_INTERN); btv->cap&=~3; bt848_set_risc_jmps(btv); + /* + * A word of warning. At this point the chip + * is still capturing because its FIFO hasn't emptied + * and the DMA control operations are posted PCI + * operations. + */ + + btread(BT848_I2C); /* This fixes the PCI posting delay */ + + /* + * This is sucky but right now I can't find a good way to + * be sure its safe to free the buffer. We wait 5-6 fields + * which is more than sufficient to be sure. + */ + + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(HZ/10); /* Wait 1/10th of a second */ + + /* + * We have allowed it to drain. + */ if(btv->fbuffer) rvfree((void *) btv->fbuffer, 2*BTTV_MAX_FBUF); btv->fbuffer=0; @@ -2363,7 +2390,7 @@ btv->user--; btv->radio = 0; - audio(btv, AUDIO_MUTE); + /*audio(btv, AUDIO_MUTE);*/ MOD_DEC_USE_COUNT; } @@ -2826,6 +2853,16 @@ } #endif +static void init_tea6300(struct i2c_bus *bus) +{ + I2CWrite(bus, I2C_TEA6300, TEA6300_VL, 0x35, 1); /* volume left 0dB */ + I2CWrite(bus, I2C_TEA6300, TEA6300_VR, 0x35, 1); /* volume right 0dB */ + I2CWrite(bus, I2C_TEA6300, TEA6300_BA, 0x07, 1); /* bass 0dB */ + I2CWrite(bus, I2C_TEA6300, TEA6300_TR, 0x07, 1); /* treble 0dB */ + I2CWrite(bus, I2C_TEA6300, TEA6300_FA, 0x0f, 1); /* fader off */ + I2CWrite(bus, I2C_TEA6300, TEA6300_SW, 0x01, 1); /* mute off input A */ +} + static void init_tda8425(struct i2c_bus *bus) { I2CWrite(bus, I2C_TDA8425, TDA8425_VL, 0xFC, 1); /* volume left 0dB */ @@ -2880,9 +2917,6 @@ } else if (I2CRead(&(btv->i2c), I2C_STBEE)>=0) { btv->type=BTTV_STB; - } else - if (I2CRead(&(btv->i2c), I2C_VHX)>=0) { - btv->type=BTTV_VHX; } else { if (I2CRead(&(btv->i2c), 0x80)>=0) /* check for msp34xx */ btv->type = BTTV_MIROPRO; @@ -2905,10 +2939,16 @@ btv->pll.pll_crystal=BT848_IFORM_XT0; } } + + if (btv->type == BTTV_PIXVIEWPLAYTV) { + btv->pll.pll_ifreq=28636363; + btv->pll.pll_crystal=BT848_IFORM_XT0; + } + if(btv->type==BTTV_AVERMEDIA98) { - btv->pll.pll_ifreq=28636363; - btv->pll.pll_crystal=BT848_IFORM_XT0; + btv->pll.pll_ifreq=28636363; + btv->pll.pll_crystal=BT848_IFORM_XT0; } if (btv->have_tuner && btv->tuner_type != -1) @@ -2948,6 +2988,14 @@ break; } + if (I2CRead(&(btv->i2c), I2C_TEA6300) >=0) + { + printk(KERN_INFO "bttv%d: fader chip: TEA6300\n",btv->nr); + btv->audio_chip = TEA6300; + init_tea6300(&(btv->i2c)); + } else + printk(KERN_INFO "bttv%d: NO fader chip: TEA6300\n",btv->nr); + printk(KERN_INFO "bttv%d: model: ",btv->nr); sprintf(btv->video_dev.name,"BT%d",btv->id); @@ -3036,7 +3084,7 @@ btv->risc_jmp[12]=BT848_RISC_JUMP; btv->risc_jmp[13]=virt_to_bus(btv->risc_jmp); - /* enable cpaturing and DMA */ + /* enable capturing */ btaor(flags, ~0x0f, BT848_CAP_CTL); if (flags&0x0f) bt848_dma(btv, 3); @@ -3241,7 +3289,7 @@ if (astat&BT848_INT_SCERR) { IDEBUG(printk ("bttv%d: IRQ_SCERR\n", btv->nr)); bt848_dma(btv, 0); - bt848_dma(btv, 1); + bt848_dma(btv, 3); wake_up_interruptible(&btv->vbiq); wake_up_interruptible(&btv->capq); @@ -3728,6 +3776,8 @@ } #ifdef MODULE + +EXPORT_NO_SYMBOLS; int init_module(void) { diff -ur --new-file old/linux/drivers/char/bttv.h new/linux/drivers/char/bttv.h --- old/linux/drivers/char/bttv.h Mon Jan 25 06:54:35 1999 +++ new/linux/drivers/char/bttv.h Sun Apr 25 02:49:37 1999 @@ -114,6 +114,7 @@ int type; /* card type */ int audio; /* audio mode */ int audio_chip; + int fader_chip; int radio; u32 *risc_jmp; @@ -206,7 +207,9 @@ #define BTTV_MIROPRO 0x0b #define BTTV_ADSTECH_TV 0x0c #define BTTV_AVERMEDIA98 0x0d -#define BTTV_VHX 0x0e +#define BTTV_VHX 0x0e +#define BTTV_ZOLTRIX 0x0f +#define BTTV_PIXVIEWPLAYTV 0x10 #define AUDIO_TUNER 0x00 #define AUDIO_RADIO 0x01 @@ -220,6 +223,7 @@ #define TDA9850 0x01 #define TDA8425 0x02 #define TDA9840 0x03 +#define TEA6300 0x04 #define I2C_TSA5522 0xc2 #define I2C_TDA9840 0x84 @@ -228,6 +232,7 @@ #define I2C_HAUPEE 0xa0 #define I2C_STBEE 0xae #define I2C_VHX 0xc0 +#define I2C_TEA6300 0x80 #define TDA9840_SW 0x00 #define TDA9840_LVADJ 0x02 @@ -247,6 +252,12 @@ #define TDA8425_BA 0x02 #define TDA8425_TR 0x03 #define TDA8425_S1 0x08 - + +#define TEA6300_VL 0x00 /* volume control left */ +#define TEA6300_VR 0x01 /* volume control right */ +#define TEA6300_BA 0x02 /* bass control */ +#define TEA6300_TR 0x03 /* treble control */ +#define TEA6300_FA 0x04 /* fader control */ +#define TEA6300_SW 0x05 /* mute and source switch */ #endif diff -ur --new-file old/linux/drivers/char/bw-qcam.c new/linux/drivers/char/bw-qcam.c --- old/linux/drivers/char/bw-qcam.c Sat Oct 31 20:03:24 1998 +++ new/linux/drivers/char/bw-qcam.c Fri Mar 26 22:57:41 1999 @@ -5,6 +5,28 @@ * * Video4Linux conversion work by Alan Cox. * Parport compatibility by Phil Blundell. + * Busy loop avoidance by Mark Cooke. + * + * Module parameters: + * + * maxpoll=<1 - 5000> + * + * When polling the QuickCam for a response, busy-wait for a + * maximum of this many loops. The default of 250 gives little + * impact on interactive response. + * + * NOTE: If this parameter is set too high, the processor + * will busy wait until this loop times out, and then + * slowly poll for a further 5 seconds before failing + * the transaction. You have been warned. + * + * yieldlines=<1 - 250> + * + * When acquiring a frame from the camera, the data gathering + * loop will yield back to the scheduler after completing + * this many lines. The default of 4 provides a trade-off + * between increased frame acquisition time and impact on + * interactive response. */ /* qcam-lib.c -- Library for programming with the Connectix QuickCam. @@ -58,6 +80,14 @@ #include "bw-qcam.h" +#if LINUX_VERSION_CODE >= 0x020117 +MODULE_PARM(maxpoll,"i"); +MODULE_PARM(yieldlines,"i"); +#endif + +static unsigned int maxpoll=250; /* Maximum busy-loop count for qcam I/O */ +static unsigned int yieldlines=4; /* Yield after this many during capture */ + extern __inline__ int read_lpstatus(struct qcam_device *q) { return parport_read_status(q->pport); @@ -154,6 +184,7 @@ q->top = 1; q->left = 14; q->mode = -1; + q->status = QC_PARAM_CHANGE; return q; } @@ -209,14 +240,17 @@ { /* 1000 is enough spins on the I/O for all normal cases, at that point we start to poll slowly - until the camera wakes up */ + until the camera wakes up. However, we are + busy blocked until the camera responds, so + setting it lower is much better for interactive + response. */ - if(runs++>1000) + if(runs++>maxpoll) { current->state=TASK_INTERRUPTIBLE; - schedule_timeout(HZ/10); + schedule_timeout(HZ/200); } - if(runs>1050) + if(runs>(maxpoll+1000)) /* 5 seconds */ return -1; } } @@ -226,14 +260,17 @@ { /* 1000 is enough spins on the I/O for all normal cases, at that point we start to poll slowly - until the camera wakes up */ + until the camera wakes up. However, we are + busy blocked until the camera responds, so + setting it lower is much better for interactive + response. */ - if(runs++>1000) + if(runs++>maxpoll) { current->state=TASK_INTERRUPTIBLE; - schedule_timeout(HZ/10); + schedule_timeout(HZ/200); } - if(runs++>1050) /* 5 seconds */ + if(runs++>(maxpoll+1000)) /* 5 seconds */ return -1; } } @@ -256,14 +293,17 @@ status = read_lpdata(q); /* 1000 is enough spins on the I/O for all normal cases, at that point we start to poll slowly - until the camera wakes up */ + until the camera wakes up. However, we are + busy blocked until the camera responds, so + setting it lower is much better for interactive + response. */ - if(runs++>1000) + if(runs++>maxpoll) { current->state=TASK_INTERRUPTIBLE; - schedule_timeout(HZ/10); + schedule_timeout(HZ/200); } - if(runs++>1050) /* 5 seconds */ + if(runs++>(maxpoll+1000)) /* 5 seconds */ return 0; } while ((status & 1) != val); @@ -287,7 +327,7 @@ lastreg = reg = read_lpstatus(q) & 0xf0; - for (i = 0; i < 300; i++) + for (i = 0; i < 500; i++) { reg = read_lpstatus(q) & 0xf0; if (reg != lastreg) @@ -296,9 +336,20 @@ mdelay(2); } - /* Be liberal in what you accept... */ - if (count > 30 && count < 200) +#if 0 + /* Force camera detection during testing. Sometimes the camera + won't be flashing these bits. Possibly unloading the module + in the middle of a grab? Or some timeout condition? + I've seen this parameter as low as 19 on my 450Mhz box - mpc */ + printk("Debugging: QCam detection counter <30-200 counts as detected>: %d\n", count); + return 1; +#endif + + /* Be (even more) liberal in what you accept... */ + +/* if (count > 30 && count < 200) */ + if (count > 20 && count < 300) return 1; /* found */ else return 0; /* not found */ @@ -352,6 +403,8 @@ static int qc_setscanmode(struct qcam_device *q) { + int old_mode = q->mode; + switch (q->transfer_scale) { case 1: @@ -383,6 +436,10 @@ case QC_UNIDIR: break; } + + if (q->mode != old_mode) + q->status |= QC_PARAM_CHANGE; + return 0; } @@ -434,8 +491,11 @@ qc_command(q, q->contrast); qc_command(q, 0x1f); qc_command(q, q->whitebal); -} + /* Clear flag that we must update the grabbing parameters on the camera + before we grab the next frame */ + q->status &= (~QC_PARAM_CHANGE); +} /* Qc_readbytes reads some bytes from the QC and puts them in the supplied buffer. It returns the number of bytes read, @@ -539,7 +599,7 @@ long qc_capture(struct qcam_device * q, char *buf, unsigned long len) { - int i, j, k; + int i, j, k, yield; int bytes; int linestotrans, transperline; int divisor; @@ -575,7 +635,7 @@ q->transfer_scale; transperline = (transperline + divisor - 1) / divisor; - for (i = 0; i < linestotrans; i++) + for (i = 0, yield = yieldlines; i < linestotrans; i++) { for (pixels_read = j = 0; j < transperline; j++) { @@ -599,6 +659,18 @@ pixels_read += bytes; } (void) qc_readbytes(q, 0); /* reset state machine */ + + /* Grabbing an entire frame from the quickcam is a lengthy + process. We don't (usually) want to busy-block the + processor for the entire frame. yieldlines is a module + parameter. If we yield every line, the minimum frame + time will be 240 / 200 = 1.2 seconds. The compile-time + default is to yield every 4 lines. */ + if (i >= yield) { + current->state=TASK_INTERRUPTIBLE; + schedule_timeout(HZ/200); + yield = i + yieldlines; + } } if ((q->port_mode & QC_MODE_MASK) == QC_BIDIR) @@ -745,9 +817,12 @@ qcam->bpp = p.depth; qc_setscanmode(qcam); - parport_claim_or_block(qcam->pdev); + qcam->status |= QC_PARAM_CHANGE; + +/* parport_claim_or_block(qcam->pdev); qc_set(qcam); parport_release(qcam->pdev); +*/ return 0; } case VIDIOCSWIN: @@ -779,6 +854,11 @@ qcam->transfer_scale = 1; } qc_setscanmode(qcam); + + /* We must update the camera before we grab. We could + just have changed the grab size */ + qcam->status |= QC_PARAM_CHANGE; + /* Ok we figured out what to use from our wide choice */ return 0; } @@ -824,11 +904,15 @@ parport_claim_or_block(qcam->pdev); /* Probably should have a semaphore against multiple users */ qc_reset(qcam); + + /* Update the camera parameters if we need to */ + if (qcam->status & QC_PARAM_CHANGE) + qc_set(qcam); + len=qc_capture(qcam, buf,count); parport_release(qcam->pdev); return len; } - static struct video_device qcam_template= { @@ -902,13 +986,54 @@ kfree(qcam); } +/* The parport parameter controls which parports will be scanned. + * Scanning all parports causes some printers to print a garbage page. + * -- March 14, 1999 Billy Donahue */ +#ifdef MODULE +static char *parport[MAX_CAMS] = { NULL, }; +MODULE_PARM(parport, "1-" __MODULE_STRING(MAX_CAMS) "s"); +#endif + #ifdef MODULE int init_module(void) { struct parport *port; - + int n; + if(parport[0] && strncmp(parport[0], "auto", 4)){ + /* user gave parport parameters */ + for(n=0; parport[n] && nnext){ + if(r!=port->number) + continue; + init_bwqcam(port); + break; + } + } + return (num_cams)?0:-ENODEV; + } + /* no parameter or "auto" */ for (port = parport_enumerate(); port; port=port->next) init_bwqcam(port); + + /* Do some sanity checks on the module parameters. */ + if (maxpoll > 5000) { + printk("Connectix Quickcam max-poll was above 5000. Using 5000.\n"); + maxpoll = 5000; + } + + if (yieldlines < 1) { + printk("Connectix Quickcam yieldlines was less than 1. Using 1.\n"); + yieldlines = 1; + } return (num_cams)?0:-ENODEV; } diff -ur --new-file old/linux/drivers/char/bw-qcam.h new/linux/drivers/char/bw-qcam.h --- old/linux/drivers/char/bw-qcam.h Mon Jan 12 23:46:16 1998 +++ new/linux/drivers/char/bw-qcam.h Thu Mar 11 02:03:52 1999 @@ -48,6 +48,9 @@ #define MAX_HEIGHT 243 #define MAX_WIDTH 336 +/* Bit fields for status flags */ +#define QC_PARAM_CHANGE 0x01 /* Camera status change has occurred */ + struct qcam_device { struct video_device vdev; struct pardevice *pdev; @@ -59,6 +62,6 @@ int port_mode; int transfer_scale; int top, left; + int status; unsigned int saved_bits; }; - diff -ur --new-file old/linux/drivers/char/console.c new/linux/drivers/char/console.c --- old/linux/drivers/char/console.c Tue Jan 19 19:10:23 1999 +++ new/linux/drivers/char/console.c Thu Mar 11 01:51:35 1999 @@ -85,7 +85,6 @@ #include #include #include -#include #include #include #include @@ -203,7 +202,14 @@ static inline unsigned short *screenpos(int currcons, int offset, int viewed) { - unsigned short *p = (unsigned short *)(visible_origin + offset); + unsigned short *p; + + if (!viewed) + p = (unsigned short *)(origin + offset); + else if (!sw->con_screen_pos) + p = (unsigned short *)(visible_origin + offset); + else + p = sw->con_screen_pos(vc_cons[currcons].d, offset); return p; } @@ -253,16 +259,16 @@ unsigned int xx, yy, offset; u16 *p; - if (start < origin) { - count -= origin - start; - start = origin; - } - if (count <= 0) - return; - offset = (start - origin) / 2; - xx = offset % video_num_columns; - yy = offset / video_num_columns; p = (u16 *) start; + if (!sw->con_getxy) { + offset = (start - origin) / 2; + xx = offset % video_num_columns; + yy = offset / video_num_columns; + } else { + int nxx, nyy; + start = sw->con_getxy(vc_cons[currcons].d, start, &nxx, &nyy); + xx = nxx; yy = nyy; + } for(;;) { u16 attrib = scr_readw(p) & 0xff00; int startx = xx; @@ -285,6 +291,10 @@ break; xx = 0; yy++; + if (sw->con_getxy) { + p = (u16 *)start; + start = sw->con_getxy(vc_cons[currcons].d, start, NULL, NULL); + } } #endif } @@ -2778,7 +2788,7 @@ set_cursor(currcons); } -u16 vcs_scr_readw(int currcons, u16 *org) +u16 vcs_scr_readw(int currcons, const u16 *org) { if ((unsigned long)org == pos && softcursor_original != -1) return softcursor_original; diff -ur --new-file old/linux/drivers/char/cyclades.c new/linux/drivers/char/cyclades.c --- old/linux/drivers/char/cyclades.c Wed Jan 20 22:26:20 1999 +++ new/linux/drivers/char/cyclades.c Mon Apr 12 19:09:47 1999 @@ -1,7 +1,7 @@ #define BLOCKMOVE #define Z_WAKE static char rcsid[] = -"$Revision: 2.2.1.10 $$Date: 1999/01/20 16:14:29 $"; +"$Revision: 2.2.2.1 $$Date: 1999/04/08 16:17:43 $"; /* * linux/drivers/char/cyclades.c @@ -31,6 +31,13 @@ * void cleanup_module(void); * * $Log: cyclades.c,v $ + * Revision 2.2.2.1 1999/04/08 16:17:43 ivan + * Fixed a bug in cy_wait_until_sent that was preventing the port to be + * closed properly after a SIGINT; + * Module usage counter scheme revisited; + * Added support to the upcoming Y PCI boards (i.e., support to additional + * PCI Device ID's). + * * Revision 2.2.1.10 1999/01/20 16:14:29 ivan * Removed all unnecessary page-alignement operations in ioremap calls * (ioremap is currently safe for these operations). @@ -525,9 +532,11 @@ #undef CY_DEBUG_COUNT #undef CY_DEBUG_DTR #undef CY_DEBUG_WAIT_UNTIL_SENT +#undef CY_DEBUG_INTERRUPTS #undef CY_16Y_HACK #undef CY_ENABLE_MONITORING #undef CY_PCI_DEBUG +#define CY_PROC #if 0 #define PAUSE __asm__("nop"); @@ -763,16 +772,20 @@ /* PCI related definitions */ -static unsigned short cy_pci_nboard = 0; -static unsigned short cy_isa_nboard = 0; -static unsigned short cy_nboard = 0; -static unsigned short cy_pci_dev_id[] = { - PCI_DEVICE_ID_CYCLOM_Y_Lo,/* PCI below 1Mb */ - PCI_DEVICE_ID_CYCLOM_Y_Hi,/* PCI above 1Mb */ - PCI_DEVICE_ID_CYCLOM_Z_Lo,/* PCI below 1Mb */ - PCI_DEVICE_ID_CYCLOM_Z_Hi,/* PCI above 1Mb */ - 0 /* end of table */ - }; +static unsigned short cy_pci_nboard = 0; +static unsigned short cy_isa_nboard = 0; +static unsigned short cy_nboard = 0; +static unsigned short cy_pci_dev_id[] = { + PCI_DEVICE_ID_CYCLOM_Y_Lo, /* PCI < 1Mb */ + PCI_DEVICE_ID_CYCLOM_Y_Hi, /* PCI > 1Mb */ + PCI_DEVICE_ID_CYCLOM_4Y_Lo, /* 4Y PCI < 1Mb */ + PCI_DEVICE_ID_CYCLOM_4Y_Hi, /* 4Y PCI > 1Mb */ + PCI_DEVICE_ID_CYCLOM_8Y_Lo, /* 8Y PCI < 1Mb */ + PCI_DEVICE_ID_CYCLOM_8Y_Hi, /* 8Y PCI > 1Mb */ + PCI_DEVICE_ID_CYCLOM_Z_Lo, /* Z PCI < 1Mb */ + PCI_DEVICE_ID_CYCLOM_Z_Hi, /* Z PCI > 1Mb */ + 0 /* end of table */ + }; static void cy_start(struct tty_struct *); @@ -2448,12 +2461,15 @@ int retval, line; unsigned long page; + MOD_INC_USE_COUNT; line = MINOR(tty->device) - tty->driver.minor_start; if ((line < 0) || (NR_PORTS <= line)){ + MOD_DEC_USE_COUNT; return -ENODEV; } info = &cy_port[line]; if (info->line < 0){ + MOD_DEC_USE_COUNT; return -ENODEV; } @@ -2479,6 +2495,8 @@ #ifdef CY_DEBUG_OTHER printk("cyc:cy_open ttyC%d\n", info->line); /* */ #endif + tty->driver_data = info; + info->tty = tty; if (serial_paranoia_check(info, tty->device, "cy_open")){ return -ENODEV; } @@ -2491,9 +2509,6 @@ printk("cyc:cy_open (%d): incrementing count to %d\n", current->pid, info->count); #endif - tty->driver_data = info; - info->tty = tty; - if (!tmp_buf) { page = get_free_page(GFP_KERNEL); if (!page) @@ -2521,8 +2536,6 @@ return retval; } - MOD_INC_USE_COUNT; - retval = block_til_ready(tty, filp, info); if (retval) { #ifdef CY_DEBUG_OPEN @@ -2563,6 +2576,10 @@ if (serial_paranoia_check(info, tty->device, "cy_wait_until_sent")) 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 @@ -2580,6 +2597,17 @@ timeout = 0; if (timeout) char_time = MIN(char_time, timeout); + /* + * If the transmitter hasn't cleared in twice the approximate + * amount of time to send the entire FIFO, it probably won't + * ever clear. This assumes the UART isn't doing flow + * control, which is currently the case. Hence, if it ever + * takes longer than info->timeout, this is probably due to a + * UART bug of some kind. So, we clamp the timeout parameter at + * 2*info->timeout. + */ + if (!timeout || timeout > 2*info->timeout) + timeout = 2*info->timeout; #ifdef CY_DEBUG_WAIT_UNTIL_SENT printk("In cy_wait_until_sent(%d) check=%lu...", timeout, char_time); printk("jiff=%lu...", jiffies); @@ -2601,7 +2629,7 @@ schedule_timeout(char_time); if (signal_pending(current)) break; - if (timeout && time_before(orig_jiffies + timeout, jiffies)) + if (timeout && time_after(jiffies, orig_jiffies + timeout)) break; } current->state = TASK_RUNNING; @@ -2631,13 +2659,9 @@ printk("cyc:cy_close ttyC%d\n", info->line); #endif - if (!info - || serial_paranoia_check(info, tty->device, "cy_close")){ + if (!info || serial_paranoia_check(info, tty->device, "cy_close")){ return; } -#ifdef CY_DEBUG_OPEN - printk("cyc:cy_close ttyC%d, count = %d\n", info->line, info->count); -#endif save_flags(flags); cli(); @@ -2648,6 +2672,9 @@ return; } +#ifdef CY_DEBUG_OPEN + printk("cyc:cy_close ttyC%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 @@ -4579,6 +4606,8 @@ cy_pci_addr2 = pdev->base_address[2]; pci_read_config_byte(pdev, PCI_REVISION_ID, &cyy_rev_id); + device_id &= ~PCI_DEVICE_ID_MASK; + if ((device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo) || (device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi)){ #ifdef CY_PCI_DEBUG @@ -4942,6 +4971,7 @@ __DATE__, __TIME__); } /* show_version */ +#ifdef CY_PROC static int cyclades_get_proc_info(char *buf, char **start, off_t offset, int length, int *eof, void *data) @@ -4998,7 +5028,7 @@ len = 0; return len; } - +#endif /* The serial driver boot-time initialization code! Hardware I/O ports are mapped to character special devices on a @@ -5028,7 +5058,9 @@ unsigned long mailbox; unsigned short chip_number; int nports; +#ifdef CY_PROC struct proc_dir_entry *ent; +#endif show_version(); @@ -5269,8 +5301,10 @@ #endif } +#ifdef CY_PROC ent = create_proc_entry("cyclades", S_IFREG | S_IRUGO, 0); ent->read_proc = cyclades_get_proc_info; +#endif return 0; @@ -5314,7 +5348,7 @@ free_irq(cy_card[i].irq,NULL); } } -#ifdef CONFIG_PROC_FS +#ifdef CY_PROC remove_proc_entry("cyclades", 0); #endif diff -ur --new-file old/linux/drivers/char/dn_keyb.c new/linux/drivers/char/dn_keyb.c --- old/linux/drivers/char/dn_keyb.c Mon Aug 24 22:02:44 1998 +++ new/linux/drivers/char/dn_keyb.c Mon Apr 26 22:28:07 1999 @@ -414,9 +414,9 @@ } else if((scancode & (~BREAK_FLAG)) == DNKEY_CAPS) { /* printk("handle_scancode: %02x\n",DNKEY_CAPS); */ - handle_scancode(DNKEY_CAPS); + handle_scancode(DNKEY_CAPS, 1); /* printk("handle_scancode: %02x\n",BREAK_FLAG | DNKEY_CAPS); */ - handle_scancode(BREAK_FLAG | DNKEY_CAPS); + handle_scancode(DNKEY_CAPS, 0); } else if( (scancode == DNKEY_REPEAT) && (prev_scancode < 0x7e) && !(prev_scancode==DNKEY_CTRL || prev_scancode==DNKEY_LSHIFT || @@ -424,13 +424,13 @@ prev_scancode==DNKEY_LALT || prev_scancode==DNKEY_RALT)) { if(jiffies-lastkeypress > DNKEY_REPEAT_DELAY) { /* printk("handle_scancode: %02x\n",prev_scancode); */ - handle_scancode(prev_scancode); + handle_scancode(prev_scancode, 1); } lastscancode=prev_scancode; } else { /* printk("handle_scancode: %02x\n",scancode); */ - handle_scancode(scancode); + handle_scancode(scancode & ~BREAK_FLAG, !(scancode & BREAK_FLAG)); lastkeypress=jiffies; } } diff -ur --new-file old/linux/drivers/char/dtlk.c new/linux/drivers/char/dtlk.c --- old/linux/drivers/char/dtlk.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/char/dtlk.c Fri Apr 16 17:20:23 1999 @@ -0,0 +1,720 @@ +/* -*- linux-c -*- + * dtlk.c - DoubleTalk PC driver for Linux kernel 2.0.29 + * + * $Id: dtlk.c,v 1.19 1999/02/28 12:13:13 jrv Exp jrv $ + * + * Original author: Chris Pallotta + * Current maintainer: Jim Van Zandt + */ + +/* This driver is for the DoubleTalk PC, a speech synthesizer + manufactured by RC Systems (http://www.rcsys.com/). It was written + based on documentation in their User's Manual file and Developer's + Tools disk. + + The DoubleTalk PC contains four voice synthesizers: text-to-speech + (TTS), linear predictive coding (LPC), PCM/ADPCM, and CVSD. It + also has a tone generator. Output data for LPC are written to the + LPC port, and output data for the other modes are written to the + TTS port. + + Two kinds of data can be read from the DoubleTalk: status + information (in response to the "\001?" interrogation command) is + read from the TTS port, and index markers (which mark the progress + of the speech) are read from the LPC port. Not all models of the + DoubleTalk PC implement index markers. Both the TTS and LPC ports + can also display status flags. + + The DoubleTalk PC generates no interrupts. + + These characteristics are mapped into the Unix stream I/O model as + follows: + + "write" sends bytes to the TTS port. It is the responsibility of + the user program to switch modes among TTS, PCM/ADPCM, and CVSD. + This driver was written for use with the text-to-speech + synthesizer. If LPC output is needed some day, other minor device + numbers can be used to select among output modes. + + "read" gets index markers from the LPC port. If the device does + not implement index markers, the read will fail with error EINVAL. + + Status information is available using the DTLK_INTERROGATE ioctl. + + */ + +#ifdef MODVERSIONS +#include +#endif + +#ifdef MODULE +#include +#include +#else +#define MOD_INC_USE_COUNT +#define MOD_DEC_USE_COUNT +#endif + +#define KERNEL +#include +#include +#include /* for verify_area */ +#include /* for -EBUSY */ +#include /* for check_region, request_region */ +#include /* for loops_per_sec */ +#include /* for put_user_byte */ +#include /* for inb_p, outb_p, inb, outb, etc. */ +#include /* for get_user, etc. */ +#include /* for wait_queue */ +#include /* for __init */ +#include /* for POLLIN, etc. */ +#include /* local header file for DoubleTalk values */ + +#ifdef TRACING +#define TRACE_TEXT(str) printk(str); +#define TRACE_RET printk(")") +#else /* !TRACING */ +#define TRACE_TEXT(str) ((void) 0) +#define TRACE_RET ((void) 0) +#endif /* TRACING */ + + +static int dtlk_major; +static int dtlk_port_lpc; +static int dtlk_port_tts; +static int dtlk_busy; +static int dtlk_timer_active; +static int dtlk_has_indexing; +static unsigned int dtlk_portlist[] = +{0x25e, 0x29e, 0x2de, 0x31e, 0x35e, 0x39e, 0}; +static struct wait_queue *dtlk_process_list = NULL; +static struct timer_list dtlk_timer; + +/* prototypes for file_operations struct */ +static ssize_t dtlk_read(struct file *, char *, + size_t nbytes, loff_t * ppos); +static ssize_t dtlk_write(struct file *, const char *, + size_t nbytes, loff_t * ppos); +static unsigned int dtlk_poll(struct file *, poll_table *); +static int dtlk_open(struct inode *, struct file *); +static int dtlk_release(struct inode *, struct file *); +static int dtlk_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg); + +static struct file_operations dtlk_fops = +{ + NULL, /* lseek */ + dtlk_read, + dtlk_write, + NULL, /* readdir */ + dtlk_poll, + dtlk_ioctl, + NULL, /* mmap */ + dtlk_open, + NULL, /* flush */ + dtlk_release, + NULL, /* fsync */ + NULL, /* fasync */ + NULL, /* check_media_change */ + NULL, /* revalidate */ + NULL /* lock */ +}; + +/* local prototypes */ +static void dtlk_delay(int ms); +static int dtlk_dev_probe(void); +static struct dtlk_settings *dtlk_interrogate(void); +static int dtlk_readable(void); +static char dtlk_read_lpc(void); +static char dtlk_read_tts(void); +static void dtlk_stop_timer(void); +static int dtlk_writeable(void); +static char dtlk_write_bytes(const char *buf, int n); +static char dtlk_write_tts(char); +/* + static void dtlk_handle_error(char, char, unsigned int); + static char dtlk_write_byte(unsigned int, const char*); + */ +static void dtlk_timer_tick(unsigned long data); + +static ssize_t dtlk_read(struct file *file, char *buf, + size_t count, loff_t * ppos) +{ + unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev); + char ch; + int retval, i = 0, retries; + + /* Can't seek (pread) on the DoubleTalk. */ + if (ppos != &file->f_pos) + return -ESPIPE; + + TRACE_TEXT("(dtlk_read"); + /* printk("DoubleTalk PC - dtlk_read()\n"); */ + + if (minor != DTLK_MINOR || !dtlk_has_indexing) + return -EINVAL; + + for (retries = 0; retries < loops_per_sec / 10; retries++) { + while (i < count && dtlk_readable()) { + ch = dtlk_read_lpc(); + /* printk("dtlk_read() reads 0x%02x\n", ch); */ + if ((retval = put_user(ch, buf++))) + return retval; + i++; + } + if (i) + return i; + if (file->f_flags & O_NONBLOCK) + break; + dtlk_delay(10); + } + if (retries == loops_per_sec) + printk(KERN_ERR "dtlk_read times out\n"); + TRACE_RET; + return -EAGAIN; +} + +static ssize_t dtlk_write(struct file *file, const char *buf, + size_t count, loff_t * ppos) +{ + int i = 0, retries = 0, err, ch; + + TRACE_TEXT("(dtlk_write"); +#ifdef TRACING + printk(" \""); + { + int i, ch; + for (i = 0; i < count; i++) { + err = get_user(ch, buf + i); + if (' ' <= ch && ch <= '~') + printk("%c", ch); + else + printk("\\%03o", ch); + } + printk("\""); + } +#endif + + /* Can't seek (pwrite) on the DoubleTalk. */ + if (ppos != &file->f_pos) + return -ESPIPE; + + if (MINOR(file->f_dentry->d_inode->i_rdev) != DTLK_MINOR) + return -EINVAL; + + while (1) { + while (i < count && (err = get_user(ch, buf)) == 0 && + (ch == DTLK_CLEAR || dtlk_writeable())) { + dtlk_write_tts(ch); + buf++; + i++; + if (i % 5 == 0) + /* We yield our time until scheduled + again. This reduces the transfer + rate to 500 bytes/sec, but that's + still enough to keep up with the + speech synthesizer. */ + dtlk_delay(1); + else { + /* the RDY bit goes zero 2-3 usec + after writing, and goes 1 again + 180-190 usec later. Here, we wait + up to 250 usec for the RDY bit to + go nonzero. */ + for (retries = 0; + retries < loops_per_sec / 4000; + retries++) + if (inb_p(dtlk_port_tts) & + TTS_WRITABLE) + break; + } + retries = 0; + } + if (i == count) + return i; + if (file->f_flags & O_NONBLOCK) + break; + + dtlk_delay(1); + + if (++retries > 10 * HZ) { /* wait no more than 10 sec + from last write */ + printk("dtlk: write timeout. " + "inb_p(dtlk_port_tts) = 0x%02x\n", + inb_p(dtlk_port_tts)); + TRACE_RET; + return -EBUSY; + } + } + TRACE_RET; + return -EAGAIN; +} + +static unsigned int dtlk_poll(struct file *file, poll_table * wait) +{ + int mask = 0; + TRACE_TEXT(" dtlk_poll"); + /* + static long int j; + printk("."); + printk("<%ld>", jiffies-j); + j=jiffies; + */ + poll_wait(file, &dtlk_process_list, wait); + + if (dtlk_has_indexing && dtlk_readable()) { + dtlk_stop_timer(); + mask = POLLIN | POLLRDNORM; + } + if (dtlk_writeable()) { + dtlk_stop_timer(); + mask |= POLLOUT | POLLWRNORM; + } + /* there are no exception conditions */ + + if (mask == 0 && !dtlk_timer_active) { + /* not ready just yet. There won't be any interrupts, + so we set a timer instead. */ + dtlk_timer_active = 1; + dtlk_timer.expires = jiffies + HZ / 100; + add_timer(&dtlk_timer); + } + return 0; +} + +static void dtlk_stop_timer() +{ + if (dtlk_timer_active) { + dtlk_timer_active = 0; + del_timer(&dtlk_timer); + } +} + +static void dtlk_timer_tick(unsigned long data) +{ + + wake_up_interruptible(&dtlk_process_list); + + if (dtlk_timer_active) { + del_timer(&dtlk_timer); + dtlk_timer.expires = jiffies + HZ / 100; + add_timer(&dtlk_timer); + } +} + +static int dtlk_ioctl(struct inode *inode, + struct file *file, + unsigned int cmd, + unsigned long arg) +{ + struct dtlk_settings *sp; + int err; + char portval; + TRACE_TEXT(" dtlk_ioctl"); + + switch (cmd) { + + case DTLK_INTERROGATE: + sp = dtlk_interrogate(); + err = copy_to_user((char *) arg, (char *) sp, + sizeof(struct dtlk_settings)); + if (err) + return -EINVAL; + return 0; + + case DTLK_STATUS: + portval = inb_p(dtlk_port_tts); + return put_user(portval, (char *) arg); + + default: + return -EINVAL; + } +} + +static int dtlk_open(struct inode *inode, struct file *file) +{ + MOD_INC_USE_COUNT; + TRACE_TEXT("(dtlk_open"); + + switch (MINOR(inode->i_rdev)) { + case DTLK_MINOR: + if (dtlk_busy) + return -EBUSY; + return 0; + + default: + return -ENXIO; + } +} + +static int dtlk_release(struct inode *inode, struct file *file) +{ + MOD_DEC_USE_COUNT; + TRACE_TEXT("(dtlk_release"); + + switch (MINOR(inode->i_rdev)) { + case DTLK_MINOR: + break; + + default: + break; + } + TRACE_RET; + + dtlk_stop_timer(); + + return 0; +} + +int __init dtlk_init(void) +{ + dtlk_port_lpc = 0; + dtlk_port_tts = 0; + dtlk_busy = 0; + dtlk_timer_active = 0; + dtlk_major = register_chrdev(0, "dtlk", &dtlk_fops); + if (dtlk_major == 0) { + printk(KERN_ERR "DoubleTalk PC - cannot register device\n"); + return 0; + } + if (dtlk_dev_probe() == 0) + printk(", MAJOR %d\n", dtlk_major); + + init_timer(&dtlk_timer); + dtlk_timer.function = dtlk_timer_tick; + dtlk_process_list = NULL; + + return 0; +} + +#ifdef MODULE +int init_module(void) +{ + return dtlk_init(); +} + +void cleanup_module(void) +{ + dtlk_write_bytes("goodbye", 8); + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(5 * HZ / 10); /* nap 0.50 sec but + could be awakened + earlier by + signals... */ + + dtlk_write_tts(DTLK_CLEAR); + unregister_chrdev(dtlk_major, "dtlk"); + release_region(dtlk_port_lpc, DTLK_IO_EXTENT); +} + +#endif + +/* ------------------------------------------------------------------------ */ + +/* sleep for ms milliseconds */ +static void dtlk_delay(int ms) +{ + current->state = TASK_INTERRUPTIBLE; + schedule_timeout((ms * HZ + 1000 - HZ) / 1000); + current->state = TASK_RUNNING; +} + +static int dtlk_readable(void) +{ + TRACE_TEXT(" dtlk_readable"); + return inb_p(dtlk_port_lpc) != 0x7f; +} + +static int dtlk_writeable(void) +{ + /* TRACE_TEXT(" dtlk_writeable"); */ +#ifdef TRACING + printk(" dtlk_writeable(%02x)", inb_p(dtlk_port_tts)); +#endif + return inb_p(dtlk_port_tts) & TTS_WRITABLE; +} + +static int __init dtlk_dev_probe(void) +{ + unsigned int testval = 0; + int i = 0; + struct dtlk_settings *sp; + + if (dtlk_port_lpc | dtlk_port_tts) + return -EBUSY; + + for (i = 0; dtlk_portlist[i]; i++) { +#if 0 + printk("DoubleTalk PC - Port %03x = %04x\n", + dtlk_portlist[i], (testval = inw_p(dtlk_portlist[i]))); +#endif + + if (check_region(dtlk_portlist[i], DTLK_IO_EXTENT)) + continue; + testval = inw_p(dtlk_portlist[i]); + if ((testval &= 0xfbff) == 0x107f) { + request_region(dtlk_portlist[i], DTLK_IO_EXTENT, + "dtlk"); + dtlk_port_lpc = dtlk_portlist[i]; + dtlk_port_tts = dtlk_port_lpc + 1; + + sp = dtlk_interrogate(); + printk("DoubleTalk PC at %03x-%03x, " + "ROM version %s, serial number %u", + dtlk_portlist[i], dtlk_portlist[i] + + DTLK_IO_EXTENT - 1, + sp->rom_version, sp->serial_number); + + /* put LPC port into known state, so + dtlk_readable() gives valid result */ + outb_p(0xff, dtlk_port_lpc); + + /* INIT string and index marker */ + dtlk_write_bytes("\036\1@\0\0012I\r", 8); + /* posting an index takes 18 msec. Here, we + wait up to 100 msec to see whether it + appears. */ + dtlk_delay(100); + dtlk_has_indexing = dtlk_readable(); + +#ifdef INSCOPE + { +/* This macro records ten samples read from the LPC port, for later display */ +#define LOOK \ +for (i = 0; i < 10; i++) \ + { \ + buffer[b++] = inb_p(dtlk_port_lpc); \ + __delay(loops_per_sec/1000000); \ + } + char buffer[1000]; + int b = 0, i, j; + + LOOK + outb_p(0xff, dtlk_port_lpc); + buffer[b++] = 0; + LOOK + dtlk_write_bytes("\0012I\r", 4); + buffer[b++] = 0; + __delay(50 * loops_per_sec / 1000); + outb_p(0xff, dtlk_port_lpc); + buffer[b++] = 0; + LOOK + + printk("\n"); + for (j = 0; j < b; j++) + printk(" %02x", buffer[j]); + printk("\n"); + } +#endif /* INSCOPE */ + +#ifdef OUTSCOPE + { +/* This macro records ten samples read from the TTS port, for later display */ +#define LOOK \ +for (i = 0; i < 10; i++) \ + { \ + buffer[b++] = inb_p(dtlk_port_tts); \ + __delay(loops_per_sec/1000000); /* 1 us */ \ + } + char buffer[1000]; + int b = 0, i, j; + + __delay(loops_per_sec / 100); /* 10 ms */ + LOOK + outb_p(0x03, dtlk_port_tts); + buffer[b++] = 0; + LOOK + LOOK + + printk("\n"); + for (j = 0; j < b; j++) + printk(" %02x", buffer[j]); + printk("\n"); + } +#endif /* OUTSCOPE */ + + dtlk_write_bytes("Double Talk found", 18); + + return 0; + } + } + + printk(KERN_INFO "\nDoubleTalk PC - not found\n"); + return -ENODEV; +} + +/* + static void dtlk_handle_error(char op, char rc, unsigned int minor) + { + printk(KERN_INFO"\nDoubleTalk PC - MINOR: %d, OPCODE: %d, ERROR: %d\n", + minor, op, rc); + return; + } + */ + +/* interrogate the DoubleTalk PC and return its settings */ +static struct dtlk_settings *dtlk_interrogate(void) +{ + unsigned char *t; + static char buf[sizeof(struct dtlk_settings) + 1]; + int total, i; + static struct dtlk_settings status; + TRACE_TEXT("(dtlk_interrogate"); + dtlk_write_bytes("\030\001?", 3); + for (total = 0, i = 0; i < 50; i++) { + buf[total] = dtlk_read_tts(); + if (total > 2 && buf[total] == 0x7f) + break; + if (total < sizeof(struct dtlk_settings)) + total++; + } + /* + if (i==50) printk("interrogate() read overrun\n"); + for (i=0; i 0); + if (retries == 0) + printk(KERN_ERR "dtlk_read_lpc() timeout\n"); + + TRACE_RET; + return ch; +} + +#ifdef NEVER +static char dtlk_write_byte(unsigned int minor, const char *buf) +{ + char ch; + int err; + /* TRACE_TEXT("(dtlk_write_byte"); */ + err = get_user(ch, buf); + /* printk(" dtlk_write_byte(%d, 0x%02x)", minor, (int)ch); */ + + ch = dtlk_write_tts(ch); + /* + TRACE_RET; */ + return ch; +} +#endif /* NEVER */ + +/* write n bytes to tts port */ +static char dtlk_write_bytes(const char *buf, int n) +{ + char val = 0; + /* printk("dtlk_write_bytes(\"%-*s\", %d)\n", n, buf, n); */ + TRACE_TEXT("(dtlk_write_bytes"); + while (n-- > 0) + val = dtlk_write_tts(*buf++); + TRACE_RET; + return val; +} + +static char dtlk_write_tts(char ch) +{ + int retries = 0; +#ifdef TRACING + printk(" dtlk_write_tts("); + if (' ' <= ch && ch <= '~') + printk("'%c'", ch); + else + printk("0x%02x", ch); +#endif + if (ch != DTLK_CLEAR) /* no flow control for CLEAR command */ + while ((inb_p(dtlk_port_tts) & TTS_WRITABLE) == 0 && + retries++ < DTLK_MAX_RETRIES) /* DT ready? */ + ; + if (retries == DTLK_MAX_RETRIES) + printk(KERN_ERR "dtlk_write_tts() timeout\n"); + + outb_p(ch, dtlk_port_tts); /* output to TTS port */ + /* the RDY bit goes zero 2-3 usec after writing, and goes + 1 again 180-190 usec later. Here, we wait up to 10 + usec for the RDY bit to go zero. */ + for (retries = 0; retries < loops_per_sec / 100000; retries++) + if ((inb_p(dtlk_port_tts) & TTS_WRITABLE) == 0) + break; + +#ifdef TRACING + printk(")\n"); +#endif + return 0; +} diff -ur --new-file old/linux/drivers/char/epca.c new/linux/drivers/char/epca.c --- old/linux/drivers/char/epca.c Sun Jan 10 04:16:43 1999 +++ new/linux/drivers/char/epca.c Tue Mar 16 23:21:51 1999 @@ -83,7 +83,6 @@ #include #include #include -#include #include #ifdef MODULE @@ -117,7 +116,7 @@ /* ---------------------- Begin defines ------------------------ */ -#define VERSION "1.1.0" +#define VERSION "1.3.0-K" /* This major needs to be submitted to Linux to join the majors list */ @@ -1814,9 +1813,10 @@ pc_callout.subtype = SERIAL_TYPE_CALLOUT; pc_info = pc_driver; - pc_info.name = "digiCtl"; + pc_info.name = "digi_ctl"; pc_info.major = DIGIINFOMAJOR; pc_info.minor_start = 0; + pc_info.num = 1; pc_info.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL; pc_info.subtype = SERIAL_TYPE_INFO; @@ -2398,7 +2398,7 @@ assertgwinon(ch); } /* End DATA_IND */ - else + /* else *//* Fix for DCD transition missed bug */ if (event & MODEMCHG_IND) { /* Begin MODEMCHG_IND */ diff -ur --new-file old/linux/drivers/char/ftape/zftape/zftape-init.c new/linux/drivers/char/ftape/zftape/zftape-init.c --- old/linux/drivers/char/ftape/zftape/zftape-init.c Mon Aug 24 22:02:45 1998 +++ new/linux/drivers/char/ftape/zftape/zftape-init.c Sun Mar 7 19:42:26 1999 @@ -280,8 +280,6 @@ static struct vm_operations_struct dummy = { NULL, }; vma->vm_ops = &dummy; #endif - vma->vm_file = filep; - filep->f_count++; } current->blocked = old_sigmask; /* restore mask */ TRACE_EXIT result; diff -ur --new-file old/linux/drivers/char/isicom.c new/linux/drivers/char/isicom.c --- old/linux/drivers/char/isicom.c Wed Dec 23 18:44:41 1998 +++ new/linux/drivers/char/isicom.c Fri May 7 20:05:30 1999 @@ -13,6 +13,23 @@ * (fixed range check bug as a side effect) * Printk clean up * 9/12/98 alan@redhat.com Rough port to 2.1.x + * + * + * *********************************************************** + * + * To use this driver you also need the support package. You + * can find this in RPM format on + * ftp://ftp.linux.org.uk/pub/linux/alan + * + * You can find the original tools for this direct from Multitech + * ftp://ftp.multitech.com/ISI-Cards/ + * + * Having installed the cards the module options (/etc/conf.modules) + * + * options isicom io=card1,card2,card3,card4 irq=card1,card2,card3,card4 + * + * Omit those entries for boards you don't have installed. + * */ #include @@ -114,6 +131,7 @@ #ifdef ISICOM_DEBUG printk(KERN_DEBUG "ISILoad:Firmware loader Opened!!!\n"); #endif + MOD_INC_USE_COUNT; return 0; } @@ -122,6 +140,7 @@ #ifdef ISICOM_DEBUG printk(KERN_DEBUG "ISILoad:Firmware loader Close(Release)d\n",); #endif + MOD_DEC_USE_COUNT; return 0; } diff -ur --new-file old/linux/drivers/char/istallion.c new/linux/drivers/char/istallion.c --- old/linux/drivers/char/istallion.c Tue Dec 29 20:29:54 1998 +++ new/linux/drivers/char/istallion.c Fri Apr 16 17:20:23 1999 @@ -3,7 +3,7 @@ /* * istallion.c -- stallion intelligent multiport serial driver. * - * Copyright (C) 1996-1998 Stallion Technologies (support@stallion.oz.au). + * Copyright (C) 1996-1999 Stallion Technologies (support@stallion.oz.au). * Copyright (C) 1994-1996 Greg Ungerer (gerg@stallion.oz.au). * * This code is loosely based on the Linux serial driver, written by @@ -26,30 +26,26 @@ /*****************************************************************************/ +#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 +#ifdef CONFIG_PCI +#include +#endif + /*****************************************************************************/ /* @@ -79,6 +75,7 @@ #define BRD_ECHPCI 26 #define BRD_ECH64PCI 27 #define BRD_EASYIOPCI 28 +#define BRD_ECPPCI 29 #define BRD_BRUMBY BRD_BRUMBY4 @@ -131,7 +128,7 @@ } stlconf_t; static stlconf_t stli_brdconf[] = { - { BRD_ECP, 0x2a0, 0, 0xcc000, 0, 0 }, + /*{ BRD_ECP, 0x2a0, 0, 0xcc000, 0, 0 },*/ }; static int stli_nrbrds = sizeof(stli_brdconf) / sizeof(stlconf_t); @@ -170,7 +167,7 @@ */ static char *stli_drvtitle = "Stallion Intelligent Multiport Serial Driver"; static char *stli_drvname = "istallion"; -static char *stli_drvversion = "5.4.7"; +static char *stli_drvversion = "5.5.1"; static char *stli_serialname = "ttyE"; static char *stli_calloutname = "cue"; @@ -296,8 +293,110 @@ "EC8/32-PCI", "EC8/64-PCI", "EasyIO-PCI", + "EC/RA-PCI", }; +/*****************************************************************************/ + +#ifdef MODULE +/* + * Define some string labels for arguments passed from the module + * load line. These allow for easy board definitions, and easy + * modification of the io, memory and irq resoucres. + */ + +static char *board0[8]; +static char *board1[8]; +static char *board2[8]; +static char *board3[8]; + +static char **stli_brdsp[] = { + (char **) &board0, + (char **) &board1, + (char **) &board2, + (char **) &board3 +}; + +/* + * Define a set of common board names, and types. This is used to + * parse any module arguments. + */ + +typedef struct stlibrdtype { + char *name; + int type; +} stlibrdtype_t; + +static stlibrdtype_t stli_brdstr[] = { + { "stallion", BRD_STALLION }, + { "1", BRD_STALLION }, + { "brumby", BRD_BRUMBY }, + { "brumby4", BRD_BRUMBY }, + { "brumby/4", BRD_BRUMBY }, + { "brumby-4", BRD_BRUMBY }, + { "brumby8", BRD_BRUMBY }, + { "brumby/8", BRD_BRUMBY }, + { "brumby-8", BRD_BRUMBY }, + { "brumby16", BRD_BRUMBY }, + { "brumby/16", BRD_BRUMBY }, + { "brumby-16", BRD_BRUMBY }, + { "2", BRD_BRUMBY }, + { "onboard2", BRD_ONBOARD2 }, + { "onboard-2", BRD_ONBOARD2 }, + { "onboard/2", BRD_ONBOARD2 }, + { "onboard-mc", BRD_ONBOARD2 }, + { "onboard/mc", BRD_ONBOARD2 }, + { "onboard-mca", BRD_ONBOARD2 }, + { "onboard/mca", BRD_ONBOARD2 }, + { "3", BRD_ONBOARD2 }, + { "onboard", BRD_ONBOARD }, + { "onboardat", BRD_ONBOARD }, + { "4", BRD_ONBOARD }, + { "onboarde", BRD_ONBOARDE }, + { "onboard-e", BRD_ONBOARDE }, + { "onboard/e", BRD_ONBOARDE }, + { "onboard-ei", BRD_ONBOARDE }, + { "onboard/ei", BRD_ONBOARDE }, + { "7", BRD_ONBOARDE }, + { "ecp", BRD_ECP }, + { "ecpat", BRD_ECP }, + { "ec8/64", BRD_ECP }, + { "ec8/64-at", BRD_ECP }, + { "ec8/64-isa", BRD_ECP }, + { "23", BRD_ECP }, + { "ecpe", BRD_ECPE }, + { "ecpei", BRD_ECPE }, + { "ec8/64-e", BRD_ECPE }, + { "ec8/64-ei", BRD_ECPE }, + { "24", BRD_ECPE }, + { "ecpmc", BRD_ECPMC }, + { "ec8/64-mc", BRD_ECPMC }, + { "ec8/64-mca", BRD_ECPMC }, + { "25", BRD_ECPMC }, + { "ecppci", BRD_ECPPCI }, + { "ec/ra", BRD_ECPPCI }, + { "ec/ra-pc", BRD_ECPPCI }, + { "ec/ra-pci", BRD_ECPPCI }, + { "29", BRD_ECPPCI }, +}; + +/* + * Define the module agruments. + */ +MODULE_AUTHOR("Greg Ungerer"); +MODULE_DESCRIPTION("Stallion Intelligent Multiport Serial Driver"); + +MODULE_PARM(board0, "1-3s"); +MODULE_PARM_DESC(board0, "Board 0 config -> name[,ioaddr[,memaddr]"); +MODULE_PARM(board1, "1-3s"); +MODULE_PARM_DESC(board1, "Board 1 config -> name[,ioaddr[,memaddr]"); +MODULE_PARM(board2, "1-3s"); +MODULE_PARM_DESC(board2, "Board 2 config -> name[,ioaddr[,memaddr]"); +MODULE_PARM(board3, "1-3s"); +MODULE_PARM_DESC(board3, "Board 3 config -> name[,ioaddr[,memaddr]"); + +#endif + /* * Set up a default memory address table for EISA board probing. * The default addresses are all bellow 1Mbyte, which has to be the @@ -317,18 +416,34 @@ static int stli_eisamempsize = sizeof(stli_eisamemprobeaddrs) / sizeof(unsigned long); int stli_eisaprobe = STLI_EISAPROBE; +/* + * Define the Stallion PCI vendor and device IDs. + */ +#ifdef CONFIG_PCI +#ifndef PCI_VENDOR_ID_STALLION +#define PCI_VENDOR_ID_STALLION 0x124d +#endif +#ifndef PCI_DEVICE_ID_ECRA +#define PCI_DEVICE_ID_ECRA 0x0004 +#endif +#endif + /*****************************************************************************/ /* * Hardware configuration info for ECP boards. These defines apply * to the directly accessible io ports of the ECP. There is a set of - * defines for each ECP board type, ISA, EISA and MCA. + * defines for each ECP board type, ISA, EISA, MCA and PCI. */ #define ECP_IOSIZE 4 + #define ECP_MEMSIZE (128 * 1024) +#define ECP_PCIMEMSIZE (256 * 1024) + #define ECP_ATPAGESIZE (4 * 1024) -#define ECP_EIPAGESIZE (64 * 1024) #define ECP_MCPAGESIZE (4 * 1024) +#define ECP_EIPAGESIZE (64 * 1024) +#define ECP_PCIPAGESIZE (64 * 1024) #define STL_EISAID 0x8c4e @@ -377,6 +492,14 @@ #define ECP_MCDISABLE 0x00 /* + * Important defines for the PCI class of ECP board. + * (It has a lot in common with the other ECP boards.) + */ +#define ECP_PCIIREG 0 +#define ECP_PCICONFR 1 +#define ECP_PCISTOP 0x01 + +/* * Hardware configuration info for ONboard and Brumby boards. These * defines apply to the directly accessible io ports of these boards. */ @@ -516,7 +639,11 @@ /* * Define some handy local macros... */ -#define MIN(a,b) (((a) <= (b)) ? (a) : (b)) +#undef MIN +#define MIN(a,b) (((a) <= (b)) ? (a) : (b)) + +#undef TOLOWER +#define TOLOWER(x) ((((x) >= 'A') && ((x) <= 'Z')) ? ((x) + 0x20) : (x)) /*****************************************************************************/ @@ -527,6 +654,10 @@ #ifdef MODULE int init_module(void); void cleanup_module(void); +static void stli_argbrds(void); +static int stli_parsebrd(stlconf_t *confp, char **argp); + +static unsigned long stli_atol(char *str); #endif int stli_init(void); @@ -583,6 +714,7 @@ static int stli_getportstruct(unsigned long arg); static int stli_getbrdstruct(unsigned long arg); static void *stli_memalloc(int len); +static stlibrd_t *stli_allocbrd(void); static void stli_ecpinit(stlibrd_t *brdp); static void stli_ecpenable(stlibrd_t *brdp); @@ -599,6 +731,9 @@ static void stli_ecpmcdisable(stlibrd_t *brdp); static char *stli_ecpmcgetmemptr(stlibrd_t *brdp, unsigned long offset, int line); static void stli_ecpmcreset(stlibrd_t *brdp); +static void stli_ecppciinit(stlibrd_t *brdp); +static char *stli_ecppcigetmemptr(stlibrd_t *brdp, unsigned long offset, int line); +static void stli_ecppcireset(stlibrd_t *brdp); static void stli_onbinit(stlibrd_t *brdp); static void stli_onbenable(stlibrd_t *brdp); @@ -625,6 +760,12 @@ static inline int stli_findeisabrds(void); static inline int stli_eisamemprobe(stlibrd_t *brdp); static inline int stli_initports(stlibrd_t *brdp); +static inline int stli_getbrdnr(void); + +#ifdef CONFIG_PCI +static inline int stli_findpcibrds(void); +static inline int stli_initpcibrd(int brdtype, struct pci_dev *devp); +#endif /*****************************************************************************/ @@ -741,8 +882,7 @@ kfree_s(stli_txcookbuf, STLI_TXBUFSIZE); for (i = 0; (i < stli_nrbrds); i++) { - brdp = stli_brds[i]; - if (brdp == (stlibrd_t *) NULL) + if ((brdp = stli_brds[i]) == (stlibrd_t *) NULL) continue; for (j = 0; (j < STL_MAXPORTS); j++) { portp = brdp->ports[j]; @@ -763,6 +903,114 @@ restore_flags(flags); } +/*****************************************************************************/ + +/* + * Check for any arguments passed in on the module load command line. + */ + +static void stli_argbrds() +{ + stlconf_t conf; + stlibrd_t *brdp; + int nrargs, i; + +#if DEBUG + printk("stli_argbrds()\n"); +#endif + + nrargs = sizeof(stli_brdsp) / sizeof(char **); + + for (i = stli_nrbrds; (i < nrargs); i++) { + memset(&conf, 0, sizeof(conf)); + if (stli_parsebrd(&conf, stli_brdsp[i]) == 0) + continue; + if ((brdp = stli_allocbrd()) == (stlibrd_t *) NULL) + continue; + stli_nrbrds = i + 1; + brdp->brdnr = i; + brdp->brdtype = conf.brdtype; + brdp->iobase = conf.ioaddr1; + brdp->memaddr = conf.memaddr; + stli_brdinit(brdp); + } +} + +/*****************************************************************************/ + +/* + * Convert an ascii string number into an unsigned long. + */ + +static unsigned long stli_atol(char *str) +{ + unsigned long val; + int base, c; + char *sp; + + val = 0; + sp = str; + if ((*sp == '0') && (*(sp+1) == 'x')) { + base = 16; + sp += 2; + } else if (*sp == '0') { + base = 8; + sp++; + } else { + base = 10; + } + + for (; (*sp != 0); sp++) { + c = (*sp > '9') ? (TOLOWER(*sp) - 'a' + 10) : (*sp - '0'); + if ((c < 0) || (c >= base)) { + printk("STALLION: invalid argument %s\n", str); + val = 0; + break; + } + val = (val * base) + c; + } + return(val); +} + +/*****************************************************************************/ + +/* + * Parse the supplied argument string, into the board conf struct. + */ + +static int stli_parsebrd(stlconf_t *confp, char **argp) +{ + char *sp; + int nrbrdnames, i; + +#if DEBUG + printk("stli_parsebrd(confp=%x,argp=%x)\n", (int) confp, (int) argp); +#endif + + if ((argp[0] == (char *) NULL) || (*argp[0] == 0)) + return(0); + + for (sp = argp[0], i = 0; ((*sp != 0) && (i < 25)); sp++, i++) + *sp = TOLOWER(*sp); + + nrbrdnames = sizeof(stli_brdstr) / sizeof(stlibrdtype_t); + for (i = 0; (i < nrbrdnames); i++) { + if (strcmp(stli_brdstr[i].name, argp[0]) == 0) + break; + } + if (i >= nrbrdnames) { + printk("STALLION: unknown board name, %s?\n", argp[0]); + return(0); + } + + confp->brdtype = stli_brdstr[i].type; + if ((argp[1] != (char *) NULL) && (*argp[1] != 0)) + confp->ioaddr1 = stli_atol(argp[1]); + if ((argp[2] != (char *) NULL) && (*argp[2] != 0)) + confp->memaddr = stli_atol(argp[2]); + return(1); +} + #endif /*****************************************************************************/ @@ -1433,7 +1681,6 @@ down(&stli_tmpwritesem); copy_from_user(stli_tmpwritebuf, chbuf, count); - up(&stli_tmpwritesem); chbuf = &stli_tmpwritebuf[0]; } @@ -1485,8 +1732,10 @@ portp->portidx; *bits |= portp->portbit; set_bit(ST_TXBUSY, &portp->state); - EBRDDISABLE(brdp); + + if (from_user) + up(&stli_tmpwritesem); restore_flags(flags); return(count); @@ -3363,6 +3612,60 @@ /*****************************************************************************/ /* + * The following set of functions act on ECP PCI boards. + */ + +static void stli_ecppciinit(stlibrd_t *brdp) +{ +#if DEBUG + printk("stli_ecppciinit(brdp=%x)\n", (int) brdp); +#endif + + outb(ECP_PCISTOP, (brdp->iobase + ECP_PCICONFR)); + udelay(10); + outb(0, (brdp->iobase + ECP_PCICONFR)); + udelay(500); +} + +/*****************************************************************************/ + +static char *stli_ecppcigetmemptr(stlibrd_t *brdp, unsigned long offset, int line) +{ + void *ptr; + unsigned char val; + +#if DEBUG + printk("stli_ecppcigetmemptr(brdp=%x,offset=%x,line=%d)\n", + (int) brdp, (int) offset, line); +#endif + + if (offset > brdp->memsize) { + printk("STALLION: shared memory pointer=%x out of range at " + "line=%d(%d), board=%d\n", (int) offset, line, + __LINE__, brdp->brdnr); + ptr = 0; + val = 0; + } else { + ptr = brdp->membase + (offset % ECP_PCIPAGESIZE); + val = (offset / ECP_PCIPAGESIZE) << 1; + } + outb(val, (brdp->iobase + ECP_PCICONFR)); + return(ptr); +} + +/*****************************************************************************/ + +static void stli_ecppcireset(stlibrd_t *brdp) +{ + outb(ECP_PCISTOP, (brdp->iobase + ECP_PCICONFR)); + udelay(10); + outb(0, (brdp->iobase + ECP_PCICONFR)); + udelay(500); +} + +/*****************************************************************************/ + +/* * The following routines act on ONboards. */ @@ -3678,7 +3981,7 @@ brdp->iosize = ECP_IOSIZE; if (check_region(brdp->iobase, brdp->iosize)) - printk("STALLION: Warning, unit %d I/O address %x conflicts " + printk("STALLION: Warning, board %d I/O address %x conflicts " "with another device\n", brdp->brdnr, brdp->iobase); /* @@ -3729,6 +4032,20 @@ name = "serial(EC8/64-MCA)"; break; + case BRD_ECPPCI: + brdp->membase = (void *) brdp->memaddr; + brdp->memsize = ECP_PCIMEMSIZE; + brdp->pagesize = ECP_PCIPAGESIZE; + brdp->init = stli_ecppciinit; + brdp->enable = NULL; + brdp->reenable = NULL; + brdp->disable = NULL; + brdp->getmemptr = stli_ecppcigetmemptr; + brdp->intr = stli_ecpintr; + brdp->reset = stli_ecppcireset; + name = "serial(EC/RA-PCI)"; + break; + default: return(-EINVAL); } @@ -3817,7 +4134,7 @@ brdp->iosize = ONB_IOSIZE; if (check_region(brdp->iobase, brdp->iosize)) - printk("STALLION: Warning, unit %d I/O address %x conflicts " + printk("STALLION: Warning, board %d I/O address %x conflicts " "with another device\n", brdp->brdnr, brdp->iobase); /* @@ -4082,6 +4399,7 @@ case BRD_ECP: case BRD_ECPE: case BRD_ECPMC: + case BRD_ECPPCI: stli_initecp(brdp); break; case BRD_ONBOARD: @@ -4104,20 +4422,20 @@ stli_brdnames[brdp->brdtype]); return(ENODEV); default: - printk("STALLION: unit=%d is unknown board type=%d\n", + printk("STALLION: board=%d is unknown board type=%d\n", brdp->brdnr, brdp->brdtype); return(ENODEV); } if ((brdp->state & BST_FOUND) == 0) { - printk("STALLION: %s board not found, unit=%d io=%x mem=%x\n", + printk("STALLION: %s board not found, board=%d io=%x mem=%x\n", stli_brdnames[brdp->brdtype], brdp->brdnr, brdp->iobase, (int) brdp->memaddr); return(ENODEV); } stli_initports(brdp); - printk("STALLION: %s found, unit=%d io=%x mem=%x " + printk("STALLION: %s found, board=%d io=%x mem=%x " "nrpanels=%d nrports=%d\n", stli_brdnames[brdp->brdtype], brdp->brdnr, brdp->iobase, (int) brdp->memaddr, brdp->nrpanels, brdp->nrports); @@ -4279,29 +4597,13 @@ continue; /* - * Check that we have room for this new board in our board - * info table. - */ - if (stli_nrbrds >= STL_MAXBRDS) { - printk("STALLION: no room for more probed boards, " - "maximum supported %d\n", STL_MAXBRDS); - break; - } - -/* * We have found a Stallion board and it is not configured already. * Allocate a board structure and initialize it. */ - brdp = (stlibrd_t *) stli_memalloc(sizeof(stlibrd_t)); - if (brdp == (stlibrd_t *) NULL) { - printk("STALLION: failed to allocate memory " - "(size=%d)\n", sizeof(stlibrd_t)); + if ((brdp = stli_allocbrd()) == (stlibrd_t *) NULL) + return(-ENOMEM); + if ((brdp->brdnr = stli_getbrdnr()) < 0) return(-ENOMEM); - } - memset(brdp, 0, sizeof(stlibrd_t)); - - brdp->magic = STLI_BOARDMAGIC; - brdp->brdnr = stli_nrbrds++; eid = inb(iobase + 0xc82); if (eid == ECP_EISAID) brdp->brdtype = BRD_ECPE; @@ -4322,6 +4624,123 @@ /*****************************************************************************/ /* + * Find the next available board number that is free. + */ + +static inline int stli_getbrdnr() +{ + int i; + + for (i = 0; (i < STL_MAXBRDS); i++) { + if (stli_brds[i] == (stlibrd_t *) NULL) { + if (i >= stli_nrbrds) + stli_nrbrds = i + 1; + return(i); + } + } + return(-1); +} + +/*****************************************************************************/ + +#ifdef CONFIG_PCI + +/* + * We have a Stallion board. Allocate a board structure and + * initialize it. Read its IO and MEMORY resources from PCI + * configuration space. + */ + +static inline int stli_initpcibrd(int brdtype, struct pci_dev *devp) +{ + stlibrd_t *brdp; + +#if DEBUG + printk("stli_initpcibrd(brdtype=%d,busnr=%x,devnr=%x)\n", brdtype, + dev->bus->number, dev->devfn); +#endif + + if ((brdp = stli_allocbrd()) == (stlibrd_t *) NULL) + return(-ENOMEM); + if ((brdp->brdnr = stli_getbrdnr()) < 0) { + printk("STALLION: too many boards found, " + "maximum supported %d\n", STL_MAXBRDS); + return(0); + } + brdp->brdtype = brdtype; + +#if DEBUG + printk("%s(%d): BAR[]=%x,%x,%x,%x\n", __FILE__, __LINE__, + devp->base_address[0], devp->base_address[1], + devp->base_address[2], devp->base_address[3]); +#endif + +/* + * We have all resources from the board, so lets setup the actual + * board structure now. + */ + brdp->iobase = (devp->base_address[3] & PCI_BASE_ADDRESS_IO_MASK); + brdp->memaddr = (devp->base_address[2] & PCI_BASE_ADDRESS_MEM_MASK); + stli_brdinit(brdp); + + return(0); +} + +/*****************************************************************************/ + +/* + * Find all Stallion PCI boards that might be installed. Initialize each + * one as it is found. + */ + +static inline int stli_findpcibrds() +{ + struct pci_dev *dev = NULL; + int rc; + +#if DEBUG + printk("stli_findpcibrds()\n"); +#endif + + if (! pci_present()) + return(0); + + while ((dev = pci_find_device(PCI_VENDOR_ID_STALLION, + PCI_DEVICE_ID_ECRA, dev))) { + if ((rc = stli_initpcibrd(BRD_ECPPCI, dev))) + return(rc); + } + + return(0); +} + +#endif + +/*****************************************************************************/ + +/* + * Allocate a new board structure. Fill out the basic info in it. + */ + +static stlibrd_t *stli_allocbrd() +{ + stlibrd_t *brdp; + + brdp = (stlibrd_t *) stli_memalloc(sizeof(stlibrd_t)); + if (brdp == (stlibrd_t *) NULL) { + printk("STALLION: failed to allocate memory (size=%d)\n", + sizeof(stlibrd_t)); + return((stlibrd_t *) NULL); + } + + memset(brdp, 0, sizeof(stlibrd_t)); + brdp->magic = STLI_BOARDMAGIC; + return(brdp); +} + +/*****************************************************************************/ + +/* * Scan through all the boards in the configuration and see what we * can find. */ @@ -4344,19 +4763,16 @@ /* * Firstly scan the list of static boards configured. Allocate - * resources and initialize the boards as found. + * resources and initialize the boards as found. If this is a + * module then let the module args override static configuration. */ for (i = 0; (i < stli_nrbrds); i++) { confp = &stli_brdconf[i]; - brdp = (stlibrd_t *) stli_memalloc(sizeof(stlibrd_t)); - if (brdp == (stlibrd_t *) NULL) { - printk("STALLION: failed to allocate memory " - "(size=%d)\n", sizeof(stlibrd_t)); +#ifdef MODULE + stli_parsebrd(confp, stli_brdsp[i]); +#endif + if ((brdp = stli_allocbrd()) == (stlibrd_t *) NULL) return(-ENOMEM); - } - memset(brdp, 0, sizeof(stlibrd_t)); - - brdp->magic = STLI_BOARDMAGIC; brdp->brdnr = i; brdp->brdtype = confp->brdtype; brdp->iobase = confp->ioaddr1; @@ -4365,10 +4781,17 @@ } /* - * Now go probing for EISA boards if enabled. + * Static configuration table done, so now use dynamic methods to + * see if any more boards should be configured. */ +#ifdef MODULE + stli_argbrds(); +#endif if (stli_eisaprobe) stli_findeisabrds(); +#ifdef CONFIG_PCI + stli_findpcibrds(); +#endif /* * All found boards are initialized. Now for a little optimization, if diff -ur --new-file old/linux/drivers/char/keyboard.c new/linux/drivers/char/keyboard.c --- old/linux/drivers/char/keyboard.c Fri Jan 8 20:11:45 1999 +++ new/linux/drivers/char/keyboard.c Mon Apr 26 22:21:42 1999 @@ -24,6 +24,7 @@ */ #include +#include #include #include #include @@ -59,6 +60,8 @@ #define KBD_DEFLOCK 0 #endif +EXPORT_SYMBOL(handle_scancode); + extern void ctrl_alt_del(void); struct wait_queue * keypress_wait = NULL; @@ -190,15 +193,15 @@ return kbd_getkeycode(scancode); } -void handle_scancode(unsigned char scancode) +void handle_scancode(unsigned char scancode, int down) { unsigned char keycode; - char up_flag; /* 0 or 0200 */ + char up_flag = down ? 0 : 0200; char raw_mode; do_poke_blanked_console = 1; mark_bh(CONSOLE_BH); - add_keyboard_randomness(scancode); + add_keyboard_randomness(scancode | up_flag); tty = ttytab? ttytab[fg_console]: NULL; if (tty && (!tty->driver_data)) { @@ -213,20 +216,15 @@ } kbd = kbd_table + fg_console; if ((raw_mode = (kbd->kbdmode == VC_RAW))) { - put_queue(scancode); + put_queue(scancode | up_flag); /* we do not return yet, because we want to maintain the key_down array, so that we have the correct values when finishing RAW mode or when changing VT's */ - } + } - if (!kbd_pretranslate(scancode, raw_mode)) - return; - /* + /* * Convert scancode to keycode - */ - up_flag = (scancode & 0200); - scancode &= 0x7f; - + */ if (!kbd_translate(scancode, &keycode, raw_mode)) return; @@ -239,10 +237,10 @@ if (up_flag) { rep = 0; - if(!test_and_clear_bit(keycode, key_down)) + if(!test_and_clear_bit(keycode, key_down)) up_flag = kbd_unexpected_up(keycode); } else - rep = test_and_set_bit(keycode, key_down); + rep = test_and_set_bit(keycode, key_down); #ifdef CONFIG_MAGIC_SYSRQ /* Handle the SysRq Hack */ if (keycode == SYSRQ_KEY) { @@ -257,11 +255,11 @@ if (kbd->kbdmode == VC_MEDIUMRAW) { /* soon keycodes will require more than one byte */ - put_queue(keycode + up_flag); + put_queue(keycode + up_flag); raw_mode = 1; /* Most key classes will be ignored */ - } + } - /* + /* * Small change in philosophy: earlier we defined repetition by * rep = keycode == prev_keycode; * prev_keycode = keycode; @@ -270,9 +268,9 @@ */ /* - * Repeat a key only if the input buffers are empty or the - * characters get echoed locally. This makes key repeat usable - * with slow applications and under heavy loads. + * Repeat a key only if the input buffers are empty or the + * characters get echoed locally. This makes key repeat usable + * with slow applications and under heavy loads. */ if (!rep || (vc_kbd_mode(kbd,VC_REPEAT) && tty && diff -ur --new-file old/linux/drivers/char/lp.c new/linux/drivers/char/lp.c --- old/linux/drivers/char/lp.c Fri Nov 27 19:23:11 1998 +++ new/linux/drivers/char/lp.c Mon May 10 19:26:31 1999 @@ -202,9 +202,7 @@ /* Test if the printer is not acking the strobe */ #define LP_NO_ACKING(status) ((status) & LP_PACK) /* Test if the printer has error conditions */ -#define LP_NO_ERROR(status) \ - (((status) & (LP_POUTPA|LP_PSELECD|LP_PERRORP)) == \ - (LP_PSELECD|LP_PERRORP)) +#define LP_NO_ERROR(status) ((status) & LP_PERRORP) #undef LP_DEBUG #undef LP_READ_DEBUG @@ -424,7 +422,10 @@ { unsigned int last = lp_table[minor].last_error; unsigned char status = r_str(minor); - if ((status & LP_POUTPA)) { + if (status & LP_PERRORP) + /* No error. */ + last = 0; + else if ((status & LP_POUTPA)) { if (last != LP_POUTPA) { last = LP_POUTPA; printk(KERN_INFO "lp%d out of paper\n", minor); @@ -434,13 +435,12 @@ last = LP_PSELECD; printk(KERN_INFO "lp%d off-line\n", minor); } - } else if (!(status & LP_PERRORP)) { + } else { if (last != LP_PERRORP) { last = LP_PERRORP; - printk(KERN_ERR "lp%d on fire!\n", minor); + printk(KERN_INFO "lp%d on fire\n", minor); } } - else last = 0; lp_table[minor].last_error = last; @@ -664,17 +664,15 @@ } if ((i & 1) != 0) { Byte |= (z<<4); - if (temp) { - if (__put_user (Byte, temp)) - { - count = -EFAULT; - temp = NULL; - } else { - temp++; + if (__put_user (Byte, temp)) + { + count = -EFAULT; + break; + } else { + temp++; - if (++count == length) - temp = NULL; - } + if (++count == length) + break; } /* Does the error line indicate end of data? */ if ((parport_read_status(port) & LP_PERRORP) == @@ -952,16 +950,12 @@ default: for (i = 0; i < LP_NO; i++) { - if (parport_nr[i] >= 0) { - char buffer[16]; - sprintf(buffer, "parport%d", parport_nr[i]); - for (port = parport_enumerate(); port; - port = port->next) { - if (!strcmp(port->name, buffer)) { - (void) lp_register(i, port); + for (port = parport_enumerate(); port; + port = port->next) { + if (port->number == parport_nr[i]) { + if (!lp_register(i, port)) count++; - break; - } + break; } } } diff -ur --new-file old/linux/drivers/char/mem.c new/linux/drivers/char/mem.c --- old/linux/drivers/char/mem.c Mon Jan 25 06:55:04 1999 +++ new/linux/drivers/char/mem.c Mon May 10 19:18:34 1999 @@ -51,7 +51,16 @@ #if defined(CONFIG_PPC) || defined(CONFIG_MAC) extern void adbdev_init(void); #endif - +#ifdef CONFIG_USB_UHCI +int uhci_init(void); +#endif +#ifdef CONFIG_USB_OHCI +int ohci_init(void); +#endif +#ifdef CONFIG_USB_OHCI_HCD +int ohci_hcd_init(void); +#endif + static ssize_t do_write_mem(struct file * file, void *p, unsigned long realp, const char * buf, size_t count, loff_t *ppos) { @@ -138,8 +147,11 @@ static inline unsigned long pgprot_noncached(unsigned long prot) { #if defined(__i386__) + /* On PPro and successors, PCD alone doesn't always mean + uncached because of interactions with the MTRRs. PCD | PWT + means definitely uncached. */ if (boot_cpu_data.x86 > 3) - prot |= _PAGE_PCD; + prot |= _PAGE_PCD | _PAGE_PWT; #elif defined(__powerpc__) prot |= _PAGE_NO_CACHE | _PAGE_GUARDED; #elif defined(__mc68000__) @@ -155,6 +167,28 @@ return prot; } +/* + * Architectures vary in how they handle caching for addresses + * outside of main memory. + */ +static inline int noncached_address(unsigned long addr) +{ +#if defined(__i386__) + /* + * On the PPro and successors, the MTRRs are used to set + * memory types for physical addresses outside main memory, + * so blindly setting PCD or PWT on those pages is wrong. + * For Pentiums and earlier, the surround logic should disable + * caching for the high addresses through the KEN pin, but + * we maintain the tradition of paranoia in this code. + */ + return !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) + && addr >= __pa(high_memory); +#else + return addr >= __pa(high_memory); +#endif +} + static int mmap_mem(struct file * file, struct vm_area_struct * vma) { unsigned long offset = vma->vm_offset; @@ -166,20 +200,20 @@ * Accessing memory above the top the kernel knows about or * through a file pointer that was marked O_SYNC will be * done non-cached. - * - * Set VM_IO, as this is likely a non-cached access to an - * I/O area, and we don't want to include that in a core - * file. */ - if (offset >= __pa(high_memory) || (file->f_flags & O_SYNC)) { - pgprot_val(vma->vm_page_prot) = pgprot_noncached(pgprot_val(vma->vm_page_prot)); + if (noncached_address(offset) || (file->f_flags & O_SYNC)) + pgprot_val(vma->vm_page_prot) + = pgprot_noncached(pgprot_val(vma->vm_page_prot)); + + /* + * Don't dump addresses that are not real memory to a core file. + */ + if (offset >= __pa(high_memory) || (file->f_flags & O_SYNC)) vma->vm_flags |= VM_IO; - } + if (remap_page_range(vma->vm_start, offset, vma->vm_end-vma->vm_start, vma->vm_page_prot)) return -EAGAIN; - vma->vm_file = file; - file->f_count++; return 0; } @@ -574,6 +608,17 @@ if (register_chrdev(MEM_MAJOR,"mem",&memory_fops)) printk("unable to get major %d for memory devs\n", MEM_MAJOR); rand_initialize(); +#ifdef CONFIG_USB +#ifdef CONFIG_USB_UHCI + uhci_init(); +#endif +#ifdef CONFIG_USB_OHCI + ohci_init(); +#endif +#ifdef CONFIG_USB_OHCI_HCD + ohci_hcd_init(); +#endif +#endif #if defined (CONFIG_FB) fbmem_init(); #endif diff -ur --new-file old/linux/drivers/char/misc.c new/linux/drivers/char/misc.c --- old/linux/drivers/char/misc.c Sat Jan 16 02:46:27 1999 +++ new/linux/drivers/char/misc.c Fri Mar 26 22:57:41 1999 @@ -73,6 +73,7 @@ extern void watchdog_init(void); extern void wdt_init(void); extern void acq_init(void); +extern void dtlk_init(void); extern void pcwatchdog_init(void); extern int rtc_init(void); extern int rtc_DP8570A_init(void); @@ -230,6 +231,9 @@ #endif #ifdef CONFIG_SOFT_WATCHDOG watchdog_init(); +#endif +#ifdef CONFIG_DTLK + dtlk_init(); #endif #ifdef CONFIG_APM apm_bios_init(); diff -ur --new-file old/linux/drivers/char/msp3400.c new/linux/drivers/char/msp3400.c --- old/linux/drivers/char/msp3400.c Mon Jan 25 06:58:50 1999 +++ new/linux/drivers/char/msp3400.c Wed Feb 17 18:37:51 1999 @@ -774,7 +774,6 @@ goto done; dprintk("msp3410: thread: sleep\n"); down_interruptible(&sem); - sem.owner = 0; dprintk("msp3410: thread: wakeup\n"); if (msp->rmmod) goto done; diff -ur --new-file old/linux/drivers/char/n_hdlc.c new/linux/drivers/char/n_hdlc.c --- old/linux/drivers/char/n_hdlc.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/char/n_hdlc.c Fri Mar 12 17:20:38 1999 @@ -0,0 +1,1151 @@ +/* generic HDLC line discipline for Linux + * + * Written by Paul Fulghum paulkf@microgate.com + * for Microgate Corporation + * + * Microgate and SyncLink are registered trademarks of Microgate Corporation + * + * Adapted from ppp.c, written by Michael Callahan , + * Al Longyear , Paul Mackerras + * + * Original release 01/11/99 + * + * This code is released under the GNU General Public License (GPL) + * + * This module implements the tty line discipline N_HDLC for use with + * tty device drivers that support bit-synchronous HDLC communications. + * + * All HDLC data is frame oriented which means: + * + * 1. tty write calls represent one complete transmit frame of data + * The device driver should accept the complete frame or none of + * the frame (busy) in the write method. Each write call should have + * a byte count in the range of 2-4096 bytes (2 is min HDLC frame + * with 1 addr byte and 1 ctrl byte). + * + * 2. receive callbacks from the device driver represents + * one received frame. The device driver should bypass + * the tty flip buffer and call the line discipline receive + * callback directly to avoid fragmenting or concatenating + * multiple frames into a single receive callback. + * + * The HDLC line discipline queues the receive frames in seperate + * buffers so complete receive frames can be returned by the + * tty read calls. + * + * 3. tty read calls returns an entire frame of data or nothing. + * + * 4. all send and receive data is considered raw. No processing + * or translation is performed by the line discipline, regardless + * of the tty flags + * + * 5. When line discipline is queried for the amount of receive + * data available (FIOC), 0 is returned if no data available, + * otherwise the count of the next available frame is returned. + * (instead of the sum of all received frame counts). + * + * These conventions allow the standard tty programming interface + * to be used for synchronous HDLC applications when used with + * this line discipline (or another line discipline that is frame + * oriented such as N_PPP). + * + * The SyncLink driver (synclink.c) implements both asynchronous + * (using standard line discipline N_TTY) and synchronous HDLC + * (using N_HDLC) communications, with the latter using the above + * conventions. + * + * This implementation is very basic and does not maintain + * any statistics. The main point is to enforce the raw data + * and frame orientation of HDLC communications. + * + * THIS SOFTWARE IS PROVIDED ``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. + */ + +#define HDLC_MAGIC 0x239e +#define HDLC_VERSION "1.0" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#undef VERSION +#define VERSION(major,minor,patch) (((((major)<<8)+(minor))<<8)+(patch)) + +#if LINUX_VERSION_CODE < VERSION(2,1,14) +#include +#endif + +#if LINUX_VERSION_CODE >= VERSION(2,1,23) +#include +#endif + +#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 + +#ifdef CONFIG_KERNELD +#include +#endif + +#if LINUX_VERSION_CODE >= VERSION(2,1,4) +#include +#define GET_USER(error,value,addr) error = get_user(value,addr) +#define COPY_FROM_USER(error,dest,src,size) error = copy_from_user(dest,src,size) ? -EFAULT : 0 +#define PUT_USER(error,value,addr) error = put_user(value,addr) +#define COPY_TO_USER(error,dest,src,size) error = copy_to_user(dest,src,size) ? -EFAULT : 0 + +#if LINUX_VERSION_CODE >= VERSION(2,1,5) +#include +#endif + +#else /* 2.0.x and 2.1.x before 2.1.4 */ + +#define GET_USER(error,value,addr) \ +do { \ + error = verify_area (VERIFY_READ, (void *) addr, sizeof (value)); \ + if (error == 0) \ + value = get_user(addr); \ +} while (0) + +#define COPY_FROM_USER(error,dest,src,size) \ +do { \ + error = verify_area (VERIFY_READ, (void *) src, size); \ + if (error == 0) \ + memcpy_fromfs (dest, src, size); \ +} while (0) + +#define PUT_USER(error,value,addr) \ +do { \ + error = verify_area (VERIFY_WRITE, (void *) addr, sizeof (value)); \ + if (error == 0) \ + put_user (value, addr); \ +} while (0) + +#define COPY_TO_USER(error,dest,src,size) \ +do { \ + error = verify_area (VERIFY_WRITE, (void *) dest, size); \ + if (error == 0) \ + memcpy_tofs (dest, src, size); \ +} while (0) + +#endif + +#if LINUX_VERSION_CODE < VERSION(2,1,0) +#define __init +typedef int spinlock_t; +#define spin_lock_irqsave(a,b) {save_flags((b));cli();} +#define spin_unlock_irqrestore(a,b) {restore_flags((b));} +#define spin_lock(a) +#define spin_unlock(a) +#define schedule_timeout(a){current->timeout = jiffies + (a); schedule();} +#endif + +#if LINUX_VERSION_CODE < VERSION(2,1,37) +#define test_and_set_bit(nr, addr) set_bit(nr, addr) +#endif + +#if LINUX_VERSION_CODE < VERSION(2,1,57) +#define signal_pending(p) ((p)->signal & ~(p)->blocked) +#endif + +#if LINUX_VERSION_CODE < VERSION(2,1,25) +#define net_device_stats enet_statistics +#endif + +#if LINUX_VERSION_CODE < VERSION(2,1,60) +typedef int rw_ret_t; +typedef unsigned int rw_count_t; +#else +typedef ssize_t rw_ret_t; +typedef size_t rw_count_t; +#endif + +/* + * Buffers for individual HDLC frames + */ +#define MAX_HDLC_FRAME_SIZE 4096 +#define DEFAULT_RX_BUF_COUNT 10 +#define MAX_RX_BUF_COUNT 30 +#define DEFAULT_TX_BUF_COUNT 1 + +typedef struct _n_hdlc_buf +{ + struct _n_hdlc_buf *link; + int count; + char buf[MAX_HDLC_FRAME_SIZE]; +} N_HDLC_BUF; + +typedef struct _n_hdlc_buf_list +{ + N_HDLC_BUF *head; + N_HDLC_BUF *tail; + int count; + spinlock_t spinlock; + +} N_HDLC_BUF_LIST; + +/* + * Per device instance data structure + */ +struct n_hdlc { + int magic; /* magic value for structure */ + __u32 flags; /* miscellaneous control flags */ + + struct tty_struct *tty; /* ptr to TTY structure */ + struct tty_struct *backup_tty; /* TTY to use if tty gets closed */ + + /* Queues for select() functionality */ + struct wait_queue *read_wait; + struct wait_queue *write_wait; + + int tbusy; /* reentrancy flag for tx wakeup code */ + int woke_up; + N_HDLC_BUF *tbuf; /* currently transmitting tx buffer */ + N_HDLC_BUF_LIST tx_buf_list; /* list of pending transmit frame buffers */ + N_HDLC_BUF_LIST rx_buf_list; /* list of received frame buffers */ + N_HDLC_BUF_LIST tx_free_buf_list; /* list unused transmit frame buffers */ + N_HDLC_BUF_LIST rx_free_buf_list; /* list unused received frame buffers */ +}; + +/* + * HDLC buffer list manipulation functions + */ +void n_hdlc_buf_list_init(N_HDLC_BUF_LIST *list); +void n_hdlc_buf_put(N_HDLC_BUF_LIST *list,N_HDLC_BUF *buf); +N_HDLC_BUF* n_hdlc_buf_get(N_HDLC_BUF_LIST *list); + +/* Local functions */ + +static struct n_hdlc *n_hdlc_alloc (void); + +#if LINUX_VERSION_CODE >= VERSION(2,1,19) +MODULE_PARM(debuglevel, "i"); +#endif + +/* debug level can be set by insmod for debugging purposes */ +#define DEBUG_LEVEL_INFO 1 +int debuglevel=0; + +/* TTY callbacks */ + +static rw_ret_t n_hdlc_tty_read(struct tty_struct *, + struct file *, __u8 *, rw_count_t); +static rw_ret_t n_hdlc_tty_write(struct tty_struct *, + struct file *, const __u8 *, rw_count_t); +static int n_hdlc_tty_ioctl(struct tty_struct *, + struct file *, unsigned int, unsigned long); +#if LINUX_VERSION_CODE < VERSION(2,1,23) +static int n_hdlc_tty_select (struct tty_struct *tty, struct inode *inode, + struct file *filp, int sel_type, select_table * wait); +#else +static unsigned int n_hdlc_tty_poll (struct tty_struct *tty, struct file *filp, + poll_table * wait); +#endif +static int n_hdlc_tty_open (struct tty_struct *); +static void n_hdlc_tty_close (struct tty_struct *); +static int n_hdlc_tty_room (struct tty_struct *tty); +static void n_hdlc_tty_receive (struct tty_struct *tty, + const __u8 * cp, char *fp, int count); +static void n_hdlc_tty_wakeup (struct tty_struct *tty); + +#define bset(p,b) ((p)[(b) >> 5] |= (1 << ((b) & 0x1f))) + +#define tty2n_hdlc(tty) ((struct n_hdlc *) ((tty)->disc_data)) +#define n_hdlc2tty(n_hdlc) ((n_hdlc)->tty) + +/* Define this string only once for all macro invocations */ +static char szVersion[] = HDLC_VERSION; + +/* n_hdlc_release() + * + * release an n_hdlc per device line discipline info structure + * + */ +static void n_hdlc_release (struct n_hdlc *n_hdlc) +{ + struct tty_struct *tty = n_hdlc2tty (n_hdlc); + N_HDLC_BUF *buf; + + if (debuglevel >= DEBUG_LEVEL_INFO) + printk("%s(%d)n_hdlc_release() called\n",__FILE__,__LINE__); + + /* Ensure that the n_hdlcd process is not hanging on select()/poll() */ + wake_up_interruptible (&n_hdlc->read_wait); + wake_up_interruptible (&n_hdlc->write_wait); + + if (tty != NULL && tty->disc_data == n_hdlc) + tty->disc_data = NULL; /* Break the tty->n_hdlc link */ + + /* Release transmit and receive buffers */ + for(;;) { + buf = n_hdlc_buf_get(&n_hdlc->rx_free_buf_list); + if (buf) { + kfree(buf); + } else + break; + } + for(;;) { + buf = n_hdlc_buf_get(&n_hdlc->tx_free_buf_list); + if (buf) { + kfree(buf); + } else + break; + } + for(;;) { + buf = n_hdlc_buf_get(&n_hdlc->rx_buf_list); + if (buf) { + kfree(buf); + } else + break; + } + for(;;) { + buf = n_hdlc_buf_get(&n_hdlc->tx_buf_list); + if (buf) { + kfree(buf); + } else + break; + } + + kfree(n_hdlc); + +} /* end of n_hdlc_release() */ + +/* n_hdlc_tty_close() + * + * Called when the line discipline is changed to something + * else, the tty is closed, or the tty detects a hangup. + */ +static void n_hdlc_tty_close(struct tty_struct *tty) +{ + struct n_hdlc *n_hdlc = tty2n_hdlc (tty); + + if (debuglevel >= DEBUG_LEVEL_INFO) + printk("%s(%d)n_hdlc_tty_close() called\n",__FILE__,__LINE__); + + if (n_hdlc != NULL) { + if (n_hdlc->magic != HDLC_MAGIC) { + printk (KERN_WARNING"n_hdlc: trying to close unopened tty!\n"); + return; + } + tty->disc_data = NULL; + if (tty == n_hdlc->backup_tty) + n_hdlc->backup_tty = 0; + if (tty != n_hdlc->tty) + return; + if (n_hdlc->backup_tty) { + n_hdlc->tty = n_hdlc->backup_tty; + } else { + n_hdlc_release (n_hdlc); + MOD_DEC_USE_COUNT; + } + } + + if (debuglevel >= DEBUG_LEVEL_INFO) + printk("%s(%d)n_hdlc_tty_close() success\n",__FILE__,__LINE__); + +} /* end of n_hdlc_tty_close() */ + +/* n_hdlc_tty_open + * + * called when line discipline changed to n_hdlc + * + * Arguments: tty pointer to tty info structure + * Return Value: 0 if success, otherwise error code + */ +static int n_hdlc_tty_open (struct tty_struct *tty) +{ + struct n_hdlc *n_hdlc = tty2n_hdlc (tty); + + if (debuglevel >= DEBUG_LEVEL_INFO) + printk("%s(%d)n_hdlc_tty_open() called\n",__FILE__,__LINE__); + + /* There should not be an existing table for this slot. */ + if (n_hdlc) { + printk (KERN_ERR"n_hdlc_tty_open:tty already associated!\n" ); + return -EEXIST; + } + + n_hdlc = n_hdlc_alloc(); + if (!n_hdlc) { + printk (KERN_ERR "n_hdlc_alloc failed\n"); + return -ENFILE; + } + + tty->disc_data = n_hdlc; + n_hdlc->tty = tty; + + MOD_INC_USE_COUNT; + + /* Flush any pending characters in the driver and discipline. */ + + if (tty->ldisc.flush_buffer) + tty->ldisc.flush_buffer (tty); + + if (tty->driver.flush_buffer) + tty->driver.flush_buffer (tty); + + if (debuglevel >= DEBUG_LEVEL_INFO) + printk("%s(%d)n_hdlc_tty_open() success\n",__FILE__,__LINE__); + + return 0; + +} /* end of n_tty_hdlc_open() */ + +/* n_hdlc_send_frames() + * + * send frames on pending send buffer list until the + * driver does not accept a frame (busy) + * this function is called after adding a frame to the + * send buffer list and by the tty wakeup callback + * + * Arguments: n_hdlc pointer to ldisc instance data + * tty pointer to tty instance data + * Return Value: None + */ +static void n_hdlc_send_frames (struct n_hdlc *n_hdlc, struct tty_struct *tty) +{ + register int actual; + unsigned long flags; + N_HDLC_BUF *tbuf; + + if (debuglevel >= DEBUG_LEVEL_INFO) + printk("%s(%d)n_hdlc_send_frames() called\n",__FILE__,__LINE__); + + save_flags(flags); + cli (); + if (n_hdlc->tbusy) { + n_hdlc->woke_up = 1; + restore_flags(flags); + return; + } + n_hdlc->tbusy = 1; + restore_flags(flags); + + /* get current transmit buffer or get new transmit */ + /* buffer from list of pending transmit buffers */ + + tbuf = n_hdlc->tbuf; + if (!tbuf) + tbuf = n_hdlc_buf_get(&n_hdlc->tx_buf_list); + + while (tbuf) { + if (debuglevel >= DEBUG_LEVEL_INFO) + printk("%s(%d)sending frame %p, count=%d\n", + __FILE__,__LINE__,tbuf,tbuf->count); + + /* Send the next block of data to device */ + n_hdlc->woke_up = 0; + tty->flags |= (1 << TTY_DO_WRITE_WAKEUP); + actual = tty->driver.write(tty, 0, tbuf->buf, tbuf->count); + + /* if transmit error, throw frame away by */ + /* pretending it was accepted by driver */ + if (actual < 0) + actual = tbuf->count; + + if (actual == tbuf->count) { + if (debuglevel >= DEBUG_LEVEL_INFO) + printk("%s(%d)frame %p completed\n", + __FILE__,__LINE__,tbuf); + + /* free current transmit buffer */ + n_hdlc_buf_put(&n_hdlc->tx_free_buf_list,tbuf); + + /* this tx buffer is done */ + n_hdlc->tbuf = NULL; + + /* wait up sleeping writers */ + wake_up_interruptible(&n_hdlc->write_wait); + + /* get next pending transmit buffer */ + tbuf = n_hdlc_buf_get(&n_hdlc->tx_buf_list); + } else { + if (debuglevel >= DEBUG_LEVEL_INFO) + printk("%s(%d)frame %p pending\n", + __FILE__,__LINE__,tbuf); + + /* buffer not accepted by driver */ + + /* check if wake up code called since last write call */ + if (n_hdlc->woke_up) + continue; + + /* set this buffer as pending buffer */ + n_hdlc->tbuf = tbuf; + break; + } + } + + if (!tbuf) + tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); + + /* Clear the re-entry flag */ + save_flags(flags); + cli (); + n_hdlc->tbusy = 0; + restore_flags(flags); + + if (debuglevel >= DEBUG_LEVEL_INFO) + printk("%s(%d)n_hdlc_send_frames() exit\n",__FILE__,__LINE__); + +} /* end of n_hdlc_send_frames() */ + +/* n_hdlc_tty_wakeup() + * + * Callback for transmit wakeup. Called when low level + * device driver can accept more send data. + * + * Arguments: tty pointer to associated tty instance data + * Return Value: None + */ +static void n_hdlc_tty_wakeup (struct tty_struct *tty) +{ + struct n_hdlc *n_hdlc = tty2n_hdlc (tty); + + if (debuglevel >= DEBUG_LEVEL_INFO) + printk("%s(%d)n_hdlc_tty_wakeup() called\n",__FILE__,__LINE__); + + if (!n_hdlc) + return; + + if (tty != n_hdlc->tty) { + tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); + return; + } + + if (!n_hdlc->tbuf) + tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); + else + n_hdlc_send_frames (n_hdlc, tty); + +} /* end of n_hdlc_tty_wakeup() */ + +/* n_hdlc_tty_room() + * + * Callback function from tty driver. Return the amount of + * space left in the receiver's buffer to decide if remote + * transmitter is to be throttled. + * + * Arguments: tty pointer to associated tty instance data + * Return Value: number of bytes left in receive buffer + */ +static int n_hdlc_tty_room (struct tty_struct *tty) +{ + if (debuglevel >= DEBUG_LEVEL_INFO) + printk("%s(%d)n_hdlc_tty_room() called\n",__FILE__,__LINE__); + /* always return a larger number to prevent */ + /* throttling of remote transmitter. */ + return 65536; +} /* end of n_hdlc_tty_root() */ + +/* n_hdlc_tty_receive() + * + * Called by tty low level driver when receive data is + * available. Data is interpreted as one HDLC frame. + * + * Arguments: tty pointer to tty isntance data + * data pointer to received data + * flags pointer to flags for data + * count count of received data in bytes + * + * Return Value: None + */ +static void n_hdlc_tty_receive(struct tty_struct *tty, + const __u8 * data, char *flags, int count) +{ + register struct n_hdlc *n_hdlc = tty2n_hdlc (tty); + register N_HDLC_BUF *buf; + + if (debuglevel >= DEBUG_LEVEL_INFO) + printk("%s(%d)n_hdlc_tty_receive() called count=%d\n", + __FILE__,__LINE__, count); + + /* This can happen if stuff comes in on the backup tty */ + if (n_hdlc == 0 || tty != n_hdlc->tty) + return; + + /* verify line is using HDLC discipline */ + if (n_hdlc->magic != HDLC_MAGIC) { + printk("%s(%d) line not using HDLC discipline\n", + __FILE__,__LINE__); + return; + } + + /* get a free HDLC buffer */ + buf = n_hdlc_buf_get(&n_hdlc->rx_free_buf_list); + if (!buf) { + /* no buffers in free list, attempt to allocate another rx buffer */ + /* unless the maximum count has been reached */ + if (n_hdlc->rx_buf_list.count < MAX_RX_BUF_COUNT) + buf = (N_HDLC_BUF*)kmalloc(sizeof(N_HDLC_BUF),GFP_ATOMIC); + } + + if (!buf) { + printk("%s(%d) no more rx buffers, data discarded\n", + __FILE__,__LINE__); + return; + } + + /* copy received data to HDLC buffer */ + memcpy(buf->buf,data,count); + buf->count=count; + + /* add HDLC buffer to list of received frames */ + n_hdlc_buf_put(&n_hdlc->rx_buf_list,buf); + + /* wake up any blocked reads and perform async signalling */ + wake_up_interruptible (&n_hdlc->read_wait); + if (n_hdlc->tty->fasync != NULL) + kill_fasync (n_hdlc->tty->fasync, SIGIO); + +} /* end of n_hdlc_tty_receive() */ + +/* n_hdlc_tty_read() + * + * Called to retreive one frame of data (if available) + * + * Arguments: + * + * tty pointer to tty instance data + * file pointer to open file object + * buf pointer to returned data buffer + * nr size of returned data buffer + * + * Return Value: + * + * Number of bytes returned or error code + */ +static rw_ret_t n_hdlc_tty_read (struct tty_struct *tty, + struct file *file, __u8 * buf, rw_count_t nr) +{ + struct n_hdlc *n_hdlc = tty2n_hdlc(tty); + int error; + rw_ret_t ret; + N_HDLC_BUF *rbuf; + + if (debuglevel >= DEBUG_LEVEL_INFO) + printk("%s(%d)n_hdlc_tty_read() called\n",__FILE__,__LINE__); + + /* Validate the pointers */ + if (!n_hdlc) + return -EIO; + + /* verify user access to buffer */ + error = verify_area (VERIFY_WRITE, buf, nr); + if (error != 0) { + printk(KERN_WARNING"%s(%d) n_hdlc_tty_read() can't verify user " + "buffer\n",__FILE__,__LINE__); + return (error); + } + + for (;;) { + n_hdlc = tty2n_hdlc (tty); + if (!n_hdlc || n_hdlc->magic != HDLC_MAGIC || + tty != n_hdlc->tty) + return 0; + + rbuf = n_hdlc_buf_get(&n_hdlc->rx_buf_list); + if (rbuf) + break; + + /* no data */ + if (file->f_flags & O_NONBLOCK) + return -EAGAIN; + + /* TODO: no timeout? current->timeout = 0;*/ + interruptible_sleep_on (&n_hdlc->read_wait); + if (signal_pending(current)) + return -EINTR; + } + + if (rbuf->count > nr) { + /* frame too large for caller's buffer (discard frame) */ + ret = (rw_ret_t)-EOVERFLOW; + } else { + /* Copy the data to the caller's buffer */ + COPY_TO_USER(error,buf,rbuf->buf,rbuf->count); + if (error) + ret = (rw_ret_t)error; + else + ret = (rw_ret_t)rbuf->count; + } + + /* return HDLC buffer to free list unless the free list */ + /* count has exceeded the default value, in which case the */ + /* buffer is freed back to the OS to conserve memory */ + if (n_hdlc->rx_free_buf_list.count > DEFAULT_RX_BUF_COUNT) + kfree(rbuf); + else + n_hdlc_buf_put(&n_hdlc->rx_free_buf_list,rbuf); + + return ret; + +} /* end of n_hdlc_tty_read() */ + +/* n_hdlc_tty_write() + * + * write a single frame of data to device + * + * Arguments: tty pointer to associated tty device instance data + * file pointer to file object data + * data pointer to transmit data (one frame) + * count size of transmit frame in bytes + * + * Return Value: number of bytes written (or error code) + */ +static rw_ret_t n_hdlc_tty_write (struct tty_struct *tty, struct file *file, + const __u8 * data, rw_count_t count) +{ + struct n_hdlc *n_hdlc = tty2n_hdlc (tty); + int error = 0; + struct wait_queue wait = {current, NULL}; + N_HDLC_BUF *tbuf; + + if (debuglevel >= DEBUG_LEVEL_INFO) + printk("%s(%d)n_hdlc_tty_write() called count=%d\n", + __FILE__,__LINE__,count); + + /* Verify pointers */ + if (!n_hdlc) + return -EIO; + + if (n_hdlc->magic != HDLC_MAGIC) + return -EIO; + + /* verify frame size */ + if (count > MAX_HDLC_FRAME_SIZE) { + if (debuglevel & DEBUG_LEVEL_INFO) + printk (KERN_WARNING + "n_hdlc_tty_write: truncating user packet " + "from %lu to %d\n", (unsigned long) count, + MAX_HDLC_FRAME_SIZE); + count = MAX_HDLC_FRAME_SIZE; + } + + /* Allocate transmit buffer */ + tbuf = n_hdlc_buf_get(&n_hdlc->tx_free_buf_list); + if (!tbuf) { + /* sleep until transmit buffer available */ + add_wait_queue(&n_hdlc->write_wait, &wait); + while (!tbuf) { + /* TODO: no timeout? current->timeout = 0;*/ + current->state = TASK_INTERRUPTIBLE; + schedule(); + + n_hdlc = tty2n_hdlc (tty); + if (!n_hdlc || n_hdlc->magic != HDLC_MAGIC || + tty != n_hdlc->tty) { + printk("n_hdlc_tty_write: %p invalid after wait!\n", n_hdlc); + error = -EIO; + break; + } + + if (signal_pending(current)) { + error = -EINTR; + break; + } + + tbuf = n_hdlc_buf_get(&n_hdlc->tx_free_buf_list); + } + current->state = TASK_RUNNING; + remove_wait_queue(&n_hdlc->write_wait, &wait); + } + + if (!error) { + /* Retrieve the user's buffer */ + COPY_FROM_USER (error, tbuf->buf, data, count); + if (error) { + /* return tx buffer to free list */ + n_hdlc_buf_put(&n_hdlc->tx_free_buf_list,tbuf); + } else { + /* Send the data */ + tbuf->count = error = count; + n_hdlc_buf_put(&n_hdlc->tx_buf_list,tbuf); + n_hdlc_send_frames(n_hdlc,tty); + } + } + + return error; + +} /* end of n_hdlc_tty_write() */ + +/* n_hdlc_tty_ioctl() + * + * Process IOCTL system call for the tty device. + * + * Arguments: + * + * tty pointer to tty instance data + * file pointer to open file object for device + * cmd IOCTL command code + * arg argument for IOCTL call (cmd dependent) + * + * Return Value: Command dependent + */ +static int n_hdlc_tty_ioctl (struct tty_struct *tty, struct file * file, + unsigned int cmd, unsigned long arg) +{ + struct n_hdlc *n_hdlc = tty2n_hdlc (tty); + int error = 0; + + if (debuglevel >= DEBUG_LEVEL_INFO) + printk("%s(%d)n_hdlc_tty_ioctl() called %d\n", + __FILE__,__LINE__,cmd); + + /* Verify the status of the device */ + if (!n_hdlc || n_hdlc->magic != HDLC_MAGIC) + return -EBADF; + + switch (cmd) { + case FIONREAD: + { + /* report count of read data available */ + /* in next available frame (if any) */ + int count; + unsigned long flags; + spin_lock_irqsave(&n_hdlc->rx_buf_list.spinlock,flags); + if (n_hdlc->rx_buf_list.head) + count = n_hdlc->rx_buf_list.head->count; + else + count = 0; + spin_unlock_irqrestore(&n_hdlc->rx_buf_list.spinlock,flags); + PUT_USER (error, count, (int *) arg); + } + break; + + default: + error = n_tty_ioctl (tty, file, cmd, arg); + break; + } + return error; + +} /* end of n_hdlc_tty_ioctl() */ + +#if LINUX_VERSION_CODE < VERSION(2,1,23) +/* n_hdlc_tty_select() + * + * Device select method. Determine if operation requires + * blocking and if so put appropriate wait queue in select + * table and return 0, otherwise return 1. + * + * Arguments: + * + * tty pointer to tty device instance data + * inode pointer to inode for device + * filp pointer to file object + * sel_type identified the select type (read/write/exception) + * wait select table for adding wait queue if appropriate + * + * Return Value: + * + * 1 if no need to block on operation + * 0 if must block and wait queue added to select table + */ +static int n_hdlc_tty_select (struct tty_struct *tty, struct inode *inode, + struct file *filp, int sel_type, select_table * wait) +{ + struct n_hdlc *n_hdlc = tty2n_hdlc(tty); + int result = 1; + + if (debuglevel >= DEBUG_LEVEL_INFO) + printk("%s(%d)n_hdlc_tty_select() called\n",__FILE__,__LINE__); + + /* Verify the status of the device */ + if (!n_hdlc) + return -EBADF; + + if (n_hdlc->magic != HDLC_MAGIC || tty != n_hdlc->tty) + return -EBADF; + + switch (sel_type) { + case SEL_IN: + if (n_hdlc->rx_buf_list.head) + break; + + case SEL_EX: /* Exceptions or read errors */ + /* Is this a pty link and the remote disconnected? */ + if (tty->flags & (1 << TTY_OTHER_CLOSED)) + break; + + /* Is this a local link and the modem disconnected? */ + if (tty_hung_up_p (filp)) + break; + + select_wait (&n_hdlc->read_wait, wait); + result = 0; + break; + + /* Write mode. A write is allowed if there is no current transmission */ + case SEL_OUT: + if (!n_hdlc->tx_free_buf_list.head) { + select_wait (&n_hdlc->write_wait, wait); + result = 0; + } + break; + } + return result; +} /* end of n_hdlc_tty_select() */ + +#else /* 2.1.23 or later */ + +/* n_hdlc_tty_poll() + * + * TTY callback for poll system call. Determine which + * operations (read/write) will not block and return + * info to caller. + * + * Arguments: + * + * tty pointer to tty instance data + * filp pointer to open file object for device + * poll_table wait queue for operations + * + * Return Value: + * + * bit mask containing info on which ops will not block + */ +static unsigned int n_hdlc_tty_poll (struct tty_struct *tty, + struct file *filp, poll_table * wait) +{ + struct n_hdlc *n_hdlc = tty2n_hdlc (tty); + unsigned int mask = 0; + + if (debuglevel >= DEBUG_LEVEL_INFO) + printk("%s(%d)n_hdlc_tty_poll() called\n",__FILE__,__LINE__); + + if (n_hdlc && n_hdlc->magic == HDLC_MAGIC && tty == n_hdlc->tty) { + /* queue current process into any wait queue that */ + /* may awaken in the future (read and write) */ +#if LINUX_VERSION_CODE < VERSION(2,1,89) + poll_wait(&n_hdlc->read_wait, wait); + poll_wait(&n_hdlc->write_wait, wait); +#else + poll_wait(filp, &n_hdlc->read_wait, wait); + poll_wait(filp, &n_hdlc->write_wait, wait); +#endif + /* set bits for operations that wont block */ + if(n_hdlc->rx_buf_list.head) + mask |= POLLIN | POLLRDNORM; /* readable */ + if(tty->flags & (1 << TTY_OTHER_CLOSED)) + mask |= POLLHUP; + if(tty_hung_up_p(filp)) + mask |= POLLHUP; + if(n_hdlc->tx_free_buf_list.head) + mask |= POLLOUT | POLLWRNORM; /* writable */ + } + return mask; +} /* end of n_hdlc_tty_poll() */ + +#endif + +/* n_hdlc_alloc() + * + * Allocate an n_hdlc instance data structure + * + * Arguments: None + * Return Value: pointer to structure if success, otherwise 0 + */ +static struct n_hdlc *n_hdlc_alloc (void) +{ + struct n_hdlc *n_hdlc; + N_HDLC_BUF *buf; + int i; + + n_hdlc = (struct n_hdlc *)kmalloc(sizeof(struct n_hdlc), GFP_KERNEL); + if (!n_hdlc) + return 0; + + memset(n_hdlc, 0, sizeof(*n_hdlc)); + + n_hdlc_buf_list_init(&n_hdlc->rx_free_buf_list); + n_hdlc_buf_list_init(&n_hdlc->tx_free_buf_list); + n_hdlc_buf_list_init(&n_hdlc->rx_buf_list); + n_hdlc_buf_list_init(&n_hdlc->tx_buf_list); + + /* allocate free rx buffer list */ + for(i=0;irx_free_buf_list,buf); + } + + /* allocate free rx buffer list */ + for(i=0;itx_free_buf_list,buf); + } + + /* Initialize the control block */ + n_hdlc->magic = HDLC_MAGIC; + + n_hdlc->flags = 0; + n_hdlc->read_wait = NULL; + n_hdlc->write_wait = NULL; + + return n_hdlc; + +} /* end of n_hdlc_alloc() */ + +/* n_hdlc_buf_list_init() + * + * initialize specified HDLC buffer list + * + * Arguments: list pointer to buffer list + * Return Value: None + */ +void n_hdlc_buf_list_init(N_HDLC_BUF_LIST *list) +{ + memset(list,0,sizeof(N_HDLC_BUF_LIST)); + +} /* end of n_hdlc_buf_list_init() */ + +/* n_hdlc_buf_put() + * + * add specified HDLC buffer to tail of specified list + * + * Arguments: + * + * list pointer to buffer list + * buf pointer to buffer + * + * Return Value: None + */ +void n_hdlc_buf_put(N_HDLC_BUF_LIST *list,N_HDLC_BUF *buf) +{ + unsigned long flags; + spin_lock_irqsave(&list->spinlock,flags); + + buf->link=NULL; + if(list->tail) + list->tail->link = buf; + else + list->head = buf; + list->tail = buf; + (list->count)++; + + spin_unlock_irqrestore(&list->spinlock,flags); + +} /* end of n_hdlc_buf_put() */ + +/* n_hdlc_buf_get() + * + * remove and return an HDLC buffer from the + * head of the specified HDLC buffer list + * + * Arguments: + * + * list pointer to HDLC buffer list + * + * Return Value: + * + * pointer to HDLC buffer if available, otherwise NULL + */ +N_HDLC_BUF* n_hdlc_buf_get(N_HDLC_BUF_LIST *list) +{ + unsigned long flags; + N_HDLC_BUF *buf; + spin_lock_irqsave(&list->spinlock,flags); + + buf = list->head; + if (buf) { + list->head = buf->link; + (list->count)--; + } + if (!list->head) + list->tail = NULL; + + spin_unlock_irqrestore(&list->spinlock,flags); + return buf; + +} /* end of n_hdlc_buf_get() */ + +/* init_module() + * + * called when module is loading to register line discipline + * + * Arguments: None + * Return Value: 0 if success, otherwise error code + */ +int init_module(void) +{ + static struct tty_ldisc n_hdlc_ldisc; + int status; + + printk("HDLC line discipline: version %s\n", szVersion); + + /* Register the tty discipline */ + + memset(&n_hdlc_ldisc, 0, sizeof (n_hdlc_ldisc)); + n_hdlc_ldisc.magic = TTY_LDISC_MAGIC; +#if LINUX_VERSION_CODE >= VERSION(2,1,28) + n_hdlc_ldisc.name = "hdlc"; +#endif + n_hdlc_ldisc.open = n_hdlc_tty_open; + n_hdlc_ldisc.close = n_hdlc_tty_close; + n_hdlc_ldisc.read = n_hdlc_tty_read; + n_hdlc_ldisc.write = n_hdlc_tty_write; + n_hdlc_ldisc.ioctl = n_hdlc_tty_ioctl; +#if LINUX_VERSION_CODE < VERSION(2,1,23) + n_hdlc_ldisc.select = n_hdlc_tty_select; +#else + n_hdlc_ldisc.poll = n_hdlc_tty_poll; +#endif + n_hdlc_ldisc.receive_room = n_hdlc_tty_room; + n_hdlc_ldisc.receive_buf = n_hdlc_tty_receive; + n_hdlc_ldisc.write_wakeup = n_hdlc_tty_wakeup; + + status = tty_register_ldisc(N_HDLC, &n_hdlc_ldisc); + if (!status) + printk (KERN_INFO"N_HDLC line discipline registered.\n"); + else + printk (KERN_ERR"error registering line discipline: %d\n",status); + + if (status) + printk(KERN_INFO"N_HDLC: init failure %d\n", status); + return (status); + +} /* end of init_module() */ + +/* cleanup_module() + * + * called when module is unloading to unregister line discipline + * + * Arguments: None + * Return Value: None + */ +void cleanup_module(void) +{ + int status; + /* Release tty registration of line discipline */ + if ((status = tty_register_ldisc(N_HDLC, NULL))) + printk("N_HDLC: can't unregister line discipline (err = %d)\n", status); + else + printk("N_HDLC: line discipline unregistered\n"); +} diff -ur --new-file old/linux/drivers/char/n_tty.c new/linux/drivers/char/n_tty.c --- old/linux/drivers/char/n_tty.c Sun Jan 17 19:39:27 1999 +++ new/linux/drivers/char/n_tty.c Sun Apr 25 02:49:37 1999 @@ -922,8 +922,14 @@ } } - if (down_interruptible(&tty->atomic_read)) - return -ERESTARTSYS; + if (file->f_flags & O_NONBLOCK) { + if (down_trylock(&tty->atomic_read)) + return -EAGAIN; + } + else { + if (down_interruptible(&tty->atomic_read)) + return -ERESTARTSYS; + } add_wait_queue(&tty->read_wait, &wait); set_bit(TTY_DONT_FLIP, &tty->flags); diff -ur --new-file old/linux/drivers/char/pc_keyb.c new/linux/drivers/char/pc_keyb.c --- old/linux/drivers/char/pc_keyb.c Thu Jan 21 23:00:21 1999 +++ new/linux/drivers/char/pc_keyb.c Mon Apr 26 22:43:01 1999 @@ -10,6 +10,9 @@ * because they share the same hardware. * Johan Myreen 1998-10-08. * + * Code fixes to handle mouse ACKs properly. + * C. Scott Ananian 1999-01-29. + * */ #include @@ -74,6 +77,8 @@ static struct aux_queue *queue; /* Mouse data buffer. */ static int aux_count = 0; +/* used when we send commands to the mouse that expect an ACK. */ +static unsigned char mouse_reply_expected = 0; #define AUX_INTS_OFF (KBD_MODE_KCC | KBD_MODE_DISABLE_MOUSE | KBD_MODE_SYS | KBD_MODE_KBD_INT) #define AUX_INTS_ON (KBD_MODE_KCC | KBD_MODE_SYS | KBD_MODE_MOUSE_INT | KBD_MODE_KBD_INT) @@ -99,7 +104,7 @@ * Controller Status register are set 0." */ -static inline void kb_wait(void) +static void kb_wait(void) { unsigned long timeout = KBC_TIMEOUT; @@ -235,8 +240,6 @@ 0, 0, 0, 0, 0, 0, 0, 0 /* 0x78-0x7f */ }; -static unsigned int prev_scancode = 0; /* remember E0, E1 */ - int pckbd_setkeycode(unsigned int scancode, unsigned int keycode) { if (scancode < SC_LIM || scancode > 255 || keycode > 127) @@ -279,41 +282,28 @@ scancode); #endif } - if (scancode == 0) { -#ifdef KBD_REPORT_ERR - printk(KERN_INFO "Keyboard buffer overflow\n"); -#endif - prev_scancode = 0; - return 0; - } return 1; } -int pckbd_pretranslate(unsigned char scancode, char raw_mode) +int pckbd_translate(unsigned char scancode, unsigned char *keycode, + char raw_mode) { - if (scancode == 0xff) { - /* in scancode mode 1, my ESC key generates 0xff */ - /* the calculator keys on a FOCUS 9000 generate 0xff */ -#ifndef KBD_IS_FOCUS_9000 -#ifdef KBD_REPORT_ERR - if (!raw_mode) - printk(KERN_DEBUG "Keyboard error\n"); -#endif -#endif - prev_scancode = 0; - return 0; - } + static int prev_scancode = 0; + /* special prefix scancodes.. */ if (scancode == 0xe0 || scancode == 0xe1) { prev_scancode = scancode; return 0; - } - return 1; -} + } + + /* 0xFF is sent by a few keyboards, ignore it. 0x00 is error */ + if (scancode == 0x00 || scancode == 0xff) { + prev_scancode = 0; + return 0; + } + + scancode &= 0x7f; -int pckbd_translate(unsigned char scancode, unsigned char *keycode, - char raw_mode) -{ if (prev_scancode) { /* * usually it will be 0xe0, but a Pause key generates @@ -400,6 +390,33 @@ return 0200; } +static inline void handle_mouse_event(unsigned char scancode) +{ +#ifdef CONFIG_PSMOUSE + if (mouse_reply_expected) { + if (scancode == AUX_ACK) { + mouse_reply_expected--; + return; + } + mouse_reply_expected = 0; + } + + add_mouse_randomness(scancode); + if (aux_count) { + int head = queue->head; + + queue->buf[head] = scancode; + head = (head + 1) & (AUX_BUF_SIZE-1); + if (head != queue->tail) { + queue->head = head; + if (queue->fasync) + kill_fasync(queue->fasync, SIGIO); + wake_up_interruptible(&queue->proc_list); + } + } +#endif +} + /* * This reads the keyboard status port, and does the * appropriate action. @@ -417,24 +434,10 @@ scancode = inb(KBD_DATA_REG); if (status & KBD_STAT_MOUSE_OBF) { -#ifdef CONFIG_PSMOUSE - /* Mouse data. */ - if (aux_count) { - int head = queue->head; - queue->buf[head] = scancode; - add_mouse_randomness(scancode); - head = (head + 1) & (AUX_BUF_SIZE-1); - if (head != queue->tail) { - queue->head = head; - if (queue->fasync) - kill_fasync(queue->fasync, SIGIO); - wake_up_interruptible(&queue->proc_list); - } - } -#endif + handle_mouse_event(scancode); } else { if (do_acknowledge(scancode)) - handle_scancode(scancode); + handle_scancode(scancode, !(scancode & 0x80)); mark_bh(KEYBOARD_BH); } @@ -716,9 +719,7 @@ static int __init detect_auxiliary_port(void) { unsigned long flags; - unsigned char status; - unsigned char val; - int loops = 5; + int loops = 10; int retval = 0; spin_lock_irqsave(&kbd_controller_lock, flags); @@ -736,20 +737,19 @@ kb_wait(); outb(0x5a, KBD_DATA_REG); /* 0x5a is a random dummy value. */ - status = inb(KBD_STATUS_REG); - while (!(status & KBD_STAT_OBF) && loops--) { - mdelay(1); - status = inb(KBD_STATUS_REG); - } + do { + unsigned char status = inb(KBD_STATUS_REG); - if (status & KBD_STAT_OBF) { - val = inb(KBD_DATA_REG); - if (status & KBD_STAT_MOUSE_OBF) { - printk(KERN_INFO "Detected PS/2 Mouse Port.\n"); - retval = 1; + if (status & KBD_STAT_OBF) { + (void) inb(KBD_DATA_REG); + if (status & KBD_STAT_MOUSE_OBF) { + printk(KERN_INFO "Detected PS/2 Mouse Port.\n"); + retval = 1; + } + break; } - } - + mdelay(1); + } while (--loops); spin_unlock_irqrestore(&kbd_controller_lock, flags); return retval; @@ -770,16 +770,33 @@ spin_unlock_irqrestore(&kbd_controller_lock, flags); } -static unsigned int get_from_queue(void) +/* + * Send a byte to the mouse & handle returned ack + */ +static void aux_write_ack(int val) +{ + unsigned long flags; + + spin_lock_irqsave(&kbd_controller_lock, flags); + kb_wait(); + outb(KBD_CCMD_WRITE_MOUSE, KBD_CNTL_REG); + kb_wait(); + outb(val, KBD_DATA_REG); + /* we expect an ACK in response. */ + mouse_reply_expected++; + kb_wait(); + spin_unlock_irqrestore(&kbd_controller_lock, flags); +} + +static unsigned char get_from_queue(void) { - unsigned int result; + unsigned char result; unsigned long flags; - save_flags(flags); - cli(); + spin_lock_irqsave(&kbd_controller_lock, flags); result = queue->buf[queue->tail]; queue->tail = (queue->tail + 1) & (AUX_BUF_SIZE-1); - restore_flags(flags); + spin_unlock_irqrestore(&kbd_controller_lock, flags); return result; } @@ -834,7 +851,7 @@ kbd_write(KBD_CNTL_REG, KBD_CCMD_MOUSE_ENABLE); /* Enable the auxiliary port on controller. */ - aux_write_dev(AUX_ENABLE_DEV); /* Enable aux device */ + aux_write_ack(AUX_ENABLE_DEV); /* Enable aux device */ kbd_write_cmd(AUX_INTS_ON); /* Enable controller ints */ return 0; @@ -951,11 +968,11 @@ #ifdef INITIALIZE_MOUSE kbd_write(KBD_CNTL_REG, KBD_CCMD_MOUSE_ENABLE); /* Enable Aux. */ - aux_write_dev(AUX_SET_SAMPLE); - aux_write_dev(100); /* 100 samples/sec */ - aux_write_dev(AUX_SET_RES); - aux_write_dev(3); /* 8 counts per mm */ - aux_write_dev(AUX_SET_SCALE21); /* 2:1 scaling */ + 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_cmd(AUX_INTS_OFF); /* Disable controller ints. */ diff -ur --new-file old/linux/drivers/char/pc_keyb.h new/linux/drivers/char/pc_keyb.h --- old/linux/drivers/char/pc_keyb.h Thu Jan 14 19:39:09 1999 +++ new/linux/drivers/char/pc_keyb.h Sat Feb 6 21:46:20 1999 @@ -114,8 +114,12 @@ #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 +#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; diff -ur --new-file old/linux/drivers/char/pcxx.c new/linux/drivers/char/pcxx.c --- old/linux/drivers/char/pcxx.c Mon Jan 18 03:28:06 1999 +++ new/linux/drivers/char/pcxx.c Thu Mar 11 01:51:35 1999 @@ -68,7 +68,6 @@ #include #include #include -#include #include #include diff -ur --new-file old/linux/drivers/char/planb.c new/linux/drivers/char/planb.c --- old/linux/drivers/char/planb.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/char/planb.c Mon May 10 19:17:28 1999 @@ -0,0 +1,2389 @@ +/* + planb - PlanB frame grabber driver + + PlanB is used in the 7x00/8x00 series of PowerMacintosh + Computers as video input DMA controller. + + Copyright (C) 1998 Michel Lanners (mlan@cpu.lu) + + Based largely on the bttv driver by Ralph Metzler (rjkm@thp.uni-koeln.de) + + Additional debugging and coding by Takashi Oe (toe@unlinfo.unl.edu) + (Some codes are stolen from proposed v4l2 videodev.c + of Bill Dirks ) + + 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. +*/ + +/* $Id: planb.c,v 1.18 1999/05/02 17:36:34 mlan 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 "planb.h" +#include "saa7196.h" + + +/* Would you mind for some ugly debugging? */ +//#define DEBUG(x...) printk(KERN_DEBUG ## x) /* Debug driver */ +#define DEBUG(x...) /* Don't debug driver */ +//#define IDEBUG(x...) printk(KERN_DEBUG ## x) /* Debug interrupt part */ +#define IDEBUG(x...) /* Don't debug interrupt part */ + +/* Ever seen a Mac with more than 1 of these? */ +#define PLANB_MAX 1 + +static int planb_num; +static struct planb planbs[PLANB_MAX]; +static volatile struct planb_registers *planb_regs; + +static int def_norm = PLANB_DEF_NORM; /* default norm */ + +MODULE_PARM(def_norm, "i"); +MODULE_PARM_DESC(def_norm, "Default startup norm (0=PAL, 1=NTSC, 2=SECAM)"); + +/* ------------------ PlanB Exported Functions ------------------ */ +static long planb_write(struct video_device *, const char *, unsigned long, int); +static long planb_read(struct video_device *, char *, unsigned long, int); +static int planb_open(struct video_device *, int); +static void planb_close(struct video_device *); +static int planb_ioctl(struct video_device *, unsigned int, void *); +static int planb_init_done(struct video_device *); +static int planb_mmap(struct video_device *, const char *, unsigned long); +static void planb_irq(int, void *, struct pt_regs *); +static void release_planb(void); +int init_planbs(struct video_init *); + +/* ------------------ PlanB Internal Functions ------------------ */ +static int planb_prepare_open(struct planb *); +static void planb_prepare_close(struct planb *); +static void saa_write_reg(unsigned char, unsigned char); +static unsigned char saa_status(int, struct planb *); +static void saa_set(unsigned char, unsigned char, struct planb *); +static void saa_init_regs(struct planb *); +static void * rvmalloc(unsigned long); +static void rvfree(void *, unsigned long); +static unsigned long vmalloc_to_bus(void *); +static unsigned long vmalloc_to_phys(void *); +static int fbuffer_alloc(struct planb *); +static int vgrab(struct planb *, struct video_mmap *); +static void add_clip(struct planb *, struct video_clip *); +static void fill_cmd_buff(struct planb *); +static void cmd_buff(struct planb *); +static volatile struct dbdma_cmd *setup_grab_cmd(int, struct planb *); +static void overlay_start(struct planb *); +static void overlay_stop(struct planb *); +static inline void tab_cmd_dbdma(volatile struct dbdma_cmd *, unsigned short, + unsigned int); +static inline void tab_cmd_store(volatile struct dbdma_cmd *, unsigned int, + unsigned int); +static inline void tab_cmd_gen(volatile struct dbdma_cmd *, unsigned short, + unsigned short, unsigned int, unsigned int); +static int init_planb(struct planb *); +static int find_planb(void); +static void planb_pre_capture(int, int, struct planb *); +static volatile struct dbdma_cmd *cmd_geo_setup(volatile struct dbdma_cmd *, + int, int, int, int, int, struct planb *); +static inline void planb_dbdma_stop(volatile struct dbdma_regs *); +static unsigned int saa_geo_setup(int, int, int, int, struct planb *); +static inline int overlay_is_active(struct planb *); + +/*******************************/ +/* Memory management functions */ +/*******************************/ + +static void * rvmalloc(unsigned long size) +{ + void *mem, *memptr; + unsigned long page; + + mem=vmalloc(size); + if (mem) + { + memset(mem, 0, size); /* Clear the ram out, leave no junk */ + memptr = mem; + while (size > 0) + { + page = vmalloc_to_phys(memptr); + mem_map_reserve(MAP_NR(phys_to_virt(page))); + memptr+=PAGE_SIZE; + size-=PAGE_SIZE; + } + } + return mem; +} + +static void rvfree(void * mem, unsigned long size) +{ + void *memptr; + unsigned long page; + + if (mem) + { + memptr = mem; + while (size > 0) + { + page = vmalloc_to_phys(memptr); + mem_map_unreserve(MAP_NR(phys_to_virt(page))); + memptr += PAGE_SIZE; + size-=PAGE_SIZE; + } + vfree(mem); + } +} + +/* Useful for using vmalloc()ed memory as DMA target */ +static unsigned long vmalloc_to_bus(void *virt) +{ + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + unsigned long a = (unsigned long)virt; + + if (pgd_none(*(pgd = pgd_offset(current->mm, a))) || + pmd_none(*(pmd = pmd_offset(pgd, a))) || + pte_none(*(pte = pte_offset(pmd, a)))) + return 0; + return virt_to_bus((void *)pte_page(*pte)) + + (a & (PAGE_SIZE - 1)); +} + +static unsigned long vmalloc_to_phys(void *virt) { + return virt_to_phys(bus_to_virt(vmalloc_to_bus(virt))); +} + +/* + * Create the giant waste of buffer space we need for now + * until we get DMA to user space sorted out (probably 2.3.x) + * + * We only create this as and when someone uses mmap + */ + +static int fbuffer_alloc(struct planb *pb) +{ + if(!pb->fbuffer) + pb->fbuffer=(unsigned char *) rvmalloc(MAX_GBUFFERS + * PLANB_MAX_FBUF); + else + printk(KERN_ERR "PlanB: Double alloc of fbuffer!\n"); + if(!pb->fbuffer) + return -ENOBUFS; + return 0; +} + +/*****************************/ +/* Hardware access functions */ +/*****************************/ + +static void saa_write_reg(unsigned char addr, unsigned char val) +{ + planb_regs->saa_addr = addr; eieio(); + planb_regs->saa_regval = val; eieio(); + return; +} + +/* return status byte 0 or 1: */ +static unsigned char saa_status(int byte, struct planb *pb) +{ + saa_regs[pb->win.norm][SAA7196_STDC] = + (saa_regs[pb->win.norm][SAA7196_STDC] & ~2) | ((byte & 1) << 1); + saa_write_reg (SAA7196_STDC, saa_regs[pb->win.norm][SAA7196_STDC]); + + /* Let's wait 30msec for this one */ + current->state = TASK_INTERRUPTIBLE; +#if LINUX_VERSION_CODE >= 0x02017F + schedule_timeout(30 * HZ / 1000); +#else + current->timeout = jiffies + 30 * HZ / 1000; /* 30 ms */; + schedule(); +#endif + + return (unsigned char)in_8 (&planb_regs->saa_status); +} + +static void saa_set(unsigned char addr, unsigned char val, struct planb *pb) +{ + if(saa_regs[pb->win.norm][addr] != val) { + saa_regs[pb->win.norm][addr] = val; + saa_write_reg (addr, val); + } + return; +} + +static void saa_init_regs(struct planb *pb) +{ + int i; + + for (i = 0; i < SAA7196_NUMREGS; i++) + saa_write_reg (i, saa_regs[pb->win.norm][i]); +} + +static unsigned int saa_geo_setup(int width, int height, int interlace, int bpp, + struct planb *pb) +{ + int ht, norm = pb->win.norm; + + switch(bpp) { + case 2: + /* RGB555+a 1x16-bit + 16-bit transparent */ + saa_regs[norm][SAA7196_FMTS] &= ~0x3; + break; + case 1: + case 4: + /* RGB888 1x24-bit + 8-bit transparent */ + saa_regs[norm][SAA7196_FMTS] &= ~0x1; + saa_regs[norm][SAA7196_FMTS] |= 0x2; + break; + default: + return -EINVAL; + } + ht = (interlace ? height / 2 : height); + saa_regs[norm][SAA7196_OUTPIX] = (unsigned char) (width & 0x00ff); + saa_regs[norm][SAA7196_HFILT] = (saa_regs[norm][SAA7196_HFILT] & ~0x3) + | (width >> 8 & 0x3); + saa_regs[norm][SAA7196_OUTLINE] = (unsigned char) (ht & 0xff); + saa_regs[norm][SAA7196_VYP] = (saa_regs[norm][SAA7196_VYP] & ~0x3) + | (ht >> 8 & 0x3); + /* feed both fields if interlaced, or else feed only even fields */ + saa_regs[norm][SAA7196_FMTS] = (interlace) ? + (saa_regs[norm][SAA7196_FMTS] & ~0x60) + : (saa_regs[norm][SAA7196_FMTS] | 0x60); + /* transparent mode; extended format enabled */ + saa_regs[norm][SAA7196_DPATH] |= 0x3; + + return 0; +} + +/***************************/ +/* DBDMA support functions */ +/***************************/ + +static inline void planb_dbdma_restart(volatile struct dbdma_regs *ch) +{ + out_le32(&ch->control, PLANB_CLR(RUN)); + out_le32(&ch->control, PLANB_SET(RUN|WAKE) | PLANB_CLR(PAUSE)); +} + +static inline void planb_dbdma_stop(volatile struct dbdma_regs *ch) +{ + int i = 0; + + out_le32(&ch->control, PLANB_CLR(RUN) | PLANB_SET(FLUSH)); + while((in_le32(&ch->status) == (ACTIVE | FLUSH)) && (i < 999)) { + IDEBUG("PlanB: waiting for DMA to stop\n"); + i++; + } +} + +static inline void tab_cmd_dbdma(volatile struct dbdma_cmd *ch, + unsigned short command, unsigned int cmd_dep) +{ + st_le16(&ch->command, command); + st_le32(&ch->cmd_dep, cmd_dep); +} + +static inline void tab_cmd_store(volatile struct dbdma_cmd *ch, + unsigned int phy_addr, unsigned int cmd_dep) +{ + st_le16(&ch->command, STORE_WORD | KEY_SYSTEM); + st_le16(&ch->req_count, 4); + st_le32(&ch->phy_addr, phy_addr); + st_le32(&ch->cmd_dep, cmd_dep); +} + +static inline void tab_cmd_gen(volatile struct dbdma_cmd *ch, + unsigned short command, unsigned short req_count, + unsigned int phy_addr, unsigned int cmd_dep) +{ + st_le16(&ch->command, command); + st_le16(&ch->req_count, req_count); + st_le32(&ch->phy_addr, phy_addr); + st_le32(&ch->cmd_dep, cmd_dep); +} + +static volatile struct dbdma_cmd *cmd_geo_setup( + volatile struct dbdma_cmd *c1, int width, int height, int interlace, + int bpp, int clip, struct planb *pb) +{ + int norm = pb->win.norm; + + if((saa_geo_setup(width, height, interlace, bpp, pb)) != 0) + return (volatile struct dbdma_cmd *)NULL; + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_addr), + SAA7196_FMTS); + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_regval), + saa_regs[norm][SAA7196_FMTS]); + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_addr), + SAA7196_DPATH); + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_regval), + saa_regs[norm][SAA7196_DPATH]); + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->even), + bpp | ((clip)? PLANB_CLIPMASK: 0)); + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->odd), + bpp | ((clip)? PLANB_CLIPMASK: 0)); + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_addr), + SAA7196_OUTPIX); + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_regval), + saa_regs[norm][SAA7196_OUTPIX]); + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_addr), + SAA7196_HFILT); + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_regval), + saa_regs[norm][SAA7196_HFILT]); + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_addr), + SAA7196_OUTLINE); + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_regval), + saa_regs[norm][SAA7196_OUTLINE]); + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_addr), + SAA7196_VYP); + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_regval), + saa_regs[norm][SAA7196_VYP]); + return c1; +} + +/******************************/ +/* misc. supporting functions */ +/******************************/ + +static void __planb_wait(struct planb *pb) +{ + struct wait_queue wait = { current, NULL }; + + add_wait_queue(&pb->lockq, &wait); +repeat: + current->state = TASK_UNINTERRUPTIBLE; + if (pb->lock) { + schedule(); + goto repeat; + } + remove_wait_queue(&pb->lockq, &wait); + current->state = TASK_RUNNING; +} + +static inline void planb_wait(struct planb *pb) +{ + DEBUG("PlanB: planb_wait\n"); + if(pb->lock) + __planb_wait(pb); +} + +static inline void planb_lock(struct planb *pb) +{ + DEBUG("PlanB: planb_lock\n"); + if(pb->lock) + __planb_wait(pb); + pb->lock = 1; +} + +static inline void planb_unlock(struct planb *pb) +{ + DEBUG("PlanB: planb_unlock\n"); + pb->lock = 0; + wake_up(&pb->lockq); +} + +/***************/ +/* Driver Core */ +/***************/ + +static int planb_prepare_open(struct planb *pb) +{ + int i, size; + + /* allocate memory for two plus alpha command buffers (size: max lines, + plus 40 commands handling, plus 1 alignment), plus dummy command buf, + plus clipmask buffer, plus frame grabbing status */ + size = (pb->tab_size*(2+MAX_GBUFFERS*TAB_FACTOR)+1+MAX_GBUFFERS + * PLANB_DUMMY)*sizeof(struct dbdma_cmd) + +(PLANB_MAXLINES*((PLANB_MAXPIXELS+7)& ~7))/8 + +MAX_GBUFFERS*sizeof(unsigned int); + if ((pb->priv_space = kmalloc (size, GFP_KERNEL)) == 0) + return -ENOMEM; + memset ((void *) pb->priv_space, 0, size); + pb->overlay_last1 = pb->ch1_cmd = (volatile struct dbdma_cmd *) + DBDMA_ALIGN (pb->priv_space); + pb->overlay_last2 = pb->ch2_cmd = pb->ch1_cmd + pb->tab_size; + pb->ch1_cmd_phys = virt_to_bus(pb->ch1_cmd); + pb->cap_cmd[0] = pb->ch2_cmd + pb->tab_size; + pb->pre_cmd[0] = pb->cap_cmd[0] + pb->tab_size * TAB_FACTOR; + for (i = 1; i < MAX_GBUFFERS; i++) { + pb->cap_cmd[i] = pb->pre_cmd[i-1] + PLANB_DUMMY; + pb->pre_cmd[i] = pb->cap_cmd[i] + pb->tab_size * TAB_FACTOR; + } + pb->frame_stat=(volatile unsigned int *)(pb->pre_cmd[MAX_GBUFFERS-1] + + PLANB_DUMMY); + pb->mask = (unsigned char *)(pb->frame_stat+MAX_GBUFFERS); + + pb->fbuffer = (unsigned char *)rvmalloc(MAX_GBUFFERS * PLANB_MAX_FBUF); + if (!pb->fbuffer) { + kfree(pb->priv_space); + return -ENOMEM; + } + pb->grabbing = 0; + for (i = 0; i < MAX_GBUFFERS; i++) { + pb->frame_stat[i] = GBUFFER_UNUSED; + pb->gwidth[i] = 0; + pb->gheight[i] = 0; + pb->gfmt[i] = 0; + pb->gnorm_switch[i] = 0; +#ifndef PLANB_GSCANLINE + pb->lsize[i] = 0; + pb->lnum[i] = 0; + pb->l_fr_addr[i]=(unsigned char *)rvmalloc(PAGE_SIZE*MAX_LNUM); + if (!pb->l_fr_addr[i]) { + int j; + kfree(pb->priv_space); + rvfree((void *)pb->fbuffer, MAX_GBUFFERS + * PLANB_MAX_FBUF); + for(j = 0; j < i; j++) + rvfree((void *)pb->l_fr_addr[j], PAGE_SIZE + * MAX_LNUM); + return -ENOMEM; + } +#endif /* PLANB_GSCANLINE */ + } + pb->gcount = 0; + pb->suspend = 0; + pb->last_fr = -999; + pb->prev_last_fr = -999; + return 0; +} + +static void planb_prepare_close(struct planb *pb) +{ +#ifndef PLANB_GSCANLINE + int i; +#endif + + /* make sure the dma's are idle */ + planb_dbdma_stop(&pb->planb_base->ch2); + planb_dbdma_stop(&pb->planb_base->ch1); + /* free kernel memory of command buffers */ + if(pb->priv_space != 0) { + kfree (pb->priv_space); + pb->priv_space = 0; + pb->cmd_buff_inited = 0; + } + if(pb->fbuffer) + rvfree((void *)pb->fbuffer, MAX_GBUFFERS*PLANB_MAX_FBUF); + pb->fbuffer = NULL; +#ifndef PLANB_GSCANLINE + for(i = 0; i < MAX_GBUFFERS; i++) { + if(pb->l_fr_addr[i]) + rvfree((void *)pb->l_fr_addr[i], PAGE_SIZE * MAX_LNUM); + pb->l_fr_addr[i] = NULL; + } +#endif /* PLANB_GSCANLINE */ +} + +/*****************************/ +/* overlay support functions */ +/*****************************/ + +static void overlay_start(struct planb *pb) +{ + + DEBUG("PlanB: overlay_start()\n"); + + if(ACTIVE & in_le32(&pb->planb_base->ch1.status)) { + + DEBUG("PlanB: presumably, grabbing is in progress...\n"); + + planb_dbdma_stop(&pb->planb_base->ch2); + out_le32 (&pb->planb_base->ch2.cmdptr, + virt_to_bus(pb->ch2_cmd)); + planb_dbdma_restart(&pb->planb_base->ch2); + st_le16 (&pb->ch1_cmd->command, DBDMA_NOP); + tab_cmd_dbdma(pb->last_cmd[pb->last_fr], + DBDMA_NOP | BR_ALWAYS, + virt_to_bus(pb->ch1_cmd)); + eieio(); + pb->prev_last_fr = pb->last_fr; + pb->last_fr = -2; + if(!(ACTIVE & in_le32(&pb->planb_base->ch1.status))) { + IDEBUG("PlanB: became inactive " + "in the mean time... reactivating\n"); + planb_dbdma_stop(&pb->planb_base->ch1); + out_le32 (&pb->planb_base->ch1.cmdptr, + virt_to_bus(pb->ch1_cmd)); + planb_dbdma_restart(&pb->planb_base->ch1); + } + } else { + + DEBUG("PlanB: currently idle, so can do whatever\n"); + + planb_dbdma_stop(&pb->planb_base->ch2); + planb_dbdma_stop(&pb->planb_base->ch1); + st_le32 (&pb->planb_base->ch2.cmdptr, + virt_to_bus(pb->ch2_cmd)); + st_le32 (&pb->planb_base->ch1.cmdptr, + virt_to_bus(pb->ch1_cmd)); + out_le16 (&pb->ch1_cmd->command, DBDMA_NOP); + planb_dbdma_restart(&pb->planb_base->ch2); + planb_dbdma_restart(&pb->planb_base->ch1); + pb->last_fr = -1; + } + return; +} + +static void overlay_stop(struct planb *pb) +{ + DEBUG("PlanB: overlay_stop()\n"); + + if(pb->last_fr == -1) { + + DEBUG("PlanB: no grabbing, it seems...\n"); + + planb_dbdma_stop(&pb->planb_base->ch2); + planb_dbdma_stop(&pb->planb_base->ch1); + pb->last_fr = -999; + } else if(pb->last_fr == -2) { + unsigned int cmd_dep; + tab_cmd_dbdma(pb->cap_cmd[pb->prev_last_fr], DBDMA_STOP, 0); + eieio(); + cmd_dep = (unsigned int)in_le32(&pb->overlay_last1->cmd_dep); + if(overlay_is_active(pb)) { + + DEBUG("PlanB: overlay is currently active\n"); + + planb_dbdma_stop(&pb->planb_base->ch2); + planb_dbdma_stop(&pb->planb_base->ch1); + if(cmd_dep != pb->ch1_cmd_phys) { + out_le32(&pb->planb_base->ch1.cmdptr, + virt_to_bus(pb->overlay_last1)); + planb_dbdma_restart(&pb->planb_base->ch1); + } + } + pb->last_fr = pb->prev_last_fr; + pb->prev_last_fr = -999; + } + return; +} + +static void suspend_overlay(struct planb *pb) +{ + int fr = -1; + struct dbdma_cmd last; + + DEBUG("PlanB: suspend_overlay: %d\n", pb->suspend); + + if(pb->suspend++) + return; + if(ACTIVE & in_le32(&pb->planb_base->ch1.status)) { + if(pb->last_fr == -2) { + fr = pb->prev_last_fr; + memcpy(&last, (void*)pb->last_cmd[fr], sizeof(last)); + tab_cmd_dbdma(pb->last_cmd[fr], DBDMA_STOP, 0); + } + if(overlay_is_active(pb)) { + planb_dbdma_stop(&pb->planb_base->ch2); + planb_dbdma_stop(&pb->planb_base->ch1); + pb->suspended.overlay = 1; + pb->suspended.frame = fr; + memcpy(&pb->suspended.cmd, &last, sizeof(last)); + return; + } + } + pb->suspended.overlay = 0; + pb->suspended.frame = fr; + memcpy(&pb->suspended.cmd, &last, sizeof(last)); + return; +} + +static void resume_overlay(struct planb *pb) +{ + + DEBUG("PlanB: resume_overlay: %d\n", pb->suspend); + + if(pb->suspend > 1) + return; + if(pb->suspended.frame != -1) { + memcpy((void*)pb->last_cmd[pb->suspended.frame], + &pb->suspended.cmd, sizeof(pb->suspended.cmd)); + } + if(ACTIVE & in_le32(&pb->planb_base->ch1.status)) { + goto finish; + } + if(pb->suspended.overlay) { + + DEBUG("PlanB: overlay being resumed\n"); + + st_le16 (&pb->ch1_cmd->command, DBDMA_NOP); + st_le16 (&pb->ch2_cmd->command, DBDMA_NOP); + /* Set command buffer addresses */ + st_le32(&pb->planb_base->ch1.cmdptr, + virt_to_bus(pb->overlay_last1)); + out_le32(&pb->planb_base->ch2.cmdptr, + virt_to_bus(pb->overlay_last2)); + /* Start the DMA controller */ + out_le32 (&pb->planb_base->ch2.control, + PLANB_CLR(PAUSE) | PLANB_SET(RUN|WAKE)); + out_le32 (&pb->planb_base->ch1.control, + PLANB_CLR(PAUSE) | PLANB_SET(RUN|WAKE)); + } else if(pb->suspended.frame != -1) { + out_le32(&pb->planb_base->ch1.cmdptr, + virt_to_bus(pb->last_cmd[pb->suspended.frame])); + out_le32 (&pb->planb_base->ch1.control, + PLANB_CLR(PAUSE) | PLANB_SET(RUN|WAKE)); + } + +finish: + pb->suspend--; + wake_up_interruptible(&pb->suspendq); +} + +static void add_clip(struct planb *pb, struct video_clip *clip) +{ + volatile unsigned char *base; + int xc = clip->x, yc = clip->y; + int wc = clip->width, hc = clip->height; + int ww = pb->win.width, hw = pb->win.height; + int x, y, xtmp1, xtmp2; + + DEBUG("PlanB: clip %dx%d+%d+%d\n", wc, hc, xc, yc); + + if(xc < 0) { + wc += xc; + xc = 0; + } + if(yc < 0) { + hc += yc; + yc = 0; + } + if(xc + wc > ww) + wc = ww - xc; + if(wc <= 0) /* Nothing to do */ + return; + if(yc + hc > hw) + hc = hw - yc; + + for (y = yc; y < yc+hc; y++) { + xtmp1=xc>>3; + xtmp2=(xc+wc)>>3; + base = pb->mask + y*96; + if(xc != 0 || wc >= 8) + *(base + xtmp1) &= (unsigned char)(0x00ff & + (0xff00 >> (xc&7))); + for (x = xtmp1 + 1; x < xtmp2; x++) { + *(base + x) = 0; + } + if(xc < (ww & ~0x7)) + *(base + xtmp2) &= (unsigned char)(0x00ff >> + ((xc+wc) & 7)); + } + + return; +} + +static void fill_cmd_buff(struct planb *pb) +{ + int restore = 0; + volatile struct dbdma_cmd last; + + DEBUG("PlanB: fill_cmd_buff()\n"); + + if(pb->overlay_last1 != pb->ch1_cmd) { + restore = 1; + last = *(pb->overlay_last1); + } + memset ((void *) pb->ch1_cmd, 0, 2 * pb->tab_size + * sizeof(struct dbdma_cmd)); + cmd_buff (pb); + if(restore) + *(pb->overlay_last1) = last; + if(pb->suspended.overlay) { + unsigned long jump_addr = in_le32(&pb->overlay_last1->cmd_dep); + if(jump_addr != pb->ch1_cmd_phys) { + int i; + + DEBUG("PlanB: adjusting ch1's jump address\n"); + + for(i = 0; i < MAX_GBUFFERS; i++) { + if(pb->need_pre_capture[i]) { + if(jump_addr == virt_to_bus(pb->pre_cmd[i])) + goto found; + } else { + if(jump_addr == virt_to_bus(pb->cap_cmd[i])) + goto found; + } + } + + DEBUG("PlanB: not found...\n"); + + goto out; +found: + if(pb->need_pre_capture[i]) + out_le32(&pb->pre_cmd[i]->phy_addr, + virt_to_bus(pb->overlay_last1)); + else + out_le32(&pb->cap_cmd[i]->phy_addr, + virt_to_bus(pb->overlay_last1)); + } + } +out: + pb->cmd_buff_inited = 1; + + return; +} + +static void cmd_buff(struct planb *pb) +{ + int i, bpp, count, nlines, stepsize, interlace; + unsigned long base, jump, addr_com, addr_dep; + volatile struct dbdma_cmd *c1 = pb->ch1_cmd; + volatile struct dbdma_cmd *c2 = pb->ch2_cmd; + + interlace = pb->win.interlace; + bpp = pb->win.bpp; + count = (bpp * ((pb->win.x + pb->win.width > pb->win.swidth) ? + (pb->win.swidth - pb->win.x) : pb->win.width)); + nlines = ((pb->win.y + pb->win.height > pb->win.sheight) ? + (pb->win.sheight - pb->win.y) : pb->win.height); + + /* Do video in: */ + + /* Preamble commands: */ + addr_com = virt_to_bus(c1); + addr_dep = virt_to_bus(&c1->cmd_dep); + tab_cmd_dbdma(c1++, DBDMA_NOP, 0); + jump = virt_to_bus(c1+16); /* 14 by cmd_geo_setup() and 2 for padding */ + if((c1 = cmd_geo_setup(c1, pb->win.width, pb->win.height, interlace, + bpp, 1, pb)) == NULL) { + printk(KERN_WARNING "PlanB: encountered serious problems\n"); + tab_cmd_dbdma(pb->ch1_cmd + 1, DBDMA_STOP, 0); + tab_cmd_dbdma(pb->ch2_cmd + 1, DBDMA_STOP, 0); + return; + } + tab_cmd_store(c1++, addr_com, (unsigned)(DBDMA_NOP | BR_ALWAYS) << 16); + tab_cmd_store(c1++, addr_dep, jump); + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.wait_sel), + PLANB_SET(FIELD_SYNC)); + /* (1) wait for field sync to be set */ + tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0); + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel), + PLANB_SET(ODD_FIELD)); + /* wait for field sync to be cleared */ + tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0); + /* if not odd field, wait until field sync is set again */ + tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFSET, virt_to_bus(c1-3)); c1++; + /* assert ch_sync to ch2 */ + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch2.control), + PLANB_SET(CH_SYNC)); + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel), + PLANB_SET(DMA_ABORT)); + + base = (pb->frame_buffer_phys + pb->offset + pb->win.y * (pb->win.bpl + + pb->win.pad) + pb->win.x * bpp); + + if (interlace) { + stepsize = 2; + jump = virt_to_bus(c1 + (nlines + 1) / 2); + } else { + stepsize = 1; + jump = virt_to_bus(c1 + nlines); + } + + /* even field data: */ + for (i=0; i < nlines; i += stepsize, c1++) + tab_cmd_gen(c1, INPUT_MORE | KEY_STREAM0 | BR_IFSET, + count, base + i * (pb->win.bpl + pb->win.pad), jump); + + /* For non-interlaced, we use even fields only */ + if (!interlace) + goto cmd_tab_data_end; + + /* Resync to odd field */ + /* (2) wait for field sync to be set */ + tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0); + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel), + PLANB_SET(ODD_FIELD)); + /* wait for field sync to be cleared */ + tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0); + /* if not odd field, wait until field sync is set again */ + tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFCLR, virt_to_bus(c1-3)); c1++; + /* assert ch_sync to ch2 */ + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch2.control), + PLANB_SET(CH_SYNC)); + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel), + PLANB_SET(DMA_ABORT)); + + /* odd field data: */ + jump = virt_to_bus(c1 + nlines / 2); + for (i=1; i < nlines; i += stepsize, c1++) + tab_cmd_gen(c1, INPUT_MORE | KEY_STREAM0 | BR_IFSET, count, + base + i * (pb->win.bpl + pb->win.pad), jump); + + /* And jump back to the start */ +cmd_tab_data_end: + pb->overlay_last1 = c1; /* keep a pointer to the last command */ + tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, virt_to_bus(pb->ch1_cmd)); + + /* Clipmask command buffer */ + + /* Preamble commands: */ + tab_cmd_dbdma(c2++, DBDMA_NOP, 0); + tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.wait_sel), + PLANB_SET(CH_SYNC)); + /* wait until ch1 asserts ch_sync */ + tab_cmd_dbdma(c2++, DBDMA_NOP | WAIT_IFCLR, 0); + /* clear ch_sync asserted by ch1 */ + tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.control), + PLANB_CLR(CH_SYNC)); + tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.wait_sel), + PLANB_SET(FIELD_SYNC)); + tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.br_sel), + PLANB_SET(ODD_FIELD)); + + /* jump to end of even field if appropriate */ + /* this points to (interlace)? pos. C: pos. B */ + jump = (interlace) ? virt_to_bus(c2 + (nlines + 1) / 2 + 2): + virt_to_bus(c2 + nlines + 2); + /* if odd field, skip over to odd field clipmasking */ + tab_cmd_dbdma(c2++, DBDMA_NOP | BR_IFSET, jump); + + /* even field mask: */ + tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.br_sel), + PLANB_SET(DMA_ABORT)); + /* this points to pos. B */ + jump = (interlace) ? virt_to_bus(c2 + nlines + 1): + virt_to_bus(c2 + nlines); + base = virt_to_bus(pb->mask); + for (i=0; i < nlines; i += stepsize, c2++) + tab_cmd_gen(c2, OUTPUT_MORE | KEY_STREAM0 | BR_IFSET, 96, + base + i * 96, jump); + + /* For non-interlaced, we use only even fields */ + if(!interlace) + goto cmd_tab_mask_end; + + /* odd field mask: */ +/* C */ tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.br_sel), + PLANB_SET(DMA_ABORT)); + /* this points to pos. B */ + jump = virt_to_bus(c2 + nlines / 2); + base = virt_to_bus(pb->mask); + for (i=1; i < nlines; i += 2, c2++) /* abort if set */ + tab_cmd_gen(c2, OUTPUT_MORE | KEY_STREAM0 | BR_IFSET, 96, + base + i * 96, jump); + + /* Inform channel 1 and jump back to start */ +cmd_tab_mask_end: + /* ok, I just realized this is kind of flawed. */ + /* this part is reached only after odd field clipmasking. */ + /* wanna clean up? */ + /* wait for field sync to be set */ + /* corresponds to fsync (1) of ch1 */ +/* B */ tab_cmd_dbdma(c2++, DBDMA_NOP | WAIT_IFCLR, 0); + /* restart ch1, meant to clear any dead bit or something */ + tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch1.control), + PLANB_CLR(RUN)); + tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch1.control), + PLANB_SET(RUN)); + pb->overlay_last2 = c2; /* keep a pointer to the last command */ + /* start over even field clipmasking */ + tab_cmd_dbdma(c2, DBDMA_NOP | BR_ALWAYS, virt_to_bus(pb->ch2_cmd)); + + eieio(); + return; +} + +/*********************************/ +/* grabdisplay support functions */ +/*********************************/ + +static int palette2fmt[] = { + 0, + PLANB_GRAY, + 0, + 0, + 0, + PLANB_COLOUR32, + PLANB_COLOUR15, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, +}; +#define PLANB_PALETTE_MAX 15 + +#define SWAP4(x) (((x>>24) & 0x000000ff) |\ + ((x>>8) & 0x0000ff00) |\ + ((x<<8) & 0x00ff0000) |\ + ((x<<24) & 0xff000000)) + +static inline int overlay_is_active(struct planb *pb) +{ + unsigned int size = pb->tab_size * sizeof(struct dbdma_cmd); + unsigned int caddr = (unsigned)in_le32(&pb->planb_base->ch1.cmdptr); + + return (in_le32(&pb->overlay_last1->cmd_dep) == pb->ch1_cmd_phys) + && (caddr < (pb->ch1_cmd_phys + size)) + && (caddr >= (unsigned)pb->ch1_cmd_phys); +} + +static int vgrab(struct planb *pb, struct video_mmap *mp) +{ + unsigned int fr = mp->frame; + unsigned int format; + + if(pb->fbuffer==NULL) { + if(fbuffer_alloc(pb)) + return -ENOBUFS; + } + + IDEBUG("PlanB: grab %d: %dx%d(%u)\n", pb->grabbing, + mp->width, mp->height, fr); + + if(pb->grabbing >= MAX_GBUFFERS) + return -ENOBUFS; + if(fr > (MAX_GBUFFERS - 1) || fr < 0) + return -EINVAL; + if(mp->height <= 0 || mp->width <= 0) + return -EINVAL; + if(mp->format < 0 || mp->format >= PLANB_PALETTE_MAX) + return -EINVAL; + if((format = palette2fmt[mp->format]) == 0) + return -EINVAL; + if (mp->height * mp->width * format > PLANB_MAX_FBUF) /* format = bpp */ + return -EINVAL; + + planb_lock(pb); + pb->gbuffer[fr] = (unsigned char *)(pb->fbuffer + PLANB_MAX_FBUF * fr); + if(mp->width != pb->gwidth[fr] || mp->height != pb->gheight[fr] || + format != pb->gfmt[fr] || (pb->gnorm_switch[fr])) { +#ifdef PLANB_GSCANLINE + int i; +#else + unsigned int osize = pb->gwidth[fr] * pb->gheight[fr] + * pb->gfmt[fr]; + unsigned int nsize = mp->width * mp->height * format; +#endif + + IDEBUG("PlanB: gwidth = %d, gheight = %d, mp->format = %u\n", + mp->width, mp->height, mp->format); + +#ifndef PLANB_GSCANLINE + if(pb->gnorm_switch[fr]) + nsize = 0; + if(nsize < osize) + memset((void *)(pb->gbuffer[fr] + nsize), 0, + osize - nsize); + memset((void *)pb->l_fr_addr[fr], 0, PAGE_SIZE * pb->lnum[fr]); +#else +/* XXX TODO */ +/* + if(pb->gnorm_switch[fr]) + memset((void *)pb->gbuffer[fr], 0, + pb->gbytes_per_line * pb->gheight[fr]); + else { + if(mp-> + for(i = 0; i < pb->gheight[fr]; i++) { + memset((void *)(pb->gbuffer[fr] + + pb->gbytes_per_line * i + } + } +*/ +#endif + pb->gwidth[fr] = mp->width; + pb->gheight[fr] = mp->height; + pb->gfmt[fr] = format; + pb->last_cmd[fr] = setup_grab_cmd(fr, pb); + planb_pre_capture(fr, pb->gfmt[fr], pb); /* gfmt = bpp */ + pb->need_pre_capture[fr] = 1; + pb->gnorm_switch[fr] = 0; + } else + pb->need_pre_capture[fr] = 0; + pb->frame_stat[fr] = GBUFFER_GRABBING; + if(!(ACTIVE & in_le32(&pb->planb_base->ch1.status))) { + + IDEBUG("PlanB: ch1 inactive, initiating grabbing\n"); + + planb_dbdma_stop(&pb->planb_base->ch1); + if(pb->need_pre_capture[fr]) { + + IDEBUG("PlanB: padding pre-capture sequence\n"); + + out_le32 (&pb->planb_base->ch1.cmdptr, + virt_to_bus(pb->pre_cmd[fr])); + } else { + tab_cmd_dbdma(pb->last_cmd[fr], DBDMA_STOP, 0); + tab_cmd_dbdma(pb->cap_cmd[fr], DBDMA_NOP, 0); + /* let's be on the safe side. here is not timing critical. */ + tab_cmd_dbdma((pb->cap_cmd[fr] + 1), DBDMA_NOP, 0); + out_le32 (&pb->planb_base->ch1.cmdptr, + virt_to_bus(pb->cap_cmd[fr])); + } + planb_dbdma_restart(&pb->planb_base->ch1); + pb->last_fr = fr; + } else { + int i; + + IDEBUG("PlanB: ch1 active, grabbing being queued\n"); + + if((pb->last_fr == -1) || ((pb->last_fr == -2) && + overlay_is_active(pb))) { + + IDEBUG("PlanB: overlay is active, grabbing defered\n"); + + tab_cmd_dbdma(pb->last_cmd[fr], + DBDMA_NOP | BR_ALWAYS, + virt_to_bus(pb->ch1_cmd)); + if(pb->need_pre_capture[fr]) { + + IDEBUG("PlanB: padding pre-capture sequence\n"); + + tab_cmd_store(pb->pre_cmd[fr], + virt_to_bus(&pb->overlay_last1->cmd_dep), + virt_to_bus(pb->ch1_cmd)); + eieio(); + out_le32 (&pb->overlay_last1->cmd_dep, + virt_to_bus(pb->pre_cmd[fr])); + } else { + tab_cmd_store(pb->cap_cmd[fr], + virt_to_bus(&pb->overlay_last1->cmd_dep), + virt_to_bus(pb->ch1_cmd)); + tab_cmd_dbdma((pb->cap_cmd[fr] + 1), + DBDMA_NOP, 0); + eieio(); + out_le32 (&pb->overlay_last1->cmd_dep, + virt_to_bus(pb->cap_cmd[fr])); + } + for(i = 0; overlay_is_active(pb) && i < 999; i++) + IDEBUG("PlanB: waiting for overlay done\n"); + tab_cmd_dbdma(pb->ch1_cmd, DBDMA_NOP, 0); + pb->prev_last_fr = fr; + pb->last_fr = -2; + } else if(pb->last_fr == -2) { + + IDEBUG("PlanB: mixed mode detected, grabbing" + " will be done before activating overlay\n"); + + tab_cmd_dbdma(pb->ch1_cmd, DBDMA_NOP, 0); + if(pb->need_pre_capture[fr]) { + + IDEBUG("PlanB: padding pre-capture sequence\n"); + + tab_cmd_dbdma(pb->last_cmd[pb->prev_last_fr], + DBDMA_NOP | BR_ALWAYS, + virt_to_bus(pb->pre_cmd[fr])); + eieio(); + } else { + tab_cmd_dbdma(pb->cap_cmd[fr], DBDMA_NOP, 0); + if(pb->gwidth[pb->prev_last_fr] != + pb->gwidth[fr] + || pb->gheight[pb->prev_last_fr] != + pb->gheight[fr] + || pb->gfmt[pb->prev_last_fr] != + pb->gfmt[fr]) + tab_cmd_dbdma((pb->cap_cmd[fr] + 1), + DBDMA_NOP, 0); + else + tab_cmd_dbdma((pb->cap_cmd[fr] + 1), + DBDMA_NOP | BR_ALWAYS, + virt_to_bus(pb->cap_cmd[fr] + 16)); + tab_cmd_dbdma(pb->last_cmd[pb->prev_last_fr], + DBDMA_NOP | BR_ALWAYS, + virt_to_bus(pb->cap_cmd[fr])); + eieio(); + } + tab_cmd_dbdma(pb->last_cmd[fr], + DBDMA_NOP | BR_ALWAYS, + virt_to_bus(pb->ch1_cmd)); + eieio(); + pb->prev_last_fr = fr; + pb->last_fr = -2; + } else { + + IDEBUG("PlanB: active grabbing session detected\n"); + + if(pb->need_pre_capture[fr]) { + + IDEBUG("PlanB: padding pre-capture sequence\n"); + + tab_cmd_dbdma(pb->last_cmd[pb->last_fr], + DBDMA_NOP | BR_ALWAYS, + virt_to_bus(pb->pre_cmd[fr])); + eieio(); + } else { + tab_cmd_dbdma(pb->last_cmd[fr], DBDMA_STOP, 0); + tab_cmd_dbdma(pb->cap_cmd[fr], DBDMA_NOP, 0); + if(pb->gwidth[pb->last_fr] != pb->gwidth[fr] + || pb->gheight[pb->last_fr] != + pb->gheight[fr] + || pb->gfmt[pb->last_fr] != + pb->gfmt[fr]) + tab_cmd_dbdma((pb->cap_cmd[fr] + 1), + DBDMA_NOP, 0); + else + tab_cmd_dbdma((pb->cap_cmd[fr] + 1), + DBDMA_NOP | BR_ALWAYS, + virt_to_bus(pb->cap_cmd[fr] + 16)); + tab_cmd_dbdma(pb->last_cmd[pb->last_fr], + DBDMA_NOP | BR_ALWAYS, + virt_to_bus(pb->cap_cmd[fr])); + eieio(); + } + pb->last_fr = fr; + } + if(!(ACTIVE & in_le32(&pb->planb_base->ch1.status))) { + + IDEBUG("PlanB: became inactive in the mean time..." + "reactivating\n"); + + planb_dbdma_stop(&pb->planb_base->ch1); + out_le32 (&pb->planb_base->ch1.cmdptr, + virt_to_bus(pb->cap_cmd[fr])); + planb_dbdma_restart(&pb->planb_base->ch1); + } + } + pb->grabbing++; + planb_unlock(pb); + + return 0; +} + +static void planb_pre_capture(int fr, int bpp, struct planb *pb) +{ + volatile struct dbdma_cmd *c1 = pb->pre_cmd[fr]; + int interlace = (pb->gheight[fr] > pb->maxlines/2)? 1: 0; + + tab_cmd_dbdma(c1++, DBDMA_NOP, 0); + if((c1 = cmd_geo_setup(c1, pb->gwidth[fr], pb->gheight[fr], interlace, + bpp, 0, pb)) == NULL) { + printk(KERN_WARNING "PlanB: encountered some problems\n"); + tab_cmd_dbdma(pb->pre_cmd[fr] + 1, DBDMA_STOP, 0); + return; + } + /* Sync to even field */ + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.wait_sel), + PLANB_SET(FIELD_SYNC)); + tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0); + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel), + PLANB_SET(ODD_FIELD)); + tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0); + tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFSET, virt_to_bus(c1-3)); c1++; + tab_cmd_dbdma(c1++, DBDMA_NOP | INTR_ALWAYS, 0); + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel), + PLANB_SET(DMA_ABORT)); + /* For non-interlaced, we use even fields only */ + if (pb->gheight[fr] <= pb->maxlines/2) + goto cmd_tab_data_end; + /* Sync to odd field */ + tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0); + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel), + PLANB_SET(ODD_FIELD)); + tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0); + tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFCLR, virt_to_bus(c1-3)); c1++; + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel), + PLANB_SET(DMA_ABORT)); +cmd_tab_data_end: + tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, virt_to_bus(pb->cap_cmd[fr])); + + eieio(); +} + +static volatile struct dbdma_cmd *setup_grab_cmd(int fr, struct planb *pb) +{ + int i, bpp, count, nlines, stepsize, interlace; +#ifdef PLANB_GSCANLINE + int scanline; +#else + int nlpp, leftover1; + unsigned long base; +#endif + unsigned long jump; + unsigned char *vaddr; + volatile struct dbdma_cmd *c1; + volatile struct dbdma_cmd *jump_addr; + + c1 = pb->cap_cmd[fr]; + interlace = (pb->gheight[fr] > pb->maxlines/2)? 1: 0; + bpp = pb->gfmt[fr]; /* gfmt = bpp */ + count = bpp * pb->gwidth[fr]; + nlines = pb->gheight[fr]; +#ifdef PLANB_GSCANLINE + scanline = pb->gbytes_per_line; +#else + pb->lsize[fr] = count; + pb->lnum[fr] = 0; +#endif + + /* Do video in: */ + + /* Preamble commands: */ + tab_cmd_dbdma(c1++, DBDMA_NOP, 0); + tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, virt_to_bus(c1 + 16)); c1++; + if((c1 = cmd_geo_setup(c1, pb->gwidth[fr], pb->gheight[fr], interlace, + bpp, 0, pb)) == NULL) { + printk(KERN_WARNING "PlanB: encountered serious problems\n"); + tab_cmd_dbdma(pb->cap_cmd[fr] + 1, DBDMA_STOP, 0); + return (pb->cap_cmd[fr] + 2); + } + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.wait_sel), + PLANB_SET(FIELD_SYNC)); + tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0); + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel), + PLANB_SET(ODD_FIELD)); + tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0); + tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFSET, virt_to_bus(c1-3)); c1++; + tab_cmd_dbdma(c1++, DBDMA_NOP | INTR_ALWAYS, 0); + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel), + PLANB_SET(DMA_ABORT)); + + if (interlace) { + stepsize = 2; + jump_addr = c1 + TAB_FACTOR * (nlines + 1) / 2; + } else { + stepsize = 1; + jump_addr = c1 + TAB_FACTOR * nlines; + } + jump = virt_to_bus(jump_addr); + + /* even field data: */ + + vaddr = pb->gbuffer[fr]; +#ifdef PLANB_GSCANLINE + for (i = 0; i < nlines; i += stepsize) { + tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count, + vmalloc_to_bus(vaddr + i * scanline), jump); + } +#else + i = 0; + leftover1 = 0; + do { + int j; + + base = vmalloc_to_bus((void*)vaddr); + nlpp = (PAGE_SIZE - leftover1) / count / stepsize; + for(j = 0; j < nlpp && i < nlines; j++, i += stepsize, c1++) + tab_cmd_gen(c1, INPUT_MORE | KEY_STREAM0 | BR_IFSET, + count, base + count * j * stepsize + leftover1, jump); + if(i < nlines) { + int lov0 = PAGE_SIZE - count * nlpp * stepsize - leftover1; + + if(lov0 == 0) + leftover1 = 0; + else { + if(lov0 >= count) { + tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count, base + + count * nlpp * stepsize + leftover1, jump); + } else { + pb->l_to_addr[fr][pb->lnum[fr]] = vaddr + count * nlpp + * stepsize + leftover1; + tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count, + vmalloc_to_bus(pb->l_fr_addr[fr] + PAGE_SIZE + * pb->lnum[fr]), jump); + if(++pb->lnum[fr] > MAX_LNUM) + pb->lnum[fr]--; + } + leftover1 = count * stepsize - lov0; + i += stepsize; + } + } + vaddr += PAGE_SIZE; + } while(i < nlines); + tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, jump); + c1 = jump_addr; +#endif /* PLANB_GSCANLINE */ + + /* For non-interlaced, we use even fields only */ + if (!interlace) + goto cmd_tab_data_end; + + /* Sync to odd field */ + tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0); + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel), + PLANB_SET(ODD_FIELD)); + tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0); + tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFCLR, virt_to_bus(c1-3)); c1++; + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel), + PLANB_SET(DMA_ABORT)); + + /* odd field data: */ + jump_addr = c1 + TAB_FACTOR * nlines / 2; + jump = virt_to_bus(jump_addr); +#ifdef PLANB_GSCANLINE + for (i = 1; i < nlines; i += stepsize) { + tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count, + vmalloc_to_bus(vaddr + i * scanline), jump); + } +#else + i = 1; + leftover1 = 0; + vaddr = pb->gbuffer[fr]; + if(nlines <= 1) + goto skip; + do { + int j; + + base = vmalloc_to_bus((void*)vaddr); + nlpp = (PAGE_SIZE - leftover1) / count / stepsize; + if(leftover1 >= count) { + tab_cmd_gen(c1++, INPUT_MORE | KEY_STREAM0 | BR_IFSET, count, + base + leftover1 - count, jump); + i += stepsize; + } + for(j = 0; j < nlpp && i < nlines; j++, i += stepsize, c1++) + tab_cmd_gen(c1, INPUT_MORE | KEY_STREAM0 | BR_IFSET, count, + base + count * (j * stepsize + 1) + leftover1, jump); + if(i < nlines) { + int lov0 = PAGE_SIZE - count * nlpp * stepsize - leftover1; + + if(lov0 == 0) + leftover1 = 0; + else { + if(lov0 > count) { + pb->l_to_addr[fr][pb->lnum[fr]] = vaddr + count + * (nlpp * stepsize + 1) + leftover1; + tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count, + vmalloc_to_bus(pb->l_fr_addr[fr] + PAGE_SIZE + * pb->lnum[fr]), jump); + if(++pb->lnum[fr] > MAX_LNUM) + pb->lnum[fr]--; + i += stepsize; + } + leftover1 = count * stepsize - lov0; + } + } + vaddr += PAGE_SIZE; + } while(i < nlines); +skip: + tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, jump); + c1 = jump_addr; +#endif /* PLANB_GSCANLINE */ + +cmd_tab_data_end: + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->intr_stat), + (fr << 2) | PLANB_FRM_IRQ | PLANB_GEN_IRQ); + /* stop it */ + tab_cmd_dbdma(c1, DBDMA_STOP, 0); + + eieio(); + return c1; +} + +static void planb_irq(int irq, void *dev_id, struct pt_regs * regs) +{ + unsigned int stat, astat; + struct planb *pb = (struct planb *)dev_id; + + IDEBUG("PlanB: planb_irq()\n"); + + /* get/clear interrupt status bits */ + stat = in_le32(&pb->planb_base->intr_stat); + astat = stat & pb->intr_mask; + out_le32(&pb->planb_base->intr_stat, PLANB_IRQ_CMD_MASK + & ~astat & stat & ~PLANB_GEN_IRQ); + + if(astat & PLANB_FRM_IRQ) { + unsigned int fr = stat >> 2; +#ifndef PLANB_GSCANLINE + int i; +#endif + IDEBUG("PlanB: PLANB_FRM_IRQ\n"); + + pb->gcount++; + + IDEBUG("PlanB: grab %d: fr = %d, gcount = %d\n", + pb->grabbing, fr, pb->gcount); +#ifndef PLANB_GSCANLINE + IDEBUG("PlanB: %d * %d bytes are being copied over\n", + pb->lnum[fr], pb->lsize[fr]); + for(i = 0; i < pb->lnum[fr]; i++) + memcpy(pb->l_to_addr[fr][i], pb->l_fr_addr[fr] + + PAGE_SIZE * i, pb->lsize[fr]); +#endif + pb->frame_stat[fr] = GBUFFER_DONE; + pb->grabbing--; + wake_up_interruptible(&pb->capq); + return; + } + /* incorrect interrupts? */ + pb->intr_mask = PLANB_CLR_IRQ; + out_le32(&pb->planb_base->intr_stat, PLANB_CLR_IRQ); + printk(KERN_ERR "PlanB: IRQ lockup, cleared intrrupts" + " unconditionally\n"); +} + +/******************************* + * Device Operations functions * + *******************************/ + +static int planb_open(struct video_device *dev, int mode) +{ + struct planb *pb = (struct planb *)dev; + + if (pb->user == 0) { + int err; + if((err = planb_prepare_open(pb)) != 0) + return err; + } + pb->user++; + + DEBUG("PlanB: device opened\n"); + + MOD_INC_USE_COUNT; + return 0; +} + +static void planb_close(struct video_device *dev) +{ + struct planb *pb = (struct planb *)dev; + + if(pb->user < 1) /* ??? */ + return; + planb_lock(pb); + if (pb->user == 1) { + if (pb->overlay) { + planb_dbdma_stop(&pb->planb_base->ch2); + planb_dbdma_stop(&pb->planb_base->ch1); + pb->overlay = 0; + } + planb_prepare_close(pb); + } + pb->user--; + planb_unlock(pb); + + DEBUG("PlanB: device closed\n"); + + MOD_DEC_USE_COUNT; +} + +static long planb_read(struct video_device *v, char *buf, unsigned long count, + int nonblock) +{ + DEBUG("planb: read request\n"); + return -EINVAL; +} + +static long planb_write(struct video_device *v, const char *buf, + unsigned long count, int nonblock) +{ + DEBUG("planb: write request\n"); + return -EINVAL; +} + +static int planb_ioctl(struct video_device *dev, unsigned int cmd, void *arg) +{ + struct planb *pb=(struct planb *)dev; + + switch (cmd) + { + case VIDIOCGCAP: + { + struct video_capability b; + + DEBUG("PlanB: IOCTL VIDIOCGCAP\n"); + + strcpy (b.name, pb->video_dev.name); + b.type = VID_TYPE_OVERLAY | VID_TYPE_CLIPPING | + VID_TYPE_FRAMERAM | VID_TYPE_SCALES | + VID_TYPE_CAPTURE; + b.channels = 2; /* composite & svhs */ + b.audios = 0; + b.maxwidth = PLANB_MAXPIXELS; + b.maxheight = PLANB_MAXLINES; + b.minwidth = 32; /* wild guess */ + b.minheight = 32; + if (copy_to_user(arg,&b,sizeof(b))) + return -EFAULT; + return 0; + } + case VIDIOCSFBUF: + { + struct video_buffer v; + unsigned short bpp; + unsigned int fmt; + + DEBUG("PlanB: IOCTL VIDIOCSFBUF\n"); + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (copy_from_user(&v, arg,sizeof(v))) + return -EFAULT; + planb_lock(pb); + switch(v.depth) { + case 8: + bpp = 1; + fmt = PLANB_GRAY; + break; + case 15: + case 16: + bpp = 2; + fmt = PLANB_COLOUR15; + break; + case 24: + case 32: + bpp = 4; + fmt = PLANB_COLOUR32; + break; + default: + planb_unlock(pb); + return -EINVAL; + } + if (bpp * v.width > v.bytesperline) { + planb_unlock(pb); + return -EINVAL; + } + pb->win.bpp = bpp; + pb->win.color_fmt = fmt; + pb->frame_buffer_phys = (unsigned long) v.base; + pb->win.sheight = v.height; + pb->win.swidth = v.width; + pb->picture.depth = pb->win.depth = v.depth; + pb->win.bpl = pb->win.bpp * pb->win.swidth; + pb->win.pad = v.bytesperline - pb->win.bpl; + + DEBUG("PlanB: Display at %p is %d by %d, bytedepth %d," + " bpl %d (+ %d)\n", v.base, v.width,v.height, + pb->win.bpp, pb->win.bpl, pb->win.pad); + + pb->cmd_buff_inited = 0; + if(pb->overlay) { + suspend_overlay(pb); + fill_cmd_buff(pb); + resume_overlay(pb); + } + planb_unlock(pb); + return 0; + } + case VIDIOCGFBUF: + { + struct video_buffer v; + + DEBUG("PlanB: IOCTL VIDIOCGFBUF\n"); + + v.base = (void *)pb->frame_buffer_phys; + v.height = pb->win.sheight; + v.width = pb->win.swidth; + v.depth = pb->win.depth; + v.bytesperline = pb->win.bpl + pb->win.pad; + if (copy_to_user(arg, &v, sizeof(v))) + return -EFAULT; + return 0; + } + case VIDIOCCAPTURE: + { + int i; + + if(copy_from_user(&i, arg, sizeof(i))) + return -EFAULT; + if(i==0) { + DEBUG("PlanB: IOCTL VIDIOCCAPTURE Stop\n"); + + if (!(pb->overlay)) + return 0; + planb_lock(pb); + pb->overlay = 0; + overlay_stop(pb); + planb_unlock(pb); + } else { + DEBUG("PlanB: IOCTL VIDIOCCAPTURE Start\n"); + + if (pb->frame_buffer_phys == 0 || + pb->win.width == 0 || + pb->win.height == 0) + return -EINVAL; + if (pb->overlay) + return 0; + planb_lock(pb); + pb->overlay = 1; + if(!(pb->cmd_buff_inited)) + fill_cmd_buff(pb); + overlay_start(pb); + planb_unlock(pb); + } + return 0; + } + case VIDIOCGCHAN: + { + struct video_channel v; + + DEBUG("PlanB: IOCTL VIDIOCGCHAN\n"); + + if(copy_from_user(&v, arg,sizeof(v))) + return -EFAULT; + v.flags = 0; + v.tuners = 0; + v.type = VIDEO_TYPE_CAMERA; + v.norm = pb->win.norm; + switch(v.channel) + { + case 0: + strcpy(v.name,"Composite"); + break; + case 1: + strcpy(v.name,"SVHS"); + break; + default: + return -EINVAL; + break; + } + if(copy_to_user(arg,&v,sizeof(v))) + return -EFAULT; + + return 0; + } + case VIDIOCSCHAN: + { + struct video_channel v; + + DEBUG("PlanB: IOCTL VIDIOCSCHAN\n"); + + if(copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + + if (v.norm != pb->win.norm) { + int i, maxlines; + + switch (v.norm) + { + case VIDEO_MODE_PAL: + case VIDEO_MODE_SECAM: + maxlines = PLANB_MAXLINES; + break; + case VIDEO_MODE_NTSC: + maxlines = PLANB_NTSC_MAXLINES; + break; + default: + return -EINVAL; + break; + } + planb_lock(pb); + /* empty the grabbing queue */ + while(pb->grabbing) + interruptible_sleep_on(&pb->capq); + pb->maxlines = maxlines; + pb->win.norm = v.norm; + /* Stop overlay if running */ + suspend_overlay(pb); + for(i = 0; i < MAX_GBUFFERS; i++) + pb->gnorm_switch[i] = 1; + /* I know it's an overkill, but.... */ + fill_cmd_buff(pb); + /* ok, now init it accordingly */ + saa_init_regs (pb); + /* restart overlay if it was running */ + resume_overlay(pb); + planb_unlock(pb); + } + + switch(v.channel) + { + case 0: /* Composite */ + saa_set (SAA7196_IOCC, + ((saa_regs[pb->win.norm][SAA7196_IOCC] & + ~7) | 3), pb); + break; + case 1: /* SVHS */ + saa_set (SAA7196_IOCC, + ((saa_regs[pb->win.norm][SAA7196_IOCC] & + ~7) | 4), pb); + break; + default: + return -EINVAL; + break; + } + + return 0; + } + case VIDIOCGPICT: + { + struct video_picture vp = pb->picture; + + DEBUG("PlanB: IOCTL VIDIOCGPICT\n"); + + switch(pb->win.color_fmt) { + case PLANB_GRAY: + vp.palette = VIDEO_PALETTE_GREY; + case PLANB_COLOUR15: + vp.palette = VIDEO_PALETTE_RGB555; + break; + case PLANB_COLOUR32: + vp.palette = VIDEO_PALETTE_RGB32; + break; + default: + vp.palette = 0; + break; + } + + if(copy_to_user(arg,&vp,sizeof(vp))) + return -EFAULT; + return 0; + } + case VIDIOCSPICT: + { + struct video_picture vp; + + DEBUG("PlanB: IOCTL VIDIOCSPICT\n"); + + if(copy_from_user(&vp,arg,sizeof(vp))) + return -EFAULT; + pb->picture = vp; + /* Should we do sanity checks here? */ + saa_set (SAA7196_BRIG, (unsigned char) + ((pb->picture.brightness) >> 8), pb); + saa_set (SAA7196_HUEC, (unsigned char) + ((pb->picture.hue) >> 8) ^ 0x80, pb); + saa_set (SAA7196_CSAT, (unsigned char) + ((pb->picture.colour) >> 9), pb); + saa_set (SAA7196_CONT, (unsigned char) + ((pb->picture.contrast) >> 9), pb); + + return 0; + } + case VIDIOCSWIN: + { + struct video_window vw; + struct video_clip clip; + int i; + + DEBUG("PlanB: IOCTL VIDIOCSWIN\n"); + + if(copy_from_user(&vw,arg,sizeof(vw))) + return -EFAULT; + + planb_lock(pb); + /* Stop overlay if running */ + suspend_overlay(pb); + pb->win.interlace = (vw.height > pb->maxlines/2)? 1: 0; + if (pb->win.x != vw.x || + pb->win.y != vw.y || + pb->win.width != vw.width || + pb->win.height != vw.height || + !pb->cmd_buff_inited) { + pb->win.x = vw.x; + pb->win.y = vw.y; + pb->win.width = vw.width; + pb->win.height = vw.height; + fill_cmd_buff(pb); + } + /* Reset clip mask */ + memset ((void *) pb->mask, 0xff, (pb->maxlines + * ((PLANB_MAXPIXELS + 7) & ~7)) / 8); + /* Add any clip rects */ + for (i = 0; i < vw.clipcount; i++) { + if (copy_from_user(&clip, vw.clips + i, + sizeof(struct video_clip))) + return -EFAULT; + add_clip(pb, &clip); + } + /* restart overlay if it was running */ + resume_overlay(pb); + planb_unlock(pb); + return 0; + } + case VIDIOCGWIN: + { + struct video_window vw; + + DEBUG("PlanB: IOCTL VIDIOCGWIN\n"); + + vw.x=pb->win.x; + vw.y=pb->win.y; + vw.width=pb->win.width; + vw.height=pb->win.height; + vw.chromakey=0; + vw.flags=0; + if(pb->win.interlace) + vw.flags|=VIDEO_WINDOW_INTERLACE; + if(copy_to_user(arg,&vw,sizeof(vw))) + return -EFAULT; + return 0; + } + case VIDIOCSYNC: { + int i; + + IDEBUG("PlanB: IOCTL VIDIOCSYNC\n"); + + if(copy_from_user((void *)&i,arg,sizeof(int))) + return -EFAULT; + + IDEBUG("PlanB: sync to frame %d\n", i); + + if(i > (MAX_GBUFFERS - 1) || i < 0) + return -EINVAL; +chk_grab: + switch (pb->frame_stat[i]) { + case GBUFFER_UNUSED: + return -EINVAL; + case GBUFFER_GRABBING: + IDEBUG("PlanB: waiting for grab" + " done (%d)\n", i); + interruptible_sleep_on(&pb->capq); + goto chk_grab; + case GBUFFER_DONE: + pb->frame_stat[i] = GBUFFER_UNUSED; + break; + } + return 0; + } + + case VIDIOCMCAPTURE: + { + struct video_mmap vm; + volatile unsigned int status; + + IDEBUG("PlanB: IOCTL VIDIOCMCAPTURE\n"); + + if(copy_from_user((void *) &vm,(void *)arg,sizeof(vm))) + return -EFAULT; + status = pb->frame_stat[vm.frame]; + if (status != GBUFFER_UNUSED) + return -EBUSY; + + return vgrab(pb, &vm); + } + + case VIDIOCGMBUF: + { + int i; + struct video_mbuf vm; + + DEBUG("PlanB: IOCTL VIDIOCGMBUF\n"); + + memset(&vm, 0 , sizeof(vm)); + vm.size = PLANB_MAX_FBUF * MAX_GBUFFERS; + vm.frames = MAX_GBUFFERS; + for(i = 0; i= SAA7196_NUMREGS) + return -EINVAL; + preg.val = saa_regs[pb->win.norm][preg.addr]; + if(copy_to_user((void *)arg, (void *)&preg, + sizeof(preg))) + return -EFAULT; + return 0; + } + + case PLANBIOCSSAAREGS: + { + struct planb_saa_regs preg; + + DEBUG("PlanB: IOCTL PLANBIOCSSAAREGS\n"); + + if(copy_from_user(&preg, arg, sizeof(preg))) + return -EFAULT; + if(preg.addr >= SAA7196_NUMREGS) + return -EINVAL; + saa_set (preg.addr, preg.val, pb); + return 0; + } + + case PLANBIOCGSTAT: + { + struct planb_stat_regs pstat; + + DEBUG("PlanB: IOCTL PLANBIOCGSTAT\n"); + + pstat.ch1_stat = in_le32(&pb->planb_base->ch1.status); + pstat.ch2_stat = in_le32(&pb->planb_base->ch2.status); + pstat.saa_stat0 = saa_status(0, pb); + pstat.saa_stat1 = saa_status(1, pb); + + if(copy_to_user((void *)arg, (void *)&pstat, + sizeof(pstat))) + return -EFAULT; + return 0; + } + + case PLANBIOCSMODE: { + int v; + + DEBUG("PlanB: IOCTL PLANBIOCSMODE\n"); + + if(copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + + switch(v) + { + case PLANB_TV_MODE: + saa_set (SAA7196_STDC, + (saa_regs[pb->win.norm][SAA7196_STDC] & + 0x7f), pb); + break; + case PLANB_VTR_MODE: + saa_set (SAA7196_STDC, + (saa_regs[pb->win.norm][SAA7196_STDC] | + 0x80), pb); + break; + default: + return -EINVAL; + break; + } + pb->win.mode = v; + return 0; + } + case PLANBIOCGMODE: { + int v=pb->win.mode; + + DEBUG("PlanB: IOCTL PLANBIOCGMODE\n"); + + if(copy_to_user(arg,&v,sizeof(v))) + return -EFAULT; + return 0; + } +#ifdef PLANB_GSCANLINE + case PLANBG_GRAB_BPL: { + int v=pb->gbytes_per_line; + + DEBUG("PlanB: IOCTL PLANBG_GRAB_BPL\n"); + + if(copy_to_user(arg,&v,sizeof(v))) + return -EFAULT; + return 0; + } +#endif /* PLANB_GSCANLINE */ + case PLANB_INTR_DEBUG: { + int i; + + DEBUG("PlanB: IOCTL PLANB_INTR_DEBUG\n"); + + if(copy_from_user(&i, arg, sizeof(i))) + return -EFAULT; + + /* avoid hang ups all together */ + for (i = 0; i < MAX_GBUFFERS; i++) { + if(pb->frame_stat[i] == GBUFFER_GRABBING) { + pb->frame_stat[i] = GBUFFER_DONE; + } + } + if(pb->grabbing) + pb->grabbing--; + wake_up_interruptible(&pb->capq); + return 0; + } + case PLANB_INV_REGS: { + int i; + struct planb_any_regs any; + + DEBUG("PlanB: IOCTL PLANB_INV_REGS\n"); + + if(copy_from_user(&any, arg, sizeof(any))) + return -EFAULT; + if(any.offset < 0 || any.offset + any.bytes > 0x400) + return -EINVAL; + if(any.bytes > 128) + return -EINVAL; + for (i = 0; i < any.bytes; i++) { + any.data[i] = + in_8((unsigned char *)pb->planb_base + + any.offset + i); + } + if(copy_to_user(arg,&any,sizeof(any))) + return -EFAULT; + return 0; + } + default: + { + DEBUG("PlanB: Unimplemented IOCTL\n"); + return -ENOIOCTLCMD; + } + /* Some IOCTLs are currently unsupported on PlanB */ + case VIDIOCGTUNER: { + DEBUG("PlanB: IOCTL VIDIOCGTUNER\n"); + goto unimplemented; } + case VIDIOCSTUNER: { + DEBUG("PlanB: IOCTL VIDIOCSTUNER\n"); + goto unimplemented; } + case VIDIOCSFREQ: { + DEBUG("PlanB: IOCTL VIDIOCSFREQ\n"); + goto unimplemented; } + case VIDIOCGFREQ: { + DEBUG("PlanB: IOCTL VIDIOCGFREQ\n"); + goto unimplemented; } + case VIDIOCKEY: { + DEBUG("PlanB: IOCTL VIDIOCKEY\n"); + goto unimplemented; } + case VIDIOCSAUDIO: { + DEBUG("PlanB: IOCTL VIDIOCSAUDIO\n"); + goto unimplemented; } + case VIDIOCGAUDIO: { + DEBUG("PlanB: IOCTL VIDIOCGAUDIO\n"); + goto unimplemented; } +unimplemented: + DEBUG(" Unimplemented\n"); + return -ENOIOCTLCMD; + } + return 0; +} + +/* + * This maps the vmalloced and reserved fbuffer to user space. + * + * FIXME: + * - PAGE_READONLY should suffice!? + * - remap_page_range is kind of inefficient for page by page remapping. + * But e.g. pte_alloc() does not work in modules ... :-( + */ + +static int planb_mmap(struct video_device *dev, const char *adr, unsigned long size) +{ + struct planb *pb=(struct planb *)dev; + unsigned long start=(unsigned long) adr; + unsigned long page; + void *pos; + + if (size>MAX_GBUFFERS*PLANB_MAX_FBUF) + return -EINVAL; + if (!pb->fbuffer) + { + if(fbuffer_alloc(pb)) + return -EINVAL; + } + pos = (void *)pb->fbuffer; + while (size > 0) + { + page = vmalloc_to_phys(pos); + if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) + return -EAGAIN; + start+=PAGE_SIZE; + pos+=PAGE_SIZE; + size-=PAGE_SIZE; + } + return 0; +} + +/* This gets called upon device registration */ +/* we could do some init here */ +static int planb_init_done(struct video_device *dev) +{ + return 0; +} + +static struct video_device planb_template= +{ + PLANB_DEVICE_NAME, + VID_TYPE_OVERLAY, + VID_HARDWARE_PLANB, + planb_open, + planb_close, + planb_read, + planb_write, +#if LINUX_VERSION_CODE >= 0x020100 + NULL, /* poll */ +#endif + planb_ioctl, + planb_mmap, /* mmap? */ + planb_init_done, + NULL, /* pointer to private data */ + 0, + 0 +}; + +static int init_planb(struct planb *pb) +{ + unsigned char saa_rev; + int i, result; + + memset ((void *) &pb->win, 0, sizeof (struct planb_window)); + /* Simple sanity check */ + if(def_norm >= NUM_SUPPORTED_NORM || def_norm < 0) { + printk(KERN_ERR "PlanB: Option(s) invalid\n"); + return -2; + } + pb->win.norm = def_norm; + pb->win.mode = PLANB_TV_MODE; /* TV mode */ + pb->win.interlace=1; + pb->win.x=0; + pb->win.y=0; + pb->win.width=768; /* 640 */ + pb->win.height=576; /* 480 */ + pb->maxlines=576; +#if 0 + btv->win.cropwidth=768; /* 640 */ + btv->win.cropheight=576; /* 480 */ + btv->win.cropx=0; + btv->win.cropy=0; +#endif + pb->win.pad=0; + pb->win.bpp=4; + pb->win.depth=32; + pb->win.color_fmt=PLANB_COLOUR32; + pb->win.bpl=1024*pb->win.bpp; + pb->win.swidth=1024; + pb->win.sheight=768; +#ifdef PLANB_GSCANLINE + if((pb->gbytes_per_line = PLANB_MAXPIXELS * 4) > PAGE_SIZE + || (pb->gbytes_per_line <= 0)) + return -3; + else { + /* page align pb->gbytes_per_line for DMA purpose */ + for(i = PAGE_SIZE; pb->gbytes_per_line < (i>>1);) + i>>=1; + pb->gbytes_per_line = i; + } +#endif + pb->tab_size = PLANB_MAXLINES + 40; + pb->suspend = 0; + pb->lock = 0; + pb->lockq = NULL; + pb->ch1_cmd = 0; + pb->ch2_cmd = 0; + pb->mask = 0; + pb->priv_space = 0; + pb->offset = 0; + pb->user = 0; + pb->overlay = 0; + pb->suspendq = NULL; + pb->cmd_buff_inited = 0; + pb->frame_buffer_phys = 0; + + /* Reset DMA controllers */ + planb_dbdma_stop(&pb->planb_base->ch2); + planb_dbdma_stop(&pb->planb_base->ch1); + + saa_rev = (saa_status(0, pb) & 0xf0) >> 4; + printk(KERN_INFO "PlanB: SAA7196 video processor rev. %d\n", saa_rev); + /* Initialize the SAA registers in memory and on chip */ + saa_init_regs (pb); + + /* clear interrupt mask */ + pb->intr_mask = PLANB_CLR_IRQ; + + result = request_irq(pb->irq, planb_irq, 0, "PlanB", (void *)pb); + if (result==-EINVAL) { + printk(KERN_ERR "PlanB: Bad irq number (%d) or handler\n", + (int)pb->irq); + return result; + } + if (result==-EBUSY) { + printk(KERN_ERR "PlanB: I don't know why, but IRQ %d busy\n", + (int)pb->irq); + return result; + } + if (result < 0) + return result; + + /* Now add the template and register the device unit. */ + memcpy(&pb->video_dev,&planb_template,sizeof(planb_template)); + + pb->picture.brightness=0x90<<8; + pb->picture.contrast = 0x70 << 8; + pb->picture.colour = 0x70<<8; + pb->picture.hue = 0x8000; + pb->picture.whiteness = 0; + pb->picture.depth = pb->win.depth; + + pb->frame_stat=NULL; + pb->capq=NULL; + for(i=0; igbuffer[i]=NULL; + pb->gwidth[i]=0; + pb->gheight[i]=0; + pb->gfmt[i]=0; + pb->cap_cmd[i]=NULL; +#ifndef PLANB_GSCANLINE + pb->l_fr_addr[i]=NULL; + pb->lsize[i] = 0; + pb->lnum[i] = 0; +#endif + } + pb->fbuffer=NULL; + pb->grabbing=0; + + /* clear interrupts */ + out_le32(&pb->planb_base->intr_stat, PLANB_CLR_IRQ); + /* set interrupt mask */ + pb->intr_mask = PLANB_FRM_IRQ; + + if(video_register_device(&pb->video_dev, VFL_TYPE_GRABBER)<0) + return -1; + + return 0; +} + +/* + * Scan for a PlanB controller, request the irq and map the io memory + */ + +static int find_planb(void) +{ + struct planb *pb; + struct device_node *planb_devices; + unsigned char dev_fn, confreg, bus; + unsigned int old_base, new_base; + unsigned int irq; + + if (_machine != _MACH_Pmac) + return 0; + + planb_devices = find_devices("planb"); + if (planb_devices == 0) { + planb_num=0; + printk(KERN_WARNING "PlanB: no device found!\n"); + return planb_num; + } + + if (planb_devices->next != NULL) + printk(KERN_ERR "Warning: only using first PlanB device!\n"); + pb = &planbs[0]; + planb_num = 1; + + if (planb_devices->n_addrs != 1) { + printk (KERN_WARNING "PlanB: expecting 1 address for planb " + "(got %d)", planb_devices->n_addrs); + return 0; + } + + if (planb_devices->n_intrs == 0) { + printk(KERN_WARNING "PlanB: no intrs for device %s\n", + planb_devices->full_name); + return 0; + } else { + irq = planb_devices->intrs[0].line; + } + + /* Initialize PlanB's PCI registers */ + + /* There is a bug with the way OF assigns addresses + to the devices behind the chaos bridge. + control needs only 0x1000 of space, but decodes only + the upper 16 bits. It therefore occupies a full 64K. + OF assigns the planb controller memory within this space; + so we need to change that here in order to access planb. */ + + /* We remap to 0xf1000000 in hope that nobody uses it ! */ + + bus = (planb_devices->addrs[0].space >> 16) & 0xff; + dev_fn = (planb_devices->addrs[0].space >> 8) & 0xff; + confreg = planb_devices->addrs[0].space & 0xff; + old_base = planb_devices->addrs[0].address; + new_base = 0xf1000000; + + DEBUG("PlanB: Found on bus %d, dev %d, func %d, " + "membase 0x%x (base reg. 0x%x)\n", + bus, PCI_SLOT(dev_fn), PCI_FUNC(dev_fn), old_base, confreg); + + /* Enable response in memory space, bus mastering, + use memory write and invalidate */ + pcibios_write_config_word (bus, dev_fn, PCI_COMMAND, + PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | + PCI_COMMAND_INVALIDATE); + /* Set PCI Cache line size & latency timer */ + pcibios_write_config_byte (bus, dev_fn, PCI_CACHE_LINE_SIZE, 0x8); + pcibios_write_config_byte (bus, dev_fn, PCI_LATENCY_TIMER, 0x40); + + /* Set the new base address */ + pcibios_write_config_dword (bus, dev_fn, confreg, new_base); + + planb_regs = (volatile struct planb_registers *) + ioremap (new_base, 0x400); + pb->planb_base = planb_regs; + pb->planb_base_phys = (struct planb_registers *)new_base; + pb->irq = irq; + + return planb_num; +} + +static void release_planb(void) +{ + int i; + struct planb *pb; + + for (i=0;iplanb_base->ch2); + planb_dbdma_stop(&pb->planb_base->ch1); + + /* clear and free interrupts */ + pb->intr_mask = PLANB_CLR_IRQ; + out_le32 (&pb->planb_base->intr_stat, PLANB_CLR_IRQ); + free_irq(pb->irq, pb); + + /* make sure all allocated memory are freed */ + planb_prepare_close(pb); + + printk(KERN_INFO "PlanB: unregistering with v4l\n"); + video_unregister_device(&pb->video_dev); + + /* note that iounmap() does nothing on the PPC right now */ + iounmap ((void *)pb->planb_base); + } +} + +#ifdef MODULE + +int init_module(void) +{ +#else +__initfunc(int init_planbs(struct video_init *unused)) +{ +#endif + int i; + + if (find_planb()<=0) + return -EIO; + + for (i=0; i +#include "saa7196.h" +#endif /* __KERNEL__ */ + +#define PLANB_DEVICE_NAME "Apple PlanB Video-In" +#define PLANB_REV "1.0" + +#ifdef __KERNEL__ +//#define PLANB_GSCANLINE /* use this if apps have the notion of */ + /* grab buffer scanline */ +/* This should be safe for both PAL and NTSC */ +#define PLANB_MAXPIXELS 768 +#define PLANB_MAXLINES 576 +#define PLANB_NTSC_MAXLINES 480 + +/* Uncomment your preferred norm ;-) */ +#define PLANB_DEF_NORM VIDEO_MODE_PAL +//#define PLANB_DEF_NORM VIDEO_MODE_NTSC +//#define PLANB_DEF_NORM VIDEO_MODE_SECAM + +/* fields settings */ +#define PLANB_GRAY 0x1 /* 8-bit mono? */ +#define PLANB_COLOUR15 0x2 /* 16-bit mode */ +#define PLANB_COLOUR32 0x4 /* 32-bit mode */ +#define PLANB_CLIPMASK 0x8 /* hardware clipmasking */ + +/* misc. flags for PlanB DMA operation */ +#define CH_SYNC 0x1 /* synchronize channels (set by ch1; + cleared by ch2) */ +#define FIELD_SYNC 0x2 /* used for the start of each field + (0 -> 1 -> 0 for ch1; 0 -> 1 for ch2) */ +#define EVEN_FIELD 0x0 /* even field is detected if unset */ +#define DMA_ABORT 0x2 /* error or just out of sync if set */ +#define ODD_FIELD 0x4 /* odd field is detected if set */ + +/* for capture operations */ +#define MAX_GBUFFERS 2 +#ifdef PLANB_GSCANLINE +#define PLANB_MAX_FBUF 0x240000 /* 576 * 1024 * 4 */ +#define TAB_FACTOR (1) +#else +#define PLANB_MAX_FBUF 0x1b0000 /* 576 * 768 * 4 */ +#define TAB_FACTOR (2) +#endif +#endif /* __KERNEL__ */ + +struct planb_saa_regs { + unsigned char addr; + unsigned char val; +}; + +struct planb_stat_regs { + unsigned int ch1_stat; + unsigned int ch2_stat; + unsigned char saa_stat0; + unsigned char saa_stat1; +}; + +struct planb_any_regs { + unsigned int offset; + unsigned int bytes; + unsigned char data[128]; +}; + +/* planb private ioctls */ +#define PLANBIOCGSAAREGS _IOWR('v', BASE_VIDIOCPRIVATE, struct planb_saa_regs) /* Read a saa7196 reg value */ +#define PLANBIOCSSAAREGS _IOW('v', BASE_VIDIOCPRIVATE + 1, struct planb_saa_regs) /* Set a saa7196 reg value */ +#define PLANBIOCGSTAT _IOR('v', BASE_VIDIOCPRIVATE + 2, struct planb_stat_regs) /* Read planb status */ +#define PLANB_TV_MODE 1 +#define PLANB_VTR_MODE 2 +#define PLANBIOCGMODE _IOR('v', BASE_VIDIOCPRIVATE + 3, int) /* Get TV/VTR mode */ +#define PLANBIOCSMODE _IOW('v', BASE_VIDIOCPRIVATE + 4, int) /* Set TV/VTR mode */ + +#ifdef PLANB_GSCANLINE +#define PLANBG_GRAB_BPL _IOR('v', BASE_VIDIOCPRIVATE + 5, int) /* # of bytes per scanline in grab buffer */ +#endif + +/* call wake_up_interruptible() with appropriate actions */ +#define PLANB_INTR_DEBUG _IOW('v', BASE_VIDIOCPRIVATE + 20, int) +/* investigate which reg does what */ +#define PLANB_INV_REGS _IOWR('v', BASE_VIDIOCPRIVATE + 21, struct planb_any_regs) + +#ifdef __KERNEL__ + +/* Potentially useful macros */ +#define PLANB_SET(x) ((x) << 16 | (x)) +#define PLANB_CLR(x) ((x) << 16) + +/* This represents the physical register layout */ +struct planb_registers { + volatile struct dbdma_regs ch1; /* 0x00: video in */ + volatile unsigned int even; /* 0x40: even field setting */ + volatile unsigned int odd; /* 0x44; odd field setting */ + unsigned int pad1[14]; /* empty? */ + volatile struct dbdma_regs ch2; /* 0x80: clipmask out */ + unsigned int pad2[16]; /* 0xc0: empty? */ + volatile unsigned int reg3; /* 0x100: ???? */ + volatile unsigned int intr_stat; /* 0x104: irq status */ +#define PLANB_CLR_IRQ 0x00 /* clear Plan B interrupt */ +#define PLANB_GEN_IRQ 0x01 /* assert Plan B interrupt */ +#define PLANB_FRM_IRQ 0x02 /* end of frame */ +#define PLANB_IRQ_CMD_MASK 0x00000003U /* reserve 2 lsbs for command */ + unsigned int pad3[1]; /* empty? */ + volatile unsigned int reg5; /* 0x10c: ??? */ + unsigned int pad4[60]; /* empty? */ + volatile unsigned char saa_addr; /* 0x200: SAA subadr */ + char pad5[3]; + volatile unsigned char saa_regval; /* SAA7196 write reg. val */ + char pad6[3]; + volatile unsigned char saa_status; /* SAA7196 status byte */ + /* There is more unused stuff here */ +}; + +struct planb_window { + int x, y; + ushort width, height; + ushort bpp, bpl, depth, pad; + ushort swidth, sheight; + int norm; + int interlace; + u32 color_fmt; + int chromakey; + int mode; /* used to switch between TV/VTR modes */ +}; + +struct planb_suspend { + int overlay; + int frame; + struct dbdma_cmd cmd; +}; + +struct planb { + struct video_device video_dev; + struct video_picture picture; /* Current picture params */ + struct video_audio audio_dev; /* Current audio params */ + + volatile struct planb_registers *planb_base; /* virt base of planb */ + struct planb_registers *planb_base_phys; /* phys base of planb */ + void *priv_space; /* Org. alloc. mem for kfree */ + int user; + unsigned int tab_size; + int maxlines; + int lock; + struct wait_queue *lockq; + unsigned int irq; /* interrupt number */ + volatile unsigned int intr_mask; + + int overlay; /* overlay running? */ + struct planb_window win; + unsigned long frame_buffer_phys; /* We need phys for DMA */ + int offset; /* offset of pixel 1 */ + volatile struct dbdma_cmd *ch1_cmd; /* Video In DMA cmd buffer */ + volatile struct dbdma_cmd *ch2_cmd; /* Clip Out DMA cmd buffer */ + volatile struct dbdma_cmd *overlay_last1; + volatile struct dbdma_cmd *overlay_last2; + unsigned long ch1_cmd_phys; + volatile unsigned char *mask; /* Clipmask buffer */ + int suspend; + struct wait_queue *suspendq; + struct planb_suspend suspended; + int cmd_buff_inited; /* cmd buffer inited? */ + + int grabbing; + unsigned int gcount; + struct wait_queue *capq; + int last_fr; + int prev_last_fr; + unsigned char *fbuffer; + unsigned char *gbuffer[MAX_GBUFFERS]; + volatile struct dbdma_cmd *cap_cmd[MAX_GBUFFERS]; + volatile struct dbdma_cmd *last_cmd[MAX_GBUFFERS]; + volatile struct dbdma_cmd *pre_cmd[MAX_GBUFFERS]; + int need_pre_capture[MAX_GBUFFERS]; +#define PLANB_DUMMY 40 /* # of command buf's allocated for pre-capture seq. */ + int gwidth[MAX_GBUFFERS], gheight[MAX_GBUFFERS]; + unsigned int gfmt[MAX_GBUFFERS]; + int gnorm_switch[MAX_GBUFFERS]; + volatile unsigned int *frame_stat; +#define GBUFFER_UNUSED 0x00U +#define GBUFFER_GRABBING 0x01U +#define GBUFFER_DONE 0x02U +#ifdef PLANB_GSCANLINE + int gbytes_per_line; +#else +#define MAX_LNUM 431 /* change this if PLANB_MAXLINES or */ + /* PLANB_MAXPIXELS changes */ + unsigned char *l_fr_addr[MAX_GBUFFERS]; + unsigned char *l_to_addr[MAX_GBUFFERS][MAX_LNUM]; + int lsize[MAX_GBUFFERS], lnum[MAX_GBUFFERS]; +#endif +}; + +#endif /* __KERNEL__ */ + +#endif /* _PLANB_H_ */ diff -ur --new-file old/linux/drivers/char/pty.c new/linux/drivers/char/pty.c --- old/linux/drivers/char/pty.c Mon Sep 28 20:07:45 1998 +++ new/linux/drivers/char/pty.c Sun Feb 7 02:28:37 1999 @@ -84,7 +84,6 @@ wake_up_interruptible(&tty->link->write_wait); set_bit(TTY_OTHER_CLOSED, &tty->link->flags); if (tty->driver.subtype == PTY_TYPE_MASTER) { - tty_hangup(tty->link); set_bit(TTY_OTHER_CLOSED, &tty->flags); #ifdef CONFIG_UNIX98_PTYS { @@ -95,6 +94,7 @@ } } #endif + tty_vhangup(tty->link); } } diff -ur --new-file old/linux/drivers/char/radio-aimslab.c new/linux/drivers/char/radio-aimslab.c --- old/linux/drivers/char/radio-aimslab.c Mon Jan 11 07:28:14 1999 +++ new/linux/drivers/char/radio-aimslab.c Thu Apr 15 14:42:40 1999 @@ -3,6 +3,11 @@ * Coverted to new API by Alan Cox * Various bugfixes and enhancements by Russell Kroll * + * History: + * 1999-02-24 Russell Kroll + * Fine tuning/VIDEO_TUNER_LOW + * Frequency range expanded to start at 87 MHz + * * TODO: Allow for more than one of these foolish entities :-) * * Notes on the hardware (reverse engineered from other peoples' @@ -156,14 +161,11 @@ /* adapted from radio-aztech.c */ - /* We want to compute x * 100 / 16 without overflow - * So we compute x*6 + (x/100)*25 to give x*6.25 - */ - - freq = freq * 6 + freq/4; /* massage the data a little */ - freq += 1070; /* IF = 10.7 MHz */ - freq /= 5; /* ref = 25 kHz */ + /* now uses VIDEO_TUNER_LOW for fine tuning */ + freq += 171200; /* Add 10.7 MHz IF */ + freq /= 800; /* Convert to 50 kHz units */ + send_0_byte (io, dev); /* 0: LSB of frequency */ for (i = 0; i < 13; i++) /* : frequency bits (1-13) */ @@ -229,10 +231,11 @@ return -EFAULT; if(v.tuner) /* Only 1 tuner */ return -EINVAL; - v.rangelow=(88*16); - v.rangehigh=(108*16); - v.flags=0; + v.rangelow=(87*16000); + v.rangehigh=(108*16000); + v.flags=VIDEO_TUNER_LOW; v.mode=VIDEO_MODE_AUTO; + strcpy(v.name, "FM"); v.signal=0xFFFF*rt_getsigstr(rt); if(copy_to_user(arg,&v, sizeof(v))) return -EFAULT; diff -ur --new-file old/linux/drivers/char/radio-aztech.c new/linux/drivers/char/radio-aztech.c --- old/linux/drivers/char/radio-aztech.c Sun Aug 23 22:32:25 1998 +++ new/linux/drivers/char/radio-aztech.c Thu Apr 15 14:42:40 1999 @@ -1,9 +1,7 @@ -/* aztech.c - Aztech radio card driver for Linux 2.1 by Russell Kroll +/* radio-aztech.c - Aztech radio card driver for Linux 2.2 * - * Heavily modified to support the new 2.1 radio card interfaces by - * Russell Kroll (rkroll@exploits.org) - * - * Based on code by + * Adapted to support the Video for Linux API by + * Russell Kroll . Based on original tuner code by: * * Quay Ly * Donald Song @@ -14,6 +12,11 @@ * The basis for this code may be found at http://bigbang.vtc.vsc.edu/fmradio/ * along with more information on the card itself. * + * History: + * 1999-02-24 Russell Kroll + * Fine tuning/VIDEO_TUNER_LOW + * Range expanded to 87-108 MHz (from 87.9-107.8) + * * Notable changes from the original source: * - includes stripped down to the essentials * - for loops used as delays replaced with udelay() @@ -113,11 +116,8 @@ { int i; - /* 6.25 * */ - frequency = frequency*6 + frequency/4; /* massage data a bit */ - - frequency += 1070; /* tuning needs 24 data bits */ - frequency /= 5; + frequency += 171200; /* Add 10.7 MHz IF */ + frequency /= 800; /* Convert to 50 kHz units */ send_0_byte (dev); /* 0: LSB of frequency */ @@ -179,13 +179,14 @@ return -EFAULT; if(v.tuner) /* Only 1 tuner */ return -EINVAL; - v.rangelow=(879*16)/10; - v.rangehigh=(1078*16)/10; - v.flags=0; + v.rangelow=(87*16000); + v.rangehigh=(108*16000); + v.flags=VIDEO_TUNER_LOW; v.mode=VIDEO_MODE_AUTO; v.signal=0xFFFF*az_getsigstr(az); if(az_getstereo(az)) v.flags|=VIDEO_TUNER_STEREO_ON; + strcpy(v.name, "FM"); if(copy_to_user(arg,&v, sizeof(v))) return -EFAULT; return 0; @@ -292,7 +293,7 @@ return -EINVAL; request_region(io, 2, "aztech"); - printk(KERN_INFO "Aztech radio card driver v0.40/19980422 rkroll@exploits.org\n"); + printk(KERN_INFO "Aztech radio card driver v1.00/19990224 rkroll@exploits.org\n"); /* mute card - prevents noisy bootups */ outb (0, io); return 0; diff -ur --new-file old/linux/drivers/char/radio-cadet.c new/linux/drivers/char/radio-cadet.c --- old/linux/drivers/char/radio-cadet.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/char/radio-cadet.c Mon May 10 22:00:10 1999 @@ -0,0 +1,614 @@ +/* cadet.c - A video4linux driver for the ADS Cadet AM/FM Radio Card + * + * by Fred Gleason + * Version 0.3.1 + * + * (Loosely) based on code for the Aztech radio card by + * + * Russell Kroll (rkroll@exploits.org) + * Quay Ly + * Donald Song + * Jason Lewis (jlewis@twilight.vtc.vsc.edu) + * Scott McGrath (smcgrath@twilight.vtc.vsc.edu) + * William McGrath (wmcgrath@twilight.vtc.vsc.edu) + * +*/ + +#include /* Modules */ +#include /* Initdata */ +#include /* check_region, request_region */ +#include /* udelay */ +#include /* outb, outb_p */ +#include /* copy to/from user */ +#include /* kernel radio structs */ +#include /* CONFIG_RADIO_CADET_PORT */ +#include + +#ifndef CONFIG_RADIO_CADET_PORT +#define CONFIG_RADIO_CADET_PORT 0x330 +#endif +#define RDS_BUFFER 256 + +static int io=CONFIG_RADIO_CADET_PORT; +static int users=0; +static int curtuner=0; +static int tunestat=0; +static int sigstrength=0; +struct wait_queue *tunerq,*rdsq,*readq; +struct timer_list tunertimer,rdstimer,readtimer; +static __u8 rdsin=0,rdsout=0,rdsstat=0; +static unsigned char rdsbuf[RDS_BUFFER]; +static int cadet_lock=0; + +/* + * Signal Strength Threshold Values + * The V4L API spec does not define any particular unit for the signal + * strength value. These values are in microvolts of RF at the tuner's input. + */ +static __u16 sigtable[2][4]={{5,10,30,150},{28,40,63,1000}}; + + + +void cadet_wake(unsigned long qnum) +{ + switch(qnum) { + case 0: /* cadet_setfreq */ + wake_up(&tunerq); + break; + case 1: /* cadet_getrds */ + wake_up(&rdsq); + break; + } +} + + + +static int cadet_getrds(void) +{ + int rdsstat=0; + + cadet_lock++; + outb(3,io); /* Select Decoder Control/Status */ + outb(inb(io+1)&0x7f,io+1); /* Reset RDS detection */ + cadet_lock--; + init_timer(&rdstimer); + rdstimer.function=cadet_wake; + rdstimer.data=(unsigned long)1; + rdstimer.expires=jiffies+(HZ/10); + rdsq=NULL; + add_timer(&rdstimer); + sleep_on(&rdsq); + + cadet_lock++; + outb(3,io); /* Select Decoder Control/Status */ + if((inb(io+1)&0x80)!=0) { + rdsstat|=VIDEO_TUNER_RDS_ON; + } + if((inb(io+1)&0x10)!=0) { + rdsstat|=VIDEO_TUNER_MBS_ON; + } + cadet_lock--; + return rdsstat; +} + + + + +static int cadet_getstereo(void) +{ + if(curtuner!=0) { /* Only FM has stereo capability! */ + return 0; + } + cadet_lock++; + outb(7,io); /* Select tuner control */ + if((inb(io+1)&0x40)==0) { + cadet_lock--; + return 1; /* Stereo pilot detected */ + } + else { + cadet_lock--; + return 0; /* Mono */ + } +} + + + +static unsigned cadet_gettune(void) +{ + int curvol,i; + unsigned fifo=0; + + /* + * Prepare for read + */ + cadet_lock++; + outb(7,io); /* Select tuner control */ + curvol=inb(io+1); /* Save current volume/mute setting */ + outb(0x00,io+1); /* Ensure WRITE-ENABLE is LOW */ + tunestat=0xffff; + + /* + * Read the shift register + */ + for(i=0;i<25;i++) { + fifo=(fifo<<1)|((inb(io+1)>>7)&0x01); + if(i<24) { + outb(0x01,io+1); + tunestat&=inb(io+1); + outb(0x00,io+1); + } + } + + /* + * Restore volume/mute setting + */ + outb(curvol,io+1); + cadet_lock--; + + return fifo; +} + + + +static unsigned cadet_getfreq(void) +{ + int i; + unsigned freq=0,test,fifo=0; + + /* + * Read current tuning + */ + fifo=cadet_gettune(); + + /* + * Convert to actual frequency + */ + if(curtuner==0) { /* FM */ + test=12500; + for(i=0;i<14;i++) { + if((fifo&0x01)!=0) { + freq+=test; + } + test=test<<1; + fifo=fifo>>1; + } + freq-=10700000; /* IF frequency is 10.7 MHz */ + freq=(freq*16)/1000000; /* Make it 1/16 MHz */ + } + if(curtuner==1) { /* AM */ + freq=((fifo&0x7fff)-2010)*16; + } + + return freq; +} + + + +static void cadet_settune(unsigned fifo) +{ + int i; + unsigned test; + + cadet_lock++; + outb(7,io); /* Select tuner control */ + /* + * Write the shift register + */ + test=0; + test=(fifo>>23)&0x02; /* Align data for SDO */ + test|=0x1c; /* SDM=1, SWE=1, SEN=1, SCK=0 */ + outb(7,io); /* Select tuner control */ + outb(test,io+1); /* Initialize for write */ + for(i=0;i<25;i++) { + test|=0x01; /* Toggle SCK High */ + outb(test,io+1); + test&=0xfe; /* Toggle SCK Low */ + outb(test,io+1); + fifo=fifo<<1; /* Prepare the next bit */ + test=0x1c|((fifo>>23)&0x02); + outb(test,io+1); + } + cadet_lock--; +} + + + +static void cadet_setfreq(unsigned freq) +{ + unsigned fifo; + int i,j,test; + int curvol; + + /* + * Formulate a fifo command + */ + fifo=0; + if(curtuner==0) { /* FM */ + test=102400; + freq=(freq*1000)/16; /* Make it kHz */ + freq+=10700; /* IF is 10700 kHz */ + for(i=0;i<14;i++) { + fifo=fifo<<1; + if(freq>=test) { + fifo|=0x01; + freq-=test; + } + test=test>>1; + } + } + if(curtuner==1) { /* AM */ + fifo=(freq/16)+2010; /* Make it kHz */ + fifo|=0x100000; /* Select AM Band */ + } + + /* + * Save current volume/mute setting + */ + cadet_lock++; + outb(7,io); /* Select tuner control */ + curvol=inb(io+1); + + /* + * Tune the card + */ + for(j=3;j>-1;j--) { + cadet_settune(fifo|(j<<16)); + outb(7,io); /* Select tuner control */ + outb(curvol,io+1); + cadet_lock--; + init_timer(&tunertimer); + tunertimer.function=cadet_wake; + tunertimer.data=(unsigned long)0; + tunertimer.expires=jiffies+(HZ/10); + tunerq=NULL; + add_timer(&tunertimer); + sleep_on(&tunerq); + cadet_gettune(); + if((tunestat&0x40)==0) { /* Tuned */ + sigstrength=sigtable[curtuner][j]; + return; + } + cadet_lock++; + } + cadet_lock--; + sigstrength=0; +} + + +static int cadet_getvol(void) +{ + cadet_lock++; + outb(7,io); /* Select tuner control */ + if((inb(io+1)&0x20)!=0) { + cadet_lock--; + return 0xffff; + } + else { + cadet_lock--; + return 0; + } +} + + +static void cadet_setvol(int vol) +{ + cadet_lock++; + outb(7,io); /* Select tuner control */ + if(vol>0) { + outb(0x20,io+1); + } + else { + outb(0x00,io+1); + } + cadet_lock--; +} + + + +void cadet_handler(unsigned long data) +{ + /* + * Service the RDS fifo + */ + if(cadet_lock==0) { + outb(0x3,io); /* Select RDS Decoder Control */ + if((inb(io+1)&0x20)!=0) { + printk(KERN_CRIT "cadet: RDS fifo overflow\n"); + } + outb(0x80,io); /* Select RDS fifo */ + while((inb(io)&0x80)!=0) { + rdsbuf[rdsin++]=inb(io+1); + if(rdsin==rdsout) { + printk(KERN_CRIT "cadet: RDS buffer overflow\n"); + } + } + } + + /* + * Service pending read + */ + if((rdsin!=rdsout)&&(readq!=NULL)) { + wake_up_interruptible(&readq); + } + + /* + * Clean up and exit + */ + init_timer(&readtimer); + readtimer.function=cadet_handler; + readtimer.data=(unsigned long)0; + readtimer.expires=jiffies+(HZ/20); + add_timer(&readtimer); +} + + + +static long cadet_read(struct video_device *v,char *buf,unsigned long count, + int nonblock) +{ + int i=0,c; + 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;i1)) { + return -EINVAL; + } + switch(v.tuner) { + case 0: + strcpy(v.name,"FM"); + v.rangelow=1400; /* 87.5 MHz */ + v.rangehigh=1728; /* 108.0 MHz */ + v.flags=0; + v.mode=0; + v.mode|=VIDEO_MODE_AUTO; + v.signal=sigstrength; + if(cadet_getstereo()==1) { + v.flags|=VIDEO_TUNER_STEREO_ON; + } + v.flags|=cadet_getrds(); + if(copy_to_user(arg,&v, sizeof(v))) { + return -EFAULT; + } + break; + case 1: + strcpy(v.name,"AM"); + v.rangelow=8320; /* 520 kHz */ + v.rangehigh=26400; /* 1650 kHz */ + v.flags=0; + v.flags|=VIDEO_TUNER_LOW; + v.mode=0; + v.mode|=VIDEO_MODE_AUTO; + v.signal=sigstrength; + if(copy_to_user(arg,&v, sizeof(v))) { + return -EFAULT; + } + break; + } + return 0; + } + case VIDIOCSTUNER: + { + struct video_tuner v; + if(copy_from_user(&v, arg, sizeof(v))) { + return -EFAULT; + } + if((v.tuner<0)||(v.tuner>1)) { + return -EINVAL; + } + curtuner=v.tuner; + return 0; + } + case VIDIOCGFREQ: + freq=cadet_getfreq(); + if(copy_to_user(arg, &freq, sizeof(freq))) + return -EFAULT; + return 0; + case VIDIOCSFREQ: + if(copy_from_user(&freq, arg,sizeof(freq))) + return -EFAULT; + if((curtuner==0)&&((freq<1400)||(freq>1728))) { + return -EINVAL; + } + if((curtuner==1)&&((freq<8320)||(freq>26400))) { + return -EINVAL; + } + cadet_setfreq(freq); + return 0; + case VIDIOCGAUDIO: + { + struct video_audio v; + memset(&v,0, sizeof(v)); + v.flags=VIDEO_AUDIO_MUTABLE|VIDEO_AUDIO_VOLUME; + if(cadet_getstereo()==0) { + v.mode=VIDEO_SOUND_MONO; + } + else { + v.mode=VIDEO_SOUND_STEREO; + } + v.volume=cadet_getvol(); + v.step=0xffff; + strcpy(v.name, "Radio"); + if(copy_to_user(arg,&v, sizeof(v))) + return -EFAULT; + return 0; + } + case VIDIOCSAUDIO: + { + struct video_audio v; + if(copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + if(v.audio) + return -EINVAL; + cadet_setvol(v.volume); + if(v.flags&VIDEO_AUDIO_MUTE) + cadet_setvol(0); + else + cadet_setvol(0xffff); + return 0; + } + default: + return -ENOIOCTLCMD; + } +} + + +static int cadet_open(struct video_device *dev, int flags) +{ + if(users) + return -EBUSY; + users++; + MOD_INC_USE_COUNT; + readq=NULL; + return 0; +} + +static void cadet_close(struct video_device *dev) +{ + if(rdsstat==1) { + del_timer(&readtimer); + rdsstat=0; + } + users--; + MOD_DEC_USE_COUNT; +} + + +static struct video_device cadet_radio= +{ + "Cadet radio", + VID_TYPE_TUNER, + VID_HARDWARE_CADET, + cadet_open, + cadet_close, + cadet_read, + NULL, /* Can't write */ + NULL, /* No poll */ + cadet_ioctl, + NULL, + NULL +}; + +__initfunc(int cadet_init(struct video_init *v)) +{ +#ifndef MODULE + if(cadet_probe()<0) { + return EINVAL; + } +#endif + if(video_register_device(&cadet_radio,VFL_TYPE_RADIO)==-1) + return -EINVAL; + + request_region(io,2,"cadet"); + printk(KERN_INFO "ADS Cadet Radio Card at %x\n",io); + return 0; +} + + +#ifndef MODULE +static int cadet_probe(void) +{ + static int iovals[8]={0x330,0x332,0x334,0x336,0x338,0x33a,0x33c,0x33e}; + int i; + + for(i=0;i<8;i++) { + io=iovals[i]; + if(check_region(io,2)) { + return -1; + } + cadet_setfreq(1410); + if(cadet_getfreq()==1410) { + return io; + } + } + return -1; +} +#endif + + + +#ifdef MODULE + +MODULE_AUTHOR("Fred Gleason, Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath"); +MODULE_DESCRIPTION("A driver for the ADS Cadet AM/FM/RDS radio card."); +MODULE_PARM(io, "i"); +MODULE_PARM_DESC(io, "I/O address of Cadet card (0x330,0x332,0x334,0x336,0x338,0x33a,0x33c,0x33e)"); + +EXPORT_NO_SYMBOLS; + +int init_module(void) +{ + if(io==-1) + { + printk(KERN_ERR "You must set an I/O address with io=0x???\n"); + return -EINVAL; + } + return cadet_init(NULL); +} + +void cleanup_module(void) +{ + video_unregister_device(&cadet_radio); + release_region(io,2); +} + +#endif + diff -ur --new-file old/linux/drivers/char/radio-gemtek.c new/linux/drivers/char/radio-gemtek.c --- old/linux/drivers/char/radio-gemtek.c Sun Dec 27 19:49:06 1998 +++ new/linux/drivers/char/radio-gemtek.c Thu Apr 15 14:42:40 1999 @@ -160,6 +160,7 @@ v.flags=VIDEO_TUNER_LOW; v.mode=VIDEO_MODE_AUTO; v.signal=0xFFFF*gemtek_getsigstr(rt); + strcpy(v.name, "FM"); if(copy_to_user(arg,&v, sizeof(v))) return -EFAULT; return 0; diff -ur --new-file old/linux/drivers/char/radio-miropcm20.c new/linux/drivers/char/radio-miropcm20.c --- old/linux/drivers/char/radio-miropcm20.c Mon Aug 31 19:32:19 1998 +++ new/linux/drivers/char/radio-miropcm20.c Thu Apr 15 14:42:40 1999 @@ -118,6 +118,7 @@ v.flags=0; v.mode=VIDEO_MODE_AUTO; v.signal=0xFFFF*pcm20_getsigstr(pcm20); + strcpy(v.name, "FM"); if(copy_to_user(arg,&v, sizeof(v))) return -EFAULT; return 0; diff -ur --new-file old/linux/drivers/char/radio-rtrack2.c new/linux/drivers/char/radio-rtrack2.c --- old/linux/drivers/char/radio-rtrack2.c Sun Aug 23 22:32:25 1998 +++ new/linux/drivers/char/radio-rtrack2.c Thu Apr 15 14:42:40 1999 @@ -130,6 +130,7 @@ v.flags=VIDEO_TUNER_LOW; v.mode=VIDEO_MODE_AUTO; v.signal=0xFFFF*rt_getsigstr(rt); + strcpy(v.name, "FM"); if(copy_to_user(arg,&v, sizeof(v))) return -EFAULT; return 0; diff -ur --new-file old/linux/drivers/char/radio-sf16fmi.c new/linux/drivers/char/radio-sf16fmi.c --- old/linux/drivers/char/radio-sf16fmi.c Fri Nov 20 17:44:06 1998 +++ new/linux/drivers/char/radio-sf16fmi.c Sun Apr 25 02:49:37 1999 @@ -4,6 +4,7 @@ * (c) 1998 Petr Vandrovec, vandrove@vc.cvut.cz * * Fitted to new interface by Alan Cox + * Made working and cleaned up functions * * Notes on the hardware * @@ -74,9 +75,10 @@ outb(0x08, port); } -static inline int fmi_setfreq(struct fmi_device *dev, unsigned long freq) +static inline int fmi_setfreq(struct fmi_device *dev) { int myport = dev->port; + unsigned long freq = dev->curfreq; int i; outbits(16, RSF16_ENCODE(freq), myport); @@ -191,8 +193,10 @@ tmp *= 1000; if ( tmpRSF16_MAXFREQ ) return -EINVAL; - fmi->curfreq = tmp; - fmi_setfreq(fmi, fmi->curfreq); + /*rounding in steps of 800 to match th freq + that will be used */ + fmi->curfreq = (tmp/800)*800; + fmi_setfreq(fmi); return 0; } case VIDIOCGAUDIO: @@ -204,7 +208,7 @@ v.treble=0; v.flags=( (!fmi->curvol)*VIDEO_AUDIO_MUTE | VIDEO_AUDIO_MUTABLE); strcpy(v.name, "Radio"); - v.mode=VIDEO_SOUND_MONO; + v.mode=VIDEO_SOUND_STEREO; v.balance=0; v.step=0; /* No volume, just (un)mute */ if(copy_to_user(arg,&v, sizeof(v))) diff -ur --new-file old/linux/drivers/char/radio-typhoon.c new/linux/drivers/char/radio-typhoon.c --- old/linux/drivers/char/radio-typhoon.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/char/radio-typhoon.c Mon May 10 22:00:10 1999 @@ -0,0 +1,433 @@ +/* Typhoon Radio Card driver for radio support + * (c) 1999 Dr. Henrik Seidel + * + * Card manufacturer: + * http://194.18.155.92/idc/prod2.idc?nr=50753&lang=e + * + * Notes on the hardware + * + * This card has two output sockets, one for speakers and one for line. + * The speaker output has volume control, but only in four discrete + * steps. The line output has neither volume control nor mute. + * + * The card has auto-stereo according to its manual, although it all + * sounds mono to me (even with the Win/DOS drivers). Maybe it's my + * antenna - I really don't know for sure. + * + * Frequency control is done digitally. + * + * Volume control is done digitally, but there are only four different + * possible values. So you should better always turn the volume up and + * use line control. I got the best results by connecting line output + * to the sound card microphone input. For such a configuration the + * volume control has no effect, since volume control only influences + * the speaker output. + * + * There is no explicit mute/unmute. So I set the radio frequency to a + * value where I do expect just noise and turn the speaker volume down. + * The frequency change is necessary since the card never seems to be + * completely silent. + */ + +#include /* Modules */ +#include /* Initdata */ +#include /* check_region, request_region */ +#include /* radio card status report */ +#include /* outb, outb_p */ +#include /* copy to/from user */ +#include /* kernel radio structs */ +#include /* CONFIG_RADIO_TYPHOON_* */ + +#define BANNER "Typhoon Radio Card driver v0.1\n" + +#ifndef CONFIG_RADIO_TYPHOON_PORT +#define CONFIG_RADIO_TYPHOON_PORT -1 +#endif + +#ifndef CONFIG_RADIO_TYPHOON_MUTEFREQ +#define CONFIG_RADIO_TYPHOON_MUTEFREQ 0 +#endif + +#ifndef CONFIG_PROC_FS +#undef CONFIG_RADIO_TYPHOON_PROC_FS +#endif + +struct typhoon_device { + int users; + int iobase; + int curvol; + int muted; + unsigned long curfreq; + unsigned long mutefreq; +}; + +static void typhoon_setvol_generic(struct typhoon_device *dev, int vol); +static int typhoon_setfreq_generic(struct typhoon_device *dev, + unsigned long frequency); +static int typhoon_setfreq(struct typhoon_device *dev, unsigned long frequency); +static void typhoon_mute(struct typhoon_device *dev); +static void typhoon_unmute(struct typhoon_device *dev); +static int typhoon_setvol(struct typhoon_device *dev, int vol); +static int typhoon_ioctl(struct video_device *dev, unsigned int cmd, void *arg); +static int typhoon_open(struct video_device *dev, int flags); +static void typhoon_close(struct video_device *dev); +#ifdef CONFIG_RADIO_TYPHOON_PROC_FS +static int typhoon_read_proc(char *buf, char **start, off_t offset, int len, + int unused); +#endif +#ifdef MODULE +int init_module(void); +void cleanup_module(void); +int typhoon_init(struct video_init *v); +#else +int typhoon_init(struct video_init *v) __init; +#endif + +static void typhoon_setvol_generic(struct typhoon_device *dev, int vol) +{ + vol >>= 14; /* Map 16 bit to 2 bit */ + vol &= 3; + outb_p(vol / 2, dev->iobase); /* Set the volume, high bit. */ + outb_p(vol % 2, dev->iobase + 2); /* Set the volume, low bit. */ +} + +static int typhoon_setfreq_generic(struct typhoon_device *dev, + unsigned long frequency) +{ + unsigned long outval; + unsigned long x; + + /* + * The frequency transfer curve is not linear. The best fit I could + * get is + * + * outval = -155 + exp((f + 15.55) * 0.057)) + * + * where frequency f is in MHz. Since we don't have exp in the kernel, + * I approximate this function by a third order polynomial. + * + */ + + x = frequency / 160; + outval = (x * x + 2500) / 5000; + outval = (outval * x + 5000) / 10000; + outval -= (10 * x * x + 10433) / 20866; + outval += 4 * x - 11505; + + outb_p((outval >> 8) & 0x01, dev->iobase + 4); + outb_p(outval >> 9, dev->iobase + 6); + outb_p(outval & 0xff, dev->iobase + 8); + + return 0; +} + +static int typhoon_setfreq(struct typhoon_device *dev, unsigned long frequency) +{ + typhoon_setfreq_generic(dev, frequency); + dev->curfreq = frequency; + return 0; +} + +static void typhoon_mute(struct typhoon_device *dev) +{ + if (dev->muted == 1) + return; + typhoon_setvol_generic(dev, 0); + typhoon_setfreq_generic(dev, dev->mutefreq); + dev->muted = 1; +} + +static void typhoon_unmute(struct typhoon_device *dev) +{ + if (dev->muted == 0) + return; + typhoon_setfreq_generic(dev, dev->curfreq); + typhoon_setvol_generic(dev, dev->curvol); + dev->muted = 0; +} + +static int typhoon_setvol(struct typhoon_device *dev, int vol) +{ + if (dev->muted && vol != 0) { /* user is unmuting the card */ + dev->curvol = vol; + typhoon_unmute(dev); + return 0; + } + if (vol == dev->curvol) /* requested volume == current */ + return 0; + + if (vol == 0) { /* volume == 0 means mute the card */ + typhoon_mute(dev); + dev->curvol = vol; + return 0; + } + typhoon_setvol_generic(dev, vol); + dev->curvol = vol; + return 0; +} + + +static int typhoon_ioctl(struct video_device *dev, unsigned int cmd, void *arg) +{ + struct typhoon_device *typhoon = dev->priv; + + switch (cmd) { + case VIDIOCGCAP: + { + struct video_capability v; + v.type = VID_TYPE_TUNER; + v.channels = 1; + v.audios = 1; + /* No we don't do pictures */ + v.maxwidth = 0; + v.maxheight = 0; + v.minwidth = 0; + v.minheight = 0; + strcpy(v.name, "Typhoon Radio"); + if (copy_to_user(arg, &v, sizeof(v))) + return -EFAULT; + return 0; + } + case VIDIOCGTUNER: + { + struct video_tuner v; + if (copy_from_user(&v, arg, sizeof(v)) != 0) + return -EFAULT; + if (v.tuner) /* Only 1 tuner */ + return -EINVAL; + v.rangelow = 875 * 1600; + v.rangehigh = 1080 * 1600; + v.flags = VIDEO_TUNER_LOW; + v.mode = VIDEO_MODE_AUTO; + v.signal = 0xFFFF; /* We can't get the signal strength */ + strcpy(v.name, "FM"); + if (copy_to_user(arg, &v, sizeof(v))) + return -EFAULT; + return 0; + } + case VIDIOCSTUNER: + { + struct video_tuner v; + if (copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + if (v.tuner != 0) + return -EINVAL; + /* Only 1 tuner so no setting needed ! */ + return 0; + } + case VIDIOCGFREQ: + if (copy_to_user(arg, &typhoon->curfreq, + sizeof(typhoon->curfreq))) + return -EFAULT; + return 0; + case VIDIOCSFREQ: + if (copy_from_user(&typhoon->curfreq, arg, + sizeof(typhoon->curfreq))) + return -EFAULT; + typhoon_setfreq(typhoon, typhoon->curfreq); + return 0; + case VIDIOCGAUDIO: + { + struct video_audio v; + memset(&v, 0, sizeof(v)); + v.flags |= VIDEO_AUDIO_MUTABLE | VIDEO_AUDIO_VOLUME; + v.mode |= VIDEO_SOUND_MONO; + v.volume = typhoon->curvol; + v.step = 1 << 14; + strcpy(v.name, "Typhoon Radio"); + if (copy_to_user(arg, &v, sizeof(v))) + return -EFAULT; + return 0; + } + case VIDIOCSAUDIO: + { + struct video_audio v; + if (copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + if (v.audio) + return -EINVAL; + + if (v.flags & VIDEO_AUDIO_MUTE) + typhoon_mute(typhoon); + else + typhoon_unmute(typhoon); + + if (v.flags & VIDEO_AUDIO_VOLUME) + typhoon_setvol(typhoon, v.volume); + + return 0; + } + default: + return -ENOIOCTLCMD; + } +} + +static int typhoon_open(struct video_device *dev, int flags) +{ + struct typhoon_device *typhoon = dev->priv; + if (typhoon->users) + return -EBUSY; + typhoon->users++; + MOD_INC_USE_COUNT; + return 0; +} + +static void typhoon_close(struct video_device *dev) +{ + struct typhoon_device *typhoon = dev->priv; + typhoon->users--; + MOD_DEC_USE_COUNT; +} + +static struct typhoon_device typhoon_unit = +{ + 0, /* users */ + CONFIG_RADIO_TYPHOON_PORT, /* iobase */ + 0, /* curvol */ + 0, /* muted */ + CONFIG_RADIO_TYPHOON_MUTEFREQ, /* curfreq */ + CONFIG_RADIO_TYPHOON_MUTEFREQ /* mutefreq */ +}; + +static struct video_device typhoon_radio = +{ + "Typhoon Radio", + VID_TYPE_TUNER, + VID_HARDWARE_TYPHOON, + typhoon_open, + typhoon_close, + NULL, /* Can't read (no capture ability) */ + NULL, /* Can't write */ + NULL, /* Can't poll */ + typhoon_ioctl, + NULL, + NULL +}; + +#ifdef CONFIG_RADIO_TYPHOON_PROC_FS + +static int typhoon_read_proc(char *buf, char **start, off_t offset, int len, + int unused) +{ + #ifdef MODULE + #define MODULEPROCSTRING "Driver loaded as a module" + #else + #define MODULEPROCSTRING "Driver compiled into kernel" + #endif + + #define LIMIT (PAGE_SIZE - 80) + + len = 0; + len += sprintf(buf + len, BANNER); + if (len > LIMIT) return len; + len += sprintf(buf + len, "Load type: " MODULEPROCSTRING "\n\n"); + if (len > LIMIT) return len; + len += sprintf(buf + len, "frequency = %lu kHz\n", + typhoon_unit.curfreq >> 4); + if (len > LIMIT) return len; + len += sprintf(buf + len, "volume = %d\n", typhoon_unit.curvol); + if (len > LIMIT) return len; + len += sprintf(buf + len, "mute = %s\n", typhoon_unit.muted ? + "on" : "off"); + if (len > LIMIT) return len; + len += sprintf(buf + len, "iobase = 0x%x\n", typhoon_unit.iobase); + if (len > LIMIT) return len; + len += sprintf(buf + len, "mute frequency = %lu kHz\n", + typhoon_unit.mutefreq >> 4); + return len; +} + +static struct proc_dir_entry typhoon_proc_entry = { + 0, /* low_ino: inode is dynamic */ + 13, "radio-typhoon", /* length of name and name */ + S_IFREG | S_IRUGO, /* mode */ + 1, 0, 0, /* nlinks, owner, group */ + 0, /* size -- not used */ + NULL, /* operations -- use default */ + &typhoon_read_proc, /* function used to read data */ + /* nothing more */ +}; + +#endif /* CONFIG_RADIO_TYPHOON_PROC_FS */ + +int typhoon_init(struct video_init *v) +{ + printk(KERN_INFO BANNER); + if (check_region(typhoon_unit.iobase, 8)) { + printk(KERN_ERR "radio-typhoon: port 0x%x already in use\n", + typhoon_unit.iobase); + return -EBUSY; + } + + typhoon_radio.priv = &typhoon_unit; + if (video_register_device(&typhoon_radio, VFL_TYPE_RADIO) == -1) + return -EINVAL; + + request_region(typhoon_unit.iobase, 8, "typhoon"); + printk(KERN_INFO "radio-typhoon: port 0x%x.\n", typhoon_unit.iobase); + printk(KERN_INFO "radio-typhoon: mute frequency is %lu kHz.\n", + typhoon_unit.mutefreq); + typhoon_unit.mutefreq <<= 4; + + /* mute card - prevents noisy bootups */ + typhoon_mute(&typhoon_unit); + +#ifdef CONFIG_RADIO_TYPHOON_PROC_FS + + if (proc_register(&proc_root, &typhoon_proc_entry)) + printk(KERN_ERR "radio-typhoon: registering /proc/radio-typhoon failed\n"); + +#endif + + return 0; +} + +#ifdef MODULE + +MODULE_AUTHOR("Dr. Henrik Seidel"); +MODULE_DESCRIPTION("A driver for the Typhoon radio card (a.k.a. EcoRadio)."); +MODULE_PARM(io, "i"); +MODULE_PARM_DESC(io, "I/O address of the Typhoon card (0x316 or 0x336)"); +MODULE_PARM(mutefreq, "i"); +MODULE_PARM_DESC(mutefreq, "Frequency used when muting the card (in kHz)"); + +EXPORT_NO_SYMBOLS; + +static int io = -1; +static unsigned long mutefreq = 0; + +int init_module(void) +{ + if (io == -1) { + printk(KERN_ERR "radio-typhoon: You must set an I/O address with io=0x316 or io=0x336\n"); + return -EINVAL; + } + typhoon_unit.iobase = io; + + if (mutefreq < 87000 || mutefreq > 108500) { + printk(KERN_ERR "radio-typhoon: You must set a frequency (in kHz) used when muting the card,\n"); + printk(KERN_ERR "radio-typhoon: e.g. with \"mutefreq=87500\" (87000 <= mutefreq <= 108500)\n"); + return -EINVAL; + } + typhoon_unit.mutefreq = mutefreq; + + return typhoon_init(NULL); +} + +void cleanup_module(void) +{ + +#ifdef CONFIG_RADIO_TYPHOON_PROC_FS + + if (proc_unregister(&proc_root, typhoon_proc_entry.low_ino)) + printk(KERN_ERR "radio-typhoon: unregistering /proc/radio-typhoon failed\n"); + +#endif + + video_unregister_device(&typhoon_radio); + release_region(io, 8); +} + +#endif + + diff -ur --new-file old/linux/drivers/char/radio-zoltrix.c new/linux/drivers/char/radio-zoltrix.c --- old/linux/drivers/char/radio-zoltrix.c Thu Jan 7 17:46:59 1999 +++ new/linux/drivers/char/radio-zoltrix.c Mon May 10 22:00:10 1999 @@ -5,14 +5,16 @@ * Due to the inconsistancy in reading from the signal flags * it is difficult to get an accurate tuned signal. * - * There seems to be a problem with the volume setting that I must still - * figure out. - * It seems that the card has is not linear to 0 volume. It cuts off - * at a low frequency, and it is not possible (at least I have not found) + * It seems that the card is not linear to 0 volume. It cuts off + * at a low volume, and it is not possible (at least I have not found) * to get fine volume control over the low volume range. * - * Some code derived from code by Frans Brinkman + * Some code derived from code by Romolo Manfredini + * romolo@bicnet.it * + * 1999-05-06 - (C. van Schaik) + * - Make signal strength and stereo scans + * kinder to cpu while in delay * 1999-01-05 - (C. van Schaik) * - Changed tuning to 1/160Mhz accuracy * - Added stereo support @@ -50,18 +52,10 @@ /* local things */ -static void sleep_delay(long n) +static void sleep_delay(void) { - /* Sleep nicely for 'n' uS */ - int d = n / (1000000 / HZ); - if (!d) - udelay(n); - else { - /* Yield CPU time */ - unsigned long x = jiffies; - while ((jiffies - x) <= d) - schedule(); - } + /* Sleep nicely for +/- 10 mS */ + schedule(); } static int zol_setvol(struct zol_device *dev, int vol) @@ -78,7 +72,7 @@ } outb(dev->curvol-1, io); - sleep_delay(10000); + sleep_delay(); inb(io + 2); return 0; @@ -124,18 +118,18 @@ while (i--) { if ((bitmask & 0x8000000000000000ull) != 0) { outb(0x80, io); - sleep_delay(50); + udelay(50); outb(0x00, io); - sleep_delay(50); + udelay(50); outb(0x80, io); - sleep_delay(50); + udelay(50); } else { outb(0xc0, io); - sleep_delay(50); + udelay(50); outb(0x40, io); - sleep_delay(50); + udelay(50); outb(0xc0, io); - sleep_delay(50); + udelay(50); } bitmask *= 2; } @@ -143,16 +137,16 @@ outb(0x80, io); outb(0xc0, io); outb(0x40, io); - sleep_delay(1000); + udelay(1000); inb(io+2); - sleep_delay(1000); + udelay(1000); if (dev->muted) { outb(0, io); outb(0, io); inb(io + 3); - sleep_delay(1000); + udelay(1000); } else zol_setvol(dev, dev->curvol); return 0; @@ -166,10 +160,11 @@ outb(0x00, io); /* This stuff I found to do nothing */ outb(dev->curvol, io); - sleep_delay(20000); + sleep_delay(); + sleep_delay(); a = inb(io); - sleep_delay(1000); + sleep_delay(); b = inb(io); if (a != b) @@ -187,10 +182,11 @@ outb(0x00, io); outb(dev->curvol, io); - sleep_delay(20000); + sleep_delay(); + sleep_delay(); x1 = inb(io); - sleep_delay(1000); + sleep_delay(); x2 = inb(io); if ((x1 == x2) && (x1 == 0xcf)) @@ -222,14 +218,11 @@ case VIDIOCGTUNER: { struct video_tuner v; -/* if (copy_from_user(&v, arg, sizeof(v))) return -EFAULT; if (v.tuner) return -EINVAL; -*/ - v.tuner = 0; - strcpy(v.name, "Zoltrix Radio"); + strcpy(v.name, "FM"); v.rangelow = (int) (88.0 * 16000); v.rangehigh = (int) (108.0 * 16000); v.flags = zol_is_stereo(zol) @@ -285,10 +278,10 @@ if (v.flags & VIDEO_AUDIO_MUTE) zol_mute(zol); else + { zol_unmute(zol); - - if (v.flags & VIDEO_AUDIO_VOLUME) zol_setvol(zol, v.volume / 4096); + } if (v.mode & VIDEO_SOUND_STEREO) { @@ -364,7 +357,8 @@ outb(0, io); outb(0, io); - sleep_delay(20000); + sleep_delay(); + sleep_delay(); inb(io + 3); zoltrix_unit.curvol = 0; diff -ur --new-file old/linux/drivers/char/rocket.c new/linux/drivers/char/rocket.c --- old/linux/drivers/char/rocket.c Thu Nov 5 18:58:43 1998 +++ new/linux/drivers/char/rocket.c Thu Mar 11 01:51:35 1999 @@ -80,7 +80,6 @@ #include #include #include -#include #include #ifdef ENABLE_PCI #include diff -ur --new-file old/linux/drivers/char/saa7196.h new/linux/drivers/char/saa7196.h --- old/linux/drivers/char/saa7196.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/char/saa7196.h Fri May 7 20:05:30 1999 @@ -0,0 +1,117 @@ +/* + Definitions for the Philips SAA7196 digital video decoder, + scaler, and clock generator circuit (DESCpro), as used in + the PlanB video input of the Powermac 7x00/8x00 series. + + Copyright (C) 1998 Michel Lanners (mlan@cpu.lu) + + The register defines are shamelessly copied from the meteor + driver out of NetBSD (with permission), + and are copyrighted (c) 1995 Mark Tinguely and Jim Lowe + (Thanks !) + + Additional debugging and coding by Takashi Oe (toe@unlinfo.unl.edu) + + The default values used for PlanB are my mistakes. +*/ + +/* $Id: saa7196.h,v 1.5 1999/03/26 23:28:47 mlan Exp $ */ + +#ifndef _SAA7196_H_ +#define _SAA7196_H_ + +#define SAA7196_NUMREGS 0x31 /* Number of registers (used)*/ +#define NUM_SUPPORTED_NORM 3 /* Number of supported norms by PlanB */ + +/* Decoder part: */ +#define SAA7196_IDEL 0x00 /* Increment delay */ +#define SAA7196_HSB5 0x01 /* H-sync begin; 50 hz */ +#define SAA7196_HSS5 0x02 /* H-sync stop; 50 hz */ +#define SAA7196_HCB5 0x03 /* H-clamp begin; 50 hz */ +#define SAA7196_HCS5 0x04 /* H-clamp stop; 50 hz */ +#define SAA7196_HSP5 0x05 /* H-sync after PHI1; 50 hz */ +#define SAA7196_LUMC 0x06 /* Luminance control */ +#define SAA7196_HUEC 0x07 /* Hue control */ +#define SAA7196_CKTQ 0x08 /* Colour Killer Threshold QAM (PAL, NTSC) */ +#define SAA7196_CKTS 0x09 /* Colour Killer Threshold SECAM */ +#define SAA7196_PALS 0x0a /* PAL switch sensitivity */ +#define SAA7196_SECAMS 0x0b /* SECAM switch sensitivity */ +#define SAA7196_CGAINC 0x0c /* Chroma gain control */ +#define SAA7196_STDC 0x0d /* Standard/Mode control */ +#define SAA7196_IOCC 0x0e /* I/O and Clock Control */ +#define SAA7196_CTRL1 0x0f /* Control #1 */ +#define SAA7196_CTRL2 0x10 /* Control #2 */ +#define SAA7196_CGAINR 0x11 /* Chroma Gain Reference */ +#define SAA7196_CSAT 0x12 /* Chroma Saturation */ +#define SAA7196_CONT 0x13 /* Luminance Contrast */ +#define SAA7196_HSB6 0x14 /* H-sync begin; 60 hz */ +#define SAA7196_HSS6 0x15 /* H-sync stop; 60 hz */ +#define SAA7196_HCB6 0x16 /* H-clamp begin; 60 hz */ +#define SAA7196_HCS6 0x17 /* H-clamp stop; 60 hz */ +#define SAA7196_HSP6 0x18 /* H-sync after PHI1; 60 hz */ +#define SAA7196_BRIG 0x19 /* Luminance Brightness */ + +/* Scaler part: */ +#define SAA7196_FMTS 0x20 /* Formats and sequence */ +#define SAA7196_OUTPIX 0x21 /* Output data pixel/line */ +#define SAA7196_INPIX 0x22 /* Input data pixel/line */ +#define SAA7196_HWS 0x23 /* Horiz. window start */ +#define SAA7196_HFILT 0x24 /* Horiz. filter */ +#define SAA7196_OUTLINE 0x25 /* Output data lines/field */ +#define SAA7196_INLINE 0x26 /* Input data lines/field */ +#define SAA7196_VWS 0x27 /* Vertical window start */ +#define SAA7196_VYP 0x28 /* AFS/vertical Y processing */ +#define SAA7196_VBS 0x29 /* Vertical Bypass start */ +#define SAA7196_VBCNT 0x2a /* Vertical Bypass count */ +#define SAA7196_VBP 0x2b /* veritcal Bypass Polarity */ +#define SAA7196_VLOW 0x2c /* Colour-keying lower V limit */ +#define SAA7196_VHIGH 0x2d /* Colour-keying upper V limit */ +#define SAA7196_ULOW 0x2e /* Colour-keying lower U limit */ +#define SAA7196_UHIGH 0x2f /* Colour-keying upper U limit */ +#define SAA7196_DPATH 0x30 /* Data path setting */ + +/* Initialization default values: */ + +unsigned char saa_regs[NUM_SUPPORTED_NORM][SAA7196_NUMREGS] = { + +/* PAL, 768x576 (no scaling), composite video-in */ +/* Decoder: */ + { 0x50, 0x30, 0x00, 0xe8, 0xb6, 0xe5, 0x63, 0xff, + 0xfe, 0xf0, 0xfe, 0xe0, 0x20, 0x06, 0x3b, 0x98, + 0x00, 0x59, 0x41, 0x45, 0x34, 0x0a, 0xf4, 0xd2, + 0xe9, 0xa2, +/* Padding */ + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* Scaler: */ + 0x72, 0x80, 0x00, 0x03, 0x8d, 0x20, 0x20, 0x12, + 0xa5, 0x12, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, + 0x87 }, + +/* NTSC, 640x480? (no scaling), composite video-in */ +/* Decoder: */ + { 0x50, 0x30, 0x00, 0xe8, 0xb6, 0xe5, 0x50, 0x00, + 0xf8, 0xf0, 0xfe, 0xe0, 0x00, 0x06, 0x3b, 0x98, + 0x00, 0x2c, 0x3d, 0x40, 0x34, 0x0a, 0xf4, 0xd2, + 0xe9, 0x98, +/* Padding */ + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* Scaler: */ + 0x72, 0x80, 0x80, 0x03, 0x89, 0xf0, 0xf0, 0x0d, + 0xa0, 0x0d, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, + 0x87 }, + +/* SECAM, 768x576 (no scaling), composite video-in */ +/* Decoder: */ + { 0x50, 0x30, 0x00, 0xe8, 0xb6, 0xe5, 0x63, 0xff, + 0xfe, 0xf0, 0xfe, 0xe0, 0x20, 0x07, 0x3b, 0x98, + 0x00, 0x59, 0x41, 0x45, 0x34, 0x0a, 0xf4, 0xd2, + 0xe9, 0xa2, +/* Padding */ + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* Scaler: */ + 0x72, 0x80, 0x00, 0x03, 0x8d, 0x20, 0x20, 0x12, + 0xa5, 0x12, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, + 0x87 } + }; + +#endif /* _SAA7196_H_ */ diff -ur --new-file old/linux/drivers/char/serial.c new/linux/drivers/char/serial.c --- old/linux/drivers/char/serial.c Thu Jan 14 19:27:53 1999 +++ new/linux/drivers/char/serial.c Tue Mar 23 22:13:58 1999 @@ -771,7 +771,7 @@ continue; if (!multi->port4) break; - if ((inb(multi->port4) & multi->mask4) == multi->match4) + if ((inb(multi->port4) & multi->mask4) != multi->match4) continue; break; } @@ -1274,6 +1274,8 @@ /* Determine divisor based on baud rate */ baud = tty_get_baud_rate(info->tty); + if (!baud) + baud = 9600; /* B0 transition handled in rs_set_termios */ baud_base = info->state->baud_base; if (baud == 38400 && ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)) @@ -1740,7 +1742,7 @@ check_and_exit: if (!state->port || !state->type) return 0; - if (state->flags & ASYNC_INITIALIZED) { + if (info->flags & ASYNC_INITIALIZED) { if (((old_state.flags & ASYNC_SPD_MASK) != (state->flags & ASYNC_SPD_MASK)) || (old_state.custom_divisor != state->custom_divisor)) { @@ -2162,8 +2164,9 @@ { struct async_struct *info = (struct async_struct *)tty->driver_data; unsigned long flags; + unsigned int cflag = tty->termios->c_cflag; - if ( (tty->termios->c_cflag == old_termios->c_cflag) + if ( (cflag == old_termios->c_cflag) && ( RELEVANT_IFLAG(tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) return; @@ -2172,7 +2175,7 @@ /* Handle transition to B0 status */ if ((old_termios->c_cflag & CBAUD) && - !(tty->termios->c_cflag & CBAUD)) { + !(cflag & CBAUD)) { info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS); save_flags(flags); cli(); serial_out(info, UART_MCR, info->MCR); @@ -2181,7 +2184,7 @@ /* Handle transition away from B0 status */ if (!(old_termios->c_cflag & CBAUD) && - (tty->termios->c_cflag & CBAUD)) { + (cflag & CBAUD)) { info->MCR |= UART_MCR_DTR; if (!(tty->termios->c_cflag & CRTSCTS) || !test_bit(TTY_THROTTLED, &tty->flags)) { diff -ur --new-file old/linux/drivers/char/softdog.c new/linux/drivers/char/softdog.c --- old/linux/drivers/char/softdog.c Mon Aug 24 22:14:10 1998 +++ new/linux/drivers/char/softdog.c Sun Apr 25 02:49:37 1999 @@ -132,7 +132,6 @@ static int softdog_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - int i; static struct watchdog_info ident= { 0, @@ -144,11 +143,9 @@ default: return -ENOIOCTLCMD; case WDIOC_GETSUPPORT: - i = verify_area(VERIFY_WRITE, (void*) arg, sizeof(struct watchdog_info)); - if (i) - return i; - else - return copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident)); + if(copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident))) + return -EFAULT; + return 0; case WDIOC_GETSTATUS: case WDIOC_GETBOOTSTATUS: return put_user(0,(int *)arg); diff -ur --new-file old/linux/drivers/char/specialix.c new/linux/drivers/char/specialix.c --- old/linux/drivers/char/specialix.c Tue Dec 29 20:29:54 1998 +++ new/linux/drivers/char/specialix.c Sun May 2 18:51:09 1999 @@ -2355,6 +2355,9 @@ int irq [SX_NBOARD] = {0,}; +MODULE_PARM(iobase,"1-" __MODULE_STRING(SX_NBOARD) "i"); +MODULE_PARM(irq,"1-" __MODULE_STRING(SX_NBOARD) "i"); + /* * You can setup up to 4 boards. * by specifying "iobase=0xXXX,0xXXX ..." as insmod parameter. diff -ur --new-file old/linux/drivers/char/stallion.c new/linux/drivers/char/stallion.c --- old/linux/drivers/char/stallion.c Tue Dec 29 20:29:54 1998 +++ new/linux/drivers/char/stallion.c Fri Apr 16 17:20:23 1999 @@ -3,7 +3,7 @@ /* * stallion.c -- stallion multiport serial driver. * - * Copyright (C) 1996-1998 Stallion Technologies (support@stallion.oz.au). + * Copyright (C) 1996-1999 Stallion Technologies (support@stallion.oz.au). * Copyright (C) 1994-1996 Greg Ungerer (gerg@stallion.oz.au). * * This code is loosely based on the Linux serial driver, written by @@ -26,29 +26,20 @@ /*****************************************************************************/ +#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 @@ -78,7 +69,7 @@ * stl_brdconf[] array is a board. Each line contains io/irq/memory * ranges for that board (as well as what type of board it is). * Some examples: - * { BRD_EASYIO, 0x2a0, 0, 0, 10, 0 } + * { BRD_EASYIO, 0x2a0, 0, 0, 10, 0 }, * This line would configure an EasyIO board (4 or 8, no difference), * at io address 2a0 and irq 10. * Another example: @@ -105,7 +96,7 @@ } stlconf_t; static stlconf_t stl_brdconf[] = { - { BRD_EASYIO, 0x2a0, 0, 0, 10, 0 }, + /*{ BRD_EASYIO, 0x2a0, 0, 0, 10, 0 },*/ }; static int stl_nrbrds = sizeof(stl_brdconf) / sizeof(stlconf_t); @@ -144,7 +135,7 @@ */ static char *stl_drvtitle = "Stallion Multiport Serial Driver"; static char *stl_drvname = "stallion"; -static char *stl_drvversion = "5.4.7"; +static char *stl_drvversion = "5.5.1"; static char *stl_serialname = "ttyE"; static char *stl_calloutname = "cue"; @@ -259,6 +250,85 @@ /*****************************************************************************/ +#ifdef MODULE +/* + * Define some string labels for arguments passed from the module + * load line. These allow for easy board definitions, and easy + * modification of the io, memory and irq resoucres. + */ + +static char *board0[4]; +static char *board1[4]; +static char *board2[4]; +static char *board3[4]; + +static char **stl_brdsp[] = { + (char **) &board0, + (char **) &board1, + (char **) &board2, + (char **) &board3 +}; + +/* + * Define a set of common board names, and types. This is used to + * parse any module arguments. + */ + +typedef struct stlbrdtype { + char *name; + int type; +} stlbrdtype_t; + +static stlbrdtype_t stl_brdstr[] = { + { "easyio", BRD_EASYIO }, + { "eio", BRD_EASYIO }, + { "20", BRD_EASYIO }, + { "ec8/32", BRD_ECH }, + { "ec8/32-at", BRD_ECH }, + { "ec8/32-isa", BRD_ECH }, + { "ech", BRD_ECH }, + { "echat", BRD_ECH }, + { "21", BRD_ECH }, + { "ec8/32-mc", BRD_ECHMC }, + { "ec8/32-mca", BRD_ECHMC }, + { "echmc", BRD_ECHMC }, + { "echmca", BRD_ECHMC }, + { "22", BRD_ECHMC }, + { "ec8/32-pc", BRD_ECHPCI }, + { "ec8/32-pci", BRD_ECHPCI }, + { "26", BRD_ECHPCI }, + { "ec8/64-pc", BRD_ECH64PCI }, + { "ec8/64-pci", BRD_ECH64PCI }, + { "ech-pci", BRD_ECH64PCI }, + { "echpci", BRD_ECH64PCI }, + { "echpc", BRD_ECH64PCI }, + { "27", BRD_ECH64PCI }, + { "easyio-pc", BRD_EASYIOPCI }, + { "easyio-pci", BRD_EASYIOPCI }, + { "eio-pci", BRD_EASYIOPCI }, + { "eiopci", BRD_EASYIOPCI }, + { "28", BRD_EASYIOPCI }, +}; + +/* + * Define the module agruments. + */ +MODULE_AUTHOR("Greg Ungerer"); +MODULE_DESCRIPTION("Stallion Multiport Serial Driver"); + +MODULE_PARM(board0, "1-4s"); +MODULE_PARM_DESC(board0, "Board 0 config -> name[,ioaddr[,ioaddr2][,irq]]"); +MODULE_PARM(board1, "1-4s"); +MODULE_PARM_DESC(board1, "Board 1 config -> name[,ioaddr[,ioaddr2][,irq]]"); +MODULE_PARM(board2, "1-4s"); +MODULE_PARM_DESC(board2, "Board 2 config -> name[,ioaddr[,ioaddr2][,irq]]"); +MODULE_PARM(board3, "1-4s"); +MODULE_PARM_DESC(board3, "Board 3 config -> name[,ioaddr[,ioaddr2][,irq]]"); + +#endif + +/*****************************************************************************/ + /* * Hardware ID bits for the EasyIO and ECH boards. These defines apply * to the directly accessible io ports of these boards (not the uarts - @@ -399,9 +469,11 @@ /* * Define some handy local macros... */ -#ifndef MIN -#define MIN(a,b) (((a) <= (b)) ? (a) : (b)) -#endif +#undef MIN +#define MIN(a,b) (((a) <= (b)) ? (a) : (b)) + +#undef TOLOWER +#define TOLOWER(x) ((((x) >= 'A') && ((x) <= 'Z')) ? ((x) + 0x20) : (x)) /*****************************************************************************/ @@ -412,6 +484,10 @@ #ifdef MODULE int init_module(void); void cleanup_module(void); +static void stl_argbrds(void); +static int stl_parsebrd(stlconf_t *confp, char **argp); + +static unsigned long stl_atol(char *str); #endif int stl_init(void); @@ -459,15 +535,17 @@ static void stl_echpci64intr(stlbrd_t *brdp); static void stl_offintr(void *private); static void *stl_memalloc(int len); +static stlbrd_t *stl_allocbrd(void); static stlport_t *stl_getport(int brdnr, int panelnr, int portnr); static inline int stl_initbrds(void); static inline int stl_initeio(stlbrd_t *brdp); static inline int stl_initech(stlbrd_t *brdp); +static inline int stl_getbrdnr(void); #ifdef CONFIG_PCI static inline int stl_findpcibrds(void); -static inline int stl_initpcibrd(int brdtype, struct pci_dev *dev); +static inline int stl_initpcibrd(int brdtype, struct pci_dev *devp); #endif /* @@ -747,7 +825,8 @@ kfree_s(stl_tmpwritebuf, STL_TXBUFSIZE); for (i = 0; (i < stl_nrbrds); i++) { - brdp = stl_brds[i]; + if ((brdp = stl_brds[i]) == (stlbrd_t *) NULL) + continue; for (j = 0; (j < STL_MAXPANELS); j++) { panelp = brdp->panels[j]; if (panelp == (stlpanel_t *) NULL) @@ -779,6 +858,124 @@ restore_flags(flags); } +/*****************************************************************************/ + +/* + * Check for any arguments passed in on the module load command line. + */ + +static void stl_argbrds() +{ + stlconf_t conf; + stlbrd_t *brdp; + int nrargs, i; + +#if DEBUG + printk("stl_argbrds()\n"); +#endif + + nrargs = sizeof(stl_brdsp) / sizeof(char **); + + for (i = stl_nrbrds; (i < nrargs); i++) { + memset(&conf, 0, sizeof(conf)); + if (stl_parsebrd(&conf, stl_brdsp[i]) == 0) + continue; + if ((brdp = stl_allocbrd()) == (stlbrd_t *) NULL) + continue; + stl_nrbrds = i + 1; + brdp->brdnr = i; + brdp->brdtype = conf.brdtype; + brdp->ioaddr1 = conf.ioaddr1; + brdp->ioaddr2 = conf.ioaddr2; + brdp->irq = conf.irq; + brdp->irqtype = conf.irqtype; + stl_brdinit(brdp); + } +} + +/*****************************************************************************/ + +/* + * Convert an ascii string number into an unsigned long. + */ + +static unsigned long stl_atol(char *str) +{ + unsigned long val; + int base, c; + char *sp; + + val = 0; + sp = str; + if ((*sp == '0') && (*(sp+1) == 'x')) { + base = 16; + sp += 2; + } else if (*sp == '0') { + base = 8; + sp++; + } else { + base = 10; + } + + for (; (*sp != 0); sp++) { + c = (*sp > '9') ? (TOLOWER(*sp) - 'a' + 10) : (*sp - '0'); + if ((c < 0) || (c >= base)) { + printk("STALLION: invalid argument %s\n", str); + val = 0; + break; + } + val = (val * base) + c; + } + return(val); +} + +/*****************************************************************************/ + +/* + * Parse the supplied argument string, into the board conf struct. + */ + +static int stl_parsebrd(stlconf_t *confp, char **argp) +{ + char *sp; + int nrbrdnames, i; + +#if DEBUG + printk("stl_parsebrd(confp=%x,argp=%x)\n", (int) confp, (int) argp); +#endif + + if ((argp[0] == (char *) NULL) || (*argp[0] == 0)) + return(0); + + for (sp = argp[0], i = 0; ((*sp != 0) && (i < 25)); sp++, i++) + *sp = TOLOWER(*sp); + + nrbrdnames = sizeof(stl_brdstr) / sizeof(stlbrdtype_t); + for (i = 0; (i < nrbrdnames); i++) { + if (strcmp(stl_brdstr[i].name, argp[0]) == 0) + break; + } + if (i >= nrbrdnames) { + printk("STALLION: unknown board name, %s?\n", argp[0]); + return(0); + } + + confp->brdtype = stl_brdstr[i].type; + + i = 1; + if ((argp[i] != (char *) NULL) && (*argp[i] != 0)) + confp->ioaddr1 = stl_atol(argp[i]); + i++; + if (confp->brdtype == BRD_ECH) { + if ((argp[i] != (char *) NULL) && (*argp[i] != 0)) + confp->ioaddr2 = stl_atol(argp[i]); + i++; + } + if ((argp[i] != (char *) NULL) && (*argp[i] != 0)) + confp->irq = stl_atol(argp[i]); + return(1); +} + #endif /*****************************************************************************/ @@ -794,6 +991,28 @@ /*****************************************************************************/ +/* + * Allocate a new board structure. Fill out the basic info in it. + */ + +static stlbrd_t *stl_allocbrd() +{ + stlbrd_t *brdp; + + brdp = (stlbrd_t *) stl_memalloc(sizeof(stlbrd_t)); + if (brdp == (stlbrd_t *) NULL) { + printk("STALLION: failed to allocate memory (size=%d)\n", + sizeof(stlbrd_t)); + return((stlbrd_t *) NULL); + } + + memset(brdp, 0, sizeof(stlbrd_t)); + brdp->magic = STL_BOARDMAGIC; + return(brdp); +} + +/*****************************************************************************/ + static int stl_open(struct tty_struct *tty, struct file *filp) { stlport_t *portp; @@ -1121,7 +1340,6 @@ down(&stl_tmpwritesem); copy_from_user(stl_tmpwritebuf, chbuf, count); - up(&stl_tmpwritesem); chbuf = &stl_tmpwritebuf[0]; } @@ -1154,6 +1372,9 @@ clear_bit(ASYI_TXLOW, &portp->istate); stl_startrxtx(portp, -1, 1); + if (from_user) + up(&stl_tmpwritesem); + return(count); } @@ -2185,12 +2406,12 @@ } if (check_region(brdp->ioaddr1, brdp->iosize1)) { - printk("STALLION: Warning, unit %d I/O address %x conflicts " + printk("STALLION: Warning, board %d I/O address %x conflicts " "with another device\n", brdp->brdnr, brdp->ioaddr1); } if (brdp->iosize2 > 0) { if (check_region(brdp->ioaddr2, brdp->iosize2)) { - printk("STALLION: Warning, unit %d I/O address %x " + printk("STALLION: Warning, board %d I/O address %x " "conflicts with another device\n", brdp->brdnr, brdp->ioaddr2); } @@ -2376,7 +2597,7 @@ conflict = check_region(brdp->ioaddr2, brdp->iosize2) ? brdp->ioaddr2 : 0; if (conflict) { - printk("STALLION: Warning, unit %d I/O address %x conflicts " + printk("STALLION: Warning, board %d I/O address %x conflicts " "with another device\n", brdp->brdnr, conflict); } @@ -2499,14 +2720,14 @@ stl_initech(brdp); break; default: - printk("STALLION: unit=%d is unknown board type=%d\n", + printk("STALLION: board=%d is unknown board type=%d\n", brdp->brdnr, brdp->brdtype); return(ENODEV); } stl_brds[brdp->brdnr] = brdp; if ((brdp->state & BRD_FOUND) == 0) { - printk("STALLION: %s board not found, unit=%d io=%x irq=%d\n", + printk("STALLION: %s board not found, board=%d io=%x irq=%d\n", stl_brdnames[brdp->brdtype], brdp->brdnr, brdp->ioaddr1, brdp->irq); return(ENODEV); @@ -2516,7 +2737,7 @@ if (brdp->panels[i] != (stlpanel_t *) NULL) stl_initports(brdp, brdp->panels[i]); - printk("STALLION: %s found, unit=%d io=%x irq=%d " + printk("STALLION: %s found, board=%d io=%x irq=%d " "nrpanels=%d nrports=%d\n", stl_brdnames[brdp->brdtype], brdp->brdnr, brdp->ioaddr1, brdp->irq, brdp->nrpanels, brdp->nrports); @@ -2525,6 +2746,26 @@ /*****************************************************************************/ +/* + * Find the next available board number that is free. + */ + +static inline int stl_getbrdnr() +{ + int i; + + for (i = 0; (i < STL_MAXBRDS); i++) { + if (stl_brds[i] == (stlbrd_t *) NULL) { + if (i >= stl_nrbrds) + stl_nrbrds = i + 1; + return(i); + } + } + return(-1); +} + +/*****************************************************************************/ + #ifdef CONFIG_PCI /* @@ -2533,42 +2774,32 @@ * configuration space. */ -static inline int stl_initpcibrd(int brdtype, struct pci_dev *dev) +static inline int stl_initpcibrd(int brdtype, struct pci_dev *devp) { - unsigned int bar[4]; stlbrd_t *brdp; - int i; - unsigned char irq; #if DEBUG - printk("stl_initpcibrd(brdtype=%d,busnr=%x,devnr=%x)\n", - brdtype, dev->bus->number, dev->devfn); + printk("stl_initpcibrd(brdtype=%d,busnr=%x,devnr=%x)\n", brdtype, + dev->bus->number, dev->devfn); #endif - brdp = (stlbrd_t *) stl_memalloc(sizeof(stlbrd_t)); - if (brdp == (stlbrd_t *) NULL) { - printk("STALLION: failed to allocate memory (size=%d)\n", - sizeof(stlbrd_t)); + if ((brdp = stl_allocbrd()) == (stlbrd_t *) NULL) return(-ENOMEM); + if ((brdp->brdnr = stl_getbrdnr()) < 0) { + printk("STALLION: too many boards found, " + "maximum supported %d\n", STL_MAXBRDS); + return(0); } - - memset(brdp, 0, sizeof(stlbrd_t)); - brdp->magic = STL_BOARDMAGIC; - brdp->brdnr = stl_nrbrds++; brdp->brdtype = brdtype; /* - * Read in all the BAR registers from this board. Different Stallion - * boards use these in different ways, so we just read in the whole - * lot and then figure out what is what later. - */ - for (i = 0; (i < 4); i++) - bar[i] = dev->base_address[i]; - irq = dev->irq; - + * Different Stallion boards use the BAR registers in different ways, + * so set up io addresses based on board type. + */ #if DEBUG printk("%s(%d): BAR[]=%x,%x,%x,%x IRQ=%x\n", __FILE__, __LINE__, - bar[0], bar[1], bar[2], bar[3], irq); + devp->base_address[0], devp->base_address[1], + devp->base_address[2], devp->base_address[3], devp->irq); #endif /* @@ -2577,29 +2808,34 @@ */ switch (brdtype) { case BRD_ECHPCI: - brdp->ioaddr2 = (bar[0] & PCI_BASE_ADDRESS_IO_MASK); - brdp->ioaddr1 = (bar[1] & PCI_BASE_ADDRESS_IO_MASK); + brdp->ioaddr2 = (devp->base_address[0] & + PCI_BASE_ADDRESS_IO_MASK); + brdp->ioaddr1 = (devp->base_address[1] & + PCI_BASE_ADDRESS_IO_MASK); break; case BRD_ECH64PCI: - brdp->ioaddr2 = (bar[2] & PCI_BASE_ADDRESS_IO_MASK); - brdp->ioaddr1 = (bar[1] & PCI_BASE_ADDRESS_IO_MASK); + brdp->ioaddr2 = (devp->base_address[2] & + PCI_BASE_ADDRESS_IO_MASK); + brdp->ioaddr1 = (devp->base_address[1] & + PCI_BASE_ADDRESS_IO_MASK); break; case BRD_EASYIOPCI: - brdp->ioaddr1 = (bar[2] & PCI_BASE_ADDRESS_IO_MASK); - brdp->ioaddr2 = (bar[1] & PCI_BASE_ADDRESS_IO_MASK); + brdp->ioaddr1 = (devp->base_address[2] & + PCI_BASE_ADDRESS_IO_MASK); + brdp->ioaddr2 = (devp->base_address[1] & + PCI_BASE_ADDRESS_IO_MASK); break; default: printk("STALLION: unknown PCI board type=%d\n", brdtype); break; } - brdp->irq = irq; + brdp->irq = devp->irq; stl_brdinit(brdp); return(0); } - /*****************************************************************************/ /* @@ -2621,17 +2857,8 @@ return(0); for (i = 0; (i < stl_nrpcibrds); i++) - while ((dev = pci_find_device(stl_pcibrds[i].vendid, stl_pcibrds[i].devid, dev))) { - -/* - * Check that we can handle more boards... - */ - if (stl_nrbrds >= STL_MAXBRDS) { - printk("STALLION: too many boards found, " - "maximum supported %d\n", STL_MAXBRDS); - i = stl_nrpcibrds; - break; - } + while ((dev = pci_find_device(stl_pcibrds[i].vendid, + stl_pcibrds[i].devid, dev))) { /* * Found a device on the PCI bus that has our vendor and @@ -2680,15 +2907,11 @@ */ for (i = 0; (i < stl_nrbrds); i++) { confp = &stl_brdconf[i]; - brdp = (stlbrd_t *) stl_memalloc(sizeof(stlbrd_t)); - if (brdp == (stlbrd_t *) NULL) { - printk("STALLION: failed to allocate memory " - "(size=%d)\n", sizeof(stlbrd_t)); +#ifdef MODULE + stl_parsebrd(confp, stl_brdsp[i]); +#endif + if ((brdp = stl_allocbrd()) == (stlbrd_t *) NULL) return(-ENOMEM); - } - memset(brdp, 0, sizeof(stlbrd_t)); - - brdp->magic = STL_BOARDMAGIC; brdp->brdnr = i; brdp->brdtype = confp->brdtype; brdp->ioaddr1 = confp->ioaddr1; @@ -2698,11 +2921,14 @@ stl_brdinit(brdp); } -#ifdef CONFIG_PCI /* - * If the PCI BIOS support is compiled in then let's go looking for - * ECH-PCI boards. + * Find any dynamically supported boards. That is via module load + * line options or auto-detected on the PCI bus. */ +#ifdef MODULE + stl_argbrds(); +#endif +#ifdef CONFIG_PCI stl_findpcibrds(); #endif diff -ur --new-file old/linux/drivers/char/synclink.c new/linux/drivers/char/synclink.c --- old/linux/drivers/char/synclink.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/char/synclink.c Sun Mar 28 20:31:31 1999 @@ -0,0 +1,6989 @@ +/* + * linux/drivers/char/synclink.c + * + * Device driver for Microgate SyncLink ISA and PCI + * high speed multiprotocol serial adapters. + * + * written by Paul Fulghum for Microgate Corporation + * paulkf@microgate.com + * + * Microgate and SyncLink are trademarks of Microgate Corporation + * + * Derived from serial.c written by Theodore Ts'o and Linus Torvalds + * + * Original release 01/11/99 + * + * This code is released under the GNU General Public License (GPL) + * + * This driver is primarily intended for use in synchronous + * HDLC mode. Asynchronous mode is also provided. + * + * When operating in synchronous mode, each call to mgsl_write() + * contains exactly one complete HDLC frame. Calling mgsl_put_char + * will start assembling an HDLC frame that will not be sent until + * mgsl_flush_chars or mgsl_write is called. + * + * Synchronous receive data is reported as complete frames. To accomplish + * this, the TTY flip buffer is bypassed (too small to hold largest + * frame and may fragment frames) and the line discipline + * receive entry point is called directly. + * + * This driver has been tested with a slightly modified ppp.c driver + * for synchronous PPP. + * + * THIS SOFTWARE IS PROVIDED ``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. + */ + +#define VERSION(ver,rel,seq) (((ver)<<16) | ((rel)<<8) | (seq)) +#define BREAKPOINT() asm(" int $3"); + +#define MAX_ISA_DEVICES 10 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if LINUX_VERSION_CODE >= VERSION(2,1,0) +#include +#include +#include +#else +#include +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#if LINUX_VERSION_CODE >= VERSION(2,1,4) +#include +#define GET_USER(error,value,addr) error = get_user(value,addr) +#define COPY_FROM_USER(error,dest,src,size) error = copy_from_user(dest,src,size) ? -EFAULT : 0 +#define PUT_USER(error,value,addr) error = put_user(value,addr) +#define COPY_TO_USER(error,dest,src,size) error = copy_to_user(dest,src,size) ? -EFAULT : 0 + +#if LINUX_VERSION_CODE >= VERSION(2,1,5) +#include +#endif + +#else /* 2.0.x and 2.1.x before 2.1.4 */ + +#define GET_USER(error,value,addr) \ +do { \ + error = verify_area (VERIFY_READ, (void *) addr, sizeof (value)); \ + if (error == 0) \ + value = get_user(addr); \ +} while (0) + +#define COPY_FROM_USER(error,dest,src,size) \ +do { \ + error = verify_area (VERIFY_READ, (void *) src, size); \ + if (error == 0) \ + memcpy_fromfs (dest, src, size); \ +} while (0) + +#define PUT_USER(error,value,addr) \ +do { \ + error = verify_area (VERIFY_WRITE, (void *) addr, sizeof (value)); \ + if (error == 0) \ + put_user (value, addr); \ +} while (0) + +#define COPY_TO_USER(error,dest,src,size) \ +do { \ + error = verify_area (VERIFY_WRITE, (void *) dest, size); \ + if (error == 0) \ + memcpy_tofs (dest, src, size); \ +} while (0) + +#endif + +#if LINUX_VERSION_CODE < VERSION(2,1,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, 115200, 230400, 460800, 0 }; + +#define __init +#define ioremap(a,b) vremap((a),(b)) +#define iounmap(a) vfree((a)) +#define SERIAL_TYPE_NORMAL 1 +#define SERIAL_TYPE_CALLOUT 2 +typedef int spinlock_t; +#define spin_lock_irqsave(a,b) {save_flags((b));cli();} +#define spin_unlock_irqrestore(a,b) {restore_flags((b));} +#define spin_lock(a) +#define spin_unlock(a) +#define schedule_timeout(a){current->timeout = jiffies + (a); schedule();} +#define signal_pending(a) ((a)->signal & ~(a)->blocked) +#endif + + + +#include "linux/synclink.h" + +#define RCLRVALUE 0xffff + +MGSL_PARAMS default_params = { + MGSL_MODE_HDLC, /* unsigned long mode */ + 0, /* unsigned char loopback; */ + HDLC_FLAG_UNDERRUN_ABORT15, /* unsigned short flags; */ + HDLC_ENCODING_NRZI_SPACE, /* unsigned char encoding; */ + 0, /* unsigned long clock_speed; */ + 0xff, /* unsigned char addr_filter; */ + HDLC_CRC_16_CCITT, /* unsigned short crc_type; */ + HDLC_PREAMBLE_LENGTH_8BITS, /* unsigned char preamble_length; */ + HDLC_PREAMBLE_PATTERN_NONE, /* unsigned char preamble; */ + 9600, /* unsigned long data_rate; */ + 8, /* unsigned char data_bits; */ + 1, /* unsigned char stop_bits; */ + ASYNC_PARITY_NONE /* unsigned char parity; */ +}; + +#define SHARED_MEM_ADDRESS_SIZE 0x40000 +#define BUFFERLISTSIZE (PAGE_SIZE) +#define DMABUFFERSIZE (PAGE_SIZE) +#define MAXRXFRAMES 7 + +typedef struct _DMABUFFERENTRY +{ + u32 phys_addr; /* 32-bit flat physical address of data buffer */ + u16 count; /* buffer size/data count */ + u16 status; /* Control/status field */ + u16 rcc; /* character count field */ + u16 reserved; /* padding required by 16C32 */ + u32 link; /* 32-bit flat link to next buffer entry */ + char *virt_addr; /* virtual address of data buffer */ + u32 phys_entry; /* physical address of this buffer entry */ +} DMABUFFERENTRY, *DMAPBUFFERENTRY; + +/* The queue of BH actions to be performed */ + +#define BH_TYPE_RECEIVE_DATA 1 +#define BH_TYPE_RECEIVE_STATUS 2 +#define BH_TYPE_RECEIVE_DMA 3 +#define BH_TYPE_TRANSMIT_DATA 4 +#define BH_TYPE_TRANSMIT_STATUS 5 +#define BH_TYPE_STATUS 6 + +typedef struct _BH_EVENT { + unsigned char type; /* Set by interrupt routines to reqst */ + u16 status; + struct _BH_EVENT *link; + +} BH_EVENT, *BH_QUEUE; /* Queue of BH actions to be done. */ + +#define MAX_BH_QUEUE_ENTRIES 200 + +#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) +/* + * Device instance data structure + */ + +struct mgsl_struct { + int magic; + int flags; + int count; /* count of opens */ + int line; + unsigned short close_delay; + unsigned short closing_wait; /* time to wait before closing */ + + struct mgsl_icount icount; + + struct termios normal_termios; + struct termios callout_termios; + + struct tty_struct *tty; + int timeout; + int x_char; /* xon/xoff character */ + int blocked_open; /* # of blocked opens */ + long session; /* Session of opening process */ + long pgrp; /* pgrp of opening process */ + u16 read_status_mask; + u16 ignore_status_mask; + unsigned char *xmit_buf; + int xmit_head; + int xmit_tail; + int xmit_cnt; + + struct wait_queue *open_wait; + struct wait_queue *close_wait; + + struct wait_queue *status_event_wait_q; + struct wait_queue *event_wait_q; + struct timer_list tx_timer; /* HDLC transmit timeout timer */ + struct mgsl_struct *next_device; /* device list link */ + + spinlock_t irq_spinlock; /* spinlock for synchronizing with ISR */ + struct tq_struct task; /* task structure for scheduling bh */ + + u32 EventMask; /* event trigger mask */ + u32 RecordedEvents; /* pending events */ + + u32 max_frame_size; /* as set by device config */ + + BH_EVENT bh_queue[MAX_BH_QUEUE_ENTRIES]; /* Pointer to alloc'ed block */ + BH_QUEUE bh_queue_head; /* Queue of BH actions */ + BH_QUEUE bh_queue_tail; /* Tail of above for perf. */ + BH_QUEUE free_bh_queue_head; /* Queue of Free BH */ + BH_QUEUE free_bh_queue_tail; /* Tail of above for perf. */ + BH_QUEUE bh_action; /* Action for BH */ + int bh_running; /* Protection from multiple */ + int isr_overflow; + int bh_requested; + + char *buffer_list; /* virtual address of Rx & Tx buffer lists */ + unsigned long buffer_list_phys; + + unsigned int rx_buffer_count; /* count of total allocated Rx buffers */ + DMABUFFERENTRY *rx_buffer_list; /* list of receive buffer entries */ + unsigned int current_rx_buffer; + + unsigned int tx_buffer_count; /* count of total allocated Tx buffers */ + DMABUFFERENTRY *tx_buffer_list; /* list of transmit buffer entries */ + + int rx_enabled; + int rx_overflow; + + int tx_enabled; + int tx_active; + u32 idle_mode; + + u16 cmr_value; + + char device_name[25]; /* device instance name */ + + unsigned int bus_type; /* expansion bus type (ISA,EISA,PCI) */ + unsigned char bus; /* expansion bus number (zero based) */ + unsigned char function; /* PCI device number */ + + unsigned int io_base; /* base I/O address of adapter */ + unsigned int io_addr_size; /* size of the I/O address range */ + int io_addr_requested; /* nonzero if I/O address requested */ + + unsigned int irq_level; /* interrupt level */ + unsigned long irq_flags; + int irq_requested; /* nonzero if IRQ requested */ + + unsigned int dma_level; /* DMA channel */ + int dma_requested; /* nonzero if dma channel requested */ + + u16 mbre_bit; + u16 loopback_bits; + u16 usc_idle_mode; + + MGSL_PARAMS params; /* communications parameters */ + + unsigned char serial_signals; /* current serial signal states */ + + int irq_occurred; /* for diagnostics use */ + unsigned int init_error; /* Initialization startup error (DIAGS) */ + int fDiagnosticsmode; /* Driver in Diagnostic mode? (DIAGS) */ + + u32 last_mem_alloc; + unsigned char* memory_base; /* shared memory address (PCI only) */ + u32 phys_memory_base; + + unsigned char* lcr_base; /* local config registers (PCI only) */ + u32 phys_lcr_base; + u32 lcr_offset; + + u32 misc_ctrl_value; + char flag_buf[HDLC_MAX_FRAME_SIZE]; + char char_buf[HDLC_MAX_FRAME_SIZE]; + BOOLEAN drop_rts_on_tx_done; +}; + +#define MGSL_MAGIC 0x5401 + +/* + * The size of the serial xmit buffer is 1 page, or 4096 bytes + */ +#define SERIAL_XMIT_SIZE 4096 + + +/* + * These macros define the offsets used in calculating the + * I/O address of the specified USC registers. + */ + + +#define DCPIN 2 /* Bit 1 of I/O address */ +#define SDPIN 4 /* Bit 2 of I/O address */ + +#define DCAR 0 /* DMA command/address register */ +#define CCAR SDPIN /* channel command/address register */ +#define DATAREG DCPIN + SDPIN /* serial data register */ +#define MSBONLY 0x41 +#define LSBONLY 0x40 + +/* + * These macros define the register address (ordinal number) + * used for writing address/value pairs to the USC. + */ + +#define CMR 0x02 /* Channel mode Register */ +#define CCSR 0x04 /* Channel Command/status Register */ +#define CCR 0x06 /* Channel Control Register */ +#define PSR 0x08 /* Port status Register */ +#define PCR 0x0a /* Port Control Register */ +#define TMDR 0x0c /* Test mode Data Register */ +#define TMCR 0x0e /* Test mode Control Register */ +#define CMCR 0x10 /* Clock mode Control Register */ +#define HCR 0x12 /* Hardware Configuration Register */ +#define IVR 0x14 /* Interrupt Vector Register */ +#define IOCR 0x16 /* Input/Output Control Register */ +#define ICR 0x18 /* Interrupt Control Register */ +#define DCCR 0x1a /* Daisy Chain Control Register */ +#define MISR 0x1c /* Misc Interrupt status Register */ +#define SICR 0x1e /* status Interrupt Control Register */ +#define RDR 0x20 /* Receive Data Register */ +#define RMR 0x22 /* Receive mode Register */ +#define RCSR 0x24 /* Receive Command/status Register */ +#define RICR 0x26 /* Receive Interrupt Control Register */ +#define RSR 0x28 /* Receive Sync Register */ +#define RCLR 0x2a /* Receive count Limit Register */ +#define RCCR 0x2c /* Receive Character count Register */ +#define TC0R 0x2e /* Time Constant 0 Register */ +#define TDR 0x30 /* Transmit Data Register */ +#define TMR 0x32 /* Transmit mode Register */ +#define TCSR 0x34 /* Transmit Command/status Register */ +#define TICR 0x36 /* Transmit Interrupt Control Register */ +#define TSR 0x38 /* Transmit Sync Register */ +#define TCLR 0x3a /* Transmit count Limit Register */ +#define TCCR 0x3c /* Transmit Character count Register */ +#define TC1R 0x3e /* Time Constant 1 Register */ + + +/* + * MACRO DEFINITIONS FOR DMA REGISTERS + */ + +#define DCR 0x06 /* DMA Control Register (shared) */ +#define DACR 0x08 /* DMA Array count Register (shared) */ +#define BDCR 0x12 /* Burst/Dwell Control Register (shared) */ +#define DIVR 0x14 /* DMA Interrupt Vector Register (shared) */ +#define DICR 0x18 /* DMA Interrupt Control Register (shared) */ +#define CDIR 0x1a /* Clear DMA Interrupt Register (shared) */ +#define SDIR 0x1c /* Set DMA Interrupt Register (shared) */ + +#define TDMR 0x02 /* Transmit DMA mode Register */ +#define TDIAR 0x1e /* Transmit DMA Interrupt Arm Register */ +#define TBCR 0x2a /* Transmit Byte count Register */ +#define TARL 0x2c /* Transmit Address Register (low) */ +#define TARU 0x2e /* Transmit Address Register (high) */ +#define NTBCR 0x3a /* Next Transmit Byte count Register */ +#define NTARL 0x3c /* Next Transmit Address Register (low) */ +#define NTARU 0x3e /* Next Transmit Address Register (high) */ + +#define RDMR 0x82 /* Receive DMA mode Register (non-shared) */ +#define RDIAR 0x9e /* Receive DMA Interrupt Arm Register */ +#define RBCR 0xaa /* Receive Byte count Register */ +#define RARL 0xac /* Receive Address Register (low) */ +#define RARU 0xae /* Receive Address Register (high) */ +#define NRBCR 0xba /* Next Receive Byte count Register */ +#define NRARL 0xbc /* Next Receive Address Register (low) */ +#define NRARU 0xbe /* Next Receive Address Register (high) */ + + +/* + * MACRO DEFINITIONS FOR MODEM STATUS BITS + */ + +#define MODEMSTATUS_DTR 0x80 +#define MODEMSTATUS_DSR 0x40 +#define MODEMSTATUS_RTS 0x20 +#define MODEMSTATUS_CTS 0x10 +#define MODEMSTATUS_RI 0x04 +#define MODEMSTATUS_DCD 0x01 + + +/* + * Channel Command/Address Register (CCAR) Command Codes + */ + +#define RTCmd_Null 0x0000 +#define RTCmd_ResetHighestIus 0x1000 +#define RTCmd_TriggerChannelLoadDma 0x2000 +#define RTCmd_TriggerRxDma 0x2800 +#define RTCmd_TriggerTxDma 0x3000 +#define RTCmd_TriggerRxAndTxDma 0x3800 +#define RTCmd_PurgeRxFifo 0x4800 +#define RTCmd_PurgeTxFifo 0x5000 +#define RTCmd_PurgeRxAndTxFifo 0x5800 +#define RTCmd_LoadRcc 0x6800 +#define RTCmd_LoadTcc 0x7000 +#define RTCmd_LoadRccAndTcc 0x7800 +#define RTCmd_LoadTC0 0x8800 +#define RTCmd_LoadTC1 0x9000 +#define RTCmd_LoadTC0AndTC1 0x9800 +#define RTCmd_SerialDataLSBFirst 0xa000 +#define RTCmd_SerialDataMSBFirst 0xa800 +#define RTCmd_SelectBigEndian 0xb000 +#define RTCmd_SelectLittleEndian 0xb800 + + +/* + * DMA Command/Address Register (DCAR) Command Codes + */ + +#define DmaCmd_Null 0x0000 +#define DmaCmd_ResetTxChannel 0x1000 +#define DmaCmd_ResetRxChannel 0x1200 +#define DmaCmd_StartTxChannel 0x2000 +#define DmaCmd_StartRxChannel 0x2200 +#define DmaCmd_ContinueTxChannel 0x3000 +#define DmaCmd_ContinueRxChannel 0x3200 +#define DmaCmd_PauseTxChannel 0x4000 +#define DmaCmd_PauseRxChannel 0x4200 +#define DmaCmd_AbortTxChannel 0x5000 +#define DmaCmd_AbortRxChannel 0x5200 +#define DmaCmd_InitTxChannel 0x7000 +#define DmaCmd_InitRxChannel 0x7200 +#define DmaCmd_ResetHighestDmaIus 0x8000 +#define DmaCmd_ResetAllChannels 0x9000 +#define DmaCmd_StartAllChannels 0xa000 +#define DmaCmd_ContinueAllChannels 0xb000 +#define DmaCmd_PauseAllChannels 0xc000 +#define DmaCmd_AbortAllChannels 0xd000 +#define DmaCmd_InitAllChannels 0xf000 + +#define TCmd_Null 0x0000 +#define TCmd_ClearTxCRC 0x2000 +#define TCmd_SelectTicrTtsaData 0x4000 +#define TCmd_SelectTicrTxFifostatus 0x5000 +#define TCmd_SelectTicrIntLevel 0x6000 +#define TCmd_SelectTicrdma_level 0x7000 +#define TCmd_SendFrame 0x8000 +#define TCmd_SendAbort 0x9000 +#define TCmd_EnableDleInsertion 0xc000 +#define TCmd_DisableDleInsertion 0xd000 +#define TCmd_ClearEofEom 0xe000 +#define TCmd_SetEofEom 0xf000 + +#define RCmd_Null 0x0000 +#define RCmd_ClearRxCRC 0x2000 +#define RCmd_EnterHuntmode 0x3000 +#define RCmd_SelectRicrRtsaData 0x4000 +#define RCmd_SelectRicrRxFifostatus 0x5000 +#define RCmd_SelectRicrIntLevel 0x6000 +#define RCmd_SelectRicrdma_level 0x7000 + +/* + * Bits for enabling and disabling IRQs in Interrupt Control Register (ICR) + */ + +#define RECEIVE_STATUS BIT5 +#define RECEIVE_DATA BIT4 +#define TRANSMIT_STATUS BIT3 +#define TRANSMIT_DATA BIT2 +#define IO_PIN BIT1 +#define MISC BIT0 + + +/* + * Receive status Bits in Receive Command/status Register RCSR + */ + +#define RXSTATUS_SHORT_FRAME BIT8 +#define RXSTATUS_CODE_VIOLATION BIT8 +#define RXSTATUS_EXITED_HUNT BIT7 +#define RXSTATUS_IDLE_RECEIVED BIT6 +#define RXSTATUS_BREAK_RECEIVED BIT5 +#define RXSTATUS_ABORT_RECEIVED BIT5 +#define RXSTATUS_RXBOUND BIT4 +#define RXSTATUS_CRC_ERROR BIT3 +#define RXSTATUS_FRAMING_ERROR BIT3 +#define RXSTATUS_ABORT BIT2 +#define RXSTATUS_PARITY_ERROR BIT2 +#define RXSTATUS_OVERRUN BIT1 +#define RXSTATUS_DATA_AVAILABLE BIT0 +#define RXSTATUS_ALL 0x01f6 +#define usc_UnlatchRxstatusBits(a,b) usc_OutReg( (a), RCSR, (u16)((b) & RXSTATUS_ALL) ) + +/* + * Values for setting transmit idle mode in + * Transmit Control/status Register (TCSR) + */ +#define IDLEMODE_FLAGS 0x0000 +#define IDLEMODE_ALT_ONE_ZERO 0x0100 +#define IDLEMODE_ZERO 0x0200 +#define IDLEMODE_ONE 0x0300 +#define IDLEMODE_ALT_MARK_SPACE 0x0500 +#define IDLEMODE_SPACE 0x0600 +#define IDLEMODE_MARK 0x0700 + +/* + * Transmit status Bits in Transmit Command/status Register (TCSR) + */ + +#define TCSR_PRESERVE 0x0700 + +#define TXSTATUS_PREAMBLE_SENT BIT7 +#define TXSTATUS_IDLE_SENT BIT6 +#define TXSTATUS_ABORT_SENT BIT5 +#define TXSTATUS_EOF_SENT BIT4 +#define TXSTATUS_EOM_SENT BIT4 +#define TXSTATUS_CRC_SENT BIT3 +#define TXSTATUS_ALL_SENT BIT2 +#define TXSTATUS_UNDERRUN BIT1 +#define TXSTATUS_FIFO_EMPTY BIT0 +#define TXSTATUS_ALL 0x00fa +#define usc_UnlatchTxstatusBits(a,b) usc_OutReg( (a), TCSR, (u16)((a)->usc_idle_mode + ((b) & 0x00FF)) ) + + +#define MISCSTATUS_RXC_LATCHED BIT15 +#define MISCSTATUS_RXC BIT14 +#define MISCSTATUS_TXC_LATCHED BIT13 +#define MISCSTATUS_TXC BIT12 +#define MISCSTATUS_RI_LATCHED BIT11 +#define MISCSTATUS_RI BIT10 +#define MISCSTATUS_DSR_LATCHED BIT9 +#define MISCSTATUS_DSR BIT8 +#define MISCSTATUS_DCD_LATCHED BIT7 +#define MISCSTATUS_DCD BIT6 +#define MISCSTATUS_CTS_LATCHED BIT5 +#define MISCSTATUS_CTS BIT4 +#define MISCSTATUS_RCC_UNDERRUN BIT3 +#define MISCSTATUS_DPLL_NO_SYNC BIT2 +#define MISCSTATUS_BRG1_ZERO BIT1 +#define MISCSTATUS_BRG0_ZERO BIT0 + +#define usc_UnlatchIostatusBits(a,b) usc_OutReg((a),MISR,(u16)((b) & 0xaaa0)) +#define usc_UnlatchMiscstatusBits(a,b) usc_OutReg((a),MISR,(u16)((b) & 0x000f)) + +#define SICR_RXC_ACTIVE BIT15 +#define SICR_RXC_INACTIVE BIT14 +#define SICR_RXC (BIT15+BIT14) +#define SICR_TXC_ACTIVE BIT13 +#define SICR_TXC_INACTIVE BIT12 +#define SICR_TXC (BIT13+BIT12) +#define SICR_RI_ACTIVE BIT11 +#define SICR_RI_INACTIVE BIT10 +#define SICR_RI (BIT11+BIT10) +#define SICR_DSR_ACTIVE BIT9 +#define SICR_DSR_INACTIVE BIT8 +#define SICR_DSR (BIT9+BIT8) +#define SICR_DCD_ACTIVE BIT7 +#define SICR_DCD_INACTIVE BIT6 +#define SICR_DCD (BIT7+BIT6) +#define SICR_CTS_ACTIVE BIT5 +#define SICR_CTS_INACTIVE BIT4 +#define SICR_CTS (BIT5+BIT4) +#define SICR_RCC_UNDERFLOW BIT3 +#define SICR_DPLL_NO_SYNC BIT2 +#define SICR_BRG1_ZERO BIT1 +#define SICR_BRG0_ZERO BIT0 + +void usc_DisableMasterIrqBit( struct mgsl_struct *info ); +void usc_EnableMasterIrqBit( struct mgsl_struct *info ); +void usc_EnableInterrupts( struct mgsl_struct *info, u16 IrqMask ); +void usc_DisableInterrupts( struct mgsl_struct *info, u16 IrqMask ); +void usc_ClearIrqPendingBits( struct mgsl_struct *info, u16 IrqMask ); + +#define usc_EnableInterrupts( a, b ) \ + usc_OutReg( (a), ICR, (u16)((usc_InReg((a),ICR) & 0xff00) + 0xc0 + (b)) ) + +#define usc_DisableInterrupts( a, b ) \ + usc_OutReg( (a), ICR, (u16)((usc_InReg((a),ICR) & 0xff00) + 0x80 + (b)) ) + +#define usc_EnableMasterIrqBit(a) \ + usc_OutReg( (a), ICR, (u16)((usc_InReg((a),ICR) & 0x0f00) + 0xb000) ) + +#define usc_DisableMasterIrqBit(a) \ + usc_OutReg( (a), ICR, (u16)(usc_InReg((a),ICR) & 0x7f00) ) + +#define usc_ClearIrqPendingBits( a, b ) usc_OutReg( (a), DCCR, 0x40 + (b) ) + +/* + * Transmit status Bits in Transmit Control status Register (TCSR) + * and Transmit Interrupt Control Register (TICR) (except BIT2, BIT0) + */ + +#define TXSTATUS_PREAMBLE_SENT BIT7 +#define TXSTATUS_IDLE_SENT BIT6 +#define TXSTATUS_ABORT_SENT BIT5 +#define TXSTATUS_EOF BIT4 +#define TXSTATUS_CRC_SENT BIT3 +#define TXSTATUS_ALL_SENT BIT2 +#define TXSTATUS_UNDERRUN BIT1 +#define TXSTATUS_FIFO_EMPTY BIT0 + +#define DICR_MASTER BIT15 +#define DICR_TRANSMIT BIT0 +#define DICR_RECEIVE BIT1 + +#define usc_EnableDmaInterrupts(a,b) \ + usc_OutDmaReg( (a), DICR, (u16)(usc_InDmaReg((a),DICR) | (b)) ) + +#define usc_DisableDmaInterrupts(a,b) \ + usc_OutDmaReg( (a), DICR, (u16)(usc_InDmaReg((a),DICR) & ~(b)) ) + +#define usc_EnableStatusIrqs(a,b) \ + usc_OutReg( (a), SICR, (u16)(usc_InReg((a),SICR) | (b)) ) + +#define usc_DisablestatusIrqs(a,b) \ + usc_OutReg( (a), SICR, (u16)(usc_InReg((a),SICR) & ~(b)) ) + +/* Transmit status Bits in Transmit Control status Register (TCSR) */ +/* and Transmit Interrupt Control Register (TICR) (except BIT2, BIT0) */ + + +#define DISABLE_UNCONDITIONAL 0 +#define DISABLE_END_OF_FRAME 1 +#define ENABLE_UNCONDITIONAL 2 +#define ENABLE_AUTO_CTS 3 +#define ENABLE_AUTO_DCD 3 +#define usc_EnableTransmitter(a,b) \ + usc_OutReg( (a), TMR, (u16)((usc_InReg((a),TMR) & 0xfffc) | (b)) ) +#define usc_EnableReceiver(a,b) \ + usc_OutReg( (a), RMR, (u16)((usc_InReg((a),RMR) & 0xfffc) | (b)) ) + +u16 usc_InDmaReg( struct mgsl_struct *info, u16 Port ); +void usc_OutDmaReg( struct mgsl_struct *info, u16 Port, u16 Value ); +void usc_DmaCmd( struct mgsl_struct *info, u16 Cmd ); + +u16 usc_InReg( struct mgsl_struct *info, u16 Port ); +void usc_OutReg( struct mgsl_struct *info, u16 Port, u16 Value ); +void usc_RTCmd( struct mgsl_struct *info, u16 Cmd ); +void usc_RCmd( struct mgsl_struct *info, u16 Cmd ); +void usc_TCmd( struct mgsl_struct *info, u16 Cmd ); + +#define usc_TCmd(a,b) usc_OutReg((a), TCSR, (u16)((a)->usc_idle_mode + (b))) +#define usc_RCmd(a,b) usc_OutReg((a), RCSR, (b)) + +void usc_start_receiver( struct mgsl_struct *info ); +void usc_stop_receiver( struct mgsl_struct *info ); + +void usc_start_transmitter( struct mgsl_struct *info ); +void usc_stop_transmitter( struct mgsl_struct *info ); +void usc_set_txidle( struct mgsl_struct *info ); +void usc_load_txfifo( struct mgsl_struct *info ); + +void usc_enable_aux_clock( struct mgsl_struct *info, u32 DataRate ); +void usc_enable_loopback( struct mgsl_struct *info, int enable ); + +void usc_get_serial_signals( struct mgsl_struct *info ); +void usc_set_serial_signals( struct mgsl_struct *info ); + +void usc_reset( struct mgsl_struct *info ); + +void usc_set_sync_mode( struct mgsl_struct *info ); +void usc_set_sdlc_mode( struct mgsl_struct *info ); +void usc_set_async_mode( struct mgsl_struct *info ); +void usc_enable_async_clock( struct mgsl_struct *info, u32 DataRate ); + +void usc_loopback_frame( struct mgsl_struct *info ); + +void mgsl_tx_timeout(unsigned long context); + +/* + * Defines a BUS descriptor value for the PCI adapter + * local bus address ranges. + */ + +#define BUS_DESCRIPTOR( WrHold, WrDly, RdDly, Nwdd, Nwad, Nxda, Nrdd, Nrad ) \ +(0x00400020 + \ +((WrHold) << 30) + \ +((WrDly) << 28) + \ +((RdDly) << 26) + \ +((Nwdd) << 20) + \ +((Nwad) << 15) + \ +((Nxda) << 13) + \ +((Nrdd) << 11) + \ +((Nrad) << 6) ) + +void mgsl_trace_block(struct mgsl_struct *info,const char* data, int count, int xmit); + +/* + * Adapter diagnostic routines + */ +BOOLEAN mgsl_register_test( struct mgsl_struct *info ); +BOOLEAN mgsl_irq_test( struct mgsl_struct *info ); +BOOLEAN mgsl_dma_test( struct mgsl_struct *info ); +BOOLEAN mgsl_memory_test( struct mgsl_struct *info ); +int mgsl_adapter_test( struct mgsl_struct *info ); + +/* + * device and resource management routines + */ +int mgsl_claim_resources(struct mgsl_struct *info); +void mgsl_release_resources(struct mgsl_struct *info); +void mgsl_add_device(struct mgsl_struct *info); +struct mgsl_struct* mgsl_allocate_device(void); +int mgsl_enumerate_devices(void); + +/* + * DMA buffer manupulation functions. + */ +void mgsl_free_rx_frame_buffers( struct mgsl_struct *info, unsigned int StartIndex, unsigned int EndIndex ); +int mgsl_get_rx_frame( struct mgsl_struct *info ); +void mgsl_reset_rx_dma_buffers( struct mgsl_struct *info ); +void mgsl_load_tx_dma_buffer( struct mgsl_struct *info, const char *Buffer, unsigned int BufferSize); +void mgsl_load_pci_memory(char* TargetPtr, const char* SourcePtr, unsigned short count); + +/* + * DMA and Shared Memory buffer allocation and formatting + */ +int mgsl_allocate_dma_buffers(struct mgsl_struct *info); +void mgsl_free_dma_buffers(struct mgsl_struct *info); +int mgsl_alloc_frame_memory(struct mgsl_struct *info, DMABUFFERENTRY *BufferList,int Buffercount); +void mgsl_free_frame_memory(struct mgsl_struct *info, DMABUFFERENTRY *BufferList,int Buffercount); +int mgsl_alloc_buffer_list_memory(struct mgsl_struct *info); +void mgsl_free_buffer_list_memory(struct mgsl_struct *info); + +/* + * Bottom half interrupt handlers + */ +void mgsl_bh_handler(void* Context); +void mgsl_bh_receive_dma( struct mgsl_struct *info, unsigned short status ); +void mgsl_bh_transmit_data( struct mgsl_struct *info, unsigned short Datacount ); +void mgsl_bh_status_handler( struct mgsl_struct *info, unsigned short status ); + +void mgsl_format_bh_queue( struct mgsl_struct *info ); +void mgsl_bh_queue_put( struct mgsl_struct *info, unsigned char type, unsigned short status ); +int mgsl_bh_queue_get( struct mgsl_struct *info ); + + +/* + * Interrupt handler routines and dispatch table. + */ +void mgsl_isr_null( struct mgsl_struct *info ); +void mgsl_isr_transmit_data( struct mgsl_struct *info ); +void mgsl_isr_receive_data( struct mgsl_struct *info ); +void mgsl_isr_receive_status( struct mgsl_struct *info ); +void mgsl_isr_transmit_status( struct mgsl_struct *info ); +void mgsl_isr_io_pin( struct mgsl_struct *info ); +void mgsl_isr_misc( struct mgsl_struct *info ); +void mgsl_isr_receive_dma( struct mgsl_struct *info ); + +typedef void (*isr_dispatch_func)(struct mgsl_struct *); + +isr_dispatch_func UscIsrTable[7] = +{ + mgsl_isr_null, + mgsl_isr_misc, + mgsl_isr_io_pin, + mgsl_isr_transmit_data, + mgsl_isr_transmit_status, + mgsl_isr_receive_data, + mgsl_isr_receive_status +}; + +/* + * ioctl call handlers + */ +static int set_modem_info(struct mgsl_struct * info, unsigned int cmd, + unsigned int *value); +static int get_modem_info(struct mgsl_struct * info, unsigned int *value); +static int mgsl_get_stats(struct mgsl_struct * info, struct mgsl_icount + *user_icount); +static int mgsl_get_params(struct mgsl_struct * info, MGSL_PARAMS *user_params); +static int mgsl_set_params(struct mgsl_struct * info, MGSL_PARAMS *new_params); +static int mgsl_get_txidle(struct mgsl_struct * info, int*idle_mode); +static int mgsl_set_txidle(struct mgsl_struct * info, int idle_mode); +static int mgsl_txenable(struct mgsl_struct * info, int enable); +static int mgsl_txabort(struct mgsl_struct * info); +static int mgsl_rxenable(struct mgsl_struct * info, int enable); +static int mgsl_wait_event(struct mgsl_struct * info, int mask); + +#define jiffies_from_ms(a) ((((a) * HZ)/1000)+1) + +/* + * Global linked list of SyncLink devices + */ +struct mgsl_struct *mgsl_device_list = NULL; +int mgsl_device_count = 0; + +/* + * Set this param to non-zero to load eax with the + * .text section address and breakpoint on module load. + * This is useful for use with gdb and add-symbol-file command. + */ +int break_on_load=0; + +/* + * Driver major number, defaults to zero to get auto + * assigned major number. May be forced as module parameter. + */ +int ttymajor=0; + +int cuamajor=0; + +/* + * Array of user specified options for ISA adapters. + */ +static int io[MAX_ISA_DEVICES] = {0,}; +static int irq[MAX_ISA_DEVICES] = {0,}; +static int dma[MAX_ISA_DEVICES] = {0,}; +static int debug_level = 0; + + +#if LINUX_VERSION_CODE >= VERSION(2,1,0) +MODULE_PARM(break_on_load,"i"); +MODULE_PARM(ttymajor,"i"); +MODULE_PARM(cuamajor,"i"); +MODULE_PARM(io,"1-" __MODULE_STRING(MAX_ISA_DEVICES) "i"); +MODULE_PARM(irq,"1-" __MODULE_STRING(MAX_ISA_DEVICES) "i"); +MODULE_PARM(dma,"1-" __MODULE_STRING(MAX_ISA_DEVICES) "i"); +MODULE_PARM(debug_level,"i"); +#endif + +static char *driver_name = "SyncLink serial driver"; +static char *driver_version = "1.00"; + +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 + + +static void mgsl_change_params(struct mgsl_struct *info); +static void mgsl_wait_until_sent(struct tty_struct *tty, int timeout); + +static struct tty_struct **serial_table = NULL; +static struct termios **serial_termios = NULL; +static struct termios **serial_termios_locked = NULL; + +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + +/* + * 1st function defined in .text section. Calling this function in + * init_module() followed by a breakpoint allows a remote debugger + * (gdb) to get the .text address for the add-symbol-file command. + * This allows remote debugging of dynamically loadable modules. + */ +void* mgsl_get_text_ptr(void); +void* mgsl_get_text_ptr() {return mgsl_get_text_ptr;} + +/* + * tmp_buf is used as a temporary buffer by mgsl_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 ioports, 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 mgsl_paranoia_check(struct mgsl_struct *info, + kdev_t device, const char *routine) +{ +#ifdef MGSL_PARANOIA_CHECK + static const char *badmagic = + "Warning: bad magic number for mgsl struct (%s) in %s\n"; + static const char *badinfo = + "Warning: null mgsl_struct for (%s) in %s\n"; + + if (!info) { + printk(badinfo, kdevname(device), routine); + return 1; + } + if (info->magic != MGSL_MAGIC) { + printk(badmagic, kdevname(device), routine); + return 1; + } +#endif + return 0; +} + +/* mgsl_stop() throttle (stop) transmitter + * + * Arguments: tty pointer to tty info structure + * Return Value: None + */ +static void mgsl_stop(struct tty_struct *tty) +{ + struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data; + unsigned long flags; + + if (mgsl_paranoia_check(info, tty->device, "mgsl_stop")) + return; + + if ( debug_level >= DEBUG_LEVEL_INFO ) + printk("mgsl_stop(%s)\n",info->device_name); + + spin_lock_irqsave(&info->irq_spinlock,flags); + if (info->tx_enabled) + usc_stop_transmitter(info); + spin_unlock_irqrestore(&info->irq_spinlock,flags); + +} /* end of mgsl_stop() */ + +/* mgsl_start() release (start) transmitter + * + * Arguments: tty pointer to tty info structure + * Return Value: None + */ +static void mgsl_start(struct tty_struct *tty) +{ + struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data; + unsigned long flags; + + if (mgsl_paranoia_check(info, tty->device, "mgsl_start")) + return; + + if ( debug_level >= DEBUG_LEVEL_INFO ) + printk("mgsl_start(%s)\n",info->device_name); + + spin_lock_irqsave(&info->irq_spinlock,flags); + if (!info->tx_enabled) + usc_start_transmitter(info); + spin_unlock_irqrestore(&info->irq_spinlock,flags); + +} /* end of mgsl_start() */ + +/* + * Bottom half work queue access functions + */ + +/* mgsl_format_bh_queue() + * + * Initialize the bottom half processing queue + * + * Arguments: info pointer to device instance data + * Return Value: None + */ +void mgsl_format_bh_queue( struct mgsl_struct *info ) +{ + BH_QUEUE bh_queue = info->bh_queue; + int i; + + /* go through sequentially tacking the little bits together */ + + for ( i=0; i < MAX_BH_QUEUE_ENTRIES; i++ ) { + if ( info->free_bh_queue_tail == NULL ) + info->free_bh_queue_head = bh_queue; + else + info->free_bh_queue_tail->link = bh_queue; + info->free_bh_queue_tail = bh_queue++; + } + + /* As a safety measure, mark the end of the chain with a NULL */ + info->free_bh_queue_tail->link = NULL; + +} /* end of mgsl_format_bh_queue() */ + +/* mgsl_bh_queue_put() + * + * Add a BH event to the BH queue + * + * Arguments: info pointer to device instance data + * type BH event type + * status BH event status + * + * Return Value: None + */ +void mgsl_bh_queue_put( struct mgsl_struct *info, unsigned char type, unsigned short status ) +{ + BH_EVENT *event = info->free_bh_queue_head; + + if ( event != NULL ) { + /* remove free element from head of free list */ + info->free_bh_queue_head = event->link; + event->link = NULL; + + /* file out new BH event */ + event->type = type; + event->status = status; + + /* add element to tail of pending list */ + if ( info->bh_queue_head != NULL ){ + /* BH queue is not empty, add current element to tail */ + info->bh_queue_tail->link = event; + } else { + /* the BH queue is empty so this element becomes the head of queue */ + info->bh_queue_head = event; + } + + /* the new element becomes tail of queue */ + info->bh_queue_tail = event; + } else { + /* No more free BH action elements in queue. */ + /* This happens when too many interrupts are occuring */ + /* for the mgsl_bh_handler to process so set a flag. */ + + info->isr_overflow = 1; + } + +} /* end of mgsl_bh_queue_put() */ + +/* mgsl_bh_queue_get() + * + * Free the current work item (if any) and get the + * next work item from the head of the pending work item queue. + * + * Effects: + * + * If a BH action element is available on the BH action queue + * then the head of the queue is removed and bh_action + * is set to point to the removed element. + * + * Arguments: info pointer to device instance data + * Return Value: 1 if BH action removed from queue + */ +int mgsl_bh_queue_get( struct mgsl_struct *info ) +{ + unsigned long flags; + + spin_lock_irqsave(&info->irq_spinlock,flags); + + if ( info->bh_action ) { + /* free the current work item */ + if ( info->free_bh_queue_head != NULL ){ + /* free queue is not empty, add current element to tail */ + info->free_bh_queue_tail->link = info->bh_action; + } else { + /* free queue is empty so this element becomes the head of queue */ + info->free_bh_queue_head = info->bh_action; + } + + /* add element to tail of free queue */ + info->free_bh_queue_tail = info->bh_action; + info->free_bh_queue_tail->link = NULL; + } + + /* attempt to remove element from head of queue */ + info->bh_action = info->bh_queue_head; + + if ( info->bh_action != NULL ){ + /* BH queue is not empty, remove element from queue head */ + info->bh_queue_head = info->bh_action->link; + spin_unlock_irqrestore(&info->irq_spinlock,flags); + return 1; + } + + /* Mark BH routine as complete */ + info->bh_running = 0; + info->bh_requested = 0; + + spin_unlock_irqrestore(&info->irq_spinlock,flags); + + return 0; + +} /* end of mgsl_bh_queue_get() */ + +/* mgsl_bh_handler() + * + * Perform bottom half processing of work items queued by ISR. + * + * Arguments: Context pointer to device instance data + * Return Value: None + */ +void mgsl_bh_handler(void* Context) +{ + struct mgsl_struct *info = (struct mgsl_struct*)Context; + + if (!info) + return; + + if ( debug_level >= DEBUG_LEVEL_BH ) + printk( "%s(%d):mgsl_bh_handler(%s) entry\n", + __FILE__,__LINE__,info->device_name); + + info->bh_running = 1; + + /* Attempt to clear out the BH queue */ + + while( mgsl_bh_queue_get(info) ) { + + /* Process work item */ + if ( debug_level >= DEBUG_LEVEL_BH ) + printk( "%s(%d):mgsl_bh_handler() work item action=%d\n", + __FILE__,__LINE__,info->bh_action->type); + + switch ( info->bh_action->type ) { + + case BH_TYPE_RECEIVE_DMA: + mgsl_bh_receive_dma( info, info->bh_action->status ); + break; + + case BH_TYPE_TRANSMIT_STATUS: + case BH_TYPE_TRANSMIT_DATA: + mgsl_bh_transmit_data( info, info->bh_action->status ); + break; + + case BH_TYPE_STATUS: + mgsl_bh_status_handler( info, info->bh_action->status ); + break; + + default: + /* unknown work item ID */ + printk("Unknown work item ID=%08X!\n", + info->bh_action->type ); + break; + } + } + + if ( info->isr_overflow ) { + printk("ISR overflow detected.\n"); + } + + if ( debug_level >= DEBUG_LEVEL_BH ) + printk( "%s(%d):mgsl_bh_handler(%s) exit\n", + __FILE__,__LINE__,info->device_name); + +} /* end of mgsl_bh_handler() */ + +/* mgsl_bh_receive_dma() + * + * Perform bottom half processing for a receive DMA interrupt + * This occurs in HDLC mode after a DMA buffer has terminated + * or the DMA buffers have been exhausted. + * + * Arguments: + * + * info pointer to device instance data + * status status word + * + * Return Value: None + */ +void mgsl_bh_receive_dma( struct mgsl_struct *info, unsigned short status ) +{ + if ( debug_level >= DEBUG_LEVEL_BH ) + printk( "%s(%d):mgsl_bh_receive_dma(%s)\n", + __FILE__,__LINE__,info->device_name); + + while( mgsl_get_rx_frame(info) ); + +} /* end of mgsl_bh_receive_dma() */ + +/* mgsl_bh_transmit_data() + * + * Process a transmit data interrupt event + * This occurs in asynchronous communications mode. + * + * Arguments: info pointer to device instance data + * Return Value: None + */ +void mgsl_bh_transmit_data( struct mgsl_struct *info, unsigned short Datacount ) +{ + struct tty_struct *tty = info->tty; + + if ( debug_level >= DEBUG_LEVEL_BH ) + printk( "%s(%d):mgsl_bh_transmit_data() entry on %s\n", + __FILE__,__LINE__,info->device_name); + + /* wakeup any waiting write requests */ + if (tty) { + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) { + if ( debug_level >= DEBUG_LEVEL_BH ) + printk( "%s(%d):calling ldisc.write_wakeup on %s\n", + __FILE__,__LINE__,info->device_name); + (tty->ldisc.write_wakeup)(tty); + } + wake_up_interruptible(&tty->write_wait); + } + +} /* End Of mgsl_bh_transmit_data() */ + +/* mgsl_bh_status_handler() + * + * Peform bottom half processing for a status interrupt + * + * This event is generated when a I/O pin (serial signal) + * has a transition. If there is a pending WaitEvent call + * and the status transition is identified in the EventMast + * of the pending call then complete the pending call. + * + * Arguments: + * + * info pointer to device instance data + * status status word + * + * Return Value: None + */ +void mgsl_bh_status_handler( struct mgsl_struct *info, unsigned short status ) +{ + if ( debug_level >= DEBUG_LEVEL_BH ) + printk( "%s(%d):mgsl_bh_status_handler() entry on %s\n", + __FILE__,__LINE__,info->device_name); + +} /* End Of mgsl_bh_status_handler() */ + +/* mgsl_isr_receive_status() + * + * Service a receive status interrupt. The type of status + * interrupt is indicated by the state of the RCSR. + * This is only used for HDLC mode. + * + * Arguments: info pointer to device instance data + * Return Value: None + */ +void mgsl_isr_receive_status( struct mgsl_struct *info ) +{ + u16 status = usc_InReg( info, RCSR ); + + if ( debug_level >= DEBUG_LEVEL_ISR ) + printk("%s(%d):mgsl_isr_receive_status status=%04X\n", + __FILE__,__LINE__,status); + + usc_ClearIrqPendingBits( info, RECEIVE_STATUS ); + usc_UnlatchRxstatusBits( info, status ); + + if (status & (RXSTATUS_EXITED_HUNT + RXSTATUS_IDLE_RECEIVED)) { + if (status & RXSTATUS_EXITED_HUNT) + info->icount.exithunt++; + if (status & RXSTATUS_IDLE_RECEIVED) + info->icount.rxidle++; + wake_up_interruptible(&info->event_wait_q); + } + + if (status & RXSTATUS_OVERRUN){ + /* Purge receive FIFO to allow DMA buffer completion + * with overrun status stored in the receive status block. + */ + usc_RCmd( info, RCmd_EnterHuntmode ); + usc_RTCmd( info, RTCmd_PurgeRxFifo ); + } + +} /* end of mgsl_isr_receive_status() */ + +/* mgsl_isr_transmit_status() + * + * Service a transmit status interrupt + * HDLC mode :end of transmit frame + * Async mode:all data is sent + * transmit status is indicated by bits in the TCSR. + * + * Arguments: info pointer to device instance data + * Return Value: None + */ +void mgsl_isr_transmit_status( struct mgsl_struct *info ) +{ + u16 status = usc_InReg( info, TCSR ); + + if ( debug_level >= DEBUG_LEVEL_ISR ) + printk("%s(%d):mgsl_isr_transmit_status status=%04X\n", + __FILE__,__LINE__,status); + + usc_ClearIrqPendingBits( info, TRANSMIT_STATUS ); + usc_UnlatchTxstatusBits( info, status ); + + if ( status & TXSTATUS_EOF_SENT ) + info->icount.txok++; + else if ( status & TXSTATUS_UNDERRUN ) + info->icount.txunder++; + else if ( status & TXSTATUS_ABORT_SENT ) + info->icount.txabort++; + else + info->icount.txunder++; + + info->tx_active = 0; + info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; + del_timer(&info->tx_timer); + + if ( info->drop_rts_on_tx_done ) { + usc_get_serial_signals( info ); + if ( info->serial_signals & SerialSignal_RTS ) { + info->serial_signals &= ~SerialSignal_RTS; + usc_set_serial_signals( info ); + } + info->drop_rts_on_tx_done = 0; + } + + if (info->tty->stopped || info->tty->hw_stopped) { + usc_stop_transmitter(info); + return; + } + + mgsl_bh_queue_put(info, BH_TYPE_TRANSMIT_STATUS, status); + +} /* end of mgsl_isr_transmit_status() */ + +/* mgsl_isr_io_pin() + * + * Service an Input/Output pin interrupt. The type of + * interrupt is indicated by bits in the MISR + * + * Arguments: info pointer to device instance data + * Return Value: None + */ +void mgsl_isr_io_pin( struct mgsl_struct *info ) +{ + struct mgsl_icount *icount; + u16 status = usc_InReg( info, MISR ); + + if ( debug_level >= DEBUG_LEVEL_ISR ) + printk("%s(%d):mgsl_isr_io_pin status=%04X\n", + __FILE__,__LINE__,status); + + usc_ClearIrqPendingBits( info, IO_PIN ); + usc_UnlatchIostatusBits( info, status ); + + if (status & (MISCSTATUS_CTS_LATCHED | MISCSTATUS_DCD_LATCHED | + MISCSTATUS_DSR_LATCHED | MISCSTATUS_RI_LATCHED) ) { + icount = &info->icount; + /* update input line counters */ + if (status & MISCSTATUS_RI_LATCHED) + icount->rng++; + if (status & MISCSTATUS_DSR_LATCHED) + icount->dsr++; + if (status & MISCSTATUS_DCD_LATCHED) { + icount->dcd++; +#ifdef CONFIG_HARD_PPS + if ((info->flags & ASYNC_HARDPPS_CD) && + (status & MISCSTATUS_DCD_LATCHED)) + hardpps(); +#endif + } + if (status & MISCSTATUS_CTS_LATCHED) + icount->cts++; + wake_up_interruptible(&info->status_event_wait_q); + wake_up_interruptible(&info->event_wait_q); + + if ( (info->flags & ASYNC_CHECK_CD) && + (status & MISCSTATUS_DCD_LATCHED) ) { + if ( debug_level >= DEBUG_LEVEL_ISR ) + printk("%s CD now %s...", info->device_name, + (status & MISCSTATUS_DCD) ? "on" : "off"); + if (status & MISCSTATUS_DCD) + wake_up_interruptible(&info->open_wait); + else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) && + (info->flags & ASYNC_CALLOUT_NOHUP))) { + if ( debug_level >= DEBUG_LEVEL_ISR ) + printk("doing serial hangup..."); + if (info->tty) + tty_hangup(info->tty); + } + } + + if ( (info->flags & ASYNC_CTS_FLOW) && + (status & MISCSTATUS_CTS_LATCHED) ) { + if (info->tty->hw_stopped) { + if (status & MISCSTATUS_CTS) { + if ( debug_level >= DEBUG_LEVEL_ISR ) + printk("CTS tx start..."); + info->tty->hw_stopped = 0; + usc_start_transmitter(info); + mgsl_bh_queue_put( info, BH_TYPE_TRANSMIT_DATA, status ); + return; + } + } else { + if (!(status & MISCSTATUS_CTS)) { + if ( debug_level >= DEBUG_LEVEL_ISR ) + printk("CTS tx stop..."); + info->tty->hw_stopped = 1; + usc_stop_transmitter(info); + } + } + } + } + + /* for diagnostics set IRQ flag */ + if ( status & MISCSTATUS_TXC_LATCHED ){ + usc_OutReg( info, SICR, + (unsigned short)(usc_InReg(info,SICR) & ~(SICR_TXC_ACTIVE+SICR_TXC_INACTIVE)) ); + usc_UnlatchIostatusBits( info, MISCSTATUS_TXC_LATCHED ); + info->irq_occurred = 1; + } + +} /* end of mgsl_isr_io_pin() */ + +/* mgsl_isr_transmit_data() + * + * Service a transmit data interrupt (async mode only). + * + * Arguments: info pointer to device instance data + * Return Value: None + */ +void mgsl_isr_transmit_data( struct mgsl_struct *info ) +{ + if ( debug_level >= DEBUG_LEVEL_ISR ) + printk("%s(%d):mgsl_isr_transmit_data xmit_cnt=%d\n", + __FILE__,__LINE__,info->xmit_cnt); + + usc_ClearIrqPendingBits( info, TRANSMIT_DATA ); + + if (info->tty->stopped || info->tty->hw_stopped) { + usc_stop_transmitter(info); + return; + } + + if ( info->xmit_cnt ) + usc_load_txfifo( info ); + else + info->tx_active = 0; + + if (info->xmit_cnt < WAKEUP_CHARS) + mgsl_bh_queue_put(info, BH_TYPE_TRANSMIT_DATA, (unsigned short)(info->xmit_cnt)); + +} /* end of mgsl_isr_transmit_data() */ + +/* mgsl_isr_receive_data() + * + * Service a receive data interrupt. This occurs + * when operating in asynchronous interrupt transfer mode. + * The receive data FIFO is flushed to the receive data buffers. + * + * Arguments: info pointer to device instance data + * Return Value: None + */ +void mgsl_isr_receive_data( struct mgsl_struct *info ) +{ + int Fifocount; + u16 status; + unsigned char DataByte; + struct tty_struct *tty = info->tty; + struct mgsl_icount *icount = &info->icount; + + if ( debug_level >= DEBUG_LEVEL_ISR ) + printk("%s(%d):mgsl_isr_receive_data\n", + __FILE__,__LINE__); + + usc_ClearIrqPendingBits( info, RECEIVE_DATA ); + + /* select FIFO status for RICR readback */ + usc_RCmd( info, RCmd_SelectRicrRxFifostatus ); + + /* clear the Wordstatus bit so that status readback */ + /* only reflects the status of this byte */ + usc_OutReg( info, RICR+LSBONLY, (u16)(usc_InReg(info, RICR+LSBONLY) & ~BIT3 )); + + /* flush the receive FIFO */ + + while( (Fifocount = (usc_InReg(info,RICR) >> 8)) ) { + /* read one byte from RxFIFO */ + outw( (inw(info->io_base + CCAR) & 0x0780) | (RDR+LSBONLY), + info->io_base + CCAR ); + DataByte = inb( info->io_base + CCAR ); + + /* get the status of the received byte */ + status = usc_InReg(info, RCSR); + if ( status & (RXSTATUS_FRAMING_ERROR + RXSTATUS_PARITY_ERROR + + RXSTATUS_OVERRUN + RXSTATUS_BREAK_RECEIVED) ) + usc_UnlatchRxstatusBits(info,RXSTATUS_ALL); + + if (tty->flip.count >= TTY_FLIPBUF_SIZE) + continue; + + *tty->flip.char_buf_ptr = DataByte; + icount->rx++; + + *tty->flip.flag_buf_ptr = 0; + if ( status & (RXSTATUS_FRAMING_ERROR + RXSTATUS_PARITY_ERROR + + RXSTATUS_OVERRUN + RXSTATUS_BREAK_RECEIVED) ) { + printk("rxerr=%04X\n",status); + /* update error statistics */ + if ( status & RXSTATUS_BREAK_RECEIVED ) { + status &= ~(RXSTATUS_FRAMING_ERROR + RXSTATUS_PARITY_ERROR); + icount->brk++; + } else if (status & RXSTATUS_PARITY_ERROR) + icount->parity++; + else if (status & RXSTATUS_FRAMING_ERROR) + icount->frame++; + else if (status & RXSTATUS_OVERRUN) { + /* must issue purge fifo cmd before */ + /* 16C32 accepts more receive chars */ + usc_RTCmd(info,RTCmd_PurgeRxFifo); + icount->overrun++; + } + + /* discard char if tty control flags say so */ + if (status & info->ignore_status_mask) + continue; + + status &= info->read_status_mask; + + if (status & RXSTATUS_BREAK_RECEIVED) { + *tty->flip.flag_buf_ptr = TTY_BREAK; + if (info->flags & ASYNC_SAK) + do_SAK(tty); + } else if (status & RXSTATUS_PARITY_ERROR) + *tty->flip.flag_buf_ptr = TTY_PARITY; + else if (status & RXSTATUS_FRAMING_ERROR) + *tty->flip.flag_buf_ptr = TTY_FRAME; + if (status & RXSTATUS_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; + } + } + } /* end of if (error) */ + + tty->flip.flag_buf_ptr++; + tty->flip.char_buf_ptr++; + tty->flip.count++; + } + + if ( debug_level >= DEBUG_LEVEL_ISR ) { + printk("%s(%d):mgsl_isr_receive_data flip count=%d\n", + __FILE__,__LINE__,tty->flip.count); + printk("%s(%d):rx=%d brk=%d parity=%d frame=%d overrun=%d\n", + __FILE__,__LINE__,icount->rx,icount->brk, + icount->parity,icount->frame,icount->overrun); + } + + if ( tty->flip.count ) { +#if LINUX_VERSION_CODE >= VERSION(2,1,0) + tty_flip_buffer_push(tty); +#else + queue_task(&tty->flip.tqueue, &tq_timer); +#endif + } + + +} /* end of mgsl_isr_receive_data() */ + +/* mgsl_isr_misc() + * + * Service a miscellaneos interrupt source. + * + * Arguments: info pointer to device extension (instance data) + * Return Value: None + */ +void mgsl_isr_misc( struct mgsl_struct *info ) +{ + u16 status = usc_InReg( info, MISR ); + + if ( debug_level >= DEBUG_LEVEL_ISR ) + printk("%s(%d):mgsl_isr_misc status=%04X\n", + __FILE__,__LINE__,status); + + usc_ClearIrqPendingBits( info, MISC ); + usc_UnlatchMiscstatusBits( info, status ); + +} /* end of mgsl_isr_misc() */ + +/* mgsl_isr_null() + * + * Services undefined interrupt vectors from the + * USC. (hence this function SHOULD never be called) + * + * Arguments: info pointer to device extension (instance data) + * Return Value: None + */ +void mgsl_isr_null( struct mgsl_struct *info ) +{ + +} /* end of mgsl_isr_null() */ + +/* mgsl_isr_receive_dma() + * + * Service a receive DMA channel interrupt. + * For this driver there are two sources of receive DMA interrupts + * as identified in the Receive DMA mode Register (RDMR): + * + * BIT3 EOA/EOL End of List, all receive buffers in receive + * buffer list have been filled (no more free buffers + * available). The DMA controller has shut down. + * + * BIT2 EOB End of Buffer. This interrupt occurs when a receive + * DMA buffer is terminated in response to completion + * of a good frame or a frame with errors. The status + * of the frame is stored in the buffer entry in the + * list of receive buffer entries. + * + * Arguments: info pointer to device instance data + * Return Value: None + */ +void mgsl_isr_receive_dma( struct mgsl_struct *info ) +{ + u16 status; + + /* clear interrupt pending and IUS bit for Rx DMA IRQ */ + usc_OutDmaReg( info, CDIR, BIT9+BIT1 ); + + /* Read the receive DMA status to identify interrupt type. */ + /* This also clears the status bits. */ + status = usc_InDmaReg( info, RDMR ); + + if ( debug_level >= DEBUG_LEVEL_ISR ) + printk("%s(%d):mgsl_isr_receive_dma(%s) status=%04X\n", + __FILE__,__LINE__,info->device_name,status); + + /* Post a receive event for BH processing. */ + mgsl_bh_queue_put( info, BH_TYPE_RECEIVE_DMA, status ); + + if ( status & BIT3 ) + info->rx_overflow = 1; + +} /* end of mgsl_isr_receive_dma() */ + +/* mgsl_interrupt() + * + * Interrupt service routine entry point. + * + * Arguments: + * + * irq interrupt number that caused interrupt + * dev_id device ID supplied during interrupt registration + * regs interrupted processor context + * + * Return Value: None + */ +static void mgsl_interrupt(int irq, void *dev_id, struct pt_regs * regs) +{ + struct mgsl_struct * info; + u16 UscVector; + u16 DmaVector; + + if ( debug_level >= DEBUG_LEVEL_ISR ) + printk("%s(%d):mgsl_interrupt(%d)entry.\n", + __FILE__,__LINE__,irq); + + info = (struct mgsl_struct *)dev_id; + if (!info) + return; + + spin_lock(&info->irq_spinlock); + + for(;;) { + /* Read the interrupt vectors from hardware. */ + UscVector = usc_InReg(info, IVR) >> 9; + DmaVector = usc_InDmaReg(info, DIVR); + + if ( debug_level >= DEBUG_LEVEL_ISR ) + printk("%s(%d):%s UscVector=%08X DmaVector=%08X\n", + __FILE__,__LINE__,info->device_name,UscVector,DmaVector); + + if ( !UscVector && !DmaVector ) + break; + + /* Dispatch interrupt vector */ + if ( UscVector ) + (*UscIsrTable[UscVector])(info); + else + mgsl_isr_receive_dma(info); + + if ( info->isr_overflow ) { + printk(KERN_ERR"%s(%d):%s isr overflow irq=%d\n", + __FILE__,__LINE__,info->device_name, irq); + /* Interrupt overflow. Reset adapter and exit. */ +// UscReset(info); +// break; + } + } + + /* Request bottom half processing if there's something + * for it to do and the bh is not already running + */ + + if ( info->bh_queue_head && !info->bh_running && !info->bh_requested ) { + if ( debug_level >= DEBUG_LEVEL_ISR ) + printk("%s(%d):%s queueing bh task.\n", + __FILE__,__LINE__,info->device_name); + queue_task(&info->task, &tq_immediate); + mark_bh(IMMEDIATE_BH); + info->bh_requested = 1; + } + + spin_unlock(&info->irq_spinlock); + + if ( debug_level >= DEBUG_LEVEL_ISR ) + printk("%s(%d):mgsl_interrupt(%d)exit.\n", + __FILE__,__LINE__,irq); + +} /* end of mgsl_interrupt() */ + +/* startup() + * + * Initialize and start device. + * + * Arguments: info pointer to device instance data + * Return Value: 0 if success, otherwise error code + */ +static int startup(struct mgsl_struct * info) +{ + int retval = 0; + + if ( debug_level >= DEBUG_LEVEL_INFO ) + printk("%s(%d):mgsl_startup(%s)\n",__FILE__,__LINE__,info->device_name); + + if (info->flags & ASYNC_INITIALIZED) + return 0; + + if (!info->xmit_buf) { + /* allocate a page of memory for a transmit buffer */ + info->xmit_buf = (unsigned char *)get_free_page(GFP_KERNEL); + if (!info->xmit_buf) { + printk(KERN_ERR"%s(%d):%s can't allocate transmit buffer\n", + __FILE__,__LINE__,info->device_name); + return -ENOMEM; + } + } + + mgsl_format_bh_queue(info); + + init_timer(&info->tx_timer); + info->tx_timer.data = (unsigned long)info; + info->tx_timer.function = mgsl_tx_timeout; + + /* Allocate and claim adapter resources */ + retval = mgsl_claim_resources(info); + + /* perform existance check and diagnostics */ + if ( !retval ) + retval = mgsl_adapter_test(info); + + if ( retval ) { +#if LINUX_VERSION_CODE >= VERSION(2,1,0) + if (capable(CAP_SYS_ADMIN) && info->tty) +#else + if (suser() && info->tty) +#endif + set_bit(TTY_IO_ERROR, &info->tty->flags); + mgsl_release_resources(info); + return retval; + } + + /* program hardware for current parameters */ + mgsl_change_params(info); + + if (info->tty) + clear_bit(TTY_IO_ERROR, &info->tty->flags); + + info->flags |= ASYNC_INITIALIZED; + + return 0; + +} /* end of startup() */ + +/* shutdown() + * + * Called by mgsl_close() and mgsl_hangup() to shutdown hardware + * + * Arguments: info pointer to device instance data + * Return Value: None + */ +static void shutdown(struct mgsl_struct * info) +{ + unsigned long flags; + + if (!(info->flags & ASYNC_INITIALIZED)) + return; + + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):mgsl_shutdown(%s)\n", + __FILE__,__LINE__, info->device_name ); + + /* clear status wait queue because status changes */ + /* can't happen after shutting down the hardware */ + wake_up_interruptible(&info->status_event_wait_q); + wake_up_interruptible(&info->event_wait_q); + + if (info->xmit_buf) { + free_page((unsigned long) info->xmit_buf); + info->xmit_buf = 0; + } + + spin_lock_irqsave(&info->irq_spinlock,flags); + usc_DisableMasterIrqBit(info); + usc_stop_receiver(info); + usc_stop_transmitter(info); + usc_DisableInterrupts(info,RECEIVE_DATA + RECEIVE_STATUS + + TRANSMIT_DATA + TRANSMIT_STATUS + IO_PIN + MISC ); + usc_DisableDmaInterrupts(info,DICR_MASTER + DICR_TRANSMIT + DICR_RECEIVE); + + /* Disable DMAEN (Port 7, Bit 14) */ + /* This disconnects the DMA request signal from the ISA bus */ + /* on the ISA adapter. This has no effect for the PCI adapter */ + usc_OutReg(info, PCR, (u16)((usc_InReg(info, PCR) | BIT15) | BIT14)); + + /* Disable INTEN (Port 6, Bit12) */ + /* This disconnects the IRQ request signal to the ISA bus */ + /* on the ISA adapter. This has no effect for the PCI adapter */ + usc_OutReg(info, PCR, (u16)((usc_InReg(info, PCR) | BIT13) | BIT12)); + + if (!info->tty || info->tty->termios->c_cflag & HUPCL) { + info->serial_signals &= ~(SerialSignal_DTR + SerialSignal_RTS); + usc_set_serial_signals(info); + } + + spin_unlock_irqrestore(&info->irq_spinlock,flags); + + mgsl_release_resources(info); + + if (info->tty) + set_bit(TTY_IO_ERROR, &info->tty->flags); + + info->flags &= ~ASYNC_INITIALIZED; + +} /* end of shutdown() */ + +/* mgsl_change_params() + * + * Reconfigure adapter based on new parameters + * + * Arguments: info pointer to device instance data + * Return Value: None + */ +static void mgsl_change_params(struct mgsl_struct *info) +{ + unsigned cflag; + unsigned long flags; + int bits_per_char; + + if (!info->tty || !info->tty->termios) + return; + + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):mgsl_change_params(%s)\n", + __FILE__,__LINE__, info->device_name ); + + cflag = info->tty->termios->c_cflag; + + /* if B0 rate (hangup) specified then negate DTR and RTS */ + /* otherwise assert DTR and RTS */ + if (cflag & CBAUD) + info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR; + else + info->serial_signals &= ~(SerialSignal_RTS + SerialSignal_DTR); + + /* byte size and parity */ + + switch (cflag & CSIZE) { + case CS5: info->params.data_bits = 5; break; + case CS6: info->params.data_bits = 6; break; + case CS7: info->params.data_bits = 7; break; + case CS8: info->params.data_bits = 8; break; + /* Never happens, but GCC is too dumb to figure it out */ + default: info->params.data_bits = 7; break; + } + + if (cflag & CSTOPB) + info->params.stop_bits = 2; + else + info->params.stop_bits = 1; + + info->params.parity = ASYNC_PARITY_NONE; + if (cflag & PARENB) { + if (cflag & PARODD) + info->params.parity = ASYNC_PARITY_ODD; + else + info->params.parity = ASYNC_PARITY_EVEN; +#ifdef CMSPAR + if (cflag & CMSPAR) + info->params.parity = ASYNC_PARITY_SPACE; +#endif + } + + /* calculate number of jiffies to transmit a full + * FIFO (32 bytes) at specified data rate + */ + bits_per_char = info->params.data_bits + + info->params.stop_bits + 1; + + /* if port data rate is set to 460800 or less then + * allow tty settings to override, otherwise keep the + * current data rate. + */ + if (info->params.data_rate <= 460800) { +#if LINUX_VERSION_CODE >= VERSION(2,1,0) + info->params.data_rate = tty_get_baud_rate(info->tty); +#else + int i = cflag & CBAUD; + if (i & CBAUDEX) { + i &= ~CBAUDEX; + if (i < 1 || i > 4) + info->tty->termios->c_cflag &= ~CBAUDEX; + else + i += 15; + } + info->params.data_rate = baud_table[i]; +#endif + } + + if ( info->params.data_rate ) { + info->timeout = (32*HZ*bits_per_char) / + info->params.data_rate; + } + info->timeout += HZ/50; /* Add .02 seconds of slop */ + + if (cflag & CRTSCTS) + info->flags |= ASYNC_CTS_FLOW; + else + info->flags &= ~ASYNC_CTS_FLOW; + + if (cflag & CLOCAL) + info->flags &= ~ASYNC_CHECK_CD; + else + info->flags |= ASYNC_CHECK_CD; + + /* process tty input control flags */ + + info->read_status_mask = RXSTATUS_OVERRUN; + if (I_INPCK(info->tty)) + info->read_status_mask |= RXSTATUS_PARITY_ERROR | RXSTATUS_FRAMING_ERROR; + if (I_BRKINT(info->tty) || I_PARMRK(info->tty)) + info->read_status_mask |= RXSTATUS_BREAK_RECEIVED; + + if (I_IGNPAR(info->tty)) + info->ignore_status_mask |= RXSTATUS_PARITY_ERROR | RXSTATUS_FRAMING_ERROR; + if (I_IGNBRK(info->tty)) { + info->ignore_status_mask |= RXSTATUS_BREAK_RECEIVED; + /* If ignoring parity and break indicators, ignore + * overruns too. (For real raw support). + */ + if (I_IGNPAR(info->tty)) + info->ignore_status_mask |= RXSTATUS_OVERRUN; + } + + /* reprogram the hardware */ + + spin_lock_irqsave(&info->irq_spinlock,flags); + + usc_stop_receiver(info); + usc_stop_transmitter(info); + info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; + + if ( info->params.mode == MGSL_MODE_HDLC ) + usc_set_sync_mode(info); + else + usc_set_async_mode(info); + + usc_set_serial_signals(info); + + /* enable modem signal IRQs and read initial signal states */ + usc_EnableStatusIrqs(info,SICR_CTS+SICR_DSR+SICR_DCD+SICR_RI); + usc_EnableInterrupts(info, IO_PIN); + usc_get_serial_signals(info); + + if ( cflag & CREAD ) + usc_start_receiver(info); + + spin_unlock_irqrestore(&info->irq_spinlock,flags); + +} /* end of mgsl_change_params() */ + +/* mgsl_put_char() + * + * Add a character to the transmit buffer. + * + * Arguments: tty pointer to tty information structure + * ch character to add to transmit buffer + * + * Return Value: None + */ +static void mgsl_put_char(struct tty_struct *tty, unsigned char ch) +{ + struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data; + unsigned long flags; + + if ( debug_level >= DEBUG_LEVEL_INFO ) { + printk( "%s(%d):mgsl_put_char(%d) on %s\n", + __FILE__,__LINE__,ch,info->device_name); + } + + if (mgsl_paranoia_check(info, tty->device, "mgsl_put_char")) + return; + + if (!tty || !info->xmit_buf) + return; + + spin_lock_irqsave(&info->irq_spinlock,flags); + + if ( (info->params.mode != MGSL_MODE_HDLC) || + !info->tx_active ) { + + if (info->xmit_cnt < SERIAL_XMIT_SIZE - 1) { + info->xmit_buf[info->xmit_head++] = ch; + info->xmit_head &= SERIAL_XMIT_SIZE-1; + info->xmit_cnt++; + } + } + + spin_unlock_irqrestore(&info->irq_spinlock,flags); + +} /* end of mgsl_put_char() */ + +/* mgsl_flush_chars() + * + * Enable transmitter so remaining characters in the + * transmit buffer are sent. + * + * Arguments: tty pointer to tty information structure + * Return Value: None + */ +static void mgsl_flush_chars(struct tty_struct *tty) +{ + struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data; + unsigned long flags; + + if ( debug_level >= DEBUG_LEVEL_INFO ) + printk( "%s(%d):mgsl_flush_chars() entry on %s xmit_cnt=%d\n", + __FILE__,__LINE__,info->device_name,info->xmit_cnt); + + if (mgsl_paranoia_check(info, tty->device, "mgsl_flush_chars")) + return; + + if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped || + !info->xmit_buf) + return; + + if ( debug_level >= DEBUG_LEVEL_INFO ) + printk( "%s(%d):mgsl_flush_chars() entry on %s starting transmitter\n", + __FILE__,__LINE__,info->device_name ); + + spin_lock_irqsave(&info->irq_spinlock,flags); + + if (!info->tx_active) { + if ( (info->params.mode == MGSL_MODE_HDLC) && + info->xmit_cnt ) { + /* operating in synchronous (frame oriented) mode */ + /* copy data from circular xmit_buf to */ + /* transmit DMA buffer. */ + mgsl_load_tx_dma_buffer(info, + info->xmit_buf,info->xmit_cnt); + } + usc_start_transmitter(info); + } + + spin_unlock_irqrestore(&info->irq_spinlock,flags); + +} /* end of mgsl_flush_chars() */ + +/* mgsl_write() + * + * Send a block of data + * + * Arguments: + * + * tty pointer to tty information structure + * from_user flag: 1 = from user process + * buf pointer to buffer containing send data + * count size of send data in bytes + * + * Return Value: number of characters written + */ +static int mgsl_write(struct tty_struct * tty, int from_user, + const unsigned char *buf, int count) +{ + int c, ret = 0, err; + struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data; + unsigned long flags; + + if ( debug_level >= DEBUG_LEVEL_INFO ) + printk( "%s(%d):mgsl_write(%s) count=%d\n", + __FILE__,__LINE__,info->device_name,count); + + if (mgsl_paranoia_check(info, tty->device, "mgsl_write")) + goto cleanup; + + if (!tty || !info->xmit_buf || !tmp_buf) + goto cleanup; + + if ( info->params.mode == MGSL_MODE_HDLC ) { + /* operating in synchronous (frame oriented) mode */ + + if (info->tx_active) { + ret = 0; goto cleanup; + } + + if ( info->xmit_cnt ) { + /* Send accumulated from send_char() calls */ + /* as frame and wait before accepting more data. */ + ret = 0; + + /* copy data from circular xmit_buf to */ + /* transmit DMA buffer. */ + mgsl_load_tx_dma_buffer(info, + info->xmit_buf,info->xmit_cnt); + if ( debug_level >= DEBUG_LEVEL_INFO ) + printk( "%s(%d):mgsl_write(%s) sync xmit_cnt flushing\n", + __FILE__,__LINE__,info->device_name); + } else { + if ( debug_level >= DEBUG_LEVEL_INFO ) + printk( "%s(%d):mgsl_write(%s) sync transmit accepted\n", + __FILE__,__LINE__,info->device_name); + ret = count; + info->xmit_cnt = count; + if (from_user) { + down(&tmp_buf_sem); + COPY_FROM_USER(err,tmp_buf, buf, count); + if (err) { + if ( debug_level >= DEBUG_LEVEL_INFO ) + printk( "%s(%d):mgsl_write(%s) sync user buf copy failed\n", + __FILE__,__LINE__,info->device_name); + ret = -EFAULT; + } else + mgsl_load_tx_dma_buffer(info,tmp_buf,count); + up(&tmp_buf_sem); + } + else + mgsl_load_tx_dma_buffer(info,buf,count); + } + } else { + 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; + + COPY_FROM_USER(err,tmp_buf, buf, c); + c -= err; + if (!c) { + if (!ret) + ret = -EFAULT; + break; + } + spin_lock_irqsave(&info->irq_spinlock,flags); + 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; + spin_unlock_irqrestore(&info->irq_spinlock,flags); + buf += c; + count -= c; + ret += c; + } + up(&tmp_buf_sem); + } else { + while (1) { + spin_lock_irqsave(&info->irq_spinlock,flags); + c = MIN(count, + MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, + SERIAL_XMIT_SIZE - info->xmit_head)); + if (c <= 0) { + spin_unlock_irqrestore(&info->irq_spinlock,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; + spin_unlock_irqrestore(&info->irq_spinlock,flags); + buf += c; + count -= c; + ret += c; + } + } + } + + if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped) { + spin_lock_irqsave(&info->irq_spinlock,flags); + if (!info->tx_active) + usc_start_transmitter(info); + spin_unlock_irqrestore(&info->irq_spinlock,flags); + } +cleanup: + if ( debug_level >= DEBUG_LEVEL_INFO ) + printk( "%s(%d):mgsl_write(%s) returning=%d\n", + __FILE__,__LINE__,info->device_name,ret); + + return ret; + +} /* end of mgsl_write() */ + +/* mgsl_write_room() + * + * Return the count of free bytes in transmit buffer + * + * Arguments: tty pointer to tty info structure + * Return Value: None + */ +static int mgsl_write_room(struct tty_struct *tty) +{ + struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data; + int ret; + + if (mgsl_paranoia_check(info, tty->device, "mgsl_write_room")) + return 0; + ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1; + if (ret < 0) + ret = 0; + + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):mgsl_write_room(%s)=%d\n", + __FILE__,__LINE__, info->device_name,ret ); + + if ( info->params.mode == MGSL_MODE_HDLC ) { + /* operating in synchronous (frame oriented) mode */ + if ( info->tx_active ) + return 0; + else + return HDLC_MAX_FRAME_SIZE; + } + + return ret; + +} /* end of mgsl_write_room() */ + +/* mgsl_chars_in_buffer() + * + * Return the count of bytes in transmit buffer + * + * Arguments: tty pointer to tty info structure + * Return Value: None + */ +static int mgsl_chars_in_buffer(struct tty_struct *tty) +{ + struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data; + + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):mgsl_chars_in_buffer(%s)\n", + __FILE__,__LINE__, info->device_name ); + + if (mgsl_paranoia_check(info, tty->device, "mgsl_chars_in_buffer")) + return 0; + + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):mgsl_chars_in_buffer(%s)=%d\n", + __FILE__,__LINE__, info->device_name,info->xmit_cnt ); + + if ( info->params.mode == MGSL_MODE_HDLC ) { + /* operating in synchronous (frame oriented) mode */ + if ( info->tx_active ) + return info->tx_buffer_list[0].rcc; + else + return 0; + } + + return info->xmit_cnt; +} /* end of mgsl_chars_in_buffer() */ + +/* mgsl_flush_buffer() + * + * Discard all data in the send buffer + * + * Arguments: tty pointer to tty info structure + * Return Value: None + */ +static void mgsl_flush_buffer(struct tty_struct *tty) +{ + struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data; + unsigned long flags; + + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):mgsl_flush_buffer(%s) entry\n", + __FILE__,__LINE__, info->device_name ); + + if (mgsl_paranoia_check(info, tty->device, "mgsl_flush_buffer")) + return; + + spin_lock_irqsave(&info->irq_spinlock,flags); + info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; + del_timer(&info->tx_timer); + spin_unlock_irqrestore(&info->irq_spinlock,flags); + + wake_up_interruptible(&tty->write_wait); + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); + +} /* end of mgsl_flush_buffer() */ + +/* mgsl_send_xchar() + * + * Send a high-priority XON/XOFF character + * + * Arguments: tty pointer to tty info structure + * ch character to send + * Return Value: None + */ +static void mgsl_send_xchar(struct tty_struct *tty, char ch) +{ + struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data; + unsigned long flags; + + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):mgsl_send_xchar(%s,%d)\n", + __FILE__,__LINE__, info->device_name, ch ); + + if (mgsl_paranoia_check(info, tty->device, "mgsl_send_xchar")) + return; + + info->x_char = ch; + if (ch) { + /* Make sure transmit interrupts are on */ + spin_lock_irqsave(&info->irq_spinlock,flags); + if (!info->tx_enabled) + usc_start_transmitter(info); + spin_unlock_irqrestore(&info->irq_spinlock,flags); + } +} /* end of mgsl_send_xchar() */ + +/* mgsl_throttle() + * + * Signal remote device to throttle send data (our receive data) + * + * Arguments: tty pointer to tty info structure + * Return Value: None + */ +static void mgsl_throttle(struct tty_struct * tty) +{ + struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data; + unsigned long flags; + + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):mgsl_throttle(%s) entry\n", + __FILE__,__LINE__, info->device_name ); + + if (mgsl_paranoia_check(info, tty->device, "mgsl_throttle")) + return; + + if (I_IXOFF(tty)) + mgsl_send_xchar(tty, STOP_CHAR(tty)); + + if (tty->termios->c_cflag & CRTSCTS) { + spin_lock_irqsave(&info->irq_spinlock,flags); + info->serial_signals &= ~SerialSignal_RTS; + usc_set_serial_signals(info); + spin_unlock_irqrestore(&info->irq_spinlock,flags); + } +} /* end of mgsl_throttle() */ + +/* mgsl_unthrottle() + * + * Signal remote device to stop throttling send data (our receive data) + * + * Arguments: tty pointer to tty info structure + * Return Value: None + */ +static void mgsl_unthrottle(struct tty_struct * tty) +{ + struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data; + unsigned long flags; + + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):mgsl_unthrottle(%s) entry\n", + __FILE__,__LINE__, info->device_name ); + + if (mgsl_paranoia_check(info, tty->device, "mgsl_unthrottle")) + return; + + if (I_IXOFF(tty)) { + if (info->x_char) + info->x_char = 0; + else + mgsl_send_xchar(tty, START_CHAR(tty)); + } + + if (tty->termios->c_cflag & CRTSCTS) { + spin_lock_irqsave(&info->irq_spinlock,flags); + info->serial_signals |= SerialSignal_RTS; + usc_set_serial_signals(info); + spin_unlock_irqrestore(&info->irq_spinlock,flags); + } + +} /* end of mgsl_unthrottle() */ + +/* mgsl_get_stats() + * + * get the current serial parameters information + * + * Arguments: info pointer to device instance data + * user_icount pointer to buffer to hold returned stats + * + * Return Value: 0 if success, otherwise error code + */ +static int mgsl_get_stats(struct mgsl_struct * info, struct mgsl_icount *user_icount) +{ + int err; + + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):mgsl_get_params(%s)\n", + __FILE__,__LINE__, info->device_name); + + COPY_TO_USER(err,user_icount, &info->icount, sizeof(struct mgsl_icount)); + if (err) { + if ( debug_level >= DEBUG_LEVEL_INFO ) + printk( "%s(%d):mgsl_get_stats(%s) user buffer copy failed\n", + __FILE__,__LINE__,info->device_name); + return -EFAULT; + } + + return 0; + +} /* end of mgsl_get_stats() */ + +/* mgsl_get_params() + * + * get the current serial parameters information + * + * Arguments: info pointer to device instance data + * user_params pointer to buffer to hold returned params + * + * Return Value: 0 if success, otherwise error code + */ +static int mgsl_get_params(struct mgsl_struct * info, MGSL_PARAMS *user_params) +{ + int err; + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):mgsl_get_params(%s)\n", + __FILE__,__LINE__, info->device_name); + + COPY_TO_USER(err,user_params, &info->params, sizeof(MGSL_PARAMS)); + if (err) { + if ( debug_level >= DEBUG_LEVEL_INFO ) + printk( "%s(%d):mgsl_get_params(%s) user buffer copy failed\n", + __FILE__,__LINE__,info->device_name); + return -EFAULT; + } + + return 0; + +} /* end of mgsl_get_params() */ + +/* mgsl_set_params() + * + * set the serial parameters + * + * Arguments: + * + * info pointer to device instance data + * new_params user buffer containing new serial params + * + * Return Value: 0 if success, otherwise error code + */ +static int mgsl_set_params(struct mgsl_struct * info, MGSL_PARAMS *new_params) +{ + unsigned long flags; + MGSL_PARAMS tmp_params; + int err; + + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):mgsl_set_params %s\n", __FILE__,__LINE__, + info->device_name ); + COPY_FROM_USER(err,&tmp_params, new_params, sizeof(MGSL_PARAMS)); + if (err) { + if ( debug_level >= DEBUG_LEVEL_INFO ) + printk( "%s(%d):mgsl_set_params(%s) user buffer copy failed\n", + __FILE__,__LINE__,info->device_name); + return -EFAULT; + } + + spin_lock_irqsave(&info->irq_spinlock,flags); + memcpy(&info->params,&tmp_params,sizeof(MGSL_PARAMS)); + spin_unlock_irqrestore(&info->irq_spinlock,flags); + + mgsl_change_params(info); + + return 0; + +} /* end of mgsl_set_params() */ + +/* mgsl_get_txidle() + * + * get the current transmit idle mode + * + * Arguments: info pointer to device instance data + * idle_mode pointer to buffer to hold returned idle mode + * + * Return Value: 0 if success, otherwise error code + */ +static int mgsl_get_txidle(struct mgsl_struct * info, int*idle_mode) +{ + int err; + + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):mgsl_get_txidle(%s)=%d\n", + __FILE__,__LINE__, info->device_name, info->idle_mode); + + COPY_TO_USER(err,idle_mode, &info->idle_mode, sizeof(int)); + if (err) { + if ( debug_level >= DEBUG_LEVEL_INFO ) + printk( "%s(%d):mgsl_get_txidle(%s) user buffer copy failed\n", + __FILE__,__LINE__,info->device_name); + return -EFAULT; + } + + return 0; + +} /* end of mgsl_get_txidle() */ + +/* mgsl_set_txidle() service ioctl to set transmit idle mode + * + * Arguments: info pointer to device instance data + * idle_mode new idle mode + * + * Return Value: 0 if success, otherwise error code + */ +static int mgsl_set_txidle(struct mgsl_struct * info, int idle_mode) +{ + unsigned long flags; + + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):mgsl_set_txidle(%s,%d)\n", __FILE__,__LINE__, + info->device_name, idle_mode ); + + spin_lock_irqsave(&info->irq_spinlock,flags); + info->idle_mode = idle_mode; + usc_set_txidle( info ); + spin_unlock_irqrestore(&info->irq_spinlock,flags); + return 0; + +} /* end of mgsl_set_txidle() */ + +/* mgsl_txenable() + * + * enable or disable the transmitter + * + * Arguments: + * + * info pointer to device instance data + * enable 1 = enable, 0 = disable + * + * Return Value: 0 if success, otherwise error code + */ +static int mgsl_txenable(struct mgsl_struct * info, int enable) +{ + unsigned long flags; + + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):mgsl_txenable(%s,%d)\n", __FILE__,__LINE__, + info->device_name, enable); + + spin_lock_irqsave(&info->irq_spinlock,flags); + if ( enable ) { + if ( !info->tx_enabled ) + usc_start_transmitter(info); + } else { + if ( info->tx_enabled ) + usc_stop_transmitter(info); + } + spin_unlock_irqrestore(&info->irq_spinlock,flags); + return 0; + +} /* end of mgsl_txenable() */ + +/* mgsl_txabort() abort send HDLC frame + * + * Arguments: info pointer to device instance data + * Return Value: 0 if success, otherwise error code + */ +static int mgsl_txabort(struct mgsl_struct * info) +{ + unsigned long flags; + + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):mgsl_txabort(%s)\n", __FILE__,__LINE__, + info->device_name); + + spin_lock_irqsave(&info->irq_spinlock,flags); + if ( info->tx_active && info->params.mode == MGSL_MODE_HDLC ) + usc_TCmd(info,TCmd_SendAbort); + spin_unlock_irqrestore(&info->irq_spinlock,flags); + return 0; + +} /* end of mgsl_txabort() */ + +/* mgsl_rxenable() enable or disable the receiver + * + * Arguments: info pointer to device instance data + * enable 1 = enable, 0 = disable + * Return Value: 0 if success, otherwise error code + */ +static int mgsl_rxenable(struct mgsl_struct * info, int enable) +{ + unsigned long flags; + + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):mgsl_rxenable(%s,%d)\n", __FILE__,__LINE__, + info->device_name, enable); + + spin_lock_irqsave(&info->irq_spinlock,flags); + if ( enable ) { + if ( !info->rx_enabled ) + usc_start_receiver(info); + } else { + if ( info->rx_enabled ) + usc_stop_receiver(info); + } + spin_unlock_irqrestore(&info->irq_spinlock,flags); + return 0; + +} /* end of mgsl_rxenable() */ + +/* mgsl_wait_event() wait for specified event to occur + * + * Arguments: info pointer to device instance data + * mask bitmask of events to wait for + * Return Value: bit mask of triggering event, otherwise error code + */ +static int mgsl_wait_event(struct mgsl_struct * info, int mask) +{ + unsigned long flags; + int s; + int rc=0; + u16 regval; + struct mgsl_icount cprev, cnow; + + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):mgsl_wait_event(%s,%d)\n", __FILE__,__LINE__, + info->device_name, mask); + + spin_lock_irqsave(&info->irq_spinlock,flags); + + /* note the counters on entry */ + cprev = info->icount; + + if (mask & MgslEvent_ExitHuntMode) { + /* enable exit hunt mode IRQ */ + regval = usc_InReg(info,RICR); + if (!(regval & RXSTATUS_EXITED_HUNT)) + usc_OutReg(info, RICR, regval | RXSTATUS_EXITED_HUNT); + } + + if (mask & MgslEvent_IdleReceived) { + /* enable idle mode received IRQ */ + regval = usc_InReg(info,RICR); + if (!(regval & RXSTATUS_IDLE_RECEIVED)) + usc_OutReg(info, RICR, regval | RXSTATUS_IDLE_RECEIVED); + } + + spin_unlock_irqrestore(&info->irq_spinlock,flags); + + while(!rc) { + /* sleep until event occurs */ + interruptible_sleep_on(&info->event_wait_q); + + /* see if a signal woke us */ + if (signal_pending(current)) { + rc = -ERESTARTSYS; + break; + } + + spin_lock_irqsave(&info->irq_spinlock,flags); + /* get icount and serial signal states */ + cnow = info->icount; + s = info->serial_signals; + spin_unlock_irqrestore(&info->irq_spinlock,flags); + + rc = 0; + + if (cnow.dsr != cprev.dsr) + rc |= (mask & ((s & SerialSignal_DSR) ? + MgslEvent_DsrActive:MgslEvent_DsrInactive)); + + if (cnow.dcd != cprev.dcd) + rc |= (mask & ((s & SerialSignal_DCD) ? + MgslEvent_DcdActive:MgslEvent_DcdInactive)); + + if (cnow.cts != cprev.cts) + rc |= (mask & ((s & SerialSignal_CTS) ? + MgslEvent_CtsActive:MgslEvent_CtsInactive)); + + if (cnow.rng != cprev.rng) + rc |= (mask & ((s & SerialSignal_RI) ? + MgslEvent_RiActive:MgslEvent_RiInactive)); + + if (cnow.exithunt != cprev.exithunt) + rc |= (mask & MgslEvent_ExitHuntMode); + + if (cnow.rxidle != cprev.rxidle) + rc |= (mask & MgslEvent_ExitHuntMode); + + if (!rc) + rc = -EIO; /* no change => error */ + + cprev = cnow; + } + + if (mask & (MgslEvent_ExitHuntMode + MgslEvent_IdleReceived)) { + spin_lock_irqsave(&info->irq_spinlock,flags); + if (!info->event_wait_q) { + /* disable enable exit hunt mode/idle rcvd IRQs */ + regval = usc_InReg(info,RICR); + usc_OutReg(info, RICR, regval & + ~(RXSTATUS_EXITED_HUNT + RXSTATUS_IDLE_RECEIVED)); + } + spin_unlock_irqrestore(&info->irq_spinlock,flags); + } + + return rc; + +} /* end of mgsl_wait_event() */ + +/* get_modem_info() + * + * Read the state of the serial control and + * status signals and return to caller. + * + * Arguments: info pointer to device instance data + * value pointer to int to hold returned info + * + * Return Value: 0 if success, otherwise error code + */ +static int get_modem_info(struct mgsl_struct * info, unsigned int *value) +{ + unsigned int result = 0; + unsigned long flags; + int err; + + spin_lock_irqsave(&info->irq_spinlock,flags); + usc_get_serial_signals(info); + spin_unlock_irqrestore(&info->irq_spinlock,flags); + + if (info->serial_signals & SerialSignal_RTS) + result |= TIOCM_RTS; + if (info->serial_signals & SerialSignal_DTR) + result |= TIOCM_DTR; + if (info->serial_signals & SerialSignal_DCD) + result |= TIOCM_CAR; + if (info->serial_signals & SerialSignal_RI) + result |= TIOCM_RNG; + if (info->serial_signals & SerialSignal_DSR) + result |= TIOCM_DSR; + if (info->serial_signals & SerialSignal_CTS) + result |= TIOCM_CTS; + + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):mgsl_get_modem_info %s value=%08X\n", + __FILE__,__LINE__, info->device_name, *value ); + + PUT_USER(err,result,value); + return err; +} /* end of get_modem_info() */ + +/* set_modem_info() + * + * Set the state of the modem control signals (DTR/RTS) + * + * Arguments: + * + * info pointer to device instance data + * cmd signal command: TIOCMBIS = set bit TIOCMBIC = clear bit + * TIOCMSET = set/clear signal values + * value bit mask for command + * + * Return Value: 0 if success, otherwise error code + */ +static int set_modem_info(struct mgsl_struct * info, unsigned int cmd, + unsigned int *value) +{ + int error; + unsigned int arg; + unsigned long flags; + + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):mgsl_set_modem_info %s\n", __FILE__,__LINE__, + info->device_name ); + + GET_USER(error,arg,value); + if (error) + return error; + + switch (cmd) { + case TIOCMBIS: + if (arg & TIOCM_RTS) + info->serial_signals |= SerialSignal_RTS; + if (arg & TIOCM_DTR) + info->serial_signals |= SerialSignal_DTR; + break; + case TIOCMBIC: + if (arg & TIOCM_RTS) + info->serial_signals &= ~SerialSignal_RTS; + if (arg & TIOCM_DTR) + info->serial_signals &= ~SerialSignal_DTR; + break; + case TIOCMSET: + if (arg & TIOCM_RTS) + info->serial_signals |= SerialSignal_RTS; + else + info->serial_signals &= ~SerialSignal_RTS; + + if (arg & TIOCM_DTR) + info->serial_signals |= SerialSignal_DTR; + else + info->serial_signals &= ~SerialSignal_DTR; + break; + default: + return -EINVAL; + } + + spin_lock_irqsave(&info->irq_spinlock,flags); + usc_set_serial_signals(info); + spin_unlock_irqrestore(&info->irq_spinlock,flags); + + return 0; + +} /* end of set_modem_info() */ + +#if LINUX_VERSION_CODE >= VERSION(2,1,0) +/* mgsl_break() Set or clear transmit break condition + * + * Arguments: tty pointer to tty instance data + * break_state -1=set break condition, 0=clear + * Return Value: None + */ +static void mgsl_break(struct tty_struct *tty, int break_state) +{ + struct mgsl_struct * info = (struct mgsl_struct *)tty->driver_data; + unsigned long flags; + + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):mgsl_break(%s,%d)\n", + __FILE__,__LINE__, info->device_name, break_state); + + if (mgsl_paranoia_check(info, tty->device, "mgsl_break")) + return; + + spin_lock_irqsave(&info->irq_spinlock,flags); + if (break_state == -1) + usc_OutReg(info,IOCR,(u16)(usc_InReg(info,IOCR) | BIT7)); + else + usc_OutReg(info,IOCR,(u16)(usc_InReg(info,IOCR) & ~BIT7)); + spin_unlock_irqrestore(&info->irq_spinlock,flags); + +} /* end of mgsl_break() */ +#endif + +/* mgsl_ioctl() Service an IOCTL request + * + * Arguments: + * + * tty pointer to tty instance data + * file pointer to associated file object for device + * cmd IOCTL command code + * arg command argument/context + * + * Return Value: 0 if success, otherwise error code + */ +static int mgsl_ioctl(struct tty_struct *tty, struct file * file, + unsigned int cmd, unsigned long arg) +{ + int error; + struct mgsl_struct * info = (struct mgsl_struct *)tty->driver_data; + struct mgsl_icount cprev, cnow; /* kernel counter temps */ + struct serial_icounter_struct *p_cuser; /* user space */ + unsigned long flags; + + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):mgsl_ioctl %s cmd=%08X\n", __FILE__,__LINE__, + info->device_name, cmd ); + + if (mgsl_paranoia_check(info, tty->device, "mgsl_ioctl")) + return -ENODEV; + + if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && + (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 MGSL_IOCGPARAMS: + return mgsl_get_params(info,(MGSL_PARAMS *)arg); + case MGSL_IOCSPARAMS: + return mgsl_set_params(info,(MGSL_PARAMS *)arg); + case MGSL_IOCGTXIDLE: + return mgsl_get_txidle(info,(int*)arg); + case MGSL_IOCSTXIDLE: + return mgsl_set_txidle(info,(int)arg); + case MGSL_IOCTXENABLE: + return mgsl_txenable(info,(int)arg); + case MGSL_IOCRXENABLE: + return mgsl_rxenable(info,(int)arg); + case MGSL_IOCTXABORT: + return mgsl_txabort(info); + case MGSL_IOCGSTATS: + return mgsl_get_stats(info,(struct mgsl_icount*)arg); + case MGSL_IOCWAITEVENT: + return mgsl_wait_event(info,(int)arg); + case MGSL_IOCCLRMODCOUNT: + while(MOD_IN_USE) + MOD_DEC_USE_COUNT; + 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: + spin_lock_irqsave(&info->irq_spinlock,flags); + /* note the counters on entry */ + cprev = info->icount; + spin_unlock_irqrestore(&info->irq_spinlock,flags); + while (1) { + interruptible_sleep_on(&info->status_event_wait_q); + /* see if a signal did it */ + if (signal_pending(current)) + return -ERESTARTSYS; + save_flags(flags); cli(); + cnow = info->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: + spin_lock_irqsave(&info->irq_spinlock,flags); + cnow = info->icount; + spin_unlock_irqrestore(&info->irq_spinlock,flags); + p_cuser = (struct serial_icounter_struct *) arg; + PUT_USER(error,cnow.cts, &p_cuser->cts); + if (error) return error; + PUT_USER(error,cnow.dsr, &p_cuser->dsr); + if (error) return error; + PUT_USER(error,cnow.rng, &p_cuser->rng); + if (error) return error; + PUT_USER(error,cnow.dcd, &p_cuser->dcd); + if (error) return error; +#if LINUX_VERSION_CODE >= VERSION(2,1,0) + PUT_USER(error,cnow.rx, &p_cuser->rx); + if (error) return error; + PUT_USER(error,cnow.tx, &p_cuser->tx); + if (error) return error; + PUT_USER(error,cnow.frame, &p_cuser->frame); + if (error) return error; + PUT_USER(error,cnow.overrun, &p_cuser->overrun); + if (error) return error; + PUT_USER(error,cnow.parity, &p_cuser->parity); + if (error) return error; + PUT_USER(error,cnow.brk, &p_cuser->brk); + if (error) return error; + PUT_USER(error,cnow.buf_overrun, &p_cuser->buf_overrun); + if (error) return error; +#endif + return 0; + + default: + return -ENOIOCTLCMD; + } + return 0; +} + +/* mgsl_set_termios() + * + * Set new termios settings + * + * Arguments: + * + * tty pointer to tty structure + * termios pointer to buffer to hold returned old termios + * + * Return Value: None + */ +static void mgsl_set_termios(struct tty_struct *tty, struct termios *old_termios) +{ + struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data; + unsigned long flags; + + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):mgsl_set_termios %s\n", __FILE__,__LINE__, + tty->driver.name ); + + /* just return if nothing has changed */ + if ((tty->termios->c_cflag == old_termios->c_cflag) + && (RELEVANT_IFLAG(tty->termios->c_iflag) + == RELEVANT_IFLAG(old_termios->c_iflag))) + return; + + mgsl_change_params(info); + + /* Handle transition to B0 status */ + if (old_termios->c_cflag & CBAUD && + !(tty->termios->c_cflag & CBAUD)) { + info->serial_signals &= ~(SerialSignal_RTS + SerialSignal_DTR); + spin_lock_irqsave(&info->irq_spinlock,flags); + usc_set_serial_signals(info); + spin_unlock_irqrestore(&info->irq_spinlock,flags); + } + + /* Handle transition away from B0 status */ + if (!(old_termios->c_cflag & CBAUD) && + tty->termios->c_cflag & CBAUD) { + info->serial_signals |= SerialSignal_DTR; + if (!(tty->termios->c_cflag & CRTSCTS) || + !test_bit(TTY_THROTTLED, &tty->flags)) { + info->serial_signals |= SerialSignal_RTS; + } + spin_lock_irqsave(&info->irq_spinlock,flags); + usc_set_serial_signals(info); + spin_unlock_irqrestore(&info->irq_spinlock,flags); + } + + /* Handle turning off CRTSCTS */ + if (old_termios->c_cflag & CRTSCTS && + !(tty->termios->c_cflag & CRTSCTS)) { + tty->hw_stopped = 0; + mgsl_start(tty); + } + +} /* end of mgsl_set_termios() */ + +/* mgsl_close() + * + * Called when port is closed. Wait for remaining data to be + * sent. Disable port and free resources. + * + * Arguments: + * + * tty pointer to open tty structure + * filp pointer to open file object + * + * Return Value: None + */ +static void mgsl_close(struct tty_struct *tty, struct file * filp) +{ + struct mgsl_struct * info = (struct mgsl_struct *)tty->driver_data; + + if (!info || mgsl_paranoia_check(info, tty->device, "mgsl_close")) + return; + + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):mgsl_close(%s) entry, count=%d\n", + __FILE__,__LINE__, info->device_name, info->count); + + if (!info->count || tty_hung_up_p(filp)) + goto cleanup; + + if ((tty->count == 1) && (info->count != 1)) { + /* + * tty->count is 1 and the tty structure will be freed. + * info->count should be one in this case. + * if it's not, correct it so that the port is shutdown. + */ + printk("mgsl_close: bad refcount; tty->count is 1, " + "info->count is %d\n", info->count); + info->count = 1; + } + + info->count--; + + /* if at least one open remaining, leave hardware active */ + if (info->count) + goto cleanup; + + 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->normal_termios = *tty->termios; + if (info->flags & ASYNC_CALLOUT_ACTIVE) + info->callout_termios = *tty->termios; + + /* set tty->closing to notify line discipline to + * only process XON/XOFF characters. Only the N_TTY + * discipline appears to use this (ppp does not). + */ + tty->closing = 1; + + /* wait for transmit data to clear all layers */ + + if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE) { + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):mgsl_close(%s) calling tty_wait_until_sent\n", + __FILE__,__LINE__, info->device_name ); + tty_wait_until_sent(tty, info->closing_wait); + } + + if (info->flags & ASYNC_INITIALIZED) + mgsl_wait_until_sent(tty, info->timeout); + + if (tty->driver.flush_buffer) + tty->driver.flush_buffer(tty); + + if (tty->ldisc.flush_buffer) + tty->ldisc.flush_buffer(tty); + + shutdown(info); + + tty->closing = 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); + +cleanup: + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):mgsl_close(%s) exit, count=%d\n", __FILE__,__LINE__, + tty->driver.name, info->count); + if(MOD_IN_USE) + MOD_DEC_USE_COUNT; + +} /* end of mgsl_close() */ + +/* mgsl_wait_until_sent() + * + * Wait until the transmitter is empty. + * + * Arguments: + * + * tty pointer to tty info structure + * timeout time to wait for send completion + * + * Return Value: None + */ +static void mgsl_wait_until_sent(struct tty_struct *tty, int timeout) +{ + struct mgsl_struct * info = (struct mgsl_struct *)tty->driver_data; + unsigned long orig_jiffies, char_time; + + if (!info ) + return; + + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):mgsl_wait_until_sent(%s) entry\n", + __FILE__,__LINE__, info->device_name ); + + if (mgsl_paranoia_check(info, tty->device, "mgsl_wait_until_sent")) + return; + + if (!(info->flags & ASYNC_INITIALIZED)) + goto exit; + + orig_jiffies = jiffies; + + /* Set check interval to 1/5 of estimated time to + * send a character, and make it at least 1. The check + * interval should also be less than the timeout. + * Note: use tight timings here to satisfy the NIST-PCTS. + */ + + if ( info->params.data_rate ) { + char_time = info->timeout/(32 * 5); + if (!char_time) + char_time++; + } else + char_time = 1; + + if (timeout) + char_time = MIN(char_time, timeout); + + if ( info->params.mode == MGSL_MODE_HDLC ) { + while (info->tx_active) { + 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; + } + } else { + while (!(usc_InReg(info,TCSR) & TXSTATUS_ALL_SENT) && + info->tx_enabled) { + 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; +exit: + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):mgsl_wait_until_sent(%s) exit\n", + __FILE__,__LINE__, info->device_name ); + +} /* end of mgsl_wait_until_sent() */ + +/* mgsl_hangup() + * + * Called by tty_hangup() when a hangup is signaled. + * This is the same as to closing all open files for the port. + * + * Arguments: tty pointer to associated tty object + * Return Value: None + */ +static void mgsl_hangup(struct tty_struct *tty) +{ + struct mgsl_struct * info = (struct mgsl_struct *)tty->driver_data; + + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):mgsl_hangup(%s)\n", + __FILE__,__LINE__, info->device_name ); + + if (mgsl_paranoia_check(info, tty->device, "mgsl_hangup")) + return; + + mgsl_flush_buffer(tty); + shutdown(info); + + info->count = 0; + info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE); + info->tty = 0; + + wake_up_interruptible(&info->open_wait); + +} /* end of mgsl_hangup() */ + +/* block_til_ready() + * + * Block the current process until the specified port + * is ready to be opened. + * + * Arguments: + * + * tty pointer to tty info structure + * filp pointer to open file object + * info pointer to device instance data + * + * Return Value: 0 if success, otherwise error code + */ +static int block_til_ready(struct tty_struct *tty, struct file * filp, + struct mgsl_struct *info) +{ + struct wait_queue wait = { current, NULL }; + int retval; + int do_clocal = 0, extra_count = 0; + unsigned long flags; + + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):block_til_ready on %s\n", + __FILE__,__LINE__, tty->driver.name ); + + if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) { + /* this is a callout device */ + /* just verify that normal device is not in use */ + 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 (filp->f_flags & O_NONBLOCK || tty->flags & (1 << TTY_IO_ERROR)){ + /* nonblock mode is set or port is not enabled */ + /* just verify that callout device is not active */ + if (info->flags & ASYNC_CALLOUT_ACTIVE) + return -EBUSY; + info->flags |= ASYNC_NORMAL_ACTIVE; + return 0; + } + + if (info->flags & ASYNC_CALLOUT_ACTIVE) { + if (info->normal_termios.c_cflag & CLOCAL) + do_clocal = 1; + } else { + if (tty->termios->c_cflag & CLOCAL) + do_clocal = 1; + } + + /* Wait for 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 + * mgsl_close() knows when to free things. We restore it upon + * exit, either normal or abnormal. + */ + + retval = 0; + add_wait_queue(&info->open_wait, &wait); + + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):block_til_ready before block on %s count=%d\n", + __FILE__,__LINE__, tty->driver.name, info->count ); + + save_flags(flags); cli(); + if (!tty_hung_up_p(filp)) { + extra_count = 1; + info->count--; + } + restore_flags(flags); + info->blocked_open++; + + while (1) { + if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && + (tty->termios->c_cflag & CBAUD)) { + spin_lock_irqsave(&info->irq_spinlock,flags); + info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR; + usc_set_serial_signals(info); + spin_unlock_irqrestore(&info->irq_spinlock,flags); + } + + current->state = TASK_INTERRUPTIBLE; + + if (tty_hung_up_p(filp) || !(info->flags & ASYNC_INITIALIZED)){ + retval = (info->flags & ASYNC_HUP_NOTIFY) ? + -EAGAIN : -ERESTARTSYS; + break; + } + + spin_lock_irqsave(&info->irq_spinlock,flags); + usc_get_serial_signals(info); + spin_unlock_irqrestore(&info->irq_spinlock,flags); + + if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && + !(info->flags & ASYNC_CLOSING) && + (do_clocal || (info->serial_signals & SerialSignal_DCD)) ) { + break; + } + + if (signal_pending(current)) { + retval = -ERESTARTSYS; + break; + } + + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):block_til_ready blocking on %s count=%d\n", + __FILE__,__LINE__, tty->driver.name, info->count ); + + schedule(); + } + + current->state = TASK_RUNNING; + remove_wait_queue(&info->open_wait, &wait); + + if (extra_count) + info->count++; + info->blocked_open--; + + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):block_til_ready after blocking on %s count=%d\n", + __FILE__,__LINE__, tty->driver.name, info->count ); + + if (!retval) + info->flags |= ASYNC_NORMAL_ACTIVE; + + return retval; + +} /* end of block_til_ready() */ + +/* mgsl_open() + * + * Called when a port is opened. Init and enable port. + * Perform serial-specific initialization for the tty structure. + * + * Arguments: tty pointer to tty info structure + * filp associated file pointer + * + * Return Value: 0 if success, otherwise error code + */ +static int mgsl_open(struct tty_struct *tty, struct file * filp) +{ + struct mgsl_struct *info; + int retval, line; + unsigned long page; + + /* verify range of specified line number */ + line = MINOR(tty->device) - tty->driver.minor_start; + if ((line < 0) || (line >= mgsl_device_count)) { + printk("%s(%d):mgsl_open with illegal line #%d.\n", + __FILE__,__LINE__,line); + return -ENODEV; + } + + /* find the info structure for the specified line */ + info = mgsl_device_list; + while(info && info->line != line) + info = info->next_device; + if ( !info ){ + printk("%s(%d):Can't find specified device on open (line=%d)\n", + __FILE__,__LINE__,line); + return -ENODEV; + } + + tty->driver_data = info; + info->tty = tty; + if (mgsl_paranoia_check(info, tty->device, "mgsl_open")) + return -ENODEV; + + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):mgsl_open(%s), old ref count = %d\n", + __FILE__,__LINE__,tty->driver.name, info->count); + + MOD_INC_USE_COUNT; + + /* If port is closing, signal caller to try again */ + if (tty_hung_up_p(filp) || info->flags & ASYNC_CLOSING){ + if (info->flags & ASYNC_CLOSING) + interruptible_sleep_on(&info->close_wait); + retval = ((info->flags & ASYNC_HUP_NOTIFY) ? + -EAGAIN : -ERESTARTSYS); + goto cleanup; + } + + if (!tmp_buf) { + page = get_free_page(GFP_KERNEL); + if (!page) { + retval = -ENOMEM; + goto cleanup; + } + if (tmp_buf) + free_page(page); + else + tmp_buf = (unsigned char *) page; + } + +#if LINUX_VERSION_CODE >= VERSION(2,1,0) + info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; +#endif + + info->count++; + if (info->count == 1) { + /* 1st open on this device, init hardware */ + retval = startup(info); + if (retval < 0) + goto cleanup; + } + + retval = block_til_ready(tty, filp, info); + if (retval) { + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):block_til_ready(%s) returned %d\n", + __FILE__,__LINE__, info->device_name, retval); + goto cleanup; + } + + if ((info->count == 1) && + info->flags & ASYNC_SPLIT_TERMIOS) { + if (tty->driver.subtype == SERIAL_TYPE_NORMAL) + *tty->termios = info->normal_termios; + else + *tty->termios = info->callout_termios; + mgsl_change_params(info); + } + + info->session = current->session; + info->pgrp = current->pgrp; + + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):mgsl_open(%s) success\n", + __FILE__,__LINE__, info->device_name); + retval = 0; + +cleanup: + if (retval) { + if(MOD_IN_USE) + MOD_DEC_USE_COUNT; + if(info->count) + info->count--; + } + + return retval; + +} /* end of mgsl_open() */ + +/* + * /proc fs routines.... + */ + +static inline int line_info(char *buf, struct mgsl_struct *info) +{ + char stat_buf[30]; + int ret; + unsigned long flags; + + if (info->bus_type == MGSL_BUS_TYPE_PCI) { + ret = sprintf(buf, "%s:PCI io:%04X irq:%d mem:%08X lcr:%08X", + info->device_name, info->io_base, info->irq_level, + info->phys_memory_base, info->phys_lcr_base); + } else { + ret = sprintf(buf, "%s:(E)ISA io:%04X irq:%d dma:%d", + info->device_name, info->io_base, + info->irq_level, info->dma_level); + } + + /* output current serial signal states */ + spin_lock_irqsave(&info->irq_spinlock,flags); + usc_get_serial_signals(info); + spin_unlock_irqrestore(&info->irq_spinlock,flags); + + stat_buf[0] = 0; + stat_buf[1] = 0; + if (info->serial_signals & SerialSignal_RTS) + strcat(stat_buf, "|RTS"); + if (info->serial_signals & SerialSignal_CTS) + strcat(stat_buf, "|CTS"); + if (info->serial_signals & SerialSignal_DTR) + strcat(stat_buf, "|DTR"); + if (info->serial_signals & SerialSignal_DSR) + strcat(stat_buf, "|DSR"); + if (info->serial_signals & SerialSignal_DCD) + strcat(stat_buf, "|CD"); + if (info->serial_signals & SerialSignal_RI) + strcat(stat_buf, "|RI"); + + if (info->params.mode == MGSL_MODE_HDLC) { + ret += sprintf(buf+ret, " HDLC txok:%d rxok:%d", + info->icount.txok, info->icount.rxok); + if (info->icount.txunder) + ret += sprintf(buf+ret, " txunder:%d", info->icount.txunder); + if (info->icount.txabort) + ret += sprintf(buf+ret, " txabort:%d", info->icount.txabort); + if (info->icount.rxshort) + ret += sprintf(buf+ret, " rxshort:%d", info->icount.rxshort); + if (info->icount.rxlong) + ret += sprintf(buf+ret, " rxlong:%d", info->icount.rxlong); + if (info->icount.rxover) + ret += sprintf(buf+ret, " rxover:%d", info->icount.rxover); + if (info->icount.rxcrc) + ret += sprintf(buf+ret, " rxlong:%d", info->icount.rxcrc); + } else { + ret += sprintf(buf+ret, " ASYNC tx:%d rx:%d", + info->icount.tx, info->icount.rx); + if (info->icount.frame) + ret += sprintf(buf+ret, " fe:%d", info->icount.frame); + if (info->icount.parity) + ret += sprintf(buf+ret, " pe:%d", info->icount.parity); + if (info->icount.brk) + ret += sprintf(buf+ret, " brk:%d", info->icount.brk); + if (info->icount.overrun) + ret += sprintf(buf+ret, " oe:%d", info->icount.overrun); + } + + /* Append serial signal status to end */ + ret += sprintf(buf+ret, " %s\n", stat_buf+1); + + ret += sprintf(buf+ret, "txactive=%d bh_req=%d bh_run=%d bh_q=%p\n", + info->tx_active,info->bh_requested,info->bh_running, + info->bh_queue_head); + + spin_lock_irqsave(&info->irq_spinlock,flags); + { + u16 Tscr = usc_InReg( info, TCSR ); + u16 Tdmr = usc_InDmaReg( info, TDMR ); + u16 Ticr = usc_InReg( info, TICR ); + u16 Rscr = usc_InReg( info, RCSR ); + u16 Rdmr = usc_InDmaReg( info, RDMR ); + u16 Ricr = usc_InReg( info, RICR ); + u16 Icr = usc_InReg( info, ICR ); + u16 Dccr = usc_InReg( info, DCCR ); + u16 Tmr = usc_InReg( info, TMR ); + u16 Tccr = usc_InReg( info, TCCR ); + u16 Ccar = inw( info->io_base + CCAR ); + ret += sprintf(buf+ret, "tcsr=%04X tdmr=%04X ticr=%04X rcsr=%04X rdmr=%04X\n" + "ricr=%04X icr =%04X dccr=%04X tmr=%04X tccr=%04X ccar=%04X\n", + Tscr,Tdmr,Ticr,Rscr,Rdmr,Ricr,Icr,Dccr,Tmr,Tccr,Ccar ); + } + spin_unlock_irqrestore(&info->irq_spinlock,flags); + +#if 0 && LINUX_VERSION_CODE >= VERSION(2,1,0) + ret += sprintf(buf+ret, "irq_spinlock=%08X\n", + info->irq_spinlock.lock ); +#endif + + return ret; + +} /* end of line_info() */ + +/* mgsl_read_proc() + * + * Called to print information about devices + * + * Arguments: + * page page of memory to hold returned info + * start + * off + * count + * eof + * data + * + * Return Value: + */ +int mgsl_read_proc(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + int len = 0, l; + off_t begin = 0; + struct mgsl_struct *info; + + len += sprintf(page, "synclink driver:%s\n", driver_version); + + info = mgsl_device_list; + while( info ) { + l = line_info(page + len, info); + len += l; + if (len+begin > off+count) + goto done; + if (len+begin < off) { + begin += len; + len = 0; + } + info = info->next_device; + } + + *eof = 1; +done: + if (off >= len+begin) + return 0; + *start = page + (begin-off); + return ((count < begin+len-off) ? count : begin+len-off); + +} /* end of mgsl_read_proc() */ + +/* mgsl_allocate_dma_buffers() + * + * Allocate and format DMA buffers (ISA adapter) + * or format shared memory buffers (PCI adapter). + * + * Arguments: info pointer to device instance data + * Return Value: 0 if success, otherwise error + */ +int mgsl_allocate_dma_buffers(struct mgsl_struct *info) +{ + unsigned short BuffersPerFrame; + + info->last_mem_alloc = 0; + + if ( info->bus_type == MGSL_BUS_TYPE_PCI ) { + /* + * The PCI adapter has 256KBytes of shared memory to use. + * This is 64 PAGE_SIZE buffers. 1 is used for the buffer + * list. 2 are used for the transmit and one is left as + * a spare. The 4K buffer list can hold 128 DMA_BUFFER + * structures at 32bytes each. + */ + + info->rx_buffer_count = 60; + info->tx_buffer_count = 2; + } else { + /* Calculate the number of PAGE_SIZE buffers needed for */ + /* receive and transmit DMA buffers. */ + + /* Calculate the number of DMA buffers necessary to hold the */ + /* largest allowable frame size. Note: If the max frame size is */ + /* not an even multiple of the DMA buffer size then we need to */ + /* round the buffer count per frame up one. */ + + BuffersPerFrame = (unsigned short)(info->max_frame_size/DMABUFFERSIZE); + if ( info->max_frame_size % DMABUFFERSIZE ) + BuffersPerFrame++; + + /* Calculate the number of DMA buffers necessary to */ + /* hold 7 max size receive frames and one max size transmit frame. */ + /* The receive buffer count is bumped by one so we avoid an */ + /* End of List condition if all receive buffers are used when */ + /* using linked list DMA buffers. */ + + info->rx_buffer_count = (BuffersPerFrame * MAXRXFRAMES) + 6; + info->tx_buffer_count = BuffersPerFrame; + } + + if ( debug_level >= DEBUG_LEVEL_INFO ) + printk("%s(%d):Allocating %d TX and %d RX DMA buffers.\n", + __FILE__,__LINE__, info->tx_buffer_count,info->rx_buffer_count); + + if ( mgsl_alloc_buffer_list_memory( info ) < 0 || + mgsl_alloc_frame_memory(info, info->rx_buffer_list, info->rx_buffer_count) < 0 || + mgsl_alloc_frame_memory(info, info->tx_buffer_list, info->tx_buffer_count) < 0) { + printk("%s(%d):Can't allocate DMA buffer memory\n",__FILE__,__LINE__); + return -ENOMEM; + } + + mgsl_reset_rx_dma_buffers( info ); + + return 0; + +} /* end of mgsl_allocate_dma_buffers() */ + +/* + * mgsl_alloc_buffer_list_memory() + * + * Allocate a common DMA buffer for use as the + * receive and transmit buffer lists. + * + * A buffer list is a set of buffer entries where each entry contains + * a pointer to an actual buffer and a pointer to the next buffer entry + * (plus some other info about the buffer). + * + * The buffer entries for a list are built to form a circular list so + * that when the entire list has been traversed you start back at the + * beginning. + * + * This function allocates memory for just the buffer entries. + * The links (pointer to next entry) are filled in with the physical + * address of the next entry so the adapter can navigate the list + * using bus master DMA. The pointers to the actual buffers are filled + * out later when the actual buffers are allocated. + * + * Arguments: info pointer to device instance data + * Return Value: 0 if success, otherwise error + */ +int mgsl_alloc_buffer_list_memory( struct mgsl_struct *info ) +{ + unsigned int i; + + if ( info->bus_type == MGSL_BUS_TYPE_PCI ) { + /* PCI adapter uses shared memory. */ + info->buffer_list = info->memory_base + info->last_mem_alloc; + info->buffer_list_phys = info->last_mem_alloc; + info->last_mem_alloc += BUFFERLISTSIZE; + } else { + /* ISA adapter uses system memory. */ + /* The buffer lists are allocated as a common buffer that both */ + /* the processor and adapter can access. This allows the driver to */ + /* inspect portions of the buffer while other portions are being */ + /* updated by the adapter using Bus Master DMA. */ + + info->buffer_list = kmalloc(BUFFERLISTSIZE, GFP_KERNEL | GFP_DMA); + if ( info->buffer_list == NULL ) + return -ENOMEM; + + info->buffer_list_phys = virt_to_bus(info->buffer_list); + } + + /* We got the memory for the buffer entry lists. */ + /* Initialize the memory block to all zeros. */ + memset( info->buffer_list, 0, BUFFERLISTSIZE ); + + /* Save virtual address pointers to the receive and */ + /* transmit buffer lists. (Receive 1st). These pointers will */ + /* be used by the processor to access the lists. */ + info->rx_buffer_list = (DMABUFFERENTRY *)info->buffer_list; + info->tx_buffer_list = (DMABUFFERENTRY *)info->buffer_list; + info->tx_buffer_list += info->rx_buffer_count; + + /* + * Build the links for the buffer entry lists such that + * two circular lists are built. (Transmit and Receive). + * + * Note: the links are physical addresses + * which are read by the adapter to determine the next + * buffer entry to use. + */ + + for ( i = 0; i < info->rx_buffer_count; i++ ) { + /* calculate and store physical address of this buffer entry */ + info->rx_buffer_list[i].phys_entry = + info->buffer_list_phys + (i * sizeof(DMABUFFERENTRY)); + + /* calculate and store physical address of */ + /* next entry in cirular list of entries */ + + info->rx_buffer_list[i].link = info->buffer_list_phys; + + if ( i < info->rx_buffer_count - 1 ) + info->rx_buffer_list[i].link += (i + 1) * sizeof(DMABUFFERENTRY); + } + + for ( i = 0; i < info->tx_buffer_count; i++ ) { + /* calculate and store physical address of this buffer entry */ + info->tx_buffer_list[i].phys_entry = info->buffer_list_phys + + ((info->rx_buffer_count + i) * sizeof(DMABUFFERENTRY)); + + /* calculate and store physical address of */ + /* next entry in cirular list of entries */ + + info->tx_buffer_list[i].link = info->buffer_list_phys + + info->rx_buffer_count * sizeof(DMABUFFERENTRY); + + if ( i < info->tx_buffer_count - 1 ) + info->tx_buffer_list[i].link += (i + 1) * sizeof(DMABUFFERENTRY); + } + + return 0; + +} /* end of mgsl_alloc_buffer_list_memory() */ + +/* + * mgsl_free_buffer_list_memory() + * + * Free the common DMA buffer allocated for use as the + * receive and transmit buffer lists. The associated Memory + * Descriptor List (MDL) is also freed. + * + * Warning: + * + * The data transfer buffers associated with the buffer list + * MUST be freed before freeing the buffer list itself because + * the buffer list contains the information necessary to free + * the individual buffers! + * + * Arguments: info pointer to device extension + * Return Value: None + */ +void mgsl_free_buffer_list_memory( struct mgsl_struct *info ) +{ + if ( info->buffer_list && info->bus_type != MGSL_BUS_TYPE_PCI ) + kfree_s(info->buffer_list, BUFFERLISTSIZE); + + info->buffer_list = NULL; + info->rx_buffer_list = NULL; + info->tx_buffer_list = NULL; + +} /* end of mgsl_free_buffer_list_memory() */ + +/* + * mgsl_alloc_frame_memory() + * + * Allocate the frame DMA buffers used by the specified buffer list. + * Each DMA buffer will be one memory page in size. This is necessary + * because memory can fragment enough that it may be impossible + * contiguous pages. + * + * Arguments: + * + * info pointer to device instance data + * BufferList pointer to list of buffer entries + * Buffercount count of buffer entries in buffer list + * + * Return Value: 0 if success, otherwise -ENOMEM + */ +int mgsl_alloc_frame_memory(struct mgsl_struct *info,DMABUFFERENTRY *BufferList,int Buffercount) +{ + int i; + unsigned long phys_addr; + + /* Allocate page sized buffers for the receive buffer list */ + + for ( i = 0; i < Buffercount; i++ ) { + if ( info->bus_type == MGSL_BUS_TYPE_PCI ) { + /* PCI adapter uses shared memory buffers. */ + BufferList[i].virt_addr = info->memory_base + info->last_mem_alloc; + phys_addr = info->last_mem_alloc; + info->last_mem_alloc += DMABUFFERSIZE; + } else { + /* ISA adapter uses system memory. */ + BufferList[i].virt_addr = + kmalloc(DMABUFFERSIZE, GFP_KERNEL | GFP_DMA); + if ( BufferList[i].virt_addr == NULL ) + return -ENOMEM; + phys_addr = virt_to_bus(BufferList[i].virt_addr); + } + BufferList[i].phys_addr = phys_addr; + } + + return 0; + +} /* end of mgsl_alloc_frame_memory() */ + +/* + * mgsl_free_frame_memory() + * + * Free the buffers associated with + * each buffer entry of a buffer list. + * + * Arguments: + * + * info pointer to device instance data + * BufferList pointer to list of buffer entries + * Buffercount count of buffer entries in buffer list + * + * Return Value: None + */ +void mgsl_free_frame_memory(struct mgsl_struct *info, DMABUFFERENTRY *BufferList, int Buffercount) +{ + int i; + + if ( BufferList ) { + for ( i = 0 ; i < Buffercount ; i++ ) { + if ( BufferList[i].virt_addr ) { + if ( info->bus_type != MGSL_BUS_TYPE_PCI ) + kfree_s(BufferList[i].virt_addr, DMABUFFERSIZE); + BufferList[i].virt_addr = NULL; + } + } + } + +} /* end of mgsl_free_frame_memory() */ + +/* mgsl_free_dma_buffers() + * + * Free DMA buffers + * + * Arguments: info pointer to device instance data + * Return Value: None + */ +void mgsl_free_dma_buffers( struct mgsl_struct *info ) +{ + mgsl_free_frame_memory( info, info->rx_buffer_list, info->rx_buffer_count ); + mgsl_free_frame_memory( info, info->tx_buffer_list, info->tx_buffer_count ); + mgsl_free_buffer_list_memory( info ); + +} /* end of mgsl_free_dma_buffers() */ + +/* mgsl_claim_resources() + * + * Claim all resources used by a device + * + * Arguments: info pointer to device instance data + * Return Value: 0 if success, otherwise -ENODEV + */ +int mgsl_claim_resources(struct mgsl_struct *info) +{ + /* claim 16C32 I/O base address */ + + if ( check_region(info->io_base,info->io_addr_size) < 0 ) { + printk( "%s(%d):I/O address conflict on device %s Addr=%08X\n", + __FILE__,__LINE__,info->device_name, info->io_base ); + return -ENODEV; + } + request_region(info->io_base,info->io_addr_size,"synclink.o"); + info->io_addr_requested = 1; + + /* claim interrupt level */ + + if ( request_irq(info->irq_level,mgsl_interrupt,info->irq_flags, + info->device_name, info ) < 0 ) { + printk( "%s(%d):Cant request interrupt on device %s IRQ=%d\n", + __FILE__,__LINE__,info->device_name, info->irq_level ); + mgsl_release_resources( info ); + return -ENODEV; + } + info->irq_requested = 1; + + if ( info->bus_type == MGSL_BUS_TYPE_PCI ) { + /* claim shared memory range */ + info->memory_base = ioremap(info->phys_memory_base,0x40000); + if (!info->memory_base) { + printk( "%s(%d):Cant map shared memory on device %s MemAddr=%08X\n", + __FILE__,__LINE__,info->device_name, info->phys_memory_base ); + mgsl_release_resources( info ); + return -ENODEV; + } + + /* test the shared memory range */ + if ( !mgsl_memory_test(info) ) { + printk( "%s(%d):Failed shared memory test %s MemAddr=%08X\n", + __FILE__,__LINE__,info->device_name, info->phys_memory_base ); + mgsl_release_resources( info ); + return -ENODEV; + } + + /* claim LCR memory range */ + info->lcr_base = ioremap(info->phys_lcr_base,PAGE_SIZE) + info->lcr_offset; + if (!info->lcr_base) { + printk( "%s(%d):Cant map LCR memory on device %s MemAddr=%08X\n", + __FILE__,__LINE__,info->device_name, info->phys_lcr_base ); + mgsl_release_resources( info ); + return -ENODEV; + } + + } else { + /* claim DMA channel */ + + if (request_dma(info->dma_level,info->device_name) < 0){ + printk( "%s(%d):Cant request DMA channel on device %s DMA=%d\n", + __FILE__,__LINE__,info->device_name, info->dma_level ); + mgsl_release_resources( info ); + return -ENODEV; + } + info->dma_requested = 1; + + /* ISA adapter uses bus master DMA */ + set_dma_mode(info->dma_level,DMA_MODE_CASCADE); + enable_dma(info->dma_level); + } + + if ( mgsl_allocate_dma_buffers(info) < 0 ) { + printk( "%s(%d):Cant allocate DMA buffers on device %s DMA=%d\n", + __FILE__,__LINE__,info->device_name, info->dma_level ); + mgsl_release_resources( info ); + return -ENODEV; + } + + return 0; + +} /* end of mgsl_claim_resources() */ + +/* mgsl_release_resources() + * + * Release all resources used by a device + * + * Arguments: info pointer to device instance data + * Return Value: None + */ +void mgsl_release_resources(struct mgsl_struct *info) +{ + if ( debug_level >= DEBUG_LEVEL_INFO ) + printk( "%s(%d):mgsl_release_resources(%s) entry\n", + __FILE__,__LINE__,info->device_name ); + + if ( info->irq_requested ) { + free_irq(info->irq_level, info); + info->irq_requested = 0; + } + + if ( info->dma_requested ) { + disable_dma(info->dma_level); + free_dma(info->dma_level); + info->dma_requested = 0; + } + mgsl_free_dma_buffers(info); + + if ( info->io_addr_requested ) { + release_region(info->io_base,info->io_addr_size); + info->io_addr_requested = 0; + } + + if (info->memory_base){ + iounmap(info->memory_base); + info->memory_base = 0; + } + + if (info->lcr_base){ + iounmap(info->lcr_base - info->lcr_offset); + info->lcr_base = 0; + } + + if ( debug_level >= DEBUG_LEVEL_INFO ) + printk( "%s(%d):mgsl_release_resources(%s) exit\n", + __FILE__,__LINE__,info->device_name ); + +} /* end of mgsl_release_resources() */ + +/* mgsl_add_device() + * + * Add the specified device instance data structure to the + * global linked list of devices and increment the device count. + * + * Arguments: info pointer to device instance data + * Return Value: None + */ +void mgsl_add_device( struct mgsl_struct *info ) +{ + info->next_device = NULL; + info->line = mgsl_device_count; + sprintf(info->device_name,"ttySL%d",info->line); + + mgsl_device_count++; + + if ( !mgsl_device_list ) + mgsl_device_list = info; + else { + struct mgsl_struct *current_dev = mgsl_device_list; + while( current_dev->next_device ) + current_dev = current_dev->next_device; + current_dev->next_device = info; + } + + if ( info->bus_type == MGSL_BUS_TYPE_PCI ) { + printk( "SyncLink device %s added:PCI bus IO=%04X IRQ=%d Mem=%08X LCR=%08X\n", + info->device_name, info->io_base, info->irq_level, + info->phys_memory_base, info->phys_lcr_base ); + } else { + printk( "SyncLink device %s added:ISA bus IO=%04X IRQ=%d DMA=%d\n", + info->device_name, info->io_base, info->irq_level, info->dma_level ); + } + +} /* end of mgsl_add_device() */ + +/* mgsl_allocate_device() + * + * Allocate and initialize a device instance structure + * + * Arguments: None + * Return Value: pointer to mgsl_struct if success, otherwise NULL + */ +struct mgsl_struct* mgsl_allocate_device() +{ + struct mgsl_struct *info; + + info = (struct mgsl_struct *)kmalloc(sizeof(struct mgsl_struct), + GFP_KERNEL); + + if (!info) { + printk("Error can't allocate device instance data\n"); + } else { + memset(info, 0, sizeof(struct mgsl_struct)); + info->magic = MGSL_MAGIC; + info->task.sync = 0; + info->task.routine = mgsl_bh_handler; + info->task.data = info; + info->max_frame_size = 4096; + info->close_delay = 5*HZ/10; + info->closing_wait = 30*HZ; + + memcpy(&info->params,&default_params,sizeof(MGSL_PARAMS)); + info->idle_mode = HDLC_TXIDLE_FLAGS; + } + + return info; + +} /* end of mgsl_allocate_device()*/ + +/* mgsl_enumerate_devices() + * + * Enumerate SyncLink serial devices based on user specified + * options for ISA adapters and autodetected PCI adapters. + * + * Arguments: None + * Return Value: 0 if success, otherwise error code + */ +int mgsl_enumerate_devices() +{ + struct mgsl_struct *info; + int i; + + /* Check for user specified ISA devices */ + + for (i=0 ;(i < MAX_ISA_DEVICES) && io[i] && irq[i]; i++){ + if ( debug_level >= DEBUG_LEVEL_INFO ) + printk("ISA device specified io=%04X,irq=%d,dma=%d\n", + io[i], irq[i], dma[i] ); + + info = mgsl_allocate_device(); + if ( !info ) { + /* error allocating device instance data */ + if ( debug_level >= DEBUG_LEVEL_ERROR ) + printk( "can't allocate device instance data.\n"); + continue; + } + + /* Copy user configuration info to device instance data */ + info->io_base = (unsigned int)io[i]; + info->irq_level = (unsigned int)irq[i]; +#if LINUX_VERSION_CODE >= VERSION(2,1,0) + info->irq_level = irq_cannonicalize(info->irq_level); +#else + if (info->irq_level == 2) + info->irq_level = 9; +#endif + info->dma_level = (unsigned int)dma[i]; + info->bus_type = MGSL_BUS_TYPE_ISA; + info->io_addr_size = 16; + info->irq_flags = 0; + + /* add new device to device list */ + mgsl_add_device( info ); + } + + +#ifdef CONFIG_PCI + /* Auto detect PCI adapters */ + + if ( pcibios_present() ) { + unsigned char bus; + unsigned char func; + unsigned int shared_mem_base; + unsigned int lcr_mem_base; + unsigned int io_base; + unsigned char irq_line; + + for(i=0;;i++){ + if ( PCIBIOS_SUCCESSFUL == pcibios_find_device( + MICROGATE_VENDOR_ID, SYNCLINK_DEVICE_ID, i, &bus, &func) ) { + + if (pcibios_read_config_dword(bus,func, + PCI_BASE_ADDRESS_3,&shared_mem_base) ) { + printk( "%s(%d):Shared mem addr not set.\n", + __FILE__,__LINE__); + continue; + } + + if (pcibios_read_config_dword(bus,func, + PCI_BASE_ADDRESS_0,&lcr_mem_base) ) { + printk( "%s(%d):LCR mem addr not set.\n", + __FILE__,__LINE__); + continue; + } + + if (pcibios_read_config_dword(bus,func, + PCI_BASE_ADDRESS_2,&io_base) ) { + printk( "%s(%d):USC I/O addr not set.\n", + __FILE__,__LINE__); + continue; + } + + if (pcibios_read_config_byte(bus,func, + PCI_INTERRUPT_LINE,&irq_line) ) { + printk( "%s(%d):USC I/O addr not set.\n", + __FILE__,__LINE__); + continue; + } + + info = mgsl_allocate_device(); + if ( !info ) { + /* error allocating device instance data */ + if ( debug_level >= DEBUG_LEVEL_ERROR ) + printk( "can't allocate device instance data.\n"); + continue; + } + + /* Copy user configuration info to device instance data */ + + info->io_base = io_base & PCI_BASE_ADDRESS_IO_MASK; + info->irq_level = (unsigned int)irq_line; +#if LINUX_VERSION_CODE >= VERSION(2,1,0) + info->irq_level = irq_cannonicalize(info->irq_level); +#else + if (info->irq_level == 2) + info->irq_level = 9; +#endif + info->phys_memory_base = shared_mem_base & PCI_BASE_ADDRESS_MEM_MASK; + + /* Because veremap only works on page boundaries we must map + * a larger area than is actually implemented for the LCR + * memory range. We map a full page starting at the page boundary. + */ + info->phys_lcr_base = lcr_mem_base & PCI_BASE_ADDRESS_MEM_MASK; + info->lcr_offset = info->phys_lcr_base & (PAGE_SIZE-1); + info->phys_lcr_base &= ~(PAGE_SIZE-1); + + info->bus_type = MGSL_BUS_TYPE_PCI; + info->io_addr_size = 8; + info->irq_flags = SA_SHIRQ; + info->bus = bus; + info->function = func; + + /* Store the PCI9050 misc control register value because a flaw + * in the PCI9050 prevents LCR registers from being read if + * BIOS assigns an LCR base address with bit 7 set. + * + * Only the misc control register is accessed for which only + * write access is needed, so set an initial value and change + * bits to the device instance data as we write the value + * to the actual misc control register. + */ + info->misc_ctrl_value = 0x087e4546; + + /* add new device to device list */ + mgsl_add_device( info ); + } else { + break; + } + } + } +#endif + + /* + * Allocate memory to hold the following tty/termios arrays + * with an element for each enumerated device. + */ + + serial_table = (struct tty_struct**)kmalloc(sizeof(struct tty_struct*)*mgsl_device_count, GFP_KERNEL); + serial_termios = (struct termios**)kmalloc(sizeof(struct termios*)*mgsl_device_count, GFP_KERNEL); + serial_termios_locked = (struct termios**)kmalloc(sizeof(struct termios*)*mgsl_device_count, GFP_KERNEL); + + if (!serial_table || !serial_termios || !serial_termios_locked){ + printk("%s(%d):Can't allocate tty/termios arrays.\n", + __FILE__,__LINE__); + return -ENOMEM; + } + + memset(serial_table,0,sizeof(struct tty_struct*)*mgsl_device_count); + memset(serial_termios,0,sizeof(struct termios*)*mgsl_device_count); + memset(serial_termios_locked,0,sizeof(struct termios*)*mgsl_device_count); + + return 0; + +} /* end of mgsl_enumerate_devices() */ + +/* mgsl_init() + * + * Driver initialization entry point. + * + * Arguments: None + * Return Value: 0 if success, otherwise error code + */ +int __init mgsl_init(void) +{ + struct mgsl_struct *info; + +#if LINUX_VERSION_CODE >= VERSION(2,1,0) + EXPORT_NO_SYMBOLS; +#else + register_symtab(NULL); +#endif + + printk("%s version %s\n", driver_name, driver_version); + + /* determine how many SyncLink devices are installed */ + mgsl_enumerate_devices(); + if ( !mgsl_device_list ) { + printk("%s(%d):No SyncLink devices found.\n",__FILE__,__LINE__); + return -ENODEV; + } + + /* Initialize the tty_driver structure */ + + memset(&serial_driver, 0, sizeof(struct tty_driver)); + serial_driver.magic = TTY_DRIVER_MAGIC; +#if LINUX_VERSION_CODE >= VERSION(2,1,0) + serial_driver.driver_name = "synclink"; +#endif + serial_driver.name = "ttySL"; + serial_driver.major = ttymajor; + serial_driver.minor_start = 64; + serial_driver.num = mgsl_device_count; + 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 = mgsl_open; + serial_driver.close = mgsl_close; + serial_driver.write = mgsl_write; + serial_driver.put_char = mgsl_put_char; + serial_driver.flush_chars = mgsl_flush_chars; + serial_driver.write_room = mgsl_write_room; + serial_driver.chars_in_buffer = mgsl_chars_in_buffer; + serial_driver.flush_buffer = mgsl_flush_buffer; + serial_driver.ioctl = mgsl_ioctl; + serial_driver.throttle = mgsl_throttle; + serial_driver.unthrottle = mgsl_unthrottle; +#if LINUX_VERSION_CODE >= VERSION(2,1,0) + serial_driver.send_xchar = mgsl_send_xchar; + serial_driver.break_ctl = mgsl_break; + serial_driver.wait_until_sent = mgsl_wait_until_sent; + serial_driver.read_proc = mgsl_read_proc; +#endif + serial_driver.set_termios = mgsl_set_termios; + serial_driver.stop = mgsl_stop; + serial_driver.start = mgsl_start; + serial_driver.hangup = mgsl_hangup; + + /* + * The callout device is just like normal device except for + * major number and the subtype code. + */ + callout_driver = serial_driver; + callout_driver.name = "cuaSL"; + callout_driver.major = cuamajor; + callout_driver.subtype = SERIAL_TYPE_CALLOUT; +#if LINUX_VERSION_CODE >= VERSION(2,1,0) + callout_driver.read_proc = 0; + callout_driver.proc_entry = 0; +#endif + + if (tty_register_driver(&serial_driver) < 0) + printk("%s(%d):Couldn't register serial driver\n", + __FILE__,__LINE__); + + if (tty_register_driver(&callout_driver) < 0) + printk("%s(%d):Couldn't register callout driver\n", + __FILE__,__LINE__); + + printk("%s version %s, tty major#%d callout major#%d\n", + driver_name, driver_version, + serial_driver.major, callout_driver.major); + + /* Propagate these values to all device instances */ + + info = mgsl_device_list; + while(info){ + info->callout_termios = callout_driver.init_termios; + info->normal_termios = serial_driver.init_termios; + info = info->next_device; + } + + return 0; + +} /* end of mgsl_init() */ + +#ifdef MODULE +int init_module(void) +{ +/* Uncomment this to kernel debug module. + * mgsl_get_text_ptr() leaves the .text address in eax + * which can be used with add-symbol-file with gdb. + */ + if (break_on_load) { + mgsl_get_text_ptr(); + BREAKPOINT(); + } + + return mgsl_init(); +} + +void cleanup_module(void) +{ + unsigned long flags; + int rc; + struct mgsl_struct *info; + + printk("Unloading %s: version %s\n", driver_name, driver_version); + save_flags(flags); + cli(); + if ((rc = tty_unregister_driver(&serial_driver))) + printk("%s(%d) failed to unregister tty driver err=%d\n", + __FILE__,__LINE__,rc); + if ((rc = tty_unregister_driver(&callout_driver))) + printk("%s(%d) failed to unregister callout driver err=%d\n", + __FILE__,__LINE__,rc); + restore_flags(flags); + + info = mgsl_device_list; + while(info) { + mgsl_release_resources(info); + info = info->next_device; + } + + if (tmp_buf) { + free_page((unsigned long) tmp_buf); + tmp_buf = NULL; + } + + if (serial_table) + kfree_s(serial_table,sizeof(struct tty_struct*)*mgsl_device_count); + + if (serial_termios) + kfree_s(serial_termios,sizeof(struct termios*)*mgsl_device_count); + + if (serial_termios_locked) + kfree_s(serial_termios_locked,sizeof(struct termios*)*mgsl_device_count); + +} /* end of cleanup_module() */ + +#endif /* MODULE */ + + +/* + * usc_RTCmd() + * + * Issue a USC Receive/Transmit command to the + * Channel Command/Address Register (CCAR). + * + * Notes: + * + * The command is encoded in the most significant 5 bits <15..11> + * of the CCAR value. Bits <10..7> of the CCAR must be preserved + * and Bits <6..0> must be written as zeros. + * + * Arguments: + * + * info pointer to device information structure + * Cmd command mask (use symbolic macros) + * + * Return Value: + * + * None + */ +void usc_RTCmd( struct mgsl_struct *info, u16 Cmd ) +{ + /* output command to CCAR in bits <15..11> */ + /* preserve bits <10..7>, bits <6..0> must be zero */ + + outw( Cmd + info->loopback_bits, info->io_base + CCAR ); + + /* Read to flush write to CCAR */ + if ( info->bus_type == MGSL_BUS_TYPE_PCI ) + inw( info->io_base + CCAR ); + +} /* end of usc_RTCmd() */ + +/* + * usc_DmaCmd() + * + * Issue a DMA command to the DMA Command/Address Register (DCAR). + * + * Arguments: + * + * info pointer to device information structure + * Cmd DMA command mask (usc_DmaCmd_XX Macros) + * + * Return Value: + * + * None + */ +void usc_DmaCmd( struct mgsl_struct *info, u16 Cmd ) +{ + /* write command mask to DCAR */ + outw( Cmd + info->mbre_bit, info->io_base ); + + /* Read to flush write to DCAR */ + if ( info->bus_type == MGSL_BUS_TYPE_PCI ) + inw( info->io_base ); + +} /* end of usc_DmaCmd() */ + +/* + * usc_OutDmaReg() + * + * Write a 16-bit value to a USC DMA register + * + * Arguments: + * + * info pointer to device info structure + * RegAddr register address (number) for write + * RegValue 16-bit value to write to register + * + * Return Value: + * + * None + * + */ +void usc_OutDmaReg( struct mgsl_struct *info, u16 RegAddr, u16 RegValue ) +{ + /* Note: The DCAR is located at the adapter base address */ + /* Note: must preserve state of BIT8 in DCAR */ + + outw( RegAddr + info->mbre_bit, info->io_base ); + outw( RegValue, info->io_base ); + + /* Read to flush write to DCAR */ + if ( info->bus_type == MGSL_BUS_TYPE_PCI ) + inw( info->io_base ); + +} /* end of usc_OutDmaReg() */ + +/* + * usc_InDmaReg() + * + * Read a 16-bit value from a DMA register + * + * Arguments: + * + * info pointer to device info structure + * RegAddr register address (number) to read from + * + * Return Value: + * + * The 16-bit value read from register + * + */ +u16 usc_InDmaReg( struct mgsl_struct *info, u16 RegAddr ) +{ + /* Note: The DCAR is located at the adapter base address */ + /* Note: must preserve state of BIT8 in DCAR */ + + outw( RegAddr + info->mbre_bit, info->io_base ); + return inw( info->io_base ); + +} /* end of usc_InDmaReg() */ + +/* + * + * usc_OutReg() + * + * Write a 16-bit value to a USC serial channel register + * + * Arguments: + * + * info pointer to device info structure + * RegAddr register address (number) to write to + * RegValue 16-bit value to write to register + * + * Return Value: + * + * None + * + */ +void usc_OutReg( struct mgsl_struct *info, u16 RegAddr, u16 RegValue ) +{ + outw( RegAddr + info->loopback_bits, info->io_base + CCAR ); + outw( RegValue, info->io_base + CCAR ); + + /* Read to flush write to CCAR */ + if ( info->bus_type == MGSL_BUS_TYPE_PCI ) + inw( info->io_base + CCAR ); + +} /* end of usc_OutReg() */ + +/* + * usc_InReg() + * + * Reads a 16-bit value from a USC serial channel register + * + * Arguments: + * + * info pointer to device extension + * RegAddr register address (number) to read from + * + * Return Value: + * + * 16-bit value read from register + */ +u16 usc_InReg( struct mgsl_struct *info, u16 RegAddr ) +{ + outw( RegAddr + info->loopback_bits, info->io_base + CCAR ); + return inw( info->io_base + CCAR ); + +} /* end of usc_InReg() */ + +/* usc_set_sdlc_mode() + * + * Set up the adapter for SDLC DMA communications. + * + * Arguments: info pointer to device instance data + * Return Value: NONE + */ +void usc_set_sdlc_mode( struct mgsl_struct *info ) +{ + u16 RegValue; + + /* Channel mode Register (CMR) + * + * <15..14> 00 Tx Sub modes, Underrun Action + * <13> 0 1 = Send Preamble before opening flag + * <12> 0 1 = Consecutive Idles share common 0 + * <11..8> 0110 Transmitter mode = HDLC/SDLC + * <7..4> 0000 Rx Sub modes, addr/ctrl field handling + * <3..0> 0110 Receiver mode = HDLC/SDLC + * + * 0000 0110 0000 0110 = 0x0606 + */ + + RegValue = 0x0606; + + if ( info->params.flags & HDLC_FLAG_UNDERRUN_ABORT15 ) + RegValue |= BIT14; + else if ( info->params.flags & HDLC_FLAG_UNDERRUN_FLAG ) + RegValue |= BIT15; + else if ( info->params.flags & HDLC_FLAG_UNDERRUN_CRC ) + RegValue |= BIT15 + BIT14; + + if ( info->params.preamble != HDLC_PREAMBLE_PATTERN_NONE ) + RegValue |= BIT13; + + if ( info->params.flags & HDLC_FLAG_SHARE_ZERO ) + RegValue |= BIT12; + + if ( info->params.addr_filter != 0xff ) + { + /* set up receive address filtering */ + usc_OutReg( info, RSR, info->params.addr_filter ); + RegValue |= BIT4; + } + + usc_OutReg( info, CMR, RegValue ); + info->cmr_value = RegValue; + + /* Receiver mode Register (RMR) + * + * <15..13> 000 encoding + * <12..11> 00 FCS = 16bit CRC CCITT (x15 + x12 + x5 + 1) + * <10> 1 1 = Set CRC to all 1s (use for SDLC/HDLC) + * <9> 0 1 = Include Receive chars in CRC + * <8> 1 1 = Use Abort/PE bit as abort indicator + * <7..6> 00 Even parity + * <5> 0 parity disabled + * <4..2> 000 Receive Char Length = 8 bits + * <1..0> 00 Disable Receiver + * + * 0000 0101 0000 0000 = 0x0500 + */ + + RegValue = 0x0500; + + switch ( info->params.encoding ) { + case HDLC_ENCODING_NRZB: RegValue |= BIT13; break; + case HDLC_ENCODING_NRZI_MARK: RegValue |= BIT14; break; + case HDLC_ENCODING_NRZI_SPACE: RegValue |= BIT14 + BIT13; break; + case HDLC_ENCODING_BIPHASE_MARK: RegValue |= BIT15; break; + case HDLC_ENCODING_BIPHASE_SPACE: RegValue |= BIT15 + BIT13; break; + case HDLC_ENCODING_BIPHASE_LEVEL: RegValue |= BIT15 + BIT14; break; + case HDLC_ENCODING_DIFF_BIPHASE_LEVEL: RegValue |= BIT15 + BIT14 + BIT13; break; + } + + if ( info->params.crc_type == HDLC_CRC_16_CCITT ) + RegValue |= BIT9; + + usc_OutReg( info, RMR, RegValue ); + + + + /* Set the Receive count Limit Register (RCLR) to 0xffff. */ + /* When an opening flag of an SDLC frame is recognized the */ + /* Receive Character count (RCC) is loaded with the value in */ + /* RCLR. The RCC is decremented for each received byte. The */ + /* value of RCC is stored after the closing flag of the frame */ + /* allowing the frame size to be computed. */ + + usc_OutReg( info, RCLR, RCLRVALUE ); + + usc_RCmd( info, RCmd_SelectRicrdma_level ); + + /* Receive Interrupt Control Register (RICR) + * + * <15..8> ? RxFIFO DMA Request Level + * <7> 0 Exited Hunt IA (Interrupt Arm) + * <6> 0 Idle Received IA + * <5> 0 Break/Abort IA + * <4> 0 Rx Bound IA + * <3> 1 Queued status reflects oldest 2 bytes in FIFO + * <2> 0 Abort/PE IA + * <1> 1 Rx Overrun IA + * <0> 0 Select TC0 value for readback + * + * 0000 0000 0000 1000 = 0x000a + */ + + /* Carry over the Exit Hunt and Idle Received bits */ + /* in case they have been armed by usc_ArmEvents. */ + + RegValue = usc_InReg( info, RICR ) & 0xc0; + + if ( info->bus_type == MGSL_BUS_TYPE_PCI ) + usc_OutReg( info, RICR, (u16)(0x030a | RegValue) ); + else + usc_OutReg( info, RICR, (u16)(0x140a | RegValue) ); + + /* Unlatch all Rx status bits and clear Rx status IRQ Pending */ + + usc_UnlatchRxstatusBits( info, RXSTATUS_ALL ); + usc_ClearIrqPendingBits( info, RECEIVE_STATUS ); + + /* Transmit mode Register (TMR) + * + * <15..13> 000 encoding + * <12..11> 00 FCS = 16bit CRC CCITT (x15 + x12 + x5 + 1) + * <10> 1 1 = Start CRC as all 1s (use for SDLC/HDLC) + * <9> 0 1 = Tx CRC Enabled + * <8> 0 1 = Append CRC to end of transmit frame + * <7..6> 00 Transmit parity Even + * <5> 0 Transmit parity Disabled + * <4..2> 000 Tx Char Length = 8 bits + * <1..0> 00 Disable Transmitter + * + * 0000 0100 0000 0000 = 0x0400 + */ + + RegValue = 0x0400; + + switch ( info->params.encoding ) { + case HDLC_ENCODING_NRZB: RegValue |= BIT13; break; + case HDLC_ENCODING_NRZI_MARK: RegValue |= BIT14; break; + case HDLC_ENCODING_NRZI_SPACE: RegValue |= BIT14 + BIT13; break; + case HDLC_ENCODING_BIPHASE_MARK: RegValue |= BIT15; break; + case HDLC_ENCODING_BIPHASE_SPACE: RegValue |= BIT15 + BIT13; break; + case HDLC_ENCODING_BIPHASE_LEVEL: RegValue |= BIT15 + BIT14; break; + case HDLC_ENCODING_DIFF_BIPHASE_LEVEL: RegValue |= BIT15 + BIT14 + BIT13; break; + } + + if ( info->params.crc_type == HDLC_CRC_16_CCITT ) + RegValue |= BIT9 + BIT8; + + usc_OutReg( info, TMR, RegValue ); + + usc_set_txidle( info ); + + + usc_TCmd( info, TCmd_SelectTicrdma_level ); + + /* Transmit Interrupt Control Register (TICR) + * + * <15..8> ? Transmit FIFO DMA Level + * <7> 0 Present IA (Interrupt Arm) + * <6> 0 Idle Sent IA + * <5> 1 Abort Sent IA + * <4> 1 EOF/EOM Sent IA + * <3> 0 CRC Sent IA + * <2> 1 1 = Wait for SW Trigger to Start Frame + * <1> 1 Tx Underrun IA + * <0> 0 TC0 constant on read back + * + * 0000 0000 0011 0110 = 0x0036 + */ + + if ( info->bus_type == MGSL_BUS_TYPE_PCI ) + usc_OutReg( info, TICR, 0x0736 ); + else + usc_OutReg( info, TICR, 0x1436 ); + + usc_UnlatchTxstatusBits( info, TXSTATUS_ALL ); + usc_ClearIrqPendingBits( info, TRANSMIT_STATUS ); + + /* Clock mode Control Register (CMCR) + * + * <15..14> 00 counter 1 Source = Disabled + * <13..12> 00 counter 0 Source = Disabled + * <11..10> 11 BRG1 Input is TxC Pin + * <9..8> 11 BRG0 Input is TxC Pin + * <7..6> 01 DPLL Input is BRG1 Output + * <5..3> XXX TxCLK comes from Port 0 + * <2..0> XXX RxCLK comes from Port 1 + * + * 0000 1111 0111 0111 = 0x0f77 + */ + + RegValue = 0x0f40; + + if ( info->params.flags & HDLC_FLAG_RXC_DPLL ) + RegValue |= 0x0003; /* RxCLK from DPLL */ + else if ( info->params.flags & HDLC_FLAG_RXC_BRG ) + RegValue |= 0x0004; /* RxCLK from BRG0 */ + else + RegValue |= 0x0007; /* RxCLK from Port1 */ + + if ( info->params.flags & HDLC_FLAG_TXC_DPLL ) + RegValue |= 0x0018; /* TxCLK from DPLL */ + else if ( info->params.flags & HDLC_FLAG_TXC_BRG ) + RegValue |= 0x0020; /* TxCLK from BRG0 */ + else + RegValue |= 0x0030; /* TxCLK from Port0 */ + + usc_OutReg( info, CMCR, RegValue ); + + + /* Hardware Configuration Register (HCR) + * + * <15..14> 00 CTR0 Divisor:00=32,01=16,10=8,11=4 + * <13> 0 CTR1DSel:0=CTR0Div determines CTR0Div + * <12> 0 CVOK:0=report code violation in biphase + * <11..10> 00 DPLL Divisor:00=32,01=16,10=8,11=4 + * <9..8> XX DPLL mode:00=disable,01=NRZ,10=Biphase,11=Biphase Level + * <7..6> 00 reserved + * <5> 0 BRG1 mode:0=continuous,1=single cycle + * <4> X BRG1 Enable + * <3..2> 00 reserved + * <1> 0 BRG0 mode:0=continuous,1=single cycle + * <0> 0 BRG0 Enable + */ + + RegValue = 0x0000; + + if ( info->params.flags & (HDLC_FLAG_RXC_DPLL + HDLC_FLAG_TXC_DPLL) ) { + u32 XtalSpeed; + u32 DpllDivisor; + u16 Tc; + + /* DPLL is enabled. Use BRG1 to provide continuous reference clock */ + /* for DPLL. DPLL mode in HCR is dependent on the encoding used. */ + + if ( info->bus_type == MGSL_BUS_TYPE_PCI ) + XtalSpeed = 11059200; + else + XtalSpeed = 14745600; + + if ( info->params.flags & HDLC_FLAG_DPLL_DIV16 ) { + DpllDivisor = 16; + RegValue |= BIT10; + } + else if ( info->params.flags & HDLC_FLAG_DPLL_DIV8 ) { + DpllDivisor = 8; + RegValue |= BIT11; + } + else + DpllDivisor = 32; + + /* Tc = (Xtal/Speed) - 1 */ + /* If twice the remainder of (Xtal/Speed) is greater than Speed */ + /* then rounding up gives a more precise time constant. Instead */ + /* of rounding up and then subtracting 1 we just don't subtract */ + /* the one in this case. */ + + Tc = (u16)((XtalSpeed/DpllDivisor)/info->params.clock_speed); + if ( !((((XtalSpeed/DpllDivisor) % info->params.clock_speed) * 2) + / info->params.clock_speed) ) + Tc--; + + /* Write 16-bit Time Constant for BRG1 */ + usc_OutReg( info, TC1R, Tc ); + + RegValue |= BIT4; /* enable BRG1 */ + + switch ( info->params.encoding ) { + case HDLC_ENCODING_NRZ: + case HDLC_ENCODING_NRZB: + case HDLC_ENCODING_NRZI_MARK: + case HDLC_ENCODING_NRZI_SPACE: RegValue |= BIT8; break; + case HDLC_ENCODING_BIPHASE_MARK: + case HDLC_ENCODING_BIPHASE_SPACE: RegValue |= BIT9; break; + case HDLC_ENCODING_BIPHASE_LEVEL: + case HDLC_ENCODING_DIFF_BIPHASE_LEVEL: RegValue |= BIT9 + BIT8; break; + } + } + + usc_OutReg( info, HCR, RegValue ); + + + /* Channel Control/status Register (CCSR) + * + * <15> X RCC FIFO Overflow status (RO) + * <14> X RCC FIFO Not Empty status (RO) + * <13> 0 1 = Clear RCC FIFO (WO) + * <12> X DPLL Sync (RW) + * <11> X DPLL 2 Missed Clocks status (RO) + * <10> X DPLL 1 Missed Clock status (RO) + * <9..8> 00 DPLL Resync on rising and falling edges (RW) + * <7> X SDLC Loop On status (RO) + * <6> X SDLC Loop Send status (RO) + * <5> 1 Bypass counters for TxClk and RxClk (RW) + * <4..2> 000 Last Char of SDLC frame has 8 bits (RW) + * <1..0> 00 reserved + * + * 0000 0000 0010 0000 = 0x0020 + */ + + usc_OutReg( info, CCSR, 0x1020 ); + + + if ( info->params.flags & HDLC_FLAG_AUTO_CTS ) { + usc_OutReg( info, SICR, + (u16)(usc_InReg(info,SICR) | SICR_CTS_INACTIVE) ); + } + + + /* enable Master Interrupt Enable bit (MIE) */ + usc_EnableMasterIrqBit( info ); + + usc_ClearIrqPendingBits( info, RECEIVE_STATUS + RECEIVE_DATA + + TRANSMIT_STATUS + TRANSMIT_DATA ); + + info->mbre_bit = 0; + outw( 0, info->io_base ); /* clear Master Bus Enable (DCAR) */ + usc_DmaCmd( info, DmaCmd_ResetAllChannels ); /* disable both DMA channels */ + info->mbre_bit = BIT8; + outw( BIT8, info->io_base ); /* set Master Bus Enable (DCAR) */ + + /* Enable DMAEN (Port 7, Bit 14) */ + /* This connects the DMA request signal to the ISA bus */ + /* on the ISA adapter. This has no effect for the PCI adapter */ + usc_OutReg( info, PCR, (u16)((usc_InReg(info, PCR) | BIT15) & ~BIT14) ); + + /* DMA Control Register (DCR) + * + * <15..14> 10 Priority mode = Alternating Tx/Rx + * 01 Rx has priority + * 00 Tx has priority + * + * <13> 1 Enable Priority Preempt per DCR<15..14> + * (WARNING DCR<11..10> must be 00 when this is 1) + * 0 Choose activate channel per DCR<11..10> + * + * <12> 0 Little Endian for Array/List + * <11..10> 00 Both Channels can use each bus grant + * <9..6> 0000 reserved + * <5> 0 7 CLK - Minimum Bus Re-request Interval + * <4> 0 1 = drive D/C and S/D pins + * <3> 1 1 = Add one wait state to all DMA cycles. + * <2> 0 1 = Strobe /UAS on every transfer. + * <1..0> 11 Addr incrementing only affects LS24 bits + * + * 0110 0000 0000 1011 = 0x600b + */ + + if ( info->bus_type == MGSL_BUS_TYPE_PCI ) { + /* PCI adapter does not need DMA wait state */ + usc_OutDmaReg( info, DCR, 0xa00b ); + } + else + usc_OutDmaReg( info, DCR, 0x800b ); + + + /* Receive DMA mode Register (RDMR) + * + * <15..14> 11 DMA mode = Linked List Buffer mode + * <13> 1 RSBinA/L = store Rx status Block in Arrary/List entry + * <12> 1 Clear count of List Entry after fetching + * <11..10> 00 Address mode = Increment + * <9> 1 Terminate Buffer on RxBound + * <8> 0 Bus Width = 16bits + * <7..0> ? status Bits (write as 0s) + * + * 1111 0010 0000 0000 = 0xf200 + */ + + usc_OutDmaReg( info, RDMR, 0xf200 ); + + + /* Transmit DMA mode Register (TDMR) + * + * <15..14> 11 DMA mode = Linked List Buffer mode + * <13> 1 TCBinA/L = fetch Tx Control Block from List entry + * <12> 1 Clear count of List Entry after fetching + * <11..10> 00 Address mode = Increment + * <9> 1 Terminate Buffer on end of frame + * <8> 0 Bus Width = 16bits + * <7..0> ? status Bits (Read Only so write as 0) + * + * 1111 0010 0000 0000 = 0xf200 + */ + + usc_OutDmaReg( info, TDMR, 0xf200 ); + + + /* DMA Interrupt Control Register (DICR) + * + * <15> 1 DMA Interrupt Enable + * <14> 0 1 = Disable IEO from USC + * <13> 0 1 = Don't provide vector during IntAck + * <12> 1 1 = Include status in Vector + * <10..2> 0 reserved, Must be 0s + * <1> 0 1 = Rx DMA Interrupt Enabled + * <0> 0 1 = Tx DMA Interrupt Enabled + * + * 1001 0000 0000 0000 = 0x9000 + */ + + usc_OutDmaReg( info, DICR, 0x9000 ); + + usc_InDmaReg( info, RDMR ); /* clear pending receive DMA IRQ bits */ + usc_InDmaReg( info, TDMR ); /* clear pending transmit DMA IRQ bits */ + usc_OutDmaReg( info, CDIR, 0x0303 ); /* clear IUS and Pending for Tx and Rx */ + + /* Channel Control Register (CCR) + * + * <15..14> 10 Use 32-bit Tx Control Blocks (TCBs) + * <13> 0 Trigger Tx on SW Command Disabled + * <12> 0 Flag Preamble Disabled + * <11..10> 00 Preamble Length + * <9..8> 00 Preamble Pattern + * <7..6> 10 Use 32-bit Rx status Blocks (RSBs) + * <5> 0 Trigger Rx on SW Command Disabled + * <4..0> 0 reserved + * + * 1000 0000 1000 0000 = 0x8080 + */ + + RegValue = 0x8080; + + switch ( info->params.preamble_length ) { + case HDLC_PREAMBLE_LENGTH_16BITS: RegValue |= BIT10; break; + case HDLC_PREAMBLE_LENGTH_32BITS: RegValue |= BIT11; break; + case HDLC_PREAMBLE_LENGTH_64BITS: RegValue |= BIT11 + BIT10; break; + } + + switch ( info->params.preamble ) { + case HDLC_PREAMBLE_PATTERN_FLAGS: RegValue |= BIT8 + BIT12; break; + case HDLC_PREAMBLE_PATTERN_ONES: RegValue |= BIT8; break; + case HDLC_PREAMBLE_PATTERN_10: RegValue |= BIT9; break; + case HDLC_PREAMBLE_PATTERN_01: RegValue |= BIT9 + BIT8; break; + } + + usc_OutReg( info, CCR, RegValue ); + + + /* + * Burst/Dwell Control Register + * + * <15..8> 0x20 Maximum number of transfers per bus grant + * <7..0> 0x00 Maximum number of clock cycles per bus grant + */ + + if ( info->bus_type == MGSL_BUS_TYPE_PCI ) { + /* don't limit bus occupancy on PCI adapter */ + usc_OutDmaReg( info, BDCR, 0x0000 ); + } + else + usc_OutDmaReg( info, BDCR, 0x2000 ); + + usc_stop_transmitter(info); + usc_stop_receiver(info); + +} /* end of usc_set_sdlc_mode() */ + +/* usc_enable_loopback() + * + * Set the 16C32 for internal loopback mode. + * The TxCLK and RxCLK signals are generated from the BRG0 and + * the TxD is looped back to the RxD internally. + * + * Arguments: info pointer to device instance data + * enable 1 = enable loopback, 0 = disable + * Return Value: None + */ +void usc_enable_loopback(struct mgsl_struct *info, int enable) +{ + if (enable) { + /* blank external TXD output */ + usc_OutReg(info,IOCR,usc_InReg(info,IOCR) | (BIT7+BIT6)); + + /* Clock mode Control Register (CMCR) + * + * <15..14> 00 counter 1 Disabled + * <13..12> 00 counter 0 Disabled + * <11..10> 11 BRG1 Input is TxC Pin + * <9..8> 11 BRG0 Input is TxC Pin + * <7..6> 01 DPLL Input is BRG1 Output + * <5..3> 100 TxCLK comes from BRG0 + * <2..0> 100 RxCLK comes from BRG0 + * + * 0000 1111 0110 0100 = 0x0f64 + */ + + usc_OutReg( info, CMCR, 0x0f64 ); + + /* Write 16-bit Time Constant for BRG0 */ + /* use clock speed if available, otherwise use 8 for diagnostics */ + if (info->params.clock_speed) { + if (info->bus_type == MGSL_BUS_TYPE_PCI) + usc_OutReg(info, TC0R, (u16)((11059200/info->params.clock_speed)-1)); + else + usc_OutReg(info, TC0R, (u16)((14745600/info->params.clock_speed)-1)); + } else + usc_OutReg(info, TC0R, (u16)8); + + /* Hardware Configuration Register (HCR) Clear Bit 1, BRG0 + mode = Continuous Set Bit 0 to enable BRG0. */ + usc_OutReg( info, HCR, (u16)((usc_InReg( info, HCR ) & ~BIT1) | BIT0) ); + + /* Input/Output Control Reg, <2..0> = 100, Drive RxC pin with BRG0 */ + usc_OutReg(info, IOCR, (u16)((usc_InReg(info, IOCR) & 0xfff8) | 0x0004)); + + /* set Internal Data loopback mode */ + info->loopback_bits = 0x300; + outw( 0x0300, info->io_base + CCAR ); + } else { + /* enable external TXD output */ + usc_OutReg(info,IOCR,usc_InReg(info,IOCR) & ~(BIT7+BIT6)); + + /* clear Internal Data loopback mode */ + info->loopback_bits = 0; + outw( 0,info->io_base + CCAR ); + } + +} /* end of usc_enable_loopback() */ + +/* usc_enable_aux_clock() + * + * Enabled the AUX clock output at the specified frequency. + * + * Arguments: + * + * info pointer to device extension + * data_rate data rate of clock in bits per second + * A data rate of 0 disables the AUX clock. + * + * Return Value: None + */ +void usc_enable_aux_clock( struct mgsl_struct *info, u32 data_rate ) +{ + u32 XtalSpeed; + u16 Tc; + + if ( data_rate ) { + if ( info->bus_type == MGSL_BUS_TYPE_PCI ) + XtalSpeed = 11059200; + else + XtalSpeed = 14745600; + + + /* Tc = (Xtal/Speed) - 1 */ + /* If twice the remainder of (Xtal/Speed) is greater than Speed */ + /* then rounding up gives a more precise time constant. Instead */ + /* of rounding up and then subtracting 1 we just don't subtract */ + /* the one in this case. */ + + + Tc = (u16)(XtalSpeed/data_rate); + if ( !(((XtalSpeed % data_rate) * 2) / data_rate) ) + Tc--; + + /* Write 16-bit Time Constant for BRG0 */ + usc_OutReg( info, TC0R, Tc ); + + /* + * Hardware Configuration Register (HCR) + * Clear Bit 1, BRG0 mode = Continuous + * Set Bit 0 to enable BRG0. + */ + + usc_OutReg( info, HCR, (u16)((usc_InReg( info, HCR ) & ~BIT1) | BIT0) ); + + /* Input/Output Control Reg, <2..0> = 100, Drive RxC pin with BRG0 */ + usc_OutReg( info, IOCR, (u16)((usc_InReg(info, IOCR) & 0xfff8) | 0x0004) ); + } else { + /* data rate == 0 so turn off BRG0 */ + usc_OutReg( info, HCR, (u16)(usc_InReg( info, HCR ) & ~BIT0) ); + } + +} /* end of usc_enable_aux_clock() */ + +/* usc_stop_receiver() + * + * Disable USC receiver + * + * Arguments: info pointer to device instance data + * Return Value: None + */ +void usc_stop_receiver( struct mgsl_struct *info ) +{ + if (debug_level >= DEBUG_LEVEL_ISR) + printk("%s(%d):usc_stop_receiver(%s)\n", + __FILE__,__LINE__, info->device_name ); + + /* Disable receive DMA channel. */ + /* This also disables receive DMA channel interrupts */ + usc_DmaCmd( info, DmaCmd_ResetRxChannel ); + + usc_UnlatchRxstatusBits( info, RXSTATUS_ALL ); + usc_ClearIrqPendingBits( info, RECEIVE_DATA + RECEIVE_STATUS ); + usc_DisableInterrupts( info, RECEIVE_DATA + RECEIVE_STATUS ); + + usc_EnableReceiver(info,DISABLE_UNCONDITIONAL); + + /* This empties the receive FIFO and loads the RCC with RCLR */ + usc_OutReg( info, CCSR, (u16)(usc_InReg(info,CCSR) | BIT13) ); + usc_RTCmd( info, RTCmd_PurgeRxFifo ); + + info->rx_enabled = 0; + info->rx_overflow = 0; + +} /* end of stop_receiver() */ + +/* usc_start_receiver() + * + * Enable the USC receiver + * + * Arguments: info pointer to device instance data + * Return Value: None + */ +void usc_start_receiver( struct mgsl_struct *info ) +{ + u32 phys_addr; + + if (debug_level >= DEBUG_LEVEL_ISR) + printk("%s(%d):usc_start_receiver(%s)\n", + __FILE__,__LINE__, info->device_name ); + + mgsl_reset_rx_dma_buffers( info ); + usc_stop_receiver( info ); + + usc_OutReg( info, CCSR, (u16)(usc_InReg(info,CCSR) | BIT13) ); + usc_RTCmd( info, RTCmd_PurgeRxFifo ); + + if ( info->params.mode == MGSL_MODE_HDLC ) { + /* DMA mode Transfers */ + /* Program the DMA controller. */ + /* Enable the DMA controller end of buffer interrupt. */ + + /* program 16C32 with physical address of 1st DMA buffer entry */ + phys_addr = info->rx_buffer_list[0].phys_entry; + usc_OutDmaReg( info, NRARL, (u16)phys_addr ); + usc_OutDmaReg( info, NRARU, (u16)(phys_addr >> 16) ); + + usc_UnlatchRxstatusBits( info, RXSTATUS_ALL ); + usc_ClearIrqPendingBits( info, RECEIVE_DATA + RECEIVE_STATUS ); + usc_EnableInterrupts( info, RECEIVE_STATUS ); + + /* 1. Arm End of Buffer (EOB) Receive DMA Interrupt (BIT2 of RDIAR) */ + /* 2. Enable Receive DMA Interrupts (BIT1 of DICR) */ + + usc_OutDmaReg( info, RDIAR, BIT3 + BIT2 ); + usc_OutDmaReg( info, DICR, (u16)(usc_InDmaReg(info,DICR) | BIT1) ); + usc_DmaCmd( info, DmaCmd_InitRxChannel ); + if ( info->params.flags & HDLC_FLAG_AUTO_DCD ) + usc_EnableReceiver(info,ENABLE_AUTO_DCD); + else + usc_EnableReceiver(info,ENABLE_UNCONDITIONAL); + } else { + usc_UnlatchRxstatusBits(info, RXSTATUS_ALL); + usc_ClearIrqPendingBits(info, RECEIVE_DATA + RECEIVE_STATUS); + usc_EnableInterrupts(info, RECEIVE_DATA); + + usc_RTCmd( info, RTCmd_PurgeRxFifo ); + usc_RCmd( info, RCmd_EnterHuntmode ); + + usc_EnableReceiver(info,ENABLE_UNCONDITIONAL); + } + + usc_OutReg( info, CCSR, 0x1020 ); + + info->rx_enabled = 1; + +} /* end of usc_start_receiver() */ + +/* usc_start_transmitter() + * + * Enable the USC transmitter and send a transmit frame if + * one is loaded in the DMA buffers. + * + * Arguments: info pointer to device instance data + * Return Value: None + */ +void usc_start_transmitter( struct mgsl_struct *info ) +{ + u32 phys_addr; + unsigned int FrameSize; + + if (debug_level >= DEBUG_LEVEL_ISR) + printk("%s(%d):usc_start_transmitter(%s)\n", + __FILE__,__LINE__, info->device_name ); + + if ( info->xmit_cnt ) { + + /* If auto RTS enabled and RTS is inactive, then assert */ + /* RTS and set a flag indicating that the driver should */ + /* negate RTS when the transmission completes. */ + + info->drop_rts_on_tx_done = 0; + + if ( info->params.flags & HDLC_FLAG_AUTO_RTS ) { + usc_get_serial_signals( info ); + if ( !(info->serial_signals & SerialSignal_RTS) ) { + info->serial_signals |= SerialSignal_RTS; + usc_set_serial_signals( info ); + info->drop_rts_on_tx_done = 1; + } + } + + + if ( info->params.mode == MGSL_MODE_ASYNC ) { + if ( !info->tx_active ) { + usc_UnlatchTxstatusBits(info, TXSTATUS_ALL); + usc_ClearIrqPendingBits(info, TRANSMIT_STATUS + TRANSMIT_DATA); + usc_EnableInterrupts(info, TRANSMIT_DATA); + usc_load_txfifo(info); + } + } else { + /* Disable transmit DMA controller while programming. */ + usc_DmaCmd( info, DmaCmd_ResetTxChannel ); + + /* Transmit DMA buffer is loaded, so program USC */ + /* to send the frame contained in the buffers. */ + + + FrameSize = info->tx_buffer_list[0].rcc; + + /* Program the Transmit Character Length Register (TCLR) */ + /* and clear FIFO (TCC is loaded with TCLR on FIFO clear) */ + usc_OutReg( info, TCLR, (u16)FrameSize ); + + usc_RTCmd( info, RTCmd_PurgeTxFifo ); + + /* Program the address of the 1st DMA Buffer Entry in linked list */ + phys_addr = info->tx_buffer_list[0].phys_entry; + usc_OutDmaReg( info, NTARL, (u16)phys_addr ); + usc_OutDmaReg( info, NTARU, (u16)(phys_addr >> 16) ); + + usc_UnlatchTxstatusBits( info, TXSTATUS_ALL ); + usc_ClearIrqPendingBits( info, TRANSMIT_STATUS ); + usc_EnableInterrupts( info, TRANSMIT_STATUS ); + + /* Initialize Transmit DMA Channel */ + usc_DmaCmd( info, DmaCmd_InitTxChannel ); + + usc_TCmd( info, TCmd_SendFrame ); + + info->tx_timer.expires = jiffies + jiffies_from_ms(5000); + add_timer(&info->tx_timer); + } + info->tx_active = 1; + } + + if ( !info->tx_enabled ) { + info->tx_enabled = 1; + if ( info->params.flags & HDLC_FLAG_AUTO_CTS ) + usc_EnableTransmitter(info,ENABLE_AUTO_CTS); + else + usc_EnableTransmitter(info,ENABLE_UNCONDITIONAL); + } + +} /* end of usc_start_transmitter() */ + +/* usc_stop_transmitter() + * + * Stops the transmitter and DMA + * + * Arguments: info pointer to device isntance data + * Return Value: None + */ +void usc_stop_transmitter( struct mgsl_struct *info ) +{ + if (debug_level >= DEBUG_LEVEL_ISR) + printk("%s(%d):usc_stop_transmitter(%s)\n", + __FILE__,__LINE__, info->device_name ); + + del_timer(&info->tx_timer); + + usc_UnlatchTxstatusBits( info, TXSTATUS_ALL ); + usc_ClearIrqPendingBits( info, TRANSMIT_STATUS + TRANSMIT_DATA ); + usc_DisableInterrupts( info, TRANSMIT_STATUS + TRANSMIT_DATA ); + + usc_EnableTransmitter(info,DISABLE_UNCONDITIONAL); + usc_DmaCmd( info, DmaCmd_ResetTxChannel ); + usc_RTCmd( info, RTCmd_PurgeTxFifo ); + + info->tx_enabled = 0; + info->tx_active = 0; + +} /* end of usc_stop_transmitter() */ + +/* usc_load_txfifo() + * + * Fill the transmit FIFO until the FIFO is full or + * there is no more data to load. + * + * Arguments: info pointer to device extension (instance data) + * Return Value: None + */ +void usc_load_txfifo( struct mgsl_struct *info ) +{ + int Fifocount; + u8 TwoBytes[2]; + + if ( !info->xmit_cnt && !info->x_char ) + return; + + /* Select transmit FIFO status readback in TICR */ + usc_TCmd( info, TCmd_SelectTicrTxFifostatus ); + + /* load the Transmit FIFO until FIFOs full or all data sent */ + + while( (Fifocount = usc_InReg(info, TICR) >> 8) && info->xmit_cnt ) { + /* there is more space in the transmit FIFO and */ + /* there is more data in transmit buffer */ + + if ( (info->xmit_cnt > 1) && (Fifocount > 1) && !info->x_char ) { + /* write a 16-bit word from transmit buffer to 16C32 */ + + TwoBytes[0] = info->xmit_buf[info->xmit_tail++]; + info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1); + TwoBytes[1] = info->xmit_buf[info->xmit_tail++]; + info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1); + + outw( *((u16 *)TwoBytes), info->io_base + DATAREG); + + info->xmit_cnt -= 2; + info->icount.tx += 2; + } else { + /* only 1 byte left to transmit or 1 FIFO slot left */ + + outw( (inw( info->io_base + CCAR) & 0x0780) | (TDR+LSBONLY), + info->io_base + CCAR ); + + if (info->x_char) { + /* transmit pending high priority char */ + outw( info->x_char,info->io_base + CCAR ); + info->x_char = 0; + } else { + outw( info->xmit_buf[info->xmit_tail++],info->io_base + CCAR ); + info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1); + info->xmit_cnt--; + } + info->icount.tx++; + } + } + +} /* end of usc_load_txfifo() */ + +/* usc_reset() + * + * Reset the adapter to a known state and prepare it for further use. + * + * Arguments: info pointer to device instance data + * Return Value: None + */ +void usc_reset( struct mgsl_struct *info ) +{ + if ( info->bus_type == MGSL_BUS_TYPE_PCI ) { + int i; + volatile u32 readval; + + /* Set BIT30 of Misc Control Register */ + /* (Local Control Register 0x50) to force reset of USC. */ + + u32 *MiscCtrl = (u32 *)(info->lcr_base + 0x50); + u32 *LCR0BRDR = (u32 *)(info->lcr_base + 0x28); + + info->misc_ctrl_value |= BIT30; + *MiscCtrl = info->misc_ctrl_value; + + /* + * Force at least 170ns delay before clearing + * reset bit. Each read from LCR takes at least + * 30ns so 10 times for 300ns to be safe. + */ + for(i=0;i<10;i++) + readval = *MiscCtrl; + + info->misc_ctrl_value &= ~BIT30; + *MiscCtrl = info->misc_ctrl_value; + + *LCR0BRDR = BUS_DESCRIPTOR( + 1, // Write Strobe Hold (0-3) + 2, // Write Strobe Delay (0-3) + 2, // Read Strobe Delay (0-3) + 0, // NWDD (Write data-data) (0-3) + 4, // NWAD (Write Addr-data) (0-31) + 0, // NXDA (Read/Write Data-Addr) (0-3) + 0, // NRDD (Read Data-Data) (0-3) + 5 // NRAD (Read Addr-Data) (0-31) + ); + } else { + /* do HW reset */ + outb( 0,info->io_base + 8 ); + } + + info->mbre_bit = 0; + info->loopback_bits = 0; + info->usc_idle_mode = 0; + + /* + * Program the Bus Configuration Register (BCR) + * + * <15> 0 Don't use seperate address + * <14..6> 0 reserved + * <5..4> 00 IAckmode = Default, don't care + * <3> 1 Bus Request Totem Pole output + * <2> 1 Use 16 Bit data bus + * <1> 0 IRQ Totem Pole output + * <0> 0 Don't Shift Right Addr + * + * 0000 0000 0000 1100 = 0x000c + * + * By writing to io_base + SDPIN the Wait/Ack pin is + * programmed to work as a Wait pin. + */ + + outw( 0x000c,info->io_base + SDPIN ); + + + outw( 0,info->io_base ); + outw( 0,info->io_base + CCAR ); + + /* select little endian byte ordering */ + usc_RTCmd( info, RTCmd_SelectLittleEndian ); + + + /* Port Control Register (PCR) + * + * <15..14> 11 Port 7 is Output (~DMAEN, Bit 14 : 0 = Enabled) + * <13..12> 11 Port 6 is Output (~INTEN, Bit 12 : 0 = Enabled) + * <11..10> 00 Port 5 is Input (No Connect, Don't Care) + * <9..8> 00 Port 4 is Input (No Connect, Don't Care) + * <7..6> 11 Port 3 is Output (~RTS, Bit 6 : 0 = Enabled ) + * <5..4> 11 Port 2 is Output (~DTR, Bit 4 : 0 = Enabled ) + * <3..2> 01 Port 1 is Input (Dedicated RxC) + * <1..0> 01 Port 0 is Input (Dedicated TxC) + * + * 1111 0000 1111 0101 = 0xf0f5 + */ + + usc_OutReg( info, PCR, 0xf0f5 ); + + + /* + * Input/Output Control Register + * + * <15..14> 00 CTS is active low input + * <13..12> 00 DCD is active low input + * <11..10> 00 TxREQ pin is input (DSR) + * <9..8> 00 RxREQ pin is input (RI) + * <7..6> 00 TxD is output (Transmit Data) + * <5..3> 000 TxC Pin in Input (14.7456MHz Clock) + * <2..0> 100 RxC is Output (drive with BRG0) + * + * 0000 0000 0000 0100 = 0x0004 + */ + + usc_OutReg( info, IOCR, 0x0004 ); + +} /* end of usc_reset() */ + +/* usc_set_async_mode() + * + * Program adapter for asynchronous communications. + * + * Arguments: info pointer to device instance data + * Return Value: None + */ +void usc_set_async_mode( struct mgsl_struct *info ) +{ + u16 RegValue; + + /* disable interrupts while programming USC */ + usc_DisableMasterIrqBit( info ); + + outw( 0, info->io_base ); /* clear Master Bus Enable (DCAR) */ + usc_DmaCmd( info, DmaCmd_ResetAllChannels ); /* disable both DMA channels */ + + usc_loopback_frame( info ); + + /* Channel mode Register (CMR) + * + * <15..14> 00 Tx Sub modes, 00 = 1 Stop Bit + * <13..12> 00 00 = 16X Clock + * <11..8> 0000 Transmitter mode = Asynchronous + * <7..6> 00 reserved? + * <5..4> 00 Rx Sub modes, 00 = 16X Clock + * <3..0> 0000 Receiver mode = Asynchronous + * + * 0000 0000 0000 0000 = 0x0 + */ + + RegValue = 0; + if ( info->params.stop_bits != 1 ) + RegValue |= BIT14; + usc_OutReg( info, CMR, RegValue ); + + + /* Receiver mode Register (RMR) + * + * <15..13> 000 encoding = None + * <12..08> 00000 reserved (Sync Only) + * <7..6> 00 Even parity + * <5> 0 parity disabled + * <4..2> 000 Receive Char Length = 8 bits + * <1..0> 00 Disable Receiver + * + * 0000 0000 0000 0000 = 0x0 + */ + + RegValue = 0; + + if ( info->params.data_bits != 8 ) + RegValue |= BIT4+BIT3+BIT2; + + if ( info->params.parity != ASYNC_PARITY_NONE ) { + RegValue |= BIT5; + if ( info->params.parity != ASYNC_PARITY_ODD ) + RegValue |= BIT6; + } + + usc_OutReg( info, RMR, RegValue ); + + + /* Set IRQ trigger level */ + + usc_RCmd( info, RCmd_SelectRicrIntLevel ); + + + /* Receive Interrupt Control Register (RICR) + * + * <15..8> ? RxFIFO IRQ Request Level + * + * Note: For async mode the receive FIFO level must be set + * to 0 to aviod the situation where the FIFO contains fewer bytes + * than the trigger level and no more data is expected. + * + * <7> 0 Exited Hunt IA (Interrupt Arm) + * <6> 0 Idle Received IA + * <5> 0 Break/Abort IA + * <4> 0 Rx Bound IA + * <3> 0 Queued status reflects oldest byte in FIFO + * <2> 0 Abort/PE IA + * <1> 0 Rx Overrun IA + * <0> 0 Select TC0 value for readback + * + * 0000 0000 0100 0000 = 0x0000 + (FIFOLEVEL in MSB) + */ + + usc_OutReg( info, RICR, 0x0000 ); + + usc_UnlatchRxstatusBits( info, RXSTATUS_ALL ); + usc_ClearIrqPendingBits( info, RECEIVE_STATUS ); + + + /* Transmit mode Register (TMR) + * + * <15..13> 000 encoding = None + * <12..08> 00000 reserved (Sync Only) + * <7..6> 00 Transmit parity Even + * <5> 0 Transmit parity Disabled + * <4..2> 000 Tx Char Length = 8 bits + * <1..0> 00 Disable Transmitter + * + * 0000 0000 0000 0000 = 0x0 + */ + + RegValue = 0; + + if ( info->params.data_bits != 8 ) + RegValue |= BIT4+BIT3+BIT2; + + if ( info->params.parity != ASYNC_PARITY_NONE ) { + RegValue |= BIT5; + if ( info->params.parity != ASYNC_PARITY_ODD ) + RegValue |= BIT6; + } + + usc_OutReg( info, TMR, RegValue ); + + usc_set_txidle( info ); + + + /* Set IRQ trigger level */ + + usc_TCmd( info, TCmd_SelectTicrIntLevel ); + + + /* Transmit Interrupt Control Register (TICR) + * + * <15..8> ? Transmit FIFO IRQ Level + * <7> 0 Present IA (Interrupt Arm) + * <6> 1 Idle Sent IA + * <5> 0 Abort Sent IA + * <4> 0 EOF/EOM Sent IA + * <3> 0 CRC Sent IA + * <2> 0 1 = Wait for SW Trigger to Start Frame + * <1> 0 Tx Underrun IA + * <0> 0 TC0 constant on read back + * + * 0000 0000 0100 0000 = 0x0040 + */ + + usc_OutReg( info, TICR, 0x1f40 ); + + usc_UnlatchTxstatusBits( info, TXSTATUS_ALL ); + usc_ClearIrqPendingBits( info, TRANSMIT_STATUS ); + + usc_enable_async_clock( info, info->params.data_rate ); + + + /* Channel Control/status Register (CCSR) + * + * <15> X RCC FIFO Overflow status (RO) + * <14> X RCC FIFO Not Empty status (RO) + * <13> 0 1 = Clear RCC FIFO (WO) + * <12> X DPLL in Sync status (RO) + * <11> X DPLL 2 Missed Clocks status (RO) + * <10> X DPLL 1 Missed Clock status (RO) + * <9..8> 00 DPLL Resync on rising and falling edges (RW) + * <7> X SDLC Loop On status (RO) + * <6> X SDLC Loop Send status (RO) + * <5> 1 Bypass counters for TxClk and RxClk (RW) + * <4..2> 000 Last Char of SDLC frame has 8 bits (RW) + * <1..0> 00 reserved + * + * 0000 0000 0010 0000 = 0x0020 + */ + + usc_OutReg( info, CCSR, 0x0020 ); + + usc_DisableInterrupts( info, TRANSMIT_STATUS + TRANSMIT_DATA + + RECEIVE_DATA + RECEIVE_STATUS ); + + usc_ClearIrqPendingBits( info, TRANSMIT_STATUS + TRANSMIT_DATA + + RECEIVE_DATA + RECEIVE_STATUS ); + + usc_EnableMasterIrqBit( info ); + + /* Enable INTEN (Port 6, Bit12) */ + /* This connects the IRQ request signal to the ISA bus */ + /* on the ISA adapter. This has no effect for the PCI adapter */ + usc_OutReg( info, PCR, (u16)((usc_InReg(info, PCR) | BIT13) & ~BIT12) ); + +} /* end of usc_set_async_mode() */ + +/* usc_loopback_frame() + * + * Loop back a small (2 byte) dummy SDLC frame. + * Interrupts and DMA are NOT used. The purpose of this is to + * clear any 'stale' status info left over from running in async mode. + * + * The 16C32 shows the strange behaviour of marking the 1st + * received SDLC frame with a CRC error even when there is no + * CRC error. To get around this a small dummy from of 2 bytes + * is looped back when switching from async to sync mode. + * + * Arguments: info pointer to device instance data + * Return Value: None + */ +void usc_loopback_frame( struct mgsl_struct *info ) +{ + int i; + + usc_DisableMasterIrqBit( info ); + + usc_set_sdlc_mode( info ); + usc_enable_loopback( info, 1 ); + + /* Write 16-bit Time Constant for BRG0 */ + usc_OutReg( info, TC0R, 0 ); + + /* Channel Control Register (CCR) + * + * <15..14> 00 Don't use 32-bit Tx Control Blocks (TCBs) + * <13> 0 Trigger Tx on SW Command Disabled + * <12> 0 Flag Preamble Disabled + * <11..10> 00 Preamble Length = 8-Bits + * <9..8> 01 Preamble Pattern = flags + * <7..6> 10 Don't use 32-bit Rx status Blocks (RSBs) + * <5> 0 Trigger Rx on SW Command Disabled + * <4..0> 0 reserved + * + * 0000 0001 0000 0000 = 0x0100 + */ + + usc_OutReg( info, CCR, 0x0100 ); + + /* SETUP RECEIVER */ + usc_RTCmd( info, RTCmd_PurgeRxFifo ); + usc_EnableReceiver(info,ENABLE_UNCONDITIONAL); + + /* SETUP TRANSMITTER */ + /* Program the Transmit Character Length Register (TCLR) */ + /* and clear FIFO (TCC is loaded with TCLR on FIFO clear) */ + usc_OutReg( info, TCLR, 2 ); + usc_RTCmd( info, RTCmd_PurgeTxFifo ); + + /* unlatch Tx status bits, and start transmit channel. */ + usc_UnlatchTxstatusBits(info,TXSTATUS_ALL); + outw(0,info->io_base + DATAREG); + + /* ENABLE TRANSMITTER */ + usc_TCmd( info, TCmd_SendFrame ); + usc_EnableTransmitter(info,ENABLE_UNCONDITIONAL); + + /* WAIT FOR RECEIVE COMPLETE */ + for (i=0 ; i<1000 ; i++) + if (usc_InReg( info, RCSR ) & (BIT8 + BIT4 + BIT3 + BIT1)) + break; + + /* clear Internal Data loopback mode */ + usc_enable_loopback(info, 0); + + usc_EnableMasterIrqBit(info); + +} /* end of usc_loopback_frame() */ + +/* usc_set_sync_mode() Programs the USC for SDLC communications. + * + * Arguments: info pointer to adapter info structure + * Return Value: None + */ +void usc_set_sync_mode( struct mgsl_struct *info ) +{ + usc_loopback_frame( info ); + usc_set_sdlc_mode( info ); + + /* Enable INTEN (Port 6, Bit12) */ + /* This connects the IRQ request signal to the ISA bus */ + /* on the ISA adapter. This has no effect for the PCI adapter */ + usc_OutReg(info, PCR, (u16)((usc_InReg(info, PCR) | BIT13) & ~BIT12)); + + usc_enable_aux_clock(info, info->params.clock_speed); + + if (info->params.loopback) + usc_enable_loopback(info,1); + +} /* end of mgsl_set_sync_mode() */ + +/* usc_set_txidle() Set the HDLC idle mode for the transmitter. + * + * Arguments: info pointer to device instance data + * Return Value: None + */ +void usc_set_txidle( struct mgsl_struct *info ) +{ + u16 usc_idle_mode = IDLEMODE_FLAGS; + + /* Map API idle mode to USC register bits */ + + switch( info->idle_mode ){ + case HDLC_TXIDLE_FLAGS: usc_idle_mode = IDLEMODE_FLAGS; break; + case HDLC_TXIDLE_ALT_ZEROS_ONES: usc_idle_mode = IDLEMODE_ALT_ONE_ZERO; break; + case HDLC_TXIDLE_ZEROS: usc_idle_mode = IDLEMODE_ZERO; break; + case HDLC_TXIDLE_ONES: usc_idle_mode = IDLEMODE_ONE; break; + case HDLC_TXIDLE_ALT_MARK_SPACE: usc_idle_mode = IDLEMODE_ALT_MARK_SPACE; break; + case HDLC_TXIDLE_SPACE: usc_idle_mode = IDLEMODE_SPACE; break; + case HDLC_TXIDLE_MARK: usc_idle_mode = IDLEMODE_MARK; break; + } + + info->usc_idle_mode = usc_idle_mode; + usc_OutReg(info, TCSR, usc_idle_mode); + +} /* end of usc_set_txidle() */ + +/* usc_get_serial_signals() + * + * Query the adapter for the state of the V24 status (input) signals. + * + * Arguments: info pointer to device instance data + * Return Value: None + */ +void usc_get_serial_signals( struct mgsl_struct *info ) +{ + u16 status; + + /* clear all serial signals except DTR and RTS */ + info->serial_signals &= SerialSignal_DTR + SerialSignal_RTS; + + /* Read the Misc Interrupt status Register (MISR) to get */ + /* the V24 status signals. */ + + status = usc_InReg( info, MISR ); + + /* set serial signal bits to reflect MISR */ + + if ( status & MISCSTATUS_CTS ) + info->serial_signals |= SerialSignal_CTS; + + if ( status & MISCSTATUS_DCD ) + info->serial_signals |= SerialSignal_DCD; + + if ( status & MISCSTATUS_RI ) + info->serial_signals |= SerialSignal_RI; + + if ( status & MISCSTATUS_DSR ) + info->serial_signals |= SerialSignal_DSR; + +} /* end of usc_get_serial_signals() */ + +/* usc_set_serial_signals() + * + * Set the state of DTR and RTS based on contents of + * serial_signals member of device extension. + * + * Arguments: info pointer to device instance data + * Return Value: None + */ +void usc_set_serial_signals( struct mgsl_struct *info ) +{ + u16 Control; + unsigned char V24Out = info->serial_signals; + + /* get the current value of the Port Control Register (PCR) */ + + Control = usc_InReg( info, PCR ); + + if ( V24Out & SerialSignal_RTS ) + Control &= ~(BIT6); + else + Control |= BIT6; + + if ( V24Out & SerialSignal_DTR ) + Control &= ~(BIT4); + else + Control |= BIT4; + + usc_OutReg( info, PCR, Control ); + +} /* end of usc_set_serial_signals() */ + +/* usc_enable_async_clock() + * + * Enable the async clock at the specified frequency. + * + * Arguments: info pointer to device instance data + * data_rate data rate of clock in bps + * 0 disables the AUX clock. + * Return Value: None + */ +void usc_enable_async_clock( struct mgsl_struct *info, u32 data_rate ) +{ + if ( data_rate ) { + /* + * Clock mode Control Register (CMCR) + * + * <15..14> 00 counter 1 Disabled + * <13..12> 00 counter 0 Disabled + * <11..10> 11 BRG1 Input is TxC Pin + * <9..8> 11 BRG0 Input is TxC Pin + * <7..6> 01 DPLL Input is BRG1 Output + * <5..3> 100 TxCLK comes from BRG0 + * <2..0> 100 RxCLK comes from BRG0 + * + * 0000 1111 0110 0100 = 0x0f64 + */ + + usc_OutReg( info, CMCR, 0x0f64 ); + + + /* + * Write 16-bit Time Constant for BRG0 + * Time Constant = (ClkSpeed / data_rate) - 1 + * ClkSpeed = 921600 (ISA), 691200 (PCI) + */ + + if ( info->bus_type == MGSL_BUS_TYPE_PCI ) + usc_OutReg( info, TC0R, (u16)((691200/data_rate) - 1) ); + else + usc_OutReg( info, TC0R, (u16)((921600/data_rate) - 1) ); + + + /* + * Hardware Configuration Register (HCR) + * Clear Bit 1, BRG0 mode = Continuous + * Set Bit 0 to enable BRG0. + */ + + usc_OutReg( info, HCR, + (u16)((usc_InReg( info, HCR ) & ~BIT1) | BIT0) ); + + + /* Input/Output Control Reg, <2..0> = 100, Drive RxC pin with BRG0 */ + + usc_OutReg( info, IOCR, + (u16)((usc_InReg(info, IOCR) & 0xfff8) | 0x0004) ); + } else { + /* data rate == 0 so turn off BRG0 */ + usc_OutReg( info, HCR, (u16)(usc_InReg( info, HCR ) & ~BIT0) ); + } + +} /* end of usc_enable_async_clock() */ + +/* + * Buffer Structures: + * + * Normal memory access uses virtual addresses that can make discontiguous + * physical memory pages appear to be contiguous in the virtual address + * space (the processors memory mapping handles the conversions). + * + * DMA transfers require physically contiguous memory. This is because + * the DMA system controller and DMA bus masters deal with memory using + * only physical addresses. + * + * This causes a problem under Windows NT when large DMA buffers are + * needed. Fragmentation of the nonpaged pool prevents allocations of + * physically contiguous buffers larger than the PAGE_SIZE. + * + * However the 16C32 supports Bus Master Scatter/Gather DMA which + * allows DMA transfers to physically discontiguous buffers. Information + * about each data transfer buffer is contained in a memory structure + * called a 'buffer entry'. A list of buffer entries is maintained + * to track and control the use of the data transfer buffers. + * + * To support this strategy we will allocate sufficient PAGE_SIZE + * contiguous memory buffers to allow for the total required buffer + * space. + * + * The 16C32 accesses the list of buffer entries using Bus Master + * DMA. Control information is read from the buffer entries by the + * 16C32 to control data transfers. status information is written to + * the buffer entries by the 16C32 to indicate the status of completed + * transfers. + * + * The CPU writes control information to the buffer entries to control + * the 16C32 and reads status information from the buffer entries to + * determine information about received and transmitted frames. + * + * Because the CPU and 16C32 (adapter) both need simultaneous access + * to the buffer entries, the buffer entry memory is allocated with + * HalAllocateCommonBuffer(). This restricts the size of the buffer + * entry list to PAGE_SIZE. + * + * The actual data buffers on the other hand will only be accessed + * by the CPU or the adapter but not by both simultaneously. This allows + * Scatter/Gather packet based DMA procedures for using physically + * discontiguous pages. + */ + +/* + * mgsl_reset_rx_dma_buffers() + * + * Set the count for all receive buffers to DMABUFFERSIZE + * and set the current buffer to the first buffer. This effectively + * makes all buffers free and discards any data in buffers. + * + * Arguments: info pointer to device instance data + * Return Value: None + */ +void mgsl_reset_rx_dma_buffers( struct mgsl_struct *info ) +{ + unsigned int i; + + for ( i = 0; i < info->rx_buffer_count; i++ ) { + *((unsigned long *)&(info->rx_buffer_list[i].count)) = DMABUFFERSIZE; +// info->rx_buffer_list[i].count = DMABUFFERSIZE; +// info->rx_buffer_list[i].status = 0; + } + + info->current_rx_buffer = 0; + +} /* end of mgsl_reset_rx_dma_buffers() */ + +/* + * mgsl_free_rx_frame_buffers() + * + * Free the receive buffers used by a received SDLC + * frame such that the buffers can be reused. + * + * Arguments: + * + * info pointer to device instance data + * StartIndex index of 1st receive buffer of frame + * EndIndex index of last receive buffer of frame + * + * Return Value: None + */ +void mgsl_free_rx_frame_buffers( struct mgsl_struct *info, unsigned int StartIndex, unsigned int EndIndex ) +{ + int Done = 0; + DMABUFFERENTRY *pBufEntry; + unsigned int Index; + + /* Starting with 1st buffer entry of the frame clear the status */ + /* field and set the count field to DMA Buffer Size. */ + + Index = StartIndex; + + while( !Done ) { + pBufEntry = &(info->rx_buffer_list[Index]); + + if ( Index == EndIndex ) { + /* This is the last buffer of the frame! */ + Done = 1; + } + + /* reset current buffer for reuse */ +// pBufEntry->status = 0; +// pBufEntry->count = DMABUFFERSIZE; + *((unsigned long *)&(pBufEntry->count)) = DMABUFFERSIZE; + + /* advance to next buffer entry in linked list */ + Index++; + if ( Index == info->rx_buffer_count ) + Index = 0; + } + + /* set current buffer to next buffer after last buffer of frame */ + info->current_rx_buffer = Index; + +} /* end of free_rx_frame_buffers() */ + +/* mgsl_get_rx_frame() + * + * This function attempts to return a received SDLC frame from the + * receive DMA buffers. Only frames received without errors are returned. + * + * Arguments: info pointer to device extension + * Return Value: 1 if frame returned, otherwise 0 + */ +int mgsl_get_rx_frame(struct mgsl_struct *info) +{ + unsigned int StartIndex, EndIndex; /* index of 1st and last buffers of Rx frame */ + unsigned short status; + DMABUFFERENTRY *pBufEntry; + unsigned int framesize; + int ReturnCode = 0; + unsigned long flags; + struct tty_struct *tty = info->tty; + + /* + * current_rx_buffer points to the 1st buffer of the next available + * receive frame. To find the last buffer of the frame look for + * a non-zero status field in the buffer entries. (The status + * field is set by the 16C32 after completing a receive frame. + */ + + StartIndex = EndIndex = info->current_rx_buffer; + + while( !info->rx_buffer_list[EndIndex].status ) { + /* + * If the count field of the buffer entry is non-zero then + * this buffer has not been used. (The 16C32 clears the count + * field when it starts using the buffer.) If an unused buffer + * is encountered then there are no frames available. + */ + + if ( info->rx_buffer_list[EndIndex].count ) + goto Cleanup; + + /* advance to next buffer entry in linked list */ + EndIndex++; + if ( EndIndex == info->rx_buffer_count ) + EndIndex = 0; + + /* if entire list searched then no frame available */ + if ( EndIndex == StartIndex ) { + /* If this occurs then something bad happened, + * all buffers have been 'used' but none mark + * the end of a frame. Reset buffers and receiver. + */ + + if ( info->rx_enabled ){ + spin_lock_irqsave(&info->irq_spinlock,flags); + usc_start_receiver(info); + spin_unlock_irqrestore(&info->irq_spinlock,flags); + } + goto Cleanup; + } + } + + + /* check status of receive frame */ + + status = info->rx_buffer_list[EndIndex].status; + + if ( status & (RXSTATUS_SHORT_FRAME + RXSTATUS_OVERRUN + + RXSTATUS_CRC_ERROR + RXSTATUS_ABORT) ) { + if ( status & RXSTATUS_SHORT_FRAME ) + info->icount.rxshort++; + else if ( status & RXSTATUS_ABORT ) + info->icount.rxabort++; + else if ( status & RXSTATUS_OVERRUN ) + info->icount.rxover++; + else + info->icount.rxcrc++; + framesize = 0; + } else { + /* receive frame has no errors, get frame size. + * The frame size is the starting value of the RCC (which was + * set to 0xffff) minus the ending value of the RCC (decremented + * once for each receive character) minus 2 for the 16-bit CRC. + */ + + framesize = RCLRVALUE - info->rx_buffer_list[EndIndex].rcc; + + /* adjust frame size for CRC if any */ + if ( info->params.crc_type == HDLC_CRC_16_CCITT ) + framesize -= 2; + } + + if ( debug_level >= DEBUG_LEVEL_BH ) + printk("%s(%d):mgsl_get_rx_frame(%s) status=%04X size=%d\n", + __FILE__,__LINE__,info->device_name,status,framesize); + + if ( debug_level >= DEBUG_LEVEL_DATA ) + mgsl_trace_block(info,info->rx_buffer_list[StartIndex].virt_addr, + framesize,0); + + if (framesize) { + if (framesize > HDLC_MAX_FRAME_SIZE) + info->icount.rxlong++; + else { + info->icount.rxok++; + pBufEntry = &(info->rx_buffer_list[StartIndex]); + /* Call the line discipline receive callback directly. */ + tty->ldisc.receive_buf(tty, pBufEntry->virt_addr, info->flag_buf, framesize); + } + } + /* Free the buffers used by this frame. */ + mgsl_free_rx_frame_buffers( info, StartIndex, EndIndex ); + + ReturnCode = 1; + +Cleanup: + + if ( info->rx_enabled && info->rx_overflow ) { + /* The receiver needs to restarted because of + * a receive overflow (buffer or FIFO). If the + * receive buffers are now empty, then restart receiver. + */ + + if ( !info->rx_buffer_list[info->current_rx_buffer].status && + info->rx_buffer_list[info->current_rx_buffer].count ) { + spin_lock_irqsave(&info->irq_spinlock,flags); + usc_start_receiver(info); + spin_unlock_irqrestore(&info->irq_spinlock,flags); + } + } + + return ReturnCode; + +} /* end of mgsl_get_rx_frame() */ + +/* mgsl_load_tx_dma_buffer() + * + * Load the transmit DMA buffer with the specified data. + * + * Arguments: + * + * info pointer to device extension + * Buffer pointer to buffer containing frame to load + * BufferSize size in bytes of frame in Buffer + * + * Return Value: None + */ +void mgsl_load_tx_dma_buffer(struct mgsl_struct *info, const char *Buffer, + unsigned int BufferSize) +{ + unsigned short Copycount; + unsigned int i = 0; + DMABUFFERENTRY *pBufEntry; + + if ( debug_level >= DEBUG_LEVEL_DATA ) + mgsl_trace_block(info,Buffer,BufferSize,1); + + /* Setup the status and RCC (Frame Size) fields of the 1st */ + /* buffer entry in the transmit DMA buffer list. */ + + info->tx_buffer_list[0].status = info->cmr_value & 0xf000; + info->tx_buffer_list[0].rcc = BufferSize; + info->tx_buffer_list[0].count = BufferSize; + + /* Copy frame data from 1st source buffer to the DMA buffers. */ + /* The frame data may span multiple DMA buffers. */ + + while( BufferSize ){ + /* Get a pointer to next DMA buffer entry. */ + pBufEntry = &info->tx_buffer_list[i++]; + + /* Calculate the number of bytes that can be copied from */ + /* the source buffer to this DMA buffer. */ + if ( BufferSize > DMABUFFERSIZE ) + Copycount = DMABUFFERSIZE; + else + Copycount = BufferSize; + + /* Actually copy data from source buffer to DMA buffer. */ + /* Also set the data count for this individual DMA buffer. */ + if ( info->bus_type == MGSL_BUS_TYPE_PCI ) + mgsl_load_pci_memory(pBufEntry->virt_addr, Buffer,Copycount); + else + memcpy(pBufEntry->virt_addr, Buffer, Copycount); + + pBufEntry->count = Copycount; + + /* Advance source pointer and reduce remaining data count. */ + Buffer += Copycount; + BufferSize -= Copycount; + } + +} /* end of mgsl_load_tx_dma_buffer() */ + +/* + * mgsl_register_test() + * + * Performs a register test of the 16C32. + * + * Arguments: info pointer to device instance data + * Return Value: TRUE if test passed, otherwise FALSE + */ +BOOLEAN mgsl_register_test( struct mgsl_struct *info ) +{ + static unsigned short BitPatterns[] = + { 0x0000, 0xffff, 0xaaaa, 0x5555, 0x1234, 0x6969, 0x9696, 0x0f0f }; + static unsigned int Patterncount = sizeof(BitPatterns)/sizeof(unsigned short); + unsigned int i; + BOOLEAN rc = TRUE; + unsigned long flags; + + spin_lock_irqsave(&info->irq_spinlock,flags); + usc_reset(info); + spin_unlock_irqrestore(&info->irq_spinlock,flags); + + /* Verify the reset state of some registers. */ + + if ( (usc_InReg( info, SICR ) != 0) || + (usc_InReg( info, IVR ) != 0) || + (usc_InDmaReg( info, DIVR ) != 0) ){ + rc = FALSE; + } + + if ( rc == TRUE ){ + /* Write bit patterns to various registers but do it out of */ + /* sync, then read back and verify values. */ + + for ( i = 0 ; i < Patterncount ; i++ ) { + usc_OutReg( info, TC0R, BitPatterns[i] ); + usc_OutReg( info, TC1R, BitPatterns[(i+1)%Patterncount] ); + usc_OutReg( info, TCLR, BitPatterns[(i+2)%Patterncount] ); + usc_OutReg( info, RCLR, BitPatterns[(i+3)%Patterncount] ); + usc_OutReg( info, RSR, BitPatterns[(i+4)%Patterncount] ); + usc_OutDmaReg( info, TBCR, BitPatterns[(i+5)%Patterncount] ); + + if ( (usc_InReg( info, TC0R ) != BitPatterns[i]) || + (usc_InReg( info, TC1R ) != BitPatterns[(i+1)%Patterncount]) || + (usc_InReg( info, TCLR ) != BitPatterns[(i+2)%Patterncount]) || + (usc_InReg( info, RCLR ) != BitPatterns[(i+3)%Patterncount]) || + (usc_InReg( info, RSR ) != BitPatterns[(i+4)%Patterncount]) || + (usc_InDmaReg( info, TBCR ) != BitPatterns[(i+5)%Patterncount]) ){ + rc = FALSE; + break; + } + } + } + + spin_lock_irqsave(&info->irq_spinlock,flags); + usc_reset(info); + spin_unlock_irqrestore(&info->irq_spinlock,flags); + + return rc; + +} /* end of mgsl_register_test() */ + +/* mgsl_irq_test() Perform interrupt test of the 16C32. + * + * Arguments: info pointer to device instance data + * Return Value: TRUE if test passed, otherwise FALSE + */ +BOOLEAN mgsl_irq_test( struct mgsl_struct *info ) +{ + unsigned long EndTime; + unsigned long flags; + + spin_lock_irqsave(&info->irq_spinlock,flags); + usc_reset(info); + spin_unlock_irqrestore(&info->irq_spinlock,flags); + + /* + * Setup 16C32 to interrupt on TxC pin (14MHz clock) transition. + * The ISR sets irq_occurred to 1. + */ + + info->irq_occurred = FALSE; + + /* Enable INTEN gate for ISA adapter (Port 6, Bit12) */ + /* Enable INTEN (Port 6, Bit12) */ + /* This connects the IRQ request signal to the ISA bus */ + /* on the ISA adapter. This has no effect for the PCI adapter */ + usc_OutReg( info, PCR, (unsigned short)((usc_InReg(info, PCR) | BIT13) & ~BIT12) ); + + usc_EnableMasterIrqBit(info); + usc_EnableInterrupts(info, IO_PIN); + usc_ClearIrqPendingBits(info, IO_PIN); + + usc_UnlatchIostatusBits(info, MISCSTATUS_TXC_LATCHED); + usc_EnableStatusIrqs(info, SICR_TXC_ACTIVE + SICR_TXC_INACTIVE); + + EndTime=100; + while( EndTime-- && !info->irq_occurred ) { + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(jiffies_from_ms(10)); + current->state = TASK_RUNNING; + } + + spin_lock_irqsave(&info->irq_spinlock,flags); + usc_reset(info); + spin_unlock_irqrestore(&info->irq_spinlock,flags); + + if ( !info->irq_occurred ) + return FALSE; + else + return TRUE; + +} /* end of mgsl_irq_test() */ + +/* mgsl_dma_test() + * + * Perform a DMA test of the 16C32. A small frame is + * transmitted via DMA from a transmit buffer to a receive buffer + * using single buffer DMA mode. + * + * Arguments: info pointer to device instance data + * Return Value: TRUE if test passed, otherwise FALSE + */ +BOOLEAN mgsl_dma_test( struct mgsl_struct *info ) +{ + unsigned short FifoLevel; + unsigned long phys_addr; + unsigned int FrameSize; + unsigned int i; + char *TmpPtr; + BOOLEAN rc = TRUE; + volatile unsigned short status; + volatile unsigned long EndTime; + unsigned long flags; + MGSL_PARAMS tmp_params; + + /* save current port options */ + memcpy(&tmp_params,&info->params,sizeof(MGSL_PARAMS)); + /* load default port options */ + memcpy(&info->params,&default_params,sizeof(MGSL_PARAMS)); + +#define TESTFRAMESIZE 40 + + spin_lock_irqsave(&info->irq_spinlock,flags); + + /* setup 16C32 for SDLC DMA transfer mode */ + + usc_reset(info); + usc_set_sdlc_mode(info); + usc_enable_loopback(info,1); + + /* Reprogram the RDMR so that the 16C32 does NOT clear the count + * field of the buffer entry after fetching buffer address. This + * way we can detect a DMA failure for a DMA read (which should be + * non-destructive to system memory) before we try and write to + * memory (where a failure could corrupt system memory). + */ + + /* Receive DMA mode Register (RDMR) + * + * <15..14> 11 DMA mode = Linked List Buffer mode + * <13> 1 RSBinA/L = store Rx status Block in List entry + * <12> 0 1 = Clear count of List Entry after fetching + * <11..10> 00 Address mode = Increment + * <9> 1 Terminate Buffer on RxBound + * <8> 0 Bus Width = 16bits + * <7..0> ? status Bits (write as 0s) + * + * 1110 0010 0000 0000 = 0xe200 + */ + + usc_OutDmaReg( info, RDMR, 0xe200 ); + + spin_unlock_irqrestore(&info->irq_spinlock,flags); + + + /* SETUP TRANSMIT AND RECEIVE DMA BUFFERS */ + + FrameSize = TESTFRAMESIZE; + + /* setup 1st transmit buffer entry: */ + /* with frame size and transmit control word */ + + info->tx_buffer_list[0].count = FrameSize; + info->tx_buffer_list[0].rcc = FrameSize; + info->tx_buffer_list[0].status = 0x4000; + + /* build a transmit frame in 1st transmit DMA buffer */ + + TmpPtr = info->tx_buffer_list[0].virt_addr; + for (i = 0; i < FrameSize; i++ ) + *TmpPtr++ = i; + + /* setup 1st receive buffer entry: */ + /* clear status, set max receive buffer size */ + + info->rx_buffer_list[0].status = 0; + info->rx_buffer_list[0].count = FrameSize + 4; + + /* zero out the 1st receive buffer */ + + memset( info->rx_buffer_list[0].virt_addr, 0, FrameSize + 4 ); + + /* Set count field of next buffer entries to prevent */ + /* 16C32 from using buffers after the 1st one. */ + + info->tx_buffer_list[1].count = 0; + info->rx_buffer_list[1].count = 0; + + + /***************************/ + /* Program 16C32 receiver. */ + /***************************/ + + spin_lock_irqsave(&info->irq_spinlock,flags); + + /* setup DMA transfers */ + usc_RTCmd( info, RTCmd_PurgeRxFifo ); + + /* program 16C32 receiver with physical address of 1st DMA buffer entry */ + phys_addr = info->rx_buffer_list[0].phys_entry; + usc_OutDmaReg( info, NRARL, (unsigned short)phys_addr ); + usc_OutDmaReg( info, NRARU, (unsigned short)(phys_addr >> 16) ); + + /* Clear the Rx DMA status bits (read RDMR) and start channel */ + usc_InDmaReg( info, RDMR ); + usc_DmaCmd( info, DmaCmd_InitRxChannel ); + + /* Enable Receiver (RMR <1..0> = 10) */ + usc_OutReg( info, RMR, (unsigned short)((usc_InReg(info, RMR) & 0xfffc) | 0x0002) ); + + spin_unlock_irqrestore(&info->irq_spinlock,flags); + + + /*************************************************************/ + /* WAIT FOR RECEIVER TO DMA ALL PARAMETERS FROM BUFFER ENTRY */ + /*************************************************************/ + + /* Wait 100ms for interrupt. */ + EndTime = jiffies + jiffies_from_ms(100); + + for(;;) { + if ( jiffies > EndTime ) { + rc = FALSE; + break; + } + + spin_lock_irqsave(&info->irq_spinlock,flags); + status = usc_InDmaReg( info, RDMR ); + spin_unlock_irqrestore(&info->irq_spinlock,flags); + + if ( !(status & BIT4) && (status & BIT5) ) { + /* INITG (BIT 4) is inactive (no entry read in progress) AND */ + /* BUSY (BIT 5) is active (channel still active). */ + /* This means the buffer entry read has completed. */ + break; + } + } + + + /******************************/ + /* Program 16C32 transmitter. */ + /******************************/ + + spin_lock_irqsave(&info->irq_spinlock,flags); + + /* Program the Transmit Character Length Register (TCLR) */ + /* and clear FIFO (TCC is loaded with TCLR on FIFO clear) */ + + usc_OutReg( info, TCLR, (unsigned short)info->tx_buffer_list[0].count ); + usc_RTCmd( info, RTCmd_PurgeTxFifo ); + + /* Program the address of the 1st DMA Buffer Entry in linked list */ + + phys_addr = info->tx_buffer_list[0].phys_entry; + usc_OutDmaReg( info, NTARL, (unsigned short)phys_addr ); + usc_OutDmaReg( info, NTARU, (unsigned short)(phys_addr >> 16) ); + + /* unlatch Tx status bits, and start transmit channel. */ + + usc_OutReg( info, TCSR, (unsigned short)(( usc_InReg(info, TCSR) & 0x0700) | 0xfa) ); + usc_DmaCmd( info, DmaCmd_InitTxChannel ); + + /* wait for DMA controller to fill transmit FIFO */ + + usc_TCmd( info, TCmd_SelectTicrTxFifostatus ); + + spin_unlock_irqrestore(&info->irq_spinlock,flags); + + + /**********************************/ + /* WAIT FOR TRANSMIT FIFO TO FILL */ + /**********************************/ + + /* Wait 100ms */ + EndTime = jiffies + jiffies_from_ms(100); + + for(;;) { + if ( jiffies > EndTime ) { + rc = FALSE; + break; + } + + spin_lock_irqsave(&info->irq_spinlock,flags); + FifoLevel = usc_InReg(info, TICR) >> 8; + spin_unlock_irqrestore(&info->irq_spinlock,flags); + + if ( FifoLevel < 16 ) + break; + else + if ( FrameSize < 32 ) { + /* This frame is smaller than the entire transmit FIFO */ + /* so wait for the entire frame to be loaded. */ + if ( FifoLevel <= (32 - FrameSize) ) + break; + } + } + + + if ( rc == TRUE ) + { + /* Enable 16C32 transmitter. */ + + spin_lock_irqsave(&info->irq_spinlock,flags); + + /* Transmit mode Register (TMR), <1..0> = 10, Enable Transmitter */ + usc_TCmd( info, TCmd_SendFrame ); + usc_OutReg( info, TMR, (unsigned short)((usc_InReg(info, TMR) & 0xfffc) | 0x0002) ); + + spin_unlock_irqrestore(&info->irq_spinlock,flags); + + + /******************************/ + /* WAIT FOR TRANSMIT COMPLETE */ + /******************************/ + + /* Wait 100ms */ + EndTime = jiffies + jiffies_from_ms(100); + + /* While timer not expired wait for transmit complete */ + + spin_lock_irqsave(&info->irq_spinlock,flags); + status = usc_InReg( info, TCSR ); + spin_unlock_irqrestore(&info->irq_spinlock,flags); + + while ( !(status & (BIT6+BIT5+BIT4+BIT2+BIT1)) ) { + if ( jiffies > EndTime ) { + rc = FALSE; + break; + } + + spin_lock_irqsave(&info->irq_spinlock,flags); + status = usc_InReg( info, TCSR ); + spin_unlock_irqrestore(&info->irq_spinlock,flags); + } + } + + + if ( rc == TRUE ){ + /* CHECK FOR TRANSMIT ERRORS */ + if ( status & (BIT5 + BIT1) ) + rc = FALSE; + } + + if ( rc == TRUE ) { + /* WAIT FOR RECEIVE COMPLETE */ + + /* Wait 100ms */ + EndTime = jiffies + jiffies_from_ms(100); + + /* Wait for 16C32 to write receive status to buffer entry. */ + status=info->rx_buffer_list[0].status; + while ( status == 0 ) { + if ( jiffies > EndTime ) { + printk(KERN_ERR"mark 4\n"); + rc = FALSE; + break; + } + status=info->rx_buffer_list[0].status; + } + } + + + if ( rc == TRUE ) { + /* CHECK FOR RECEIVE ERRORS */ + status = info->rx_buffer_list[0].status; + + if ( status & (BIT8 + BIT3 + BIT1) ) { + /* receive error has occured */ + rc = FALSE; + } else { + if ( memcmp( info->tx_buffer_list[0].virt_addr , + info->rx_buffer_list[0].virt_addr, FrameSize ) ){ + rc = FALSE; + } + } + } + + usc_reset( info ); + + /* restore current port options */ + memcpy(&info->params,&tmp_params,sizeof(MGSL_PARAMS)); + + return rc; + +} /* end of mgsl_dma_test() */ + +/* mgsl_adapter_test() + * + * Perform the register, IRQ, and DMA tests for the 16C32. + * + * Arguments: info pointer to device instance data + * Return Value: 0 if success, otherwise -ENODEV + */ +int mgsl_adapter_test( struct mgsl_struct *info ) +{ + if ( debug_level >= DEBUG_LEVEL_INFO ) + printk( "%s(%d):Testing device %s\n", + __FILE__,__LINE__,info->device_name ); + + if ( !mgsl_register_test( info ) ) { + info->init_error = DiagStatus_AddressFailure; + printk( "%s(%d):Register test failure for device %s Addr=%04X\n", + __FILE__,__LINE__,info->device_name, (unsigned short)(info->io_base) ); + return -ENODEV; + } + + if ( !mgsl_irq_test( info ) ) { + info->init_error = DiagStatus_IrqFailure; + printk( "%s(%d):Interrupt test failure for device %s IRQ=%d\n", + __FILE__,__LINE__,info->device_name, (unsigned short)(info->irq_level) ); + return -ENODEV; + } + + if ( !mgsl_dma_test( info ) ) { + info->init_error = DiagStatus_DmaFailure; + printk( "%s(%d):DMA test failure for device %s DMA=%d\n", + __FILE__,__LINE__,info->device_name, (unsigned short)(info->dma_level) ); + return -ENODEV; + } + + if ( debug_level >= DEBUG_LEVEL_INFO ) + printk( "%s(%d):device %s passed diagnostics\n", + __FILE__,__LINE__,info->device_name ); + + return 0; + +} /* end of mgsl_adapter_test() */ + +/* mgsl_memory_test() + * + * Test the shared memory on a PCI adapter. + * + * Arguments: info pointer to device instance data + * Return Value: TRUE if test passed, otherwise FALSE + */ +BOOLEAN mgsl_memory_test( struct mgsl_struct *info ) +{ + static unsigned long BitPatterns[] = { 0x0, 0x55555555, 0xaaaaaaaa, + 0x66666666, 0x99999999, 0xffffffff, 0x12345678 }; + unsigned long Patterncount = sizeof(BitPatterns)/sizeof(unsigned long); + unsigned long i; + unsigned long TestLimit = SHARED_MEM_ADDRESS_SIZE/sizeof(unsigned long); + unsigned long * TestAddr; + + if ( info->bus_type != MGSL_BUS_TYPE_PCI ) + return TRUE; + + TestAddr = (unsigned long *)info->memory_base; + + /* Test data lines with test pattern at one location. */ + + for ( i = 0 ; i < Patterncount ; i++ ) { + *TestAddr = BitPatterns[i]; + if ( *TestAddr != BitPatterns[i] ) + return FALSE; + } + + /* Test address lines with incrementing pattern over */ + /* entire address range. */ + + for ( i = 0 ; i < TestLimit ; i++ ) { + *TestAddr = i * 4; + TestAddr++; + } + + TestAddr = (unsigned long *)info->memory_base; + + for ( i = 0 ; i < TestLimit ; i++ ) { + if ( *TestAddr != i * 4 ) + return FALSE; + TestAddr++; + } + + memset( info->memory_base, 0, SHARED_MEM_ADDRESS_SIZE ); + + return TRUE; + +} /* End Of mgsl_memory_test() */ + + +#pragma optimize( "", off ) +/* mgsl_load_pci_memory() + * + * Load a large block of data into the PCI shared memory. + * Use this instead of memcpy() or memmove() to move data + * into the PCI shared memory. + * + * Notes: + * + * This function prevents the PCI9050 interface chip from hogging + * the adapter local bus, which can starve the 16C32 by preventing + * 16C32 bus master cycles. + * + * The PCI9050 documentation says that the 9050 will always release + * control of the local bus after completing the current read + * or write operation. + * + * It appears that as long as the PCI9050 write FIFO is full, the + * PCI9050 treats all of the writes as a single burst transaction + * and will not release the bus. This causes DMA latency problems + * at high speeds when copying large data blocks to the shared + * memory. + * + * This function in effect, breaks the a large shared memory write + * into multiple transations by interleaving a shared memory read + * which will flush the write FIFO and 'complete' the write + * transation. This allows any pending DMA request to gain control + * of the local bus in a timely fasion. + * + * Arguments: + * + * TargetPtr pointer to target address in PCI shared memory + * SourcePtr pointer to source buffer for data + * count count in bytes of data to copy + * + * Return Value: None + */ +void mgsl_load_pci_memory( char* TargetPtr, const char* SourcePtr, + unsigned short count ) +{ + /*******************************************************/ + /* A load interval of 16 allows for 4 32-bit writes at */ + /* 60ns each for a maximum latency of 240ns on the */ + /* local bus. */ + /*******************************************************/ + +#define PCI_LOAD_INTERVAL 64 + + unsigned short Intervalcount = count / PCI_LOAD_INTERVAL; + unsigned short Index; + unsigned long Dummy; + + for ( Index = 0 ; Index < Intervalcount ; Index++ ) + { + memcpy(TargetPtr, SourcePtr, PCI_LOAD_INTERVAL); + Dummy = *((unsigned long *)TargetPtr); + TargetPtr += PCI_LOAD_INTERVAL; + SourcePtr += PCI_LOAD_INTERVAL; + } + + memcpy( TargetPtr, SourcePtr, count % PCI_LOAD_INTERVAL ); + +} /* End Of mgsl_load_pci_memory() */ +#pragma optimize( "", on ) + +void mgsl_trace_block(struct mgsl_struct *info,const char* data, int count, int xmit) +{ + int i; + int linecount; + if (xmit) + printk("%s tx data:\n",info->device_name); + else + printk("%s rx data:\n",info->device_name); + + while(count) { + if (count > 16) + linecount = 16; + else + linecount = count; + + for(i=0;i=040 && data[i]<=0176) + printk("%c",data[i]); + else + printk("."); + } + printk("\n"); + + data += linecount; + count -= linecount; + } +} /* end of mgsl_trace_block() */ + +/* mgsl_tx_timeout() + * + * called when HDLC frame times out + * update stats and do tx completion processing + * + * Arguments: context pointer to device instance data + * Return Value: None + */ +void mgsl_tx_timeout(unsigned long context) +{ + struct mgsl_struct *info = (struct mgsl_struct*)context; + unsigned long flags; + + if ( debug_level >= DEBUG_LEVEL_INFO ) + printk( "%s(%d):mgsl_tx_timeout(%s)\n", + __FILE__,__LINE__,info->device_name); + if(info->tx_active && info->params.mode == MGSL_MODE_HDLC) { + info->icount.txtimeout++; + } + + spin_lock_irqsave(&info->irq_spinlock,flags); + info->tx_active = 0; + info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; + spin_unlock_irqrestore(&info->irq_spinlock,flags); + + mgsl_bh_transmit_data(info,0); + +} /* end of mgsl_tx_timeout() */ + diff -ur --new-file old/linux/drivers/char/tpqic02.c new/linux/drivers/char/tpqic02.c --- old/linux/drivers/char/tpqic02.c Wed Dec 23 18:44:41 1998 +++ new/linux/drivers/char/tpqic02.c Thu Mar 11 01:51:35 1999 @@ -75,7 +75,6 @@ #include -#include #include #include #include diff -ur --new-file old/linux/drivers/char/tty_io.c new/linux/drivers/char/tty_io.c --- old/linux/drivers/char/tty_io.c Sat Jan 16 02:46:27 1999 +++ new/linux/drivers/char/tty_io.c Mon Mar 22 19:06:21 1999 @@ -1143,7 +1143,7 @@ /* * We've decremented tty->count, so we should zero out * filp->private_data, to break the link between the tty and - * the file descriptor. Otherwise if close_fp() blocks before + * the file descriptor. Otherwise if filp_close() blocks before * the the file descriptor is removed from the inuse_filp * list, check_tty_count() could observe a discrepancy and * printk a warning message to the user. diff -ur --new-file old/linux/drivers/char/vc_screen.c new/linux/drivers/char/vc_screen.c --- old/linux/drivers/char/vc_screen.c Mon Aug 24 22:02:44 1998 +++ new/linux/drivers/char/vc_screen.c Thu Feb 25 19:02:12 1999 @@ -89,6 +89,7 @@ long p = *ppos; long viewed, attr, size, read; char *buf0; + int col, maxcol; unsigned short *org = NULL; attr = (currcons & 128); @@ -111,10 +112,19 @@ count = size - p; buf0 = buf; + maxcol = video_num_columns; if (!attr) { org = screen_pos(currcons, p, viewed); - while (count-- > 0) + col = p % maxcol; + p += maxcol - col; + while (count-- > 0) { put_user(vcs_scr_readw(currcons, org++) & 0xff, buf++); + if (++col == maxcol) { + org = screen_pos(currcons, p, viewed); + col = 0; + p += maxcol; + } + } } else { if (p < HEADER_SIZE) { char header[HEADER_SIZE]; @@ -124,20 +134,35 @@ while (p < HEADER_SIZE && count > 0) { count--; put_user(header[p++], buf++); } } + p -= HEADER_SIZE; + col = (p/2) % maxcol; if (count > 0) { - p -= HEADER_SIZE; - org = screen_pos(currcons, p/2, viewed); - if ((p & 1) && count > 0) + org = screen_pos(currcons, p/2, viewed); + if ((p & 1) && count > 0) { + count--; #ifdef __BIG_ENDIAN - { count--; put_user(vcs_scr_readw(currcons, org++) & 0xff, buf++); } + put_user(vcs_scr_readw(currcons, org++) & 0xff, buf++); #else - { count--; put_user(vcs_scr_readw(currcons, org++) >> 8, buf++); } + put_user(vcs_scr_readw(currcons, org++) >> 8, buf++); #endif + p++; + if (++col == maxcol) { + org = screen_pos(currcons, p/2, viewed); + col = 0; + } + } + p /= 2; + p += maxcol - col; } while (count > 1) { put_user(vcs_scr_readw(currcons, org++), (unsigned short *) buf); buf += 2; count -= 2; + if (++col == maxcol) { + org = screen_pos(currcons, p, viewed); + col = 0; + p += maxcol; + } } if (count > 0) #ifdef __BIG_ENDIAN @@ -159,6 +184,7 @@ long p = *ppos; long viewed, attr, size, written; const char *buf0; + int col, maxcol; u16 *org0 = NULL, *org = NULL; attr = (currcons & 128); @@ -181,14 +207,22 @@ count = size - p; buf0 = buf; + maxcol = video_num_columns; if (!attr) { org0 = org = screen_pos(currcons, p, viewed); + col = p % maxcol; + p += maxcol - col; while (count > 0) { unsigned char c; count--; get_user(c, (const unsigned char*)buf++); vcs_scr_writew(currcons, (vcs_scr_readw(currcons, org) & 0xff00) | c, org); org++; + if (++col == maxcol) { + org = screen_pos(currcons, p, viewed); + col = 0; + p += maxcol; + } } } else { if (p < HEADER_SIZE) { @@ -199,8 +233,9 @@ if (!viewed) putconsxy(currcons, header+2); } + p -= HEADER_SIZE; + col = (p/2) % maxcol; if (count > 0) { - p -= HEADER_SIZE; org0 = org = screen_pos(currcons, p/2, viewed); if ((p & 1) && count > 0) { char c; @@ -214,7 +249,14 @@ (vcs_scr_readw(currcons, org) & 0xff), org); #endif org++; + p++; + if (++col == maxcol) { + org = screen_pos(currcons, p/2, viewed); + col = 0; + } } + p /= 2; + p += maxcol - col; } while (count > 1) { unsigned short w; @@ -222,6 +264,11 @@ vcs_scr_writew(currcons, w, org++); buf += 2; count -= 2; + if (++col == maxcol) { + org = screen_pos(currcons, p, viewed); + col = 0; + p += maxcol; + } } if (count > 0) { unsigned char c; diff -ur --new-file old/linux/drivers/char/videodev.c new/linux/drivers/char/videodev.c --- old/linux/drivers/char/videodev.c Tue Jan 19 22:49:12 1999 +++ new/linux/drivers/char/videodev.c Thu Apr 15 14:42:40 1999 @@ -72,6 +72,12 @@ #ifdef CONFIG_RADIO_GEMTEK extern int gemtek_init(struct video_init *); #endif +#ifdef CONFIG_RADIO_TYPHOON +extern int typhoon_init(struct video_init *); +#endif +#ifdef CONFIG_RADIO_CADET +extern int cadet_init(struct video_init *); +#endif #ifdef CONFIG_VIDEO_PMS extern int init_pms_cards(struct video_init *); #endif @@ -101,16 +107,22 @@ #endif #ifdef CONFIG_RADIO_RTRACK {"RTrack", rtrack_init}, -#endif +#endif #ifdef CONFIG_RADIO_SF16FMI {"SF16FMI", fmi_init}, #endif #ifdef CONFIG_RADIO_MIROPCM20 {"PCM20", pcm20_init}, #endif +#ifdef CONFIG_RADIO_CADET + {"Cadet", cadet_init}, +#endif #ifdef CONFIG_RADIO_GEMTEK {"GemTek", gemtek_init}, #endif +#ifdef CONFIG_RADIO_TYPHOON + {"radio-typhoon", typhoon_init}, +#endif {"end", NULL} }; @@ -423,6 +435,12 @@ { unregister_chrdev(VIDEO_MAJOR, "video_capture"); } + + + + + + #endif diff -ur --new-file old/linux/drivers/char/vt.c new/linux/drivers/char/vt.c --- old/linux/drivers/char/vt.c Mon Jan 11 07:56:43 1999 +++ new/linux/drivers/char/vt.c Thu Feb 4 07:57:41 1999 @@ -165,7 +165,7 @@ val = K_HOLE; } else val = (i ? K_HOLE : K_NOSUCHMAP); - return __put_user(val, &user_kbe->kb_value); + return put_user(val, &user_kbe->kb_value); case KDSKBENT: if (!perm) return -EPERM; @@ -244,7 +244,7 @@ case KDGETKEYCODE: kc = getkeycode(tmp.scancode); if (kc >= 0) - kc = __put_user(kc, &user_kbkc->keycode); + kc = put_user(kc, &user_kbkc->keycode); break; case KDSETKEYCODE: if (!perm) @@ -282,8 +282,8 @@ p = func_table[i]; if(p) for ( ; *p && sz; p++, sz--) - __put_user(*p, q++); - __put_user('\0', q); + put_user(*p, q++); + put_user('\0', q); return ((p && *p) ? -EOVERFLOW : 0); case KDSKBSENT: if (!perm) @@ -603,12 +603,10 @@ { struct kbdiacrs *a = (struct kbdiacrs *)arg; - i = verify_area(VERIFY_WRITE, (void *) a, sizeof(struct kbdiacrs)); - if (i) - return i; - __put_user(accent_table_size, &a->kb_cnt); - __copy_to_user(a->kbdiacr, accent_table, - accent_table_size*sizeof(struct kbdiacr)); + if (put_user(accent_table_size, &a->kb_cnt)) + return -EFAULT; + if (copy_to_user(a->kbdiacr, accent_table, accent_table_size*sizeof(struct kbdiacr))) + return -EFAULT; return 0; } @@ -619,14 +617,13 @@ if (!perm) return -EPERM; - i = verify_area(VERIFY_READ, (void *) a, sizeof(struct kbdiacrs)); - if (i) - return i; - __get_user(ct,&a->kb_cnt); + if (get_user(ct,&a->kb_cnt)) + return -EFAULT; if (ct >= MAX_DIACR) return -EINVAL; accent_table_size = ct; - __copy_from_user(accent_table, a->kbdiacr, ct*sizeof(struct kbdiacr)); + if (copy_from_user(accent_table, a->kbdiacr, ct*sizeof(struct kbdiacr))) + return -EFAULT; return 0; } @@ -717,12 +714,12 @@ i = verify_area(VERIFY_WRITE,(void *)vtstat, sizeof(struct vt_stat)); if (i) return i; - __put_user(fg_console + 1, &vtstat->v_active); + put_user(fg_console + 1, &vtstat->v_active); state = 1; /* /dev/tty0 is always open */ for (i = 0, mask = 2; i < MAX_NR_CONSOLES && mask; ++i, mask <<= 1) if (VT_IS_IN_USE(i)) state |= mask; - return __put_user(state, &vtstat->v_state); + return put_user(state, &vtstat->v_state); } /* @@ -856,8 +853,8 @@ i = verify_area(VERIFY_READ, (void *)vtsizes, sizeof(struct vt_sizes)); if (i) return i; - __get_user(ll, &vtsizes->v_rows); - __get_user(cc, &vtsizes->v_cols); + get_user(ll, &vtsizes->v_rows); + get_user(cc, &vtsizes->v_cols); return vc_resize_all(ll, cc); } @@ -870,12 +867,12 @@ i = verify_area(VERIFY_READ, (void *)vtconsize, sizeof(struct vt_consize)); if (i) return i; - __get_user(ll, &vtconsize->v_rows); - __get_user(cc, &vtconsize->v_cols); - __get_user(vlin, &vtconsize->v_vlin); - __get_user(clin, &vtconsize->v_clin); - __get_user(vcol, &vtconsize->v_vcol); - __get_user(ccol, &vtconsize->v_ccol); + get_user(ll, &vtconsize->v_rows); + get_user(cc, &vtconsize->v_cols); + get_user(vlin, &vtconsize->v_vlin); + get_user(clin, &vtconsize->v_clin); + get_user(vcol, &vtconsize->v_vcol); + get_user(ccol, &vtconsize->v_ccol); vlin = vlin ? vlin : video_scan_lines; if ( clin ) { diff -ur --new-file old/linux/drivers/fc4/Config.in new/linux/drivers/fc4/Config.in --- old/linux/drivers/fc4/Config.in Thu Nov 26 02:21:48 1998 +++ new/linux/drivers/fc4/Config.in Tue Mar 16 01:11:29 1999 @@ -7,12 +7,21 @@ tristate 'Fibre Channel and FC4 SCSI support' CONFIG_FC4 if [ ! "$CONFIG_FC4" = "n" ]; then comment 'FC4 drivers' - tristate 'Sun SOC/Sbus' CONFIG_FC4_SOC + if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then + tristate 'Sun SOC/Sbus' CONFIG_FC4_SOC + tristate 'Sun SOC+ (aka SOCAL)' CONFIG_FC4_SOCAL + fi comment 'FC4 targets' dep_tristate 'SparcSTORAGE Array 100 and 200 series' CONFIG_SCSI_PLUTO $CONFIG_SCSI + if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then + dep_tristate 'Sun Enterprise Network Array (A5000 and EX500)' CONFIG_SCSI_FCAL $CONFIG_SCSI + else + dep_tristate 'Generic FC-AL disk driver' CONFIG_SCSI_FCAL $CONFIG_SCSI + fi else define_bool CONFIG_FC4_SOC n + define_bool CONFIG_FC4_SOCAL n define_bool CONFIG_SCSI_PLUTO n + define_bool CONFIG_SCSI_FCAL n fi endmenu - diff -ur --new-file old/linux/drivers/fc4/Makefile new/linux/drivers/fc4/Makefile --- old/linux/drivers/fc4/Makefile Tue Jan 13 00:19:36 1998 +++ new/linux/drivers/fc4/Makefile Tue Mar 16 01:11:29 1999 @@ -33,6 +33,14 @@ endif endif +ifeq ($(CONFIG_FC4_SOCAL),y) +L_OBJS += socal.o +else + ifeq ($(CONFIG_FC4_SOCAL),m) + M_OBJS += socal.o + endif +endif + include $(TOPDIR)/Rules.make fc4.o: $(MIX_OBJS) fc.o diff -ur --new-file old/linux/drivers/fc4/fc-al.h new/linux/drivers/fc4/fc-al.h --- old/linux/drivers/fc4/fc-al.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/fc4/fc-al.h Tue Mar 16 01:11:29 1999 @@ -0,0 +1,27 @@ +/* fc-al.h: Definitions for Fibre Channel Arbitrated Loop topology. + * + * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * + * Sources: + * Fibre Channel Arbitrated Loop (FC-AL), ANSI, Rev. 4.5, 1995 + */ + +#ifndef __FC_AL_H +#define __FC_AL_H + +/* Loop initialization payloads */ +#define FC_AL_LISM 0x11010000 /* Select Master, 12B payload */ +#define FC_AL_LIFA 0x11020000 /* Fabric Assign AL_PA bitmap, 20B payload */ +#define FC_AL_LIPA 0x11030000 /* Previously Acquired AL_PA bitmap, 20B payload */ +#define FC_AL_LIHA 0x11040000 /* Hard Assigned AL_PA bitmap, 20B payload */ +#define FC_AL_LISA 0x11050000 /* Soft Assigned AL_PA bitmap, 20B payload */ +#define FC_AL_LIRP 0x11060000 /* Report AL_PA position map, 132B payload */ +#define FC_AL_LILP 0x11070000 /* Loop AL_PA position map, 132B payload */ + +typedef struct { + u32 magic; + u8 len; + u8 alpa[127]; +} fc_al_posmap; + +#endif /* !(__FC_H) */ diff -ur --new-file old/linux/drivers/fc4/fc.c new/linux/drivers/fc4/fc.c --- old/linux/drivers/fc4/fc.c Wed Dec 16 22:39:11 1998 +++ new/linux/drivers/fc4/fc.c Tue Mar 16 01:11:29 1999 @@ -1,11 +1,24 @@ /* fc.c: Generic Fibre Channel and FC4 SCSI driver. * - * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * Copyright (C) 1997,1998,1999 Jakub Jelinek (jj@ultra.linux.cz) * Copyright (C) 1997,1998 Jirka Hanika (geo@ff.cuni.cz) * + * There are two kinds of Fibre Channel adapters used in Linux. Either + * the adapter is "smart" and does all FC bookkeeping by itself and + * just presents a standard SCSI interface to the operating system + * (that's e.g. the case with Qlogic FC cards), or leaves most of the FC + * bookkeeping to the OS (e.g. soc, socal). Drivers for the former adapters + * will look like normal SCSI drivers (with the exception of max_id will be + * usually 127), the latter on the other side allows SCSI, IP over FC and other + * protocols. This driver tree is for the latter adapters. + * + * This file should support both Point-to-Point and Arbitrated Loop topologies. + * * Sources: * Fibre Channel Physical & Signaling Interface (FC-PH), dpANS, 1994 * dpANS Fibre Channel Protocol for SCSI (X3.269-199X), Rev. 012, 1995 + * Fibre Channel Arbitrated Loop (FC-AL), Rev. 4.5, 1995 + * Fibre Channel Private Loop SCSI Direct Attach (FC-PLDA), Rev. 2.1, 1997 */ #include @@ -25,7 +38,7 @@ #include #include #include -#include "fcp_scsi.h" +#include "fcp_impl.h" #include "../scsi/hosts.h" /* #define FCDEBUG */ @@ -43,7 +56,7 @@ #ifdef __sparc__ static inline void *fc_dma_alloc(long size, char *name, dma_handle *dma) { - return (void *) sparc_dvma_malloc (size, "FCP SCSI cmd & rsp queues", dma); + return (void *) sparc_dvma_malloc (size, name, dma); } static inline dma_handle fc_sync_dma_entry(void *buf, int len, fc_channel *fc) @@ -73,6 +86,9 @@ #define FC_SCMND(SCpnt) ((fc_channel *)(SCpnt->host->hostdata[0])) #define SC_FCMND(fcmnd) ((Scsi_Cmnd *)((long)fcmnd - (long)&(((Scsi_Cmnd *)0)->SCp))) +static int fcp_scsi_queue_it(fc_channel *, Scsi_Cmnd *, fcp_cmnd *, int); +void fcp_queue_empty(fc_channel *); + static void fcp_scsi_insert_queue (fc_channel *fc, fcp_cmnd *fcmd) { if (!fc->scsi_que) { @@ -101,7 +117,7 @@ fc_channel *fc_channels = NULL; -#define LSMAGIC 0x2a3b4d2a +#define LSMAGIC 620829043 typedef struct { /* Must be first */ struct semaphore sem; @@ -111,10 +127,10 @@ fcp_cmnd *fcmds; atomic_t todo; struct timer_list timer; - int grace[1]; + unsigned char grace[0]; } ls; -#define LSOMAGIC 0x2a3c4e3c +#define LSOMAGIC 654907799 typedef struct { /* Must be first */ struct semaphore sem; @@ -125,6 +141,15 @@ struct timer_list timer; } lso; +#define LSEMAGIC 84482456 +typedef struct { + /* Must be first */ + struct semaphore sem; + int magic; + int status; + struct timer_list timer; +} lse; + static void fcp_login_timeout(unsigned long data) { ls *l = (ls *)data; @@ -225,6 +250,97 @@ } } +static void fcp_report_map_done(fc_channel *fc, int i, int status) +{ + fcp_cmnd *fcmd; + fc_hdr *fch; + unsigned char j; + ls *l = (ls *)fc->ls; + fc_al_posmap *p; + + FCD(("Report map done %d %d\n", i, status)) + switch (status) { + case FC_STATUS_OK: /* Ok, let's have a fun on a loop */ + fc_sync_dma_exit (l->fcmds[i].cmd, 3 * sizeof(logi), fc); + p = (fc_al_posmap *)(l->logi + 3 * i); +#ifdef FCDEBUG + { + u32 *u = (u32 *)p; + FCD(("%08x\n", u[0])) + u ++; + FCD(("%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x\n", u[0],u[1],u[2],u[3],u[4],u[5],u[6],u[7])) + } +#endif + if ((p->magic & 0xffff0000) != FC_AL_LILP || !p->len) { + printk ("FC: Bad magic from REPORT_AL_MAP on %s - %08x\n", fc->name, p->magic); + fc->state = FC_STATE_OFFLINE; + } else { + fc->posmap = (fcp_posmap *)kmalloc(sizeof(fcp_posmap)+p->len, GFP_KERNEL); + if (!fc->posmap) { + printk("FC: Not enough memory, offlining channel\n"); + fc->state = FC_STATE_OFFLINE; + } else { + int k; + memset(fc->posmap, 0, sizeof(fcp_posmap)+p->len); + /* FIXME: This is where SOCAL transfers our AL-PA. + Keep it here till we found out what other cards do... */ + fc->sid = (p->magic & 0xff); + for (i = 0; i < p->len; i++) + if (p->alpa[i] == fc->sid) + break; + k = p->len; + if (i == p->len) + i = 0; + else { + p->len--; + i++; + } + fc->posmap->len = p->len; + for (j = 0; j < p->len; j++) { + if (i == k) i = 0; + fc->posmap->list[j] = p->alpa[i++]; + } + fc->state = FC_STATE_ONLINE; + } + } + printk ("%s: ONLINE\n", fc->name); + if (atomic_dec_and_test (&l->todo)) + up(&l->sem); + break; + case FC_STATUS_POINTTOPOINT: /* We're Point-to-Point, no AL... */ + FCD(("SID %d DID %d\n", fc->sid, fc->did)) + fcmd = l->fcmds + i; + fc_sync_dma_exit(fcmd->cmd, 3 * sizeof(logi), fc); + fch = &fcmd->fch; + memset(l->logi + 3 * i, 0, 3 * sizeof(logi)); + FILL_FCHDR_RCTL_DID(fch, R_CTL_ELS_REQ, FS_FABRIC_F_PORT); + FILL_FCHDR_SID(fch, 0); + FILL_FCHDR_TYPE_FCTL(fch, TYPE_EXTENDED_LS, F_CTL_FIRST_SEQ | F_CTL_SEQ_INITIATIVE); + FILL_FCHDR_SEQ_DF_SEQ(fch, 0, 0, 0); + FILL_FCHDR_OXRX(fch, 0xffff, 0xffff); + fch->param = 0; + l->logi [3 * i].code = LS_FLOGI; + fcmd->cmd = fc_sync_dma_entry (l->logi + 3 * i, 3 * sizeof(logi), fc); + fcmd->rsp = fcmd->cmd + sizeof(logi); + fcmd->cmdlen = sizeof(logi); + fcmd->rsplen = sizeof(logi); + fcmd->data = (dma_handle)NULL; + fcmd->class = FC_CLASS_SIMPLE; + fcmd->proto = TYPE_EXTENDED_LS; + if (fc->hw_enque (fc, fcmd)) + printk ("FC: Cannot enque FLOGI packet on %s\n", fc->name); + break; + case FC_STATUS_ERR_OFFLINE: + fc->state = FC_STATE_MAYBEOFFLINE; + FCD (("FC is offline %d\n", l->grace[i])) + break; + default: + printk ("FLOGI failed for %s with status %d\n", fc->name, status); + /* Do some sort of error recovery here */ + break; + } +} + void fcp_register(fc_channel *fc, u8 type, int unregister) { int size, i; @@ -247,12 +363,13 @@ for (i = fc->can_queue; i < fc->scsi_bitmap_end; i++) set_bit (i, fc->scsi_bitmap); fc->scsi_free = fc->can_queue; - fc->token_tab = (fcp_cmnd **)kmalloc(slots * sizeof(fcp_cmnd*), GFP_KERNEL); + fc->cmd_slots = (fcp_cmnd **)kmalloc(slots * sizeof(fcp_cmnd*), GFP_KERNEL); + memset(fc->cmd_slots, 0, slots * sizeof(fcp_cmnd*)); fc->abort_count = 0; } else { fc->scsi_name[0] = 0; kfree (fc->scsi_bitmap); - kfree (fc->token_tab); + kfree (fc->cmd_slots); FCND(("Unregistering\n")); if (fc->rst_pkt) { if (fc->rst_pkt->eh_state == SCSI_STATE_UNUSED) @@ -279,7 +396,7 @@ int sense_len; int rsp_status; - fcmd = fc->token_tab[token]; + fcmd = fc->cmd_slots[token]; if (!fcmd) return; rsp = (fcp_rsp *) (fc->scsi_rsp_pool + fc->rsp_size * token); SCpnt = SC_FCMND(fcmd); @@ -343,27 +460,47 @@ fcmd->done=NULL; clear_bit(token, fc->scsi_bitmap); fc->scsi_free++; - FCD(("Calling scsi_done with %08lx\n", SCpnt->result)) + FCD(("Calling scsi_done with %08x\n", SCpnt->result)) SCpnt->scsi_done(SCpnt); } void fcp_receive_solicited(fc_channel *fc, int proto, int token, int status, fc_hdr *fch) { + int magic; FCD(("receive_solicited %d %d %d\n", proto, token, status)) switch (proto) { case TYPE_SCSI_FCP: fcp_scsi_receive(fc, token, status, fch); break; case TYPE_EXTENDED_LS: - if (fc->ls && ((ls *)(fc->ls))->magic == LSMAGIC) { + case PROTO_REPORT_AL_MAP: + magic = 0; + if (fc->ls) + magic = ((ls *)(fc->ls))->magic; + if (magic == LSMAGIC) { ls *l = (ls *)fc->ls; int i = (token >= l->count) ? token - l->count : token; /* Let's be sure */ if ((unsigned)i < l->count && l->fcmds[i].fc == fc) { - fcp_login_done(fc, token, status); + if (proto == TYPE_EXTENDED_LS) + fcp_login_done(fc, token, status); + else + fcp_report_map_done(fc, token, status); break; } } + FCD(("fc %p fc->ls %p fc->cmd_slots %p\n", fc, fc->ls, fc->cmd_slots)) + if (proto == TYPE_EXTENDED_LS && !fc->ls && fc->cmd_slots) { + fcp_cmnd *fcmd; + + fcmd = fc->cmd_slots[token]; + if (fcmd && fcmd->ls && ((ls *)(fcmd->ls))->magic == LSEMAGIC) { + lse *l = (lse *)fcmd->ls; + + l->status = status; + up (&l->sem); + } + } break; case PROTO_OFFLINE: if (fc->ls && ((lso *)(fc->ls))->magic == LSOMAGIC) { @@ -405,12 +542,12 @@ FCND(("fcp_inititialize %08lx\n", (long)fcp_init)) FCND(("fc_channels %08lx\n", (long)fc_channels)) FCND((" SID %d DID %d\n", fcchain->sid, fcchain->did)) - l = kmalloc(sizeof (ls) + count * sizeof(int), GFP_KERNEL); + l = kmalloc(sizeof (ls) + count, GFP_KERNEL); if (!l) { printk ("FC: Cannot allocate memory for initialization\n"); return -ENOMEM; } - memset (l, 0, sizeof(ls) + count * sizeof(int)); + memset (l, 0, sizeof(ls) + count); l->magic = LSMAGIC; l->count = count; FCND(("FCP Init for %d channels\n", count)) @@ -429,36 +566,25 @@ } memset (l->logi, 0, count * 3 * sizeof(logi)); memset (l->fcmds, 0, count * sizeof(fcp_cmnd)); - FCND(("Initializing FLOGI packets\n")) for (fc = fcchain, i = 0; fc && i < count; fc = fc->next, i++) { - fc_hdr *fch; - - FCD(("SID %d DID %d\n", fc->sid, fc->did)) fc->state = FC_STATE_UNINITED; + fc->rst_pkt = NULL; /* kmalloc when first used */ + } + /* First try if we are in a AL topology */ + FCND(("Initializing REPORT_MAP packets\n")) + for (fc = fcchain, i = 0; fc && i < count; fc = fc->next, i++) { fcmd = l->fcmds + i; fc->login = fcmd; fc->ls = (void *)l; - fc->rst_pkt = NULL; /* kmalloc when first used */ - fch = &fcmd->fch; - FILL_FCHDR_RCTL_DID(fch, R_CTL_ELS_REQ, FS_FABRIC_F_PORT); - FILL_FCHDR_SID(fch, 0); - FILL_FCHDR_TYPE_FCTL(fch, TYPE_EXTENDED_LS, F_CTL_FIRST_SEQ | F_CTL_SEQ_INITIATIVE); - FILL_FCHDR_SEQ_DF_SEQ(fch, 0, 0, 0); - FILL_FCHDR_OXRX(fch, 0xffff, 0xffff); - fch->param = 0; - l->logi [3 * i].code = LS_FLOGI; + /* Assumes sizeof(fc_al_posmap) < 3 * sizeof(logi), which is true */ fcmd->cmd = fc_sync_dma_entry (l->logi + 3 * i, 3 * sizeof(logi), fc); - fcmd->rsp = fcmd->cmd + sizeof(logi); - fcmd->cmdlen = sizeof(logi); - fcmd->rsplen = sizeof(logi); - fcmd->data = (dma_handle)NULL; - fcmd->class = FC_CLASS_SIMPLE; - fcmd->proto = TYPE_EXTENDED_LS; + fcmd->proto = PROTO_REPORT_AL_MAP; fcmd->token = i; fcmd->fc = fc; } for (retry = 0; retry < 8; retry++) { - FCND(("Sending FLOGI/PLOGI packets\n")) + int nqueued = 0; + FCND(("Sending REPORT_MAP/FLOGI/PLOGI packets\n")) for (fc = fcchain, i = 0; fc && i < count; fc = fc->next, i++) { if (fc->state == FC_STATE_ONLINE || fc->state == FC_STATE_OFFLINE) continue; @@ -477,27 +603,56 @@ } ret = fc->hw_enque (fc, fc->login); enable_irq(fc->irq); - if (ret) printk ("FC: Cannot enque FLOGI packet on %s\n", fc->name); + if (!ret) { + nqueued++; + continue; + } + if (ret == -ENOSYS && fc->login->proto == PROTO_REPORT_AL_MAP) { + /* Oh yes, this card handles Point-to-Point only, so let's try that. */ + fc_hdr *fch; + + FCD(("SID %d DID %d\n", fc->sid, fc->did)) + fcmd = l->fcmds + i; + fc_sync_dma_exit(fcmd->cmd, 3 * sizeof(logi), fc); + fch = &fcmd->fch; + FILL_FCHDR_RCTL_DID(fch, R_CTL_ELS_REQ, FS_FABRIC_F_PORT); + FILL_FCHDR_SID(fch, 0); + FILL_FCHDR_TYPE_FCTL(fch, TYPE_EXTENDED_LS, F_CTL_FIRST_SEQ | F_CTL_SEQ_INITIATIVE); + FILL_FCHDR_SEQ_DF_SEQ(fch, 0, 0, 0); + FILL_FCHDR_OXRX(fch, 0xffff, 0xffff); + fch->param = 0; + l->logi [3 * i].code = LS_FLOGI; + fcmd->cmd = fc_sync_dma_entry (l->logi + 3 * i, 3 * sizeof(logi), fc); + fcmd->rsp = fcmd->cmd + sizeof(logi); + fcmd->cmdlen = sizeof(logi); + fcmd->rsplen = sizeof(logi); + fcmd->data = (dma_handle)NULL; + fcmd->class = FC_CLASS_SIMPLE; + fcmd->proto = TYPE_EXTENDED_LS; + } else + printk ("FC: Cannot enque FLOGI/REPORT_MAP packet on %s\n", fc->name); } - l->timer.expires = jiffies + 5 * HZ; - add_timer(&l->timer); - - down(&l->sem); - if (!atomic_read(&l->todo)) { - FCND(("All channels answered in time\n")) - break; /* All fc channels have answered us */ + if (nqueued) { + l->timer.expires = jiffies + 5 * HZ; + add_timer(&l->timer); + + down(&l->sem); + if (!atomic_read(&l->todo)) { + FCND(("All channels answered in time\n")) + break; /* All fc channels have answered us */ + } } } all_done: - for (fc = fcchain, i = 0; fc && i < count; fc = fc->next, i += 3) { + for (fc = fcchain, i = 0; fc && i < count; fc = fc->next, i++) { + fc->ls = NULL; switch (fc->state) { case FC_STATE_ONLINE: break; case FC_STATE_OFFLINE: break; default: fc_sync_dma_exit (l->fcmds[i].cmd, 3 * sizeof(logi), fc); break; } - fc->ls = NULL; } del_timer(&l->timer); kfree (l->logi); @@ -534,6 +689,7 @@ fcmd = l.fcmds + i; fc->login = fcmd; fc->ls = (void *)&l; + fcmd->did = fc->did; fcmd->class = FC_CLASS_OFFLINE; fcmd->proto = PROTO_OFFLINE; fcmd->token = i; @@ -549,6 +705,8 @@ down(&l.sem); del_timer(&l.timer); + for (fc = fcchain, i = 0; fc && i < count; fc = fc->next, i++) + fc->ls = NULL; kfree (l.fcmds); return 0; } @@ -565,14 +723,14 @@ } ret = fcp_initialize (fcchain, count); - - if (!ret) { - if (!fc_channels) - fc_channels = fcchain; - else { - for (fc = fc_channels; fc->next; fc = fc->next); - fc->next = fcchain; - } + if (ret) + return ret; + + if (!fc_channels) + fc_channels = fcchain; + else { + for (fc = fc_channels; fc->next; fc = fc->next); + fc->next = fcchain; } return ret; } @@ -622,7 +780,7 @@ fcmd->token = i; cmd = fc->scsi_cmd_pool + i; - if (fc->encode_addr (SCpnt, cmd->fcp_addr)) { + if (fc->encode_addr (SCpnt, cmd->fcp_addr, fc, fcmd)) { /* Invalid channel/id/lun and couldn't map it into fcp_addr */ clear_bit (i, fc->scsi_bitmap); SCpnt->result = (DID_BAD_TARGET << 16); @@ -630,7 +788,7 @@ return 0; } fc->scsi_free--; - fc->token_tab[fcmd->token] = fcmd; + fc->cmd_slots[fcmd->token] = fcmd; if (SCpnt->device->tagged_supported) { if (jiffies - fc->ages[SCpnt->channel * fc->targets + SCpnt->target] > (5 * 60 * HZ)) { @@ -670,14 +828,14 @@ memset (cmd->fcp_cdb+SCpnt->cmd_len, 0, sizeof(cmd->fcp_cdb)-SCpnt->cmd_len); FCD(("XXX: %04x.%04x.%04x.%04x - %08x%08x%08x\n", cmd->fcp_addr[0], cmd->fcp_addr[1], cmd->fcp_addr[2], cmd->fcp_addr[3], *(u32 *)SCpnt->cmnd, *(u32 *)(SCpnt->cmnd+4), *(u32 *)(SCpnt->cmnd+8))) } - FCD(("Trying to enque %08x\n", (int)fcmd)) + FCD(("Trying to enque %p\n", fcmd)) if (!fc->scsi_que) { if (!fc->hw_enque (fc, fcmd)) { - FCD(("hw_enque succeeded for %08x\n", (int)fcmd)) + FCD(("hw_enque succeeded for %p\n", fcmd)) return 0; } } - FCD(("Putting into que1 %08x\n", (int)fcmd)) + FCD(("Putting into que1 %p\n", fcmd)) fcp_scsi_insert_queue (fc, fcmd); return 0; } @@ -687,7 +845,7 @@ fcp_cmnd *fcmd = FCP_CMND(SCpnt); fc_channel *fc = FC_SCMND(SCpnt); - FCD(("Entering SCSI queuecommand %08x\n", (int)fcmd)) + FCD(("Entering SCSI queuecommand %p\n", fcmd)) if (SCpnt->done != fcp_scsi_done) { fcmd->done = SCpnt->done; SCpnt->done = fcp_scsi_done; @@ -708,11 +866,12 @@ void fcp_queue_empty(fc_channel *fc) { fcp_cmnd *fcmd; + FCD(("Queue empty\n")) while ((fcmd = fc->scsi_que)) { /* The hw told us we can try again queue some packet */ if (fc->hw_enque (fc, fcmd)) - return; + break; fcp_scsi_remove_queue (fc, fcmd); } } @@ -725,7 +884,7 @@ int fcp_scsi_abort(Scsi_Cmnd *SCpnt) { - /* Internal bookkeeping only. Lose 1 token_tab slot. */ + /* Internal bookkeeping only. Lose 1 cmd_slots slot. */ fcp_cmnd *fcmd = FCP_CMND(SCpnt); fc_channel *fc = FC_SCMND(SCpnt); @@ -733,14 +892,14 @@ * We react to abort requests by simply forgetting * about the command and pretending everything's sweet. * This may or may not be silly. We can't, however, - * immediately reuse the command's token_tab slot, + * immediately reuse the command's cmd_slots slot, * as its result may arrive later and we cannot * check whether it is the aborted one, can't we? * * Therefore, after the first few aborts are done, * we tell the scsi error handler to do something clever. * It will eventually call host reset, refreshing - * token_tab for us. + * cmd_slots for us. * * There is a theoretical chance that we sometimes allow * more than can_queue packets to the jungle this way, @@ -786,13 +945,13 @@ fcmd->token = 0; cmd = fc->scsi_cmd_pool + 0; FCD(("Preparing rst packet\n")) - if (fc->encode_addr (SCpnt, /*?*/cmd->fcp_addr)) + fc->encode_addr (SCpnt, cmd->fcp_addr, fc, fcmd); fc->rst_pkt->channel = SCpnt->channel; fc->rst_pkt->target = SCpnt->target; fc->rst_pkt->lun = 0; fc->rst_pkt->cmd_len = 0; - fc->token_tab[0] = fcmd; + fc->cmd_slots[0] = fcmd; cmd->fcp_cntl = FCP_CNTL_QTYPE_ORDERED | FCP_CNTL_RESET; fcmd->data = (dma_handle)NULL; @@ -859,16 +1018,137 @@ printk ("FC: host reset\n"); for (i=0; i < fc->can_queue; i++) { - if (fc->token_tab[i] && SCpnt->result != DID_ABORT) { + if (fc->cmd_slots[i] && SCpnt->result != DID_ABORT) { SCpnt->result = DID_RESET; fcmd->done(SCpnt); - fc->token_tab[i] = NULL; + fc->cmd_slots[i] = NULL; } } fc->reset(fc); fc->abort_count = 0; if (fcp_initialize(fc, 1)) return SUCCESS; else return FAILED; +} + +static int fcp_els_queue_it(fc_channel *fc, fcp_cmnd *fcmd) +{ + long i; + + i = find_first_zero_bit (fc->scsi_bitmap, fc->scsi_bitmap_end); + set_bit (i, fc->scsi_bitmap); + fcmd->token = i; + fc->scsi_free--; + fc->cmd_slots[fcmd->token] = fcmd; + return fcp_scsi_queue_it(fc, NULL, fcmd, 0); +} + +static int fc_do_els(fc_channel *fc, unsigned int alpa, void *data, int len) +{ + fcp_cmnd _fcmd, *fcmd; + fc_hdr *fch; + lse l; + int i; + + fcmd = &_fcmd; + memset(fcmd, 0, sizeof(fcmd)); + FCD(("PLOGI SID %d DID %d\n", fc->sid, alpa)) + fch = &fcmd->fch; + FILL_FCHDR_RCTL_DID(fch, R_CTL_ELS_REQ, alpa); + FILL_FCHDR_SID(fch, fc->sid); + FILL_FCHDR_TYPE_FCTL(fch, TYPE_EXTENDED_LS, F_CTL_FIRST_SEQ | F_CTL_SEQ_INITIATIVE); + FILL_FCHDR_SEQ_DF_SEQ(fch, 0, 0, 0); + FILL_FCHDR_OXRX(fch, 0xffff, 0xffff); + fch->param = 0; + fcmd->cmd = fc_sync_dma_entry (data, 2 * len, fc); + fcmd->rsp = fcmd->cmd + len; + fcmd->cmdlen = len; + fcmd->rsplen = len; + fcmd->data = (dma_handle)NULL; + fcmd->fc = fc; + fcmd->class = FC_CLASS_SIMPLE; + fcmd->proto = TYPE_EXTENDED_LS; + + memset (&l, 0, sizeof(lse)); + l.magic = LSEMAGIC; + l.sem = MUTEX_LOCKED; + l.timer.function = fcp_login_timeout; + l.timer.data = (unsigned long)&l; + l.status = FC_STATUS_TIMED_OUT; + fcmd->ls = (void *)&l; + + disable_irq(fc->irq); + fcp_els_queue_it(fc, fcmd); + enable_irq(fc->irq); + + for (i = 0;;) { + l.timer.expires = jiffies + 5 * HZ; + add_timer(&l.timer); + down(&l.sem); + del_timer(&l.timer); + if (l.status != FC_STATUS_TIMED_OUT) break; + if (++i == 3) break; + disable_irq(fc->irq); + fcp_scsi_queue_it(fc, NULL, fcmd, 0); + enable_irq(fc->irq); + } + + clear_bit(fcmd->token, fc->scsi_bitmap); + fc->scsi_free++; + fc_sync_dma_exit (fcmd->cmd, 2 * len, fc); + return l.status; +} + +int fc_do_plogi(fc_channel *fc, unsigned char alpa, fc_wwn *node, fc_wwn *nport) +{ + logi *l; + int status; + + l = (logi *)kmalloc(2 * sizeof(logi), GFP_DMA); + if (!l) return -ENOMEM; + memset(l, 0, 2 * sizeof(logi)); + l->code = LS_PLOGI; + memcpy (&l->nport_wwn, &fc->wwn_nport, sizeof(fc_wwn)); + memcpy (&l->node_wwn, &fc->wwn_node, sizeof(fc_wwn)); + memcpy (&l->common, fc->common_svc, sizeof(common_svc_parm)); + memcpy (&l->class1, fc->class_svcs, 3*sizeof(svc_parm)); + status = fc_do_els(fc, alpa, l, sizeof(logi)); + if (status == FC_STATUS_OK) { + if (l[1].code == LS_ACC) { +#ifdef FCDEBUG + u32 *u = (u32 *)&l[1].nport_wwn; + FCD(("AL-PA %02x: Port WWN %08x%08x Node WWN %08x%08x\n", alpa, + u[0], u[1], u[2], u[3])) +#endif + memcpy(nport, &l[1].nport_wwn, sizeof(fc_wwn)); + memcpy(node, &l[1].node_wwn, sizeof(fc_wwn)); + } else + status = FC_STATUS_BAD_RSP; + } + kfree(l); + return status; +} + +typedef struct { + unsigned int code; + unsigned params[4]; +} prli; + +int fc_do_prli(fc_channel *fc, unsigned char alpa) +{ + prli *p; + int status; + + p = (prli *)kmalloc(2 * sizeof(prli), GFP_DMA); + if (!p) return -ENOMEM; + memset(p, 0, 2 * sizeof(prli)); + p->code = LS_PRLI; + p->params[0] = 0x08002000; + p->params[3] = 0x00000022; + status = fc_do_els(fc, alpa, p, sizeof(prli)); + if (status == FC_STATUS_OK && p[1].code != LS_PRLI_ACC && p[1].code != LS_ACC) + status = FC_STATUS_BAD_RSP; + kfree(p); + return status; } #ifdef MODULE diff -ur --new-file old/linux/drivers/fc4/fc.h new/linux/drivers/fc4/fc.h --- old/linux/drivers/fc4/fc.h Tue Jan 13 00:19:36 1998 +++ new/linux/drivers/fc4/fc.h Tue Mar 16 01:11:29 1999 @@ -1,6 +1,6 @@ /* fc.h: Definitions for Fibre Channel Physical and Signaling Interface. * - * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * Copyright (C) 1996-1997,1999 Jakub Jelinek (jj@ultra.linux.cz) * * Sources: * Fibre Channel Physical & Signaling Interface (FC-PH), dpANS, 1994 @@ -11,13 +11,16 @@ #define __FC_H /* World Wide Name */ -#define NAAID_IEEE 1 -#define NAAID_IEEE_EXT 2 -#define NAAID_LOCAL 3 -#define NAAID_IP 4 -#define NAAID_CCITT 12 -#define NAAID_CCITT_GRP 14 +#define NAAID_IEEE 1 +#define NAAID_IEEE_EXT 2 +#define NAAID_LOCAL 3 +#define NAAID_IP 4 +#define NAAID_IEEE_REG 5 +#define NAAID_IEEE_REG_EXT 6 +#define NAAID_CCITT 12 +#define NAAID_CCITT_GRP 14 +/* This is NAAID_IEEE_EXT scheme */ typedef struct { u32 naaid:4; u32 nportid:12; @@ -165,6 +168,7 @@ /* Extended SVC commands */ #define LS_RJT 0x01000000 #define LS_ACC 0x02000000 +#define LS_PRLI_ACC 0x02100014 #define LS_PLOGI 0x03000000 #define LS_FLOGI 0x04000000 #define LS_LOGO 0x05000000 @@ -182,7 +186,11 @@ #define LS_TEST 0x11000000 #define LS_RRQ 0x12000000 #define LS_IDENT 0x20000000 +#define LS_PRLI 0x20100014 #define LS_DISPLAY 0x21000000 +#define LS_PRLO 0x21100014 +#define LS_PDISC 0x50000000 +#define LS_ADISC 0x52000000 typedef struct { u8 fcph_hi, fcph_lo; diff -ur --new-file old/linux/drivers/fc4/fc_syms.c new/linux/drivers/fc4/fc_syms.c --- old/linux/drivers/fc4/fc_syms.c Wed Apr 15 02:44:21 1998 +++ new/linux/drivers/fc4/fc_syms.c Tue Mar 16 01:11:29 1999 @@ -13,7 +13,7 @@ #include #include -#include "fcp_scsi.h" +#include "fcp_impl.h" EXPORT_SYMBOL(fcp_init); EXPORT_SYMBOL(fcp_release); @@ -21,6 +21,8 @@ EXPORT_SYMBOL(fcp_receive_solicited); EXPORT_SYMBOL(fc_channels); EXPORT_SYMBOL(fcp_state_change); +EXPORT_SYMBOL(fc_do_plogi); +EXPORT_SYMBOL(fc_do_prli); /* SCSI stuff */ EXPORT_SYMBOL(fcp_scsi_queuecommand); diff -ur --new-file old/linux/drivers/fc4/fcp_impl.h new/linux/drivers/fc4/fcp_impl.h --- old/linux/drivers/fc4/fcp_impl.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/fc4/fcp_impl.h Tue Mar 16 01:11:29 1999 @@ -0,0 +1,168 @@ +/* fcp_impl.h: Generic SCSI on top of FC4 - our interface defines. + * + * Copyright (C) 1997-1999 Jakub Jelinek (jj@ultra.linux.cz) + * Copyright (C) 1998 Jirka Hanika (geo@ff.cuni.cz) + */ + +#ifndef _FCP_SCSI_H +#define _FCP_SCSI_H + +#include +#include +#include "../scsi/scsi.h" + +#include "fc.h" +#include "fcp.h" +#include "fc-al.h" + +#ifdef __sparc__ + +#include +typedef u32 dma_handle; + +#else +#error Need to port FC layer to your architecture +#endif + +/* 0 or 1 */ +#define FCP_SCSI_USE_NEW_EH_CODE 0 + +#define FC_CLASS_OUTBOUND 0x01 +#define FC_CLASS_INBOUND 0x02 +#define FC_CLASS_SIMPLE 0x03 +#define FC_CLASS_IO_WRITE 0x04 +#define FC_CLASS_IO_READ 0x05 +#define FC_CLASS_UNSOLICITED 0x06 +#define FC_CLASS_OFFLINE 0x08 + +#define PROTO_OFFLINE 0x02 +#define PROTO_REPORT_AL_MAP 0x03 +#define PROTO_FORCE_LIP 0x06 + +struct _fc_channel; + +typedef struct fcp_cmnd { + struct fcp_cmnd *next; + struct fcp_cmnd *prev; + void (*done)(Scsi_Cmnd *); + unsigned short proto; + unsigned short token; + unsigned int did; + /* FCP SCSI stuff */ + dma_handle data; + /* From now on this cannot be touched for proto == TYPE_SCSI_FCP */ + fc_hdr fch; + dma_handle cmd; + dma_handle rsp; + int cmdlen; + int rsplen; + int class; + int datalen; + /* This is just used as a verification during login */ + struct _fc_channel *fc; + void *ls; +} fcp_cmnd; + +typedef struct { + unsigned int len; + unsigned char list[0]; +} fcp_posmap; + +typedef struct _fc_channel { + struct _fc_channel *next; + int irq; + int state; + int sid; + int did; + char name[16]; + void (*fcp_register)(struct _fc_channel *, u8, int); + void (*reset)(struct _fc_channel *); + int (*hw_enque)(struct _fc_channel *, fcp_cmnd *); + fc_wwn wwn_node; + fc_wwn wwn_nport; + fc_wwn wwn_dest; + common_svc_parm *common_svc; + svc_parm *class_svcs; +#ifdef __sparc__ + struct linux_sbus_device *dev; +#endif + struct module *module; + /* FCP SCSI stuff */ + short can_queue; + short abort_count; + int rsp_size; + fcp_cmd *scsi_cmd_pool; + char *scsi_rsp_pool; + dma_handle dma_scsi_cmd, dma_scsi_rsp; + long *scsi_bitmap; + long scsi_bitmap_end; + int scsi_free; + int (*encode_addr)(Scsi_Cmnd *, u16 *, struct _fc_channel *, fcp_cmnd *); + fcp_cmnd *scsi_que; + char scsi_name[4]; + fcp_cmnd **cmd_slots; + int channels; + int targets; + long *ages; + Scsi_Cmnd *rst_pkt; + fcp_posmap *posmap; + /* LOGIN stuff */ + fcp_cmnd *login; + void *ls; +} fc_channel; + +extern fc_channel *fc_channels; + +#define FC_STATE_UNINITED 0 +#define FC_STATE_ONLINE 1 +#define FC_STATE_OFFLINE 2 +#define FC_STATE_RESETING 3 +#define FC_STATE_FPORT_OK 4 +#define FC_STATE_MAYBEOFFLINE 5 + +#define FC_STATUS_OK 0 +#define FC_STATUS_P_RJT 2 +#define FC_STATUS_F_RJT 3 +#define FC_STATUS_P_BSY 4 +#define FC_STATUS_F_BSY 5 +#define FC_STATUS_ERR_OFFLINE 0x11 +#define FC_STATUS_TIMEOUT 0x12 +#define FC_STATUS_ERR_OVERRUN 0x13 +#define FC_STATUS_POINTTOPOINT 0x15 +#define FC_STATUS_AL 0x16 +#define FC_STATUS_UNKNOWN_CQ_TYPE 0x20 +#define FC_STATUS_BAD_SEG_CNT 0x21 +#define FC_STATUS_MAX_XCHG_EXCEEDED 0x22 +#define FC_STATUS_BAD_XID 0x23 +#define FC_STATUS_XCHG_BUSY 0x24 +#define FC_STATUS_BAD_POOL_ID 0x25 +#define FC_STATUS_INSUFFICIENT_CQES 0x26 +#define FC_STATUS_ALLOC_FAIL 0x27 +#define FC_STATUS_BAD_SID 0x28 +#define FC_STATUS_NO_SEQ_INIT 0x29 +#define FC_STATUS_TIMED_OUT -1 +#define FC_STATUS_BAD_RSP -2 + +void fcp_queue_empty(fc_channel *); +int fcp_init(fc_channel *); +void fcp_release(fc_channel *fc_chain, int count); +void fcp_receive_solicited(fc_channel *, int, int, int, fc_hdr *); +void fcp_state_change(fc_channel *, int); +int fc_do_plogi(fc_channel *, unsigned char, fc_wwn *, fc_wwn *); +int fc_do_prli(fc_channel *, unsigned char); + +#define for_each_fc_channel(fc) \ + for (fc = fc_channels; fc; fc = fc->next) + +#define for_each_online_fc_channel(fc) \ + for_each_fc_channel(fc) \ + if (fc->state == FC_STATE_ONLINE) + +int fcp_scsi_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *)); +int fcp_old_abort(Scsi_Cmnd *); +int fcp_scsi_abort(Scsi_Cmnd *); +int fcp_scsi_dev_reset(Scsi_Cmnd *); +int fcp_scsi_bus_reset(Scsi_Cmnd *); +int fcp_scsi_host_reset(Scsi_Cmnd *); + +#endif /* !(_FCP_SCSI_H) */ diff -ur --new-file old/linux/drivers/fc4/fcp_scsi.h new/linux/drivers/fc4/fcp_scsi.h --- old/linux/drivers/fc4/fcp_scsi.h Wed Dec 16 22:39:11 1998 +++ new/linux/drivers/fc4/fcp_scsi.h Thu Jan 1 01:00:00 1970 @@ -1,151 +0,0 @@ -/* fcp_scsi.h: Generic SCSI on top of FC4 - interface defines. - * - * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) - * Copyright (C) 1998 Jirka Hanika (geo@ff.cuni.cz) - */ - -#ifndef _FCP_SCSI_H -#define _FCP_SCSI_H - -#include -#include -#include "../scsi/scsi.h" - -#include "fc.h" -#include "fcp.h" - -#ifdef __sparc__ - -#include -typedef u32 dma_handle; - -#else -#error Need to port FC layer to your architecture -#endif - -/* 0 or 1 */ -#define FCP_SCSI_USE_NEW_EH_CODE 0 - -#define FC_CLASS_OUTBOUND 0x01 -#define FC_CLASS_INBOUND 0x02 -#define FC_CLASS_SIMPLE 0x03 -#define FC_CLASS_IO_WRITE 0x04 -#define FC_CLASS_IO_READ 0x05 -#define FC_CLASS_UNSOLICITED 0x06 -#define FC_CLASS_OFFLINE 0x08 - -#define PROTO_OFFLINE 0x02 - -struct _fc_channel; - -typedef struct fcp_cmnd { - struct fcp_cmnd *next; - struct fcp_cmnd *prev; - void (*done)(Scsi_Cmnd *); - int proto; - int token; - /* FCP SCSI stuff */ - dma_handle data; - /* From now on this cannot be touched for proto == TYPE_SCSI_FCP */ - fc_hdr fch; - dma_handle cmd; - dma_handle rsp; - int cmdlen; - int rsplen; - int class; - int datalen; - /* This is just used as a verification during login */ - struct _fc_channel *fc; -} fcp_cmnd; - -typedef struct _fc_channel { - struct _fc_channel *next; - int irq; - int state; - int sid; - int did; - char name[16]; - void (*fcp_register)(struct _fc_channel *, u8, int); - void (*reset)(struct _fc_channel *); - int (*hw_enque)(struct _fc_channel *, fcp_cmnd *); - fc_wwn wwn_node; - fc_wwn wwn_nport; - fc_wwn wwn_dest; - common_svc_parm *common_svc; - svc_parm *class_svcs; -#ifdef __sparc__ - struct linux_sbus_device *dev; -#endif - struct module *module; - /* FCP SCSI stuff */ - short can_queue; - short abort_count; - int rsp_size; - fcp_cmd *scsi_cmd_pool; - char *scsi_rsp_pool; - dma_handle dma_scsi_cmd, dma_scsi_rsp; - long *scsi_bitmap; - long scsi_bitmap_end; - int scsi_free; - int (*encode_addr)(Scsi_Cmnd *cmnd, u16 *addr); - fcp_cmnd *scsi_que; - char scsi_name[4]; - fcp_cmnd **token_tab; - int channels; - int targets; - long *ages; - Scsi_Cmnd *rst_pkt; - /* LOGIN stuff */ - fcp_cmnd *login; - void *ls; -} fc_channel; - -extern fc_channel *fc_channels; - -#define FC_STATE_UNINITED 0 -#define FC_STATE_ONLINE 1 -#define FC_STATE_OFFLINE 2 -#define FC_STATE_RESETING 3 -#define FC_STATE_FPORT_OK 4 -#define FC_STATE_MAYBEOFFLINE 5 - -#define FC_STATUS_OK 0 -#define FC_STATUS_P_RJT 2 -#define FC_STATUS_F_RJT 3 -#define FC_STATUS_P_BSY 4 -#define FC_STATUS_F_BSY 5 -#define FC_STATUS_ERR_OFFLINE 0x11 -#define FC_STATUS_TIMEOUT 0x12 -#define FC_STATUS_ERR_OVERRUN 0x13 -#define FC_STATUS_UNKNOWN_CQ_TYPE 0x20 -#define FC_STATUS_BAD_SEG_CNT 0x21 -#define FC_STATUS_MAX_XCHG_EXCEEDED 0x22 -#define FC_STATUS_BAD_XID 0x23 -#define FC_STATUS_XCHG_BUSY 0x24 -#define FC_STATUS_BAD_POOL_ID 0x25 -#define FC_STATUS_INSUFFICIENT_CQES 0x26 -#define FC_STATUS_ALLOC_FAIL 0x27 -#define FC_STATUS_BAD_SID 0x28 -#define FC_STATUS_NO_SEQ_INIT 0x29 - -void fcp_queue_empty(fc_channel *); -int fcp_init(fc_channel *); -void fcp_release(fc_channel *fc_chain, int count); -void fcp_receive_solicited(fc_channel *, int, int, int, fc_hdr *); -void fcp_state_change(fc_channel *, int); - -#define for_each_fc_channel(fc) \ - for (fc = fc_channels; fc; fc = fc->next) - -#define for_each_online_fc_channel(fc) \ - for_each_fc_channel(fc) \ - if (fc->state == FC_STATE_ONLINE) - -int fcp_scsi_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *)); -int fcp_old_abort(Scsi_Cmnd *); -int fcp_scsi_abort(Scsi_Cmnd *); -int fcp_scsi_dev_reset(Scsi_Cmnd *); -int fcp_scsi_bus_reset(Scsi_Cmnd *); -int fcp_scsi_host_reset(Scsi_Cmnd *); - -#endif /* !(_FCP_SCSI_H) */ diff -ur --new-file old/linux/drivers/fc4/soc.c new/linux/drivers/fc4/soc.c --- old/linux/drivers/fc4/soc.c Wed Dec 16 22:39:11 1998 +++ new/linux/drivers/fc4/soc.c Fri Mar 26 22:57:41 1999 @@ -1,6 +1,6 @@ /* soc.c: Sparc SUNW,soc (Serial Optical Channel) Fibre Channel Sbus adapter support. * - * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * Copyright (C) 1996,1997,1999 Jakub Jelinek (jj@ultra.linux.cz) * Copyright (C) 1997,1998 Jirka Hanika (geo@ff.cuni.cz) * * Sources: @@ -9,8 +9,6 @@ * * Supported hardware: * Tested on SOC sbus card bought with SS1000 in Linux running on SS5 and Ultra1. - * Should run on on-board SOC/SOC+ cards of Ex000 servers as well, but it is not - * tested (let us know if you succeed). * For SOC sbus cards, you have to make sure your FCode is 1.52 or later. * If you have older FCode, you should try to upgrade or get SOC microcode from Sun * (the microcode is present in Solaris soc driver as well). In that case you need @@ -20,7 +18,7 @@ */ static char *version = - "soc.c:v1.2 27/Feb/98 Jakub Jelinek (jj@sunsite.mff.cuni.cz), Jirka Hanika (geo@ff.cuni.cz)\n"; + "soc.c:v1.3 9/Feb/99 Jakub Jelinek (jj@ultra.linux.cz), Jirka Hanika (geo@ff.cuni.cz)\n"; #include #include @@ -34,7 +32,6 @@ #include #include #include -#include #include #include #include @@ -44,17 +41,16 @@ #include #include #include -#include #include #include /* #define SOCDEBUG */ /* #define HAVE_SOC_UCODE */ -#include "fcp_scsi.h" +#include "fcp_impl.h" #include "soc.h" #ifdef HAVE_SOC_UCODE -#include "soc_asm.c" +#include "soc_asm.h" #endif #define soc_printk printk ("soc%d: ", s->soc_no); printk @@ -397,6 +393,10 @@ FILL_FCHDR_OXRX(fch, 0xffff, 0xffff); request->shdr.flags = port->flags; break; + + case PROTO_REPORT_AL_MAP: + /* SOC only supports Point-to-Point topology, no FC-AL, sorry... */ + return -ENOSYS; default: request->shdr.token = TOKEN(fcmd->proto, port->mask, fcmd->token); diff -ur --new-file old/linux/drivers/fc4/soc.h new/linux/drivers/fc4/soc.h --- old/linux/drivers/fc4/soc.h Tue Jan 13 00:19:36 1998 +++ new/linux/drivers/fc4/soc.h Tue Mar 16 01:11:29 1999 @@ -8,7 +8,7 @@ #include "fc.h" #include "fcp.h" -#include "fcp_scsi.h" +#include "fcp_impl.h" /* Hardware structures and constants first {{{ */ diff -ur --new-file old/linux/drivers/fc4/socal.c new/linux/drivers/fc4/socal.c --- old/linux/drivers/fc4/socal.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/fc4/socal.c Sun Mar 28 19:07:47 1999 @@ -0,0 +1,856 @@ +/* socal.c: Sparc SUNW,socal (SOC+) Fibre Channel Sbus adapter support. + * + * Copyright (C) 1998,1999 Jakub Jelinek (jj@ultra.linux.cz) + * + * Sources: + * Fibre Channel Physical & Signaling Interface (FC-PH), dpANS, 1994 + * dpANS Fibre Channel Protocol for SCSI (X3.269-199X), Rev. 012, 1995 + * SOC+ Programming Guide 0.1 + * Fibre Channel Arbitrated Loop (FC-AL), dpANS rev. 4.5, 1995 + * + * Supported hardware: + * On-board SOC+ adapters of Ultra Enterprise servers and sun4d. + */ + +static char *version = + "socal.c: SOC+ driver v1.1 9/Feb/99 Jakub Jelinek (jj@ultra.linux.cz)\n"; + +#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 SOCALDEBUG */ +/* #define HAVE_SOCAL_UCODE */ +/* #define USE_64BIT_MODE */ + +#include "fcp_impl.h" +#include "socal.h" +#ifdef HAVE_SOCAL_UCODE +#include "socal_asm.h" +#endif + +#define socal_printk printk ("socal%d: ", s->socal_no); printk + +#ifdef SOCALDEBUG +#define SOD(x) socal_printk x; +#else +#define SOD(x) +#endif + +#define for_each_socal(s) for (s = socals; s; s = s->next) +struct socal *socals = NULL; + +/* I don't think our VIS mem* routines will behave well + in IO... */ +static void socal_memcpy(void *d, void *s, int size) +{ + u32 *dp = (u32 *)d, *sp = (u32 *)s; + while (size) { + *dp++ = *sp++; + size -= sizeof(u32); + } +} + +#ifdef HAVE_SOCAL_UCODE +static void socal_bzero(void *d, int size) +{ + u32 *dp = (u32 *)d; + while (size) { + *dp++ = 0; + size -= sizeof(u32); + } +} +#endif + +static inline void socal_disable(struct socal *s) +{ + s->regs->imask = 0; s->regs->cmd = SOCAL_CMD_SOFT_RESET; +} + +static inline void socal_enable(struct socal *s) +{ + SOD(("enable %08x\n", s->cfg)) + s->regs->sae = 0; s->regs->cfg = s->cfg; + s->regs->cmd = SOCAL_CMD_RSP_QALL; + SOCAL_SETIMASK(s, SOCAL_IMASK_RSP_QALL | SOCAL_IMASK_SAE); + SOD(("imask %08x %08x\n", s->imask, s->regs->imask)); +} + +static void socal_reset(fc_channel *fc) +{ + socal_port *port = (socal_port *)fc; + struct socal *s = port->s; + + /* FIXME */ + socal_disable(s); + s->req[0].seqno = 1; + s->req[1].seqno = 1; + s->rsp[0].seqno = 1; + s->rsp[1].seqno = 1; + s->req[0].in = 0; + s->req[1].in = 0; + s->rsp[0].in = 0; + s->rsp[1].in = 0; + s->req[0].out = 0; + s->req[1].out = 0; + s->rsp[0].out = 0; + s->rsp[1].out = 0; + + /* FIXME */ + socal_enable(s); +} + +static void inline socal_solicited (struct socal *s, int qno) +{ + fc_hdr fchdr; + socal_rsp *hwrsp; + socal_cq *sw_cq; + int token; + int status; + fc_channel *fc; + + sw_cq = &s->rsp[qno]; + + if (sw_cq->pool == NULL) { + SOD(("address %08x xram %p\n", sw_cq->hw_cq->address, s->xram)) + sw_cq->pool = + (socal_req *)(s->xram + (sw_cq->hw_cq->address & 0xfffe)); + } + /* Finally an improvement against old SOC :) */ + sw_cq->in = s->regs->respr[qno]; + SOD (("socal_solicited, %d packets arrived\n", (sw_cq->in - sw_cq->out) & sw_cq->last)) + for (;;) { + hwrsp = (socal_rsp *)sw_cq->pool + sw_cq->out; + SOD(("hwrsp %p out %d\n", hwrsp, sw_cq->out)) + +#if defined(SOCALDEBUG) && 0 + { + u32 *u = (u32 *)hwrsp; + SOD(("%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x\n", u[0],u[1],u[2],u[3],u[4],u[5],u[6],u[7])) + u += 8; + SOD(("%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x\n", u[0],u[1],u[2],u[3],u[4],u[5],u[6],u[7])) + u = (u32 *)s->xram; + while (u < ((u32 *)s->regs)) { + if (u[0] == 0x00003000 || u[0] == 0x00003801) { + SOD(("Found at %04lx\n", (unsigned long)u - (unsigned long)s->xram)) + SOD((" %08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x\n", u[0],u[1],u[2],u[3],u[4],u[5],u[6],u[7])) + u += 8; + SOD((" %08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x\n", u[0],u[1],u[2],u[3],u[4],u[5],u[6],u[7])) + u -= 8; + } + u++; + } + } +#endif + + token = hwrsp->shdr.token; + status = hwrsp->status; + fc = (fc_channel *)(&s->port[(token >> 11) & 1]); + + SOD(("Solicited token %08x status %08x\n", token, status)) + if (status == SOCAL_OK) + fcp_receive_solicited(fc, token >> 12, token & ((1 << 11) - 1), FC_STATUS_OK, NULL); + else { + socal_memcpy(&fchdr, &hwrsp->fchdr, sizeof(fchdr)); + /* We have intentionally defined FC_STATUS_* constants to match SOCAL_* constants, otherwise + we'd have to translate status */ + fcp_receive_solicited(fc, token >> 12, token & ((1 << 11) - 1), status, &fchdr); + } + + if (++sw_cq->out > sw_cq->last) { + sw_cq->seqno++; + sw_cq->out = 0; + } + + if (sw_cq->out == sw_cq->in) { + sw_cq->in = s->regs->respr[qno]; + if (sw_cq->out == sw_cq->in) { + /* Tell the hardware about it */ + s->regs->cmd = (sw_cq->out << 24) | (SOCAL_CMD_RSP_QALL & ~(SOCAL_CMD_RSP_Q0 << qno)); + /* Read it, so that we're sure it has been updated */ + s->regs->cmd; + sw_cq->in = s->regs->respr[qno]; + if (sw_cq->out == sw_cq->in) + break; + } + } + } +} + +static void inline socal_request (struct socal *s, u32 cmd) +{ + SOCAL_SETIMASK(s, s->imask & ~(cmd & SOCAL_CMD_REQ_QALL)); + SOD(("imask %08x %08x\n", s->imask, s->regs->imask)); + + SOD(("Queues available %08x OUT %X\n", cmd, s->regs->reqpr[0])) + if (s->port[s->curr_port].fc.state != FC_STATE_OFFLINE) { + fcp_queue_empty ((fc_channel *)&(s->port[s->curr_port])); + if (((s->req[1].in + 1) & s->req[1].last) != (s->req[1].out)) + fcp_queue_empty ((fc_channel *)&(s->port[1 - s->curr_port])); + } else + fcp_queue_empty ((fc_channel *)&(s->port[1 - s->curr_port])); + if (s->port[1 - s->curr_port].fc.state != FC_STATE_OFFLINE) + s->curr_port ^= 1; +} + +static void inline socal_unsolicited (struct socal *s, int qno) +{ + socal_rsp *hwrsp, *hwrspc; + socal_cq *sw_cq; + int count; + int status; + int flags; + fc_channel *fc; + + sw_cq = &s->rsp[qno]; + if (sw_cq->pool == NULL) { + SOD(("address %08x xram %p\n", sw_cq->hw_cq->address, s->xram)) + sw_cq->pool = + (socal_req *)(s->xram + (sw_cq->hw_cq->address & 0xfffe)); + } + + sw_cq->in = s->regs->respr[qno]; + SOD (("socal_unsolicited, %d packets arrived, in %d\n", (sw_cq->in - sw_cq->out) & sw_cq->last, sw_cq->in)) + while (sw_cq->in != sw_cq->out) { + /* ...real work per entry here... */ + hwrsp = (socal_rsp *)sw_cq->pool + sw_cq->out; + SOD(("hwrsp %p out %d\n", hwrsp, sw_cq->out)) + +#if defined(SOCALDEBUG) && 0 + { + u32 *u = (u32 *)hwrsp; + SOD(("%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x\n", u[0],u[1],u[2],u[3],u[4],u[5],u[6],u[7])) + u += 8; + SOD(("%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x\n", u[0],u[1],u[2],u[3],u[4],u[5],u[6],u[7])) + } +#endif + + hwrspc = NULL; + flags = hwrsp->shdr.flags; + count = hwrsp->count; + fc = (fc_channel *)&s->port[flags & SOCAL_PORT_B]; + SOD(("FC %08lx\n", (long)fc)) + + if (count != 1) { + /* Ugh, continuation entries */ + u8 in; + + if (count != 2) { + printk("%s: Too many continuations entries %d\n", fc->name, count); + goto update_out; + } + + in = sw_cq->in; + if (in < sw_cq->out) in += sw_cq->last + 1; + if (in < sw_cq->out + 2) { + /* Ask the hardware about it if they haven't arrived yet */ + s->regs->cmd = (sw_cq->out << 24) | (SOCAL_CMD_RSP_QALL & ~(SOCAL_CMD_RSP_Q0 << qno)); + /* Read it, so that we're sure it has been updated */ + s->regs->cmd; + sw_cq->in = s->regs->respr[qno]; + in = sw_cq->in; + if (in < sw_cq->out) in += sw_cq->last + 1; + if (in < sw_cq->out + 2) /* Nothing came, let us wait */ + return; + } + if (sw_cq->out == sw_cq->last) + hwrspc = (socal_rsp *)sw_cq->pool; + else + hwrspc = hwrsp + 1; + } + + switch (flags & ~SOCAL_PORT_B) { + case SOCAL_STATUS: + status = hwrsp->status; + switch (status) { + case SOCAL_ONLINE: + SOD(("State change to ONLINE\n")); + fcp_state_change(fc, FC_STATE_ONLINE); + break; + case SOCAL_ONLINE_LOOP: + SOD(("State change to ONLINE_LOOP\n")); + fcp_state_change(fc, FC_STATE_ONLINE); + break; + case SOCAL_OFFLINE: + SOD(("State change to OFFLINE\n")); + fcp_state_change(fc, FC_STATE_OFFLINE); + break; + default: + printk ("%s: Unknown STATUS no %d\n", fc->name, status); + break; + } + break; + case (SOCAL_UNSOLICITED|SOCAL_FC_HDR): + { + int r_ctl = *((u8 *)&hwrsp->fchdr); + unsigned len; + char buf[64]; + + if ((r_ctl & 0xf0) == R_CTL_EXTENDED_SVC) { + len = hwrsp->shdr.bytecnt; + if (len < 4 || !hwrspc) + printk ("%s: Invalid R_CTL %02x continuation entries\n", fc->name, r_ctl); + else { + if (len > 60) len = 60; + socal_memcpy (buf, hwrspc, (len + 3) & ~3); + if (*(u32 *)buf == LS_DISPLAY) { + int i; + + for (i = 4; i < len; i++) + if (buf[i] == '\n') buf[i] = ' '; + buf[len] = 0; + printk ("%s message: %s\n", fc->name, buf + 4); + } else { + printk ("%s: Unknown LS_CMD %08x\n", fc->name, *(u32 *)buf); + } + } + } else + printk ("%s: Unsolicited R_CTL %02x not handled\n", fc->name, r_ctl); + } + break; + default: + printk ("%s: Unexpected flags %08x\n", fc->name, flags); + break; + } +update_out: + if (++sw_cq->out > sw_cq->last) { + sw_cq->seqno++; + sw_cq->out = 0; + } + + if (hwrspc) { + if (++sw_cq->out > sw_cq->last) { + sw_cq->seqno++; + sw_cq->out = 0; + } + } + + if (sw_cq->out == sw_cq->in) { + sw_cq->in = s->regs->respr[qno]; + if (sw_cq->out == sw_cq->in) { + /* Tell the hardware about it */ + s->regs->cmd = (sw_cq->out << 24) | (SOCAL_CMD_RSP_QALL & ~(SOCAL_CMD_RSP_Q0 << qno)); + /* Read it, so that we're sure it has been updated */ + s->regs->cmd; + sw_cq->in = s->regs->respr[qno]; + } + } + } +} + +static void socal_intr(int irq, void *dev_id, struct pt_regs *regs) +{ + u32 cmd; + unsigned long flags; + register struct socal *s = (struct socal *)dev_id; + + spin_lock_irqsave(&io_request_lock, flags); + cmd = s->regs->cmd; + for (; (cmd = SOCAL_INTR (s, cmd)); cmd = s->regs->cmd) { +#ifdef SOCALDEBUG + static int cnt = 0; + if (cnt++ < 50) printk("soc_intr %08x\n", cmd); +#endif + if (cmd & SOCAL_CMD_RSP_Q2) socal_unsolicited (s, SOCAL_UNSOLICITED_RSP_Q); + if (cmd & SOCAL_CMD_RSP_Q1) socal_unsolicited (s, SOCAL_SOLICITED_BAD_RSP_Q); + if (cmd & SOCAL_CMD_RSP_Q0) socal_solicited (s, SOCAL_SOLICITED_RSP_Q); + if (cmd & SOCAL_CMD_REQ_QALL) socal_request (s, cmd); + } + spin_unlock_irqrestore(&io_request_lock, flags); +} + +#define TOKEN(proto, port, token) (((proto)<<12)|(token)|(port)) + +static int socal_hw_enque (fc_channel *fc, fcp_cmnd *fcmd) +{ + socal_port *port = (socal_port *)fc; + struct socal *s = port->s; + int qno; + socal_cq *sw_cq; + int cq_next_in; + socal_req *request; + fc_hdr *fch; + int i; + + if (fcmd->proto == TYPE_SCSI_FCP) + qno = 1; + else + qno = 0; + SOD(("Putting a FCP packet type %d into hw queue %d\n", fcmd->proto, qno)) + if (s->imask & (SOCAL_IMASK_REQ_Q0 << qno)) { + SOD(("EIO %08x\n", s->imask)) + return -EIO; + } + sw_cq = s->req + qno; + cq_next_in = (sw_cq->in + 1) & sw_cq->last; + + if (cq_next_in == sw_cq->out + && cq_next_in == (sw_cq->out = s->regs->reqpr[qno])) { + SOD(("%d IN %d OUT %d LAST %d\n", qno, sw_cq->in, sw_cq->out, sw_cq->last)) + SOCAL_SETIMASK(s, s->imask | (SOCAL_IMASK_REQ_Q0 << qno)); + SOD(("imask %08x %08x\n", s->imask, s->regs->imask)); + /* If queue is full, just say NO */ + return -EBUSY; + } + + request = sw_cq->pool + sw_cq->in; + fch = &request->fchdr; + + switch (fcmd->proto) { + case TYPE_SCSI_FCP: + request->shdr.token = TOKEN(TYPE_SCSI_FCP, port->mask, fcmd->token); + request->data[0].base = fc->dma_scsi_cmd + fcmd->token * sizeof(fcp_cmd); + request->data[0].count = sizeof(fcp_cmd); + request->data[1].base = fc->dma_scsi_rsp + fcmd->token * fc->rsp_size; + request->data[1].count = fc->rsp_size; + if (fcmd->data) { + request->shdr.segcnt = 3; + i = fc->scsi_cmd_pool[fcmd->token].fcp_data_len; + request->shdr.bytecnt = i; + request->data[2].base = fcmd->data; + request->data[2].count = i; + request->type = (fc->scsi_cmd_pool[fcmd->token].fcp_cntl & FCP_CNTL_WRITE) ? + SOCAL_CQTYPE_IO_WRITE : SOCAL_CQTYPE_IO_READ; + } else { + request->shdr.segcnt = 2; + request->shdr.bytecnt = 0; + request->data[2].base = 0; + request->data[2].count = 0; + request->type = SOCAL_CQTYPE_SIMPLE; + } + FILL_FCHDR_RCTL_DID(fch, R_CTL_COMMAND, fcmd->did); + FILL_FCHDR_SID(fch, fc->sid); + FILL_FCHDR_TYPE_FCTL(fch, TYPE_SCSI_FCP, F_CTL_FIRST_SEQ | F_CTL_SEQ_INITIATIVE); + FILL_FCHDR_SEQ_DF_SEQ(fch, 0, 0, 0); + FILL_FCHDR_OXRX(fch, 0xffff, 0xffff); + fch->param = 0; + request->shdr.flags = port->flags; + request->shdr.class = fc->posmap ? 3 : 2; + break; + + case PROTO_OFFLINE: + memset (request, 0, sizeof(*request)); + request->shdr.token = TOKEN(PROTO_OFFLINE, port->mask, fcmd->token); + request->type = SOCAL_CQTYPE_OFFLINE; + FILL_FCHDR_RCTL_DID(fch, R_CTL_COMMAND, fcmd->did); + FILL_FCHDR_SID(fch, fc->sid); + FILL_FCHDR_TYPE_FCTL(fch, TYPE_SCSI_FCP, F_CTL_FIRST_SEQ | F_CTL_SEQ_INITIATIVE); + FILL_FCHDR_SEQ_DF_SEQ(fch, 0, 0, 0); + FILL_FCHDR_OXRX(fch, 0xffff, 0xffff); + request->shdr.flags = port->flags; + break; + + case PROTO_REPORT_AL_MAP: + memset (request, 0, sizeof(*request)); + request->shdr.token = TOKEN(PROTO_REPORT_AL_MAP, port->mask, fcmd->token); + request->type = SOCAL_CQTYPE_REPORT_MAP; + request->shdr.flags = port->flags; + request->shdr.segcnt = 1; + request->shdr.bytecnt = sizeof(fc_al_posmap); + request->data[0].base = fcmd->cmd; + request->data[0].count = sizeof(fc_al_posmap); + break; + + default: + request->shdr.token = TOKEN(fcmd->proto, port->mask, fcmd->token); + request->shdr.class = fc->posmap ? 3 : 2; + request->shdr.flags = port->flags; + memcpy (fch, &fcmd->fch, sizeof(fc_hdr)); + request->data[0].count = fcmd->cmdlen; + request->data[1].count = fcmd->rsplen; + request->type = fcmd->class; + switch (fcmd->class) { + case FC_CLASS_OUTBOUND: + request->data[0].base = fcmd->cmd; + request->data[0].count = fcmd->cmdlen; + request->type = SOCAL_CQTYPE_OUTBOUND; + request->shdr.bytecnt = fcmd->cmdlen; + request->shdr.segcnt = 1; + break; + case FC_CLASS_INBOUND: + request->data[0].base = fcmd->rsp; + request->data[0].count = fcmd->rsplen; + request->type = SOCAL_CQTYPE_INBOUND; + request->shdr.bytecnt = 0; + request->shdr.segcnt = 1; + break; + case FC_CLASS_SIMPLE: + request->data[0].base = fcmd->cmd; + request->data[1].base = fcmd->rsp; + request->data[0].count = fcmd->cmdlen; + request->data[1].count = fcmd->rsplen; + request->type = SOCAL_CQTYPE_SIMPLE; + request->shdr.bytecnt = fcmd->cmdlen; + request->shdr.segcnt = 2; + break; + case FC_CLASS_IO_READ: + case FC_CLASS_IO_WRITE: + request->data[0].base = fcmd->cmd; + request->data[1].base = fcmd->rsp; + request->data[0].count = fcmd->cmdlen; + request->data[1].count = fcmd->rsplen; + request->type = (fcmd->class == FC_CLASS_IO_READ) ? SOCAL_CQTYPE_IO_READ : SOCAL_CQTYPE_IO_WRITE; + if (fcmd->data) { + request->data[2].base = fcmd->data; + request->data[2].count = fcmd->datalen; + request->shdr.bytecnt = fcmd->datalen; + request->shdr.segcnt = 3; + } else { + request->shdr.bytecnt = 0; + request->shdr.segcnt = 2; + } + break; + } + break; + } + + request->count = 1; + request->flags = 0; + request->seqno = sw_cq->seqno; + + SOD(("queueing token %08x\n", request->shdr.token)) + + /* And now tell the SOCAL about it */ + + if (++sw_cq->in > sw_cq->last) { + sw_cq->in = 0; + sw_cq->seqno++; + } + + SOD(("Putting %08x into cmd\n", SOCAL_CMD_RSP_QALL | (sw_cq->in << 24) | (SOCAL_CMD_REQ_Q0 << qno))) + + s->regs->cmd = SOCAL_CMD_RSP_QALL | (sw_cq->in << 24) | (SOCAL_CMD_REQ_Q0 << qno); + /* Read so that command is completed */ + s->regs->cmd; + + return 0; +} + +static inline void socal_download_fw(struct socal *s) +{ +#ifdef HAVE_SOCAL_UCODE + SOD(("Loading %ld bytes from %p to %p\n", sizeof(socal_ucode), socal_ucode, s->xram)) + socal_memcpy (s->xram, socal_ucode, sizeof(socal_ucode)); + SOD(("Clearing the rest of memory\n")) + socal_bzero (s->xram + sizeof(socal_ucode), 65536 - sizeof(socal_ucode)); + SOD(("Done\n")) +#endif +} + +/* Check for what the best SBUS burst we can use happens + * to be on this machine. + */ +static inline void socal_init_bursts(struct socal *s, struct linux_sbus_device *sdev) +{ + int bsizes, bsizes_more; + u32 cfg; + + bsizes = (prom_getintdefault(sdev->prom_node,"burst-sizes",0xff) & 0xff); + bsizes_more = (prom_getintdefault(sdev->my_bus->prom_node, "burst-sizes", 0xff) & 0xff); + bsizes &= bsizes_more; +#ifdef USE_64BIT_MODE +#ifdef __sparc_v9__ + mmu_set_sbus64(sdev, bsizes >> 16); +#endif +#endif + if ((bsizes & 0x7f) == 0x7f) + cfg = SOCAL_CFG_BURST_64; + else if ((bsizes & 0x3f) == 0x3f) + cfg = SOCAL_CFG_BURST_32; + else if ((bsizes & 0x1f) == 0x1f) + cfg = SOCAL_CFG_BURST_16; + else + cfg = SOCAL_CFG_BURST_4; +#ifdef USE_64BIT_MODE +#ifdef __sparc_v9__ + /* What is BURST_128? -jj */ + if ((bsizes & 0x780000) == 0x780000) + cfg |= (SOCAL_CFG_BURST_64 << 8) | SOCAL_CFG_SBUS_ENHANCED; + else if ((bsizes & 0x380000) == 0x380000) + cfg |= (SOCAL_CFG_BURST_32 << 8) | SOCAL_CFG_SBUS_ENHANCED; + else if ((bsizes & 0x180000) == 0x180000) + cfg |= (SOCAL_CFG_BURST_16 << 8) | SOCAL_CFG_SBUS_ENHANCED; + else + cfg |= (SOCAL_CFG_BURST_8 << 8) | SOCAL_CFG_SBUS_ENHANCED; +#endif +#endif + s->cfg = cfg; +} + +static inline void socal_init(struct linux_sbus_device *sdev, int no) +{ + unsigned char tmp[60]; + int propl; + struct socal *s; + static unsigned version_printed = 0; + socal_hw_cq cq[8]; + int size, i; + int irq, node; + + s = kmalloc (sizeof (struct socal), GFP_KERNEL); + if (!s) return; + memset (s, 0, sizeof(struct socal)); + s->socal_no = no; + + SOD(("socals %08lx socal_intr %08lx socal_hw_enque %08lx\n", (long)socals, (long)socal_intr, (long)socal_hw_enque)) + if (version_printed++ == 0) + printk (version); +#ifdef MODULE + s->port[0].fc.module = &__this_module; + s->port[1].fc.module = &__this_module; +#else + s->port[0].fc.module = NULL; + s->port[1].fc.module = NULL; +#endif + + s->next = socals; + socals = s; + s->port[0].fc.dev = sdev; + s->port[1].fc.dev = sdev; + s->port[0].s = s; + s->port[1].s = s; + + s->port[0].fc.next = &s->port[1].fc; + + /* World Wide Name of SOCAL */ + propl = prom_getproperty (sdev->prom_node, "wwn", tmp, sizeof(tmp)); + if (propl != sizeof (fc_wwn)) { + s->wwn.naaid = NAAID_IEEE_REG; + s->wwn.nportid = 0x123; + s->wwn.hi = 0x1234; + s->wwn.lo = 0x12345678; + } else + memcpy (&s->wwn, tmp, sizeof (fc_wwn)); + + memcpy (&s->port[0].fc.wwn_nport, &s->wwn, sizeof (fc_wwn)); + s->port[0].fc.wwn_nport.lo++; + memcpy (&s->port[1].fc.wwn_nport, &s->wwn, sizeof (fc_wwn)); + s->port[1].fc.wwn_nport.lo+=2; + + node = prom_getchild (sdev->prom_node); + while (node && (node = prom_searchsiblings (node, "sf"))) { + int port; + + port = prom_getintdefault(node, "port#", -1); + switch (port) { + case 0: + case 1: + if (prom_getproplen(node, "port-wwn") == sizeof (fc_wwn)) + prom_getproperty (node, "port-wwn", + (char *)&s->port[port].fc.wwn_nport, + sizeof (fc_wwn)); + break; + default: + break; + } + node = prom_getsibling(node); + } + + memcpy (&s->port[0].fc.wwn_node, &s->wwn, sizeof (fc_wwn)); + memcpy (&s->port[1].fc.wwn_node, &s->wwn, sizeof (fc_wwn)); + SOD(("Got wwns %08x%08x ports %08x%08x and %08x%08x\n", + *(u32 *)&s->port[0].fc.wwn_node, s->port[0].fc.wwn_node.lo, + *(u32 *)&s->port[0].fc.wwn_nport, s->port[0].fc.wwn_nport.lo, + *(u32 *)&s->port[1].fc.wwn_nport, s->port[1].fc.wwn_nport.lo)) + + s->port[0].fc.sid = 1; + s->port[1].fc.sid = 17; + s->port[0].fc.did = 2; + s->port[1].fc.did = 18; + + s->port[0].fc.reset = socal_reset; + s->port[1].fc.reset = socal_reset; + + /* Setup the reg property for this device. */ + prom_apply_sbus_ranges(sdev->my_bus, sdev->reg_addrs, sdev->num_registers, sdev); + + if (sdev->num_registers == 1) { + s->eeprom = (u8 *) + sparc_alloc_io (sdev->reg_addrs [0].phys_addr, 0, + sdev->reg_addrs [0].reg_size, "socal_xram", + sdev->reg_addrs [0].which_io, 0); + if (sdev->reg_addrs [0].reg_size > 0x20000) + s->xram = s->eeprom + 0x10000; + else + s->xram = s->eeprom; + s->regs = (struct socal_regs *)(s->xram + 0x10000); + } else { + /* E.g. starfire presents 3 registers for SOCAL */ + s->xram = (u8 *) + sparc_alloc_io (sdev->reg_addrs [1].phys_addr, 0, + sdev->reg_addrs [1].reg_size, "socal_xram", + sdev->reg_addrs [1].which_io, 0); + s->regs = (struct socal_regs *) + sparc_alloc_io (sdev->reg_addrs [2].phys_addr, 0, + sdev->reg_addrs [2].reg_size, "socal_regs", + sdev->reg_addrs [2].which_io, 0); + } + + socal_init_bursts(s, sdev); + + SOD(("Disabling SOCAL\n")) + + socal_disable (s); + + irq = sdev->irqs[0]; + + if (request_irq (irq, socal_intr, SA_SHIRQ, "SOCAL", (void *)s)) { + socal_printk ("Cannot order irq %d to go\n", irq); + socals = s->next; + return; + } + + SOD(("SOCAL uses IRQ %s\n", __irq_itoa(irq))) + + s->port[0].fc.irq = irq; + s->port[1].fc.irq = irq; + + sprintf (s->port[0].fc.name, "socal%d port A", no); + sprintf (s->port[1].fc.name, "socal%d port B", no); + s->port[0].flags = SOCAL_FC_HDR | SOCAL_PORT_A; + s->port[1].flags = SOCAL_FC_HDR | SOCAL_PORT_B; + s->port[1].mask = (1 << 11); + + s->port[0].fc.hw_enque = socal_hw_enque; + s->port[1].fc.hw_enque = socal_hw_enque; + + socal_download_fw (s); + + SOD(("Downloaded firmware\n")) + + /* Now setup xram circular queues */ + memset (cq, 0, sizeof(cq)); + + size = (SOCAL_CQ_REQ0_SIZE + SOCAL_CQ_REQ1_SIZE + SOCAL_CQ_RSP0_SIZE + SOCAL_CQ_RSP1_SIZE + SOCAL_CQ_RSP2_SIZE) * sizeof(socal_req); + s->req[0].pool = (socal_req *) sparc_dvma_malloc (size, "SOCAL request queues", &cq[0].address); + s->req[1].pool = s->req[0].pool + SOCAL_CQ_REQ0_SIZE; + s->rsp[0].pool = s->req[1].pool + SOCAL_CQ_REQ1_SIZE; + s->rsp[1].pool = s->rsp[0].pool + SOCAL_CQ_RSP0_SIZE; + s->rsp[2].pool = s->rsp[1].pool + SOCAL_CQ_RSP1_SIZE; + + s->req[0].hw_cq = (socal_hw_cq *)(s->xram + SOCAL_CQ_REQ_OFFSET); + s->req[1].hw_cq = (socal_hw_cq *)(s->xram + SOCAL_CQ_REQ_OFFSET + sizeof(socal_hw_cq)); + s->rsp[0].hw_cq = (socal_hw_cq *)(s->xram + SOCAL_CQ_RSP_OFFSET); + s->rsp[1].hw_cq = (socal_hw_cq *)(s->xram + SOCAL_CQ_RSP_OFFSET + sizeof(socal_hw_cq)); + s->rsp[2].hw_cq = (socal_hw_cq *)(s->xram + SOCAL_CQ_RSP_OFFSET + 2 * sizeof(socal_hw_cq)); + + cq[1].address = cq[0].address + (SOCAL_CQ_REQ0_SIZE * sizeof(socal_req)); + cq[4].address = cq[1].address + (SOCAL_CQ_REQ1_SIZE * sizeof(socal_req)); + cq[5].address = cq[4].address + (SOCAL_CQ_RSP0_SIZE * sizeof(socal_req)); + cq[6].address = cq[5].address + (SOCAL_CQ_RSP1_SIZE * sizeof(socal_req)); + + cq[0].last = SOCAL_CQ_REQ0_SIZE - 1; + cq[1].last = SOCAL_CQ_REQ1_SIZE - 1; + cq[4].last = SOCAL_CQ_RSP0_SIZE - 1; + cq[5].last = SOCAL_CQ_RSP1_SIZE - 1; + cq[6].last = SOCAL_CQ_RSP2_SIZE - 1; + for (i = 0; i < 8; i++) + cq[i].seqno = 1; + + s->req[0].last = SOCAL_CQ_REQ0_SIZE - 1; + s->req[1].last = SOCAL_CQ_REQ1_SIZE - 1; + s->rsp[0].last = SOCAL_CQ_RSP0_SIZE - 1; + s->rsp[1].last = SOCAL_CQ_RSP1_SIZE - 1; + s->rsp[2].last = SOCAL_CQ_RSP2_SIZE - 1; + + s->req[0].seqno = 1; + s->req[1].seqno = 1; + s->rsp[0].seqno = 1; + s->rsp[1].seqno = 1; + s->rsp[2].seqno = 1; + + socal_memcpy (s->xram + SOCAL_CQ_REQ_OFFSET, cq, sizeof(cq)); + + SOD(("Setting up params\n")) + + /* Make our sw copy of SOCAL service parameters */ + socal_memcpy (s->serv_params, s->xram + 0x280, sizeof (s->serv_params)); + + s->port[0].fc.common_svc = (common_svc_parm *)s->serv_params; + s->port[0].fc.class_svcs = (svc_parm *)(s->serv_params + 0x20); + s->port[1].fc.common_svc = (common_svc_parm *)&s->serv_params; + s->port[1].fc.class_svcs = (svc_parm *)(s->serv_params + 0x20); + + socal_enable (s); + + SOD(("Enabled SOCAL\n")) +} + +#ifndef MODULE +__initfunc(int socal_probe(void)) +#else +int init_module(void) +#endif +{ + struct linux_sbus *bus; + struct linux_sbus_device *sdev = 0; + struct socal *s; + int cards = 0; + + for_each_sbus(bus) { + for_each_sbusdev(sdev, bus) { + if(!strcmp(sdev->prom_name, "SUNW,socal")) { + socal_init(sdev, cards); + cards++; + } + } + } + if (!cards) return -EIO; + + for_each_socal(s) + if (s->next) + s->port[1].fc.next = &s->next->port[0].fc; + + fcp_init (&socals->port[0].fc); + return 0; +} + +EXPORT_NO_SYMBOLS; + +#ifdef MODULE +void cleanup_module(void) +{ + struct socal *s; + int irq; + struct linux_sbus_device *sdev; + + for_each_socal(s) { + irq = s->port[0].fc.irq; + disable_irq (irq); + free_irq (irq, s); + + fcp_release(&(s->port[0].fc), 2); + + sdev = s->port[0].fc.dev; + if (sdev->num_registers == 1) + sparc_free_io (s->eeprom, sdev->reg_addrs [0].reg_size); + else { + sparc_free_io (s->xram, sdev->reg_addrs [1].reg_size); + sparc_free_io ((char *)s->regs, sdev->reg_addrs [2].reg_size); + } + /* FIXME: sparc_dvma_free() ??? */ + } +} +#endif diff -ur --new-file old/linux/drivers/fc4/socal.h new/linux/drivers/fc4/socal.h --- old/linux/drivers/fc4/socal.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/fc4/socal.h Tue Mar 16 01:11:29 1999 @@ -0,0 +1,319 @@ +/* socal.h: Definitions for Sparc SUNW,socal (SOC+) Fibre Channel Sbus driver. + * + * Copyright (C) 1998,1999 Jakub Jelinek (jj@ultra.linux.cz) + */ + +#ifndef __SOCAL_H +#define __SOCAL_H + +#include "fc.h" +#include "fcp.h" +#include "fcp_impl.h" + +/* Hardware structures and constants first {{{ */ + +union socal_rq_reg { + volatile u8 read[4]; + volatile u32 write; +}; +struct socal_regs { + volatile u32 cfg; /* Config Register */ + volatile u32 sae; /* Slave Access Error Register */ + volatile u32 cmd; /* Command & Status Register */ + volatile u32 imask; /* Interrupt Mask Register */ + union socal_rq_reg reqp; /* Request Queue Index Register */ + union socal_rq_reg resp; /* Response Queue Index Register */ +#define reqpr reqp.read +#define reqpw reqp.write +#define respr resp.read +#define respw resp.write +}; + +/* Config Register */ +#define SOCAL_CFG_EXT_RAM_BANK_MASK 0x07000000 +#define SOCAL_CFG_EEPROM_BANK_MASK 0x00030000 +#define SOCAL_CFG_BURST64_MASK 0x00000700 +#define SOCAL_CFG_SBUS_PARITY_TEST 0x00000020 +#define SOCAL_CFG_SBUS_PARITY_CHECK 0x00000010 +#define SOCAL_CFG_SBUS_ENHANCED 0x00000008 +#define SOCAL_CFG_BURST_MASK 0x00000007 +/* Bursts */ +#define SOCAL_CFG_BURST_4 0x00000000 +#define SOCAL_CFG_BURST_8 0x00000003 +#define SOCAL_CFG_BURST_16 0x00000004 +#define SOCAL_CFG_BURST_32 0x00000005 +#define SOCAL_CFG_BURST_64 0x00000006 +#define SOCAL_CFG_BURST_128 0x00000007 + +/* Slave Access Error Register */ +#define SOCAL_SAE_ALIGNMENT 0x00000004 +#define SOCAL_SAE_UNSUPPORTED 0x00000002 +#define SOCAL_SAE_PARITY 0x00000001 + +/* Command & Status Register */ +#define SOCAL_CMD_RSP_QALL 0x000f0000 +#define SOCAL_CMD_RSP_Q0 0x00010000 +#define SOCAL_CMD_RSP_Q1 0x00020000 +#define SOCAL_CMD_RSP_Q2 0x00040000 +#define SOCAL_CMD_RSP_Q3 0x00080000 +#define SOCAL_CMD_REQ_QALL 0x00000f00 +#define SOCAL_CMD_REQ_Q0 0x00000100 +#define SOCAL_CMD_REQ_Q1 0x00000200 +#define SOCAL_CMD_REQ_Q2 0x00000400 +#define SOCAL_CMD_REQ_Q3 0x00000800 +#define SOCAL_CMD_SAE 0x00000080 +#define SOCAL_CMD_INTR_PENDING 0x00000008 +#define SOCAL_CMD_NON_QUEUED 0x00000004 +#define SOCAL_CMD_IDLE 0x00000002 +#define SOCAL_CMD_SOFT_RESET 0x00000001 + +/* Interrupt Mask Register */ +#define SOCAL_IMASK_RSP_QALL 0x000f0000 +#define SOCAL_IMASK_RSP_Q0 0x00010000 +#define SOCAL_IMASK_RSP_Q1 0x00020000 +#define SOCAL_IMASK_RSP_Q2 0x00040000 +#define SOCAL_IMASK_RSP_Q3 0x00080000 +#define SOCAL_IMASK_REQ_QALL 0x00000f00 +#define SOCAL_IMASK_REQ_Q0 0x00000100 +#define SOCAL_IMASK_REQ_Q1 0x00000200 +#define SOCAL_IMASK_REQ_Q2 0x00000400 +#define SOCAL_IMASK_REQ_Q3 0x00000800 +#define SOCAL_IMASK_SAE 0x00000080 +#define SOCAL_IMASK_NON_QUEUED 0x00000004 + +#define SOCAL_INTR(s, cmd) \ + (((cmd & SOCAL_CMD_RSP_QALL) | ((~cmd) & SOCAL_CMD_REQ_QALL)) \ + & s->imask) + +#define SOCAL_SETIMASK(s, i) \ + (s)->imask = (i); (s)->regs->imask = (i) + +#define SOCAL_MAX_EXCHANGES 1024 + +/* XRAM + * + * This is a 64KB register area. + * From the documentation, it seems like it is finally able to cope + * at least with 1,2,4 byte accesses for read and 2,4 byte accesses for write. + */ + +/* Circular Queue */ + +#define SOCAL_CQ_REQ_OFFSET 0x200 +#define SOCAL_CQ_RSP_OFFSET 0x220 + +typedef struct { + u32 address; + u8 in; + u8 out; + u8 last; + u8 seqno; +} socal_hw_cq; + +#define SOCAL_PORT_A 0x0000 /* From/To Port A */ +#define SOCAL_PORT_B 0x0001 /* From/To Port A */ +#define SOCAL_FC_HDR 0x0002 /* Contains FC Header */ +#define SOCAL_NORSP 0x0004 /* Don't generate response nor interrupt */ +#define SOCAL_NOINT 0x0008 /* Generate response but not interrupt */ +#define SOCAL_XFERRDY 0x0010 /* Generate XFERRDY */ +#define SOCAL_IGNOREPARAM 0x0020 /* Ignore PARAM field in the FC header */ +#define SOCAL_COMPLETE 0x0040 /* Command completed */ +#define SOCAL_UNSOLICITED 0x0080 /* For request this is the packet to establish unsolicited pools, */ + /* for rsp this is unsolicited packet */ +#define SOCAL_STATUS 0x0100 /* State change (on/off line) */ +#define SOCAL_RSP_HDR 0x0200 /* Return frame header in any case */ + +typedef struct { + u32 token; + u16 flags; + u8 class; + u8 segcnt; + u32 bytecnt; +} socal_hdr; + +typedef struct { + u32 base; + u32 count; +} socal_data; + +#define SOCAL_CQTYPE_NOP 0x00 +#define SOCAL_CQTYPE_OUTBOUND 0x01 +#define SOCAL_CQTYPE_INBOUND 0x02 +#define SOCAL_CQTYPE_SIMPLE 0x03 +#define SOCAL_CQTYPE_IO_WRITE 0x04 +#define SOCAL_CQTYPE_IO_READ 0x05 +#define SOCAL_CQTYPE_UNSOLICITED 0x06 +#define SOCAL_CQTYPE_BYPASS_DEV 0x06 +#define SOCAL_CQTYPE_DIAG 0x07 +#define SOCAL_CQTYPE_OFFLINE 0x08 +#define SOCAL_CQTYPE_ADD_POOL 0x09 +#define SOCAL_CQTYPE_DELETE_POOL 0x0a +#define SOCAL_CQTYPE_ADD_BUFFER 0x0b +#define SOCAL_CQTYPE_ADD_POOL_BUFFER 0x0c +#define SOCAL_CQTYPE_REQUEST_ABORT 0x0d +#define SOCAL_CQTYPE_REQUEST_LIP 0x0e +#define SOCAL_CQTYPE_REPORT_MAP 0x0f +#define SOCAL_CQTYPE_RESPONSE 0x10 +#define SOCAL_CQTYPE_INLINE 0x20 + +#define SOCAL_CQFLAGS_CONT 0x01 +#define SOCAL_CQFLAGS_FULL 0x02 +#define SOCAL_CQFLAGS_BADHDR 0x04 +#define SOCAL_CQFLAGS_BADPKT 0x08 + +typedef struct { + socal_hdr shdr; + socal_data data[3]; + fc_hdr fchdr; + u8 count; + u8 type; + u8 flags; + u8 seqno; +} socal_req; + +#define SOCAL_OK 0 +#define SOCAL_P_RJT 2 +#define SOCAL_F_RJT 3 +#define SOCAL_P_BSY 4 +#define SOCAL_F_BSY 5 +#define SOCAL_ONLINE 0x10 +#define SOCAL_OFFLINE 0x11 +#define SOCAL_TIMEOUT 0x12 +#define SOCAL_OVERRUN 0x13 +#define SOCAL_ONLINE_LOOP 0x14 +#define SOCAL_OLD_PORT 0x15 +#define SOCAL_AL_PORT 0x16 +#define SOCAL_UNKOWN_CQ_TYPE 0x20 +#define SOCAL_BAD_SEG_CNT 0x21 +#define SOCAL_MAX_XCHG_EXCEEDED 0x22 +#define SOCAL_BAD_XID 0x23 +#define SOCAL_XCHG_BUSY 0x24 +#define SOCAL_BAD_POOL_ID 0x25 +#define SOCAL_INSUFFICIENT_CQES 0x26 +#define SOCAL_ALLOC_FAIL 0x27 +#define SOCAL_BAD_SID 0x28 +#define SOCAL_NO_SEG_INIT 0x29 +#define SOCAL_BAD_DID 0x2a +#define SOCAL_ABORTED 0x30 +#define SOCAL_ABORT_FAILED 0x31 + +typedef struct { + socal_hdr shdr; + u32 status; + socal_data data; + u8 xxx1[10]; + u16 ncmds; + fc_hdr fchdr; + u8 count; + u8 type; + u8 flags; + u8 seqno; +} socal_rsp; + +typedef struct { + socal_hdr shdr; + u8 xxx1[48]; + u8 count; + u8 type; + u8 flags; + u8 seqno; +} socal_cmdonly; + +#define SOCAL_DIAG_NOP 0x00 +#define SOCAL_DIAG_INT_LOOP 0x01 +#define SOCAL_DIAG_EXT_LOOP 0x02 +#define SOCAL_DIAG_REM_LOOP 0x03 +#define SOCAL_DIAG_XRAM_TEST 0x04 +#define SOCAL_DIAG_SOC_TEST 0x05 +#define SOCAL_DIAG_HCB_TEST 0x06 +#define SOCAL_DIAG_SOCLB_TEST 0x07 +#define SOCAL_DIAG_SRDSLB_TEST 0x08 +#define SOCAL_DIAG_EXTOE_TEST 0x09 + +typedef struct { + socal_hdr shdr; + u32 cmd; + u8 xxx1[44]; + u8 count; + u8 type; + u8 flags; + u8 seqno; +} socal_diag_req; + +#define SOCAL_POOL_MASK_RCTL 0x800000 +#define SOCAL_POOL_MASK_DID 0x700000 +#define SOCAL_POOL_MASK_SID 0x070000 +#define SOCAL_POOL_MASK_TYPE 0x008000 +#define SOCAL_POOL_MASK_F_CTL 0x007000 +#define SOCAL_POOL_MASK_SEQ_ID 0x000800 +#define SOCAL_POOL_MASK_D_CTL 0x000400 +#define SOCAL_POOL_MASK_SEQ_CNT 0x000300 +#define SOCAL_POOL_MASK_OX_ID 0x0000f0 +#define SOCAL_POOL_MASK_PARAM 0x00000f + +typedef struct { + socal_hdr shdr; + u32 pool_id; + u32 header_mask; + u32 buf_size; + u32 entries; + u8 xxx1[8]; + fc_hdr fchdr; + u8 count; + u8 type; + u8 flags; + u8 seqno; +} socal_pool_req; + +/* }}} */ + +/* Now our software structures and constants we use to drive the beast {{{ */ + +#define SOCAL_CQ_REQ0_SIZE 4 +#define SOCAL_CQ_REQ1_SIZE 256 +#define SOCAL_CQ_RSP0_SIZE 8 +#define SOCAL_CQ_RSP1_SIZE 4 +#define SOCAL_CQ_RSP2_SIZE 4 + +#define SOCAL_SOLICITED_RSP_Q 0 +#define SOCAL_SOLICITED_BAD_RSP_Q 1 +#define SOCAL_UNSOLICITED_RSP_Q 2 + +struct socal; + +typedef struct { + /* This must come first */ + fc_channel fc; + struct socal *s; + u16 flags; + u16 mask; +} socal_port; + +typedef struct { + socal_hw_cq *hw_cq; /* Related XRAM cq */ + socal_req *pool; + u8 in; + u8 out; + u8 last; + u8 seqno; +} socal_cq; + +struct socal { + socal_port port[2]; /* Every SOCAL has one or two FC ports */ + socal_cq req[4]; /* Request CQs */ + socal_cq rsp[4]; /* Response CQs */ + int socal_no; + struct socal_regs *regs; + u8 *xram; + u8 *eeprom; + fc_wwn wwn; + u32 imask; /* Our copy of regs->imask */ + u32 cfg; /* Our copy of regs->cfg */ + char serv_params[80]; + struct socal *next; + int curr_port; /* Which port will have priority to fcp_queue_empty */ +}; + +/* }}} */ + +#endif /* !(__SOCAL_H) */ diff -ur --new-file old/linux/drivers/isdn/Config.in new/linux/drivers/isdn/Config.in --- old/linux/drivers/isdn/Config.in Tue Dec 29 20:29:54 1998 +++ new/linux/drivers/isdn/Config.in Tue Mar 16 01:11:29 1999 @@ -39,7 +39,8 @@ bool 'HiSax Support for Niccy PnP/PCI card' CONFIG_HISAX_NICCY if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then - bool 'HiSax Support for Am7930' CONFIG_HISAX_AMD7930 + bool 'HiSax Support for SPARC Am7930' CONFIG_HISAX_AMD7930 + bool 'HiSax Support for SPARC DBRI' CONFIG_HISAX_DBRI fi fi fi diff -ur --new-file old/linux/drivers/isdn/act2000/act2000.h new/linux/drivers/isdn/act2000/act2000.h --- old/linux/drivers/isdn/act2000/act2000.h Thu Apr 2 02:20:57 1998 +++ new/linux/drivers/isdn/act2000/act2000.h Mon May 10 22:00:10 1999 @@ -213,7 +213,7 @@ char regname[35]; /* Name used for request_region */ } act2000_card; -extern act2000_card *cards; +extern act2000_card *actcards; extern __inline__ void act2000_schedule_tx(act2000_card *card) { diff -ur --new-file old/linux/drivers/isdn/act2000/module.c new/linux/drivers/isdn/act2000/module.c --- old/linux/drivers/isdn/act2000/module.c Thu Apr 2 02:20:57 1998 +++ new/linux/drivers/isdn/act2000/module.c Mon May 10 22:00:10 1999 @@ -57,7 +57,7 @@ }; #define ISA_NRPORTS (sizeof(isa_ports)/sizeof(unsigned short)) -act2000_card *cards = (act2000_card *) NULL; +act2000_card *actcards = (act2000_card *) NULL; /* Parameters to be set by insmod */ static int act_bus = 0; @@ -589,7 +589,7 @@ static inline act2000_card * act2000_findcard(int driverid) { - act2000_card *p = cards; + act2000_card *p = actcards; while (p) { if (p->myid == driverid) @@ -714,8 +714,8 @@ card->bus = bus; card->port = port; card->irq = irq; - card->next = cards; - cards = card; + card->next = actcards; + actcards = card; } /* @@ -805,9 +805,9 @@ bus); } } - if (!cards) + if (!actcards) return 1; - p = cards; + p = actcards; while (p) { initialized = 0; if (!p->interface.statcallb) { @@ -870,9 +870,9 @@ kfree(p); p = q->next; } else { - cards = p->next; + actcards = p->next; kfree(p); - p = cards; + p = actcards; } failed++; } @@ -890,9 +890,9 @@ act2000_init(void) { printk(KERN_INFO "%s\n", DRIVERNAME); - if (!cards) + if (!actcards) act2000_addcard(act_bus, act_port, act_irq, act_id); - if (!cards) + if (!actcards) printk(KERN_INFO "act2000: No cards defined yet\n"); /* No symbols to export, hide all symbols */ EXPORT_NO_SYMBOLS; @@ -903,14 +903,14 @@ void cleanup_module(void) { - act2000_card *card = cards; + act2000_card *card = actcards; act2000_card *last; while (card) { unregister_card(card); del_timer(&card->ptimer); card = card->next; } - card = cards; + card = actcards; while (card) { last = card; card = card->next; diff -ur --new-file old/linux/drivers/isdn/hisax/Makefile new/linux/drivers/isdn/hisax/Makefile --- old/linux/drivers/isdn/hisax/Makefile Thu Apr 2 02:20:57 1998 +++ new/linux/drivers/isdn/hisax/Makefile Tue Mar 16 01:11:29 1999 @@ -108,8 +108,10 @@ HFC_2BDS0 := hfc_2bds0.o endif ifeq ($(CONFIG_HISAX_AMD7930),y) - O_OBJS += amd7930.o - RAWHDLC_OBJ := rawhdlc.o + RAWHDLC_OBJ := foreign.o rawhdlc.o +endif +ifeq ($(CONFIG_HISAX_DBRI),y) + RAWHDLC_OBJ := foreign.o rawhdlc.o endif ifeq ($(CONFIG_HISAX_NICCY),y) diff -ur --new-file old/linux/drivers/isdn/hisax/config.c new/linux/drivers/isdn/hisax/config.c --- old/linux/drivers/isdn/hisax/config.c Mon Jan 4 20:37:29 1999 +++ new/linux/drivers/isdn/hisax/config.c Tue Mar 16 01:11:30 1999 @@ -193,6 +193,13 @@ #define DEFAULT_CFG {12,0x3e0,0,0} #endif +#ifdef CONFIG_HISAX_DBRI +#undef DEFAULT_CARD +#undef DEFAULT_CFG +#define DEFAULT_CARD ISDN_CTYPE_DBRI +#define DEFAULT_CFG {0,0x0,0,0} +#endif + #ifdef CONFIG_HISAX_NICCY #undef DEFAULT_CARD #undef DEFAULT_CFG @@ -486,6 +493,7 @@ case ISDN_CTYPE_ELSA_PCI: case ISDN_CTYPE_NETJET: case ISDN_CTYPE_AMD7930: + case ISDN_CTYPE_DBRI: break; } } diff -ur --new-file old/linux/drivers/isdn/hisax/foreign.c new/linux/drivers/isdn/hisax/foreign.c --- old/linux/drivers/isdn/hisax/foreign.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/isdn/hisax/foreign.c Tue Mar 16 01:11:30 1999 @@ -0,0 +1,780 @@ +/* $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 -ur --new-file old/linux/drivers/isdn/hisax/foreign.h new/linux/drivers/isdn/hisax/foreign.h --- old/linux/drivers/isdn/hisax/foreign.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/isdn/hisax/foreign.h Tue Mar 16 01:11:30 1999 @@ -0,0 +1,193 @@ +/* $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 -ur --new-file old/linux/drivers/isdn/hisax/hisax.h new/linux/drivers/isdn/hisax/hisax.h --- old/linux/drivers/isdn/hisax/hisax.h Thu Apr 2 02:20:58 1998 +++ new/linux/drivers/isdn/hisax/hisax.h Tue Mar 16 01:11:30 1999 @@ -397,7 +397,8 @@ u_char s_state; }; -struct amd7930_hw { +struct foreign_hw { + int doHDLCprocessing; u_char *tx_buff; u_char *rv_buff; int rv_buff_in; @@ -437,7 +438,7 @@ struct hscx_hw hscx; struct hfcB_hw hfc; struct tiger_hw tiger; - struct amd7930_hw amd7930; + struct foreign_hw foreign; } hw; }; @@ -640,6 +641,7 @@ struct njet_hw njet; struct hfcD_hw hfcD; struct ix1_hw niccy; + struct foreign_interface *foreign; } hw; int myid; isdn_if iif; @@ -710,8 +712,9 @@ #define ISDN_CTYPE_SEDLBAUER_PCMCIA 22 #define ISDN_CTYPE_AMD7930 23 #define ISDN_CTYPE_NICCY 24 +#define ISDN_CTYPE_DBRI 25 -#define ISDN_CTYPE_COUNT 24 +#define ISDN_CTYPE_COUNT 25 #ifdef ISDN_CHIP_ISAC #undef ISDN_CHIP_ISAC @@ -856,12 +859,18 @@ #define CARD_NICCY 0 #endif +#ifdef CONFIG_HISAX_DBRI +#define CARD_DBRI (1 << ISDN_CTYPE_DBRI) +#else +#define CARD_DBRI 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_NICCY | CARD_DBRI) #define TEI_PER_CARD 0 diff -ur --new-file old/linux/drivers/isdn/hisax/isdnl1.c new/linux/drivers/isdn/hisax/isdnl1.c --- old/linux/drivers/isdn/hisax/isdnl1.c Sat Oct 31 19:37:14 1998 +++ new/linux/drivers/isdn/hisax/isdnl1.c Tue Mar 16 01:11:30 1999 @@ -144,8 +144,8 @@ extern int setup_t163c(struct IsdnCard *card); #endif -#if CARD_AMD7930 -extern int setup_amd7930(struct IsdnCard *card); +#if CARD_AMD7930 || CARD_DBRI +extern int setup_foreign(struct IsdnCard *card); #endif #if CARD_NICCY @@ -163,7 +163,7 @@ "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" + "AMD 7930", "NICCY", "DBRI" }; extern struct IsdnCard cards[]; @@ -366,7 +366,7 @@ void debugl1(struct IsdnCardState *cs, char *msg) { - char tmp[256], tm[32]; + char tmp[1024], tm[32]; jiftime(tm, jiffies); sprintf(tmp, "%s Card %d %s\n", tm, cs->cardnr + 1, msg); @@ -842,9 +842,10 @@ ret = setup_niccy(card); break; #endif -#if CARD_AMD7930 +#if CARD_AMD7930 || CARD_DBRI case ISDN_CTYPE_AMD7930: - ret = setup_amd7930(card); + case ISDN_CTYPE_DBRI: + ret = setup_foreign(card); break; #endif default: diff -ur --new-file old/linux/drivers/macintosh/Makefile new/linux/drivers/macintosh/Makefile --- old/linux/drivers/macintosh/Makefile Sun Nov 15 19:51:46 1998 +++ new/linux/drivers/macintosh/Makefile Thu Apr 29 21:53:48 1999 @@ -16,7 +16,7 @@ M_OBJS := ifndef CONFIG_MBX -L_OBJS := via-cuda.o nvram.o macio-adb.o via-pmu.o mediabay.o +L_OBJS := via-cuda.o macio-adb.o via-pmu.o mediabay.o LX_OBJS := adb.o endif @@ -25,6 +25,14 @@ else ifeq ($(CONFIG_MAC_SERIAL),m) M_OBJS += macserial.o + endif +endif + +ifeq ($(CONFIG_NVRAM),y) + L_OBJS += nvram.o +else + ifeq ($(CONFIG_NVRAM),m) + M_OBJS += nvram.o endif endif diff -ur --new-file old/linux/drivers/macintosh/adb.c new/linux/drivers/macintosh/adb.c --- old/linux/drivers/macintosh/adb.c Sun Nov 15 19:51:46 1998 +++ new/linux/drivers/macintosh/adb.c Thu Apr 29 21:53:48 1999 @@ -3,7 +3,19 @@ * and the /dev/adb device on macintoshes. * * Copyright (C) 1996 Paul Mackerras. + * + * Modified to declare controllers as structures, added + * client notification of bus reset and handles PowerBook + * sleep, by Benjamin Herrenschmidt. + * + * To do: + * + * - /proc/adb to list the devices and infos + * - more /dev/adb to allow userland to receive the + * flow of auto-polling datas from a given device. */ + +#include #include #include #include @@ -20,12 +32,23 @@ #include #include +EXPORT_SYMBOL(adb_controller); +EXPORT_SYMBOL(adb_client_list); EXPORT_SYMBOL(adb_hardware); +struct adb_controller *adb_controller = NULL; +struct notifier_block *adb_client_list = NULL; enum adb_hw adb_hardware = ADB_NONE; -int (*adb_send_request)(struct adb_request *req, int sync); -int (*adb_autopoll)(int devs); -int (*adb_reset_bus)(void); + +#ifdef CONFIG_PMAC_PBOOK +static int adb_notify_sleep(struct notifier_block *, unsigned long, void *); +static struct notifier_block adb_sleep_notifier = { + adb_notify_sleep, + NULL, + 0 +}; +#endif + static int adb_scan_bus(void); static struct adb_handler { @@ -34,13 +57,6 @@ int handler_id; } adb_handler[16]; -__openfirmware - -static int adb_nodev(void) -{ - return -1; -} - #if 0 static void printADBreply(struct adb_request *req) { @@ -60,8 +76,6 @@ int devmask = 0; struct adb_request req; - adb_reset_bus(); /* reset ADB bus */ - /* assumes adb_handler[] is all zeroes at this point */ for (i = 1; i < 16; i++) { /* see if there is anything at address i */ @@ -146,22 +160,96 @@ void adb_init(void) { - adb_send_request = (void *) adb_nodev; - adb_autopoll = (void *) adb_nodev; - adb_reset_bus = adb_nodev; if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) ) return; + via_cuda_init(); via_pmu_init(); macio_adb_init(); - if (adb_hardware == ADB_NONE) + + if (adb_controller == NULL) printk(KERN_WARNING "Warning: no ADB interface detected\n"); - else { - int devs = adb_scan_bus(); - adb_autopoll(devs); + else + { + adb_hardware = adb_controller->kind; +#ifdef CONFIG_PMAC_PBOOK + notifier_chain_register(&sleep_notifier_list, + &adb_sleep_notifier); +#endif /* CONFIG_PMAC_PBOOK */ + + adb_reset_bus(); } } + +#ifdef CONFIG_PMAC_PBOOK +/* + * notify clients before sleep and reset bus afterwards + */ +int +adb_notify_sleep(struct notifier_block *this, unsigned long code, void *x) +{ + int ret; + + switch (code) { + case PBOOK_SLEEP: + ret = notifier_call_chain(&adb_client_list, ADB_MSG_POWERDOWN, NULL); + if (ret & NOTIFY_STOP_MASK) + return -EBUSY; + case PBOOK_WAKE: + adb_reset_bus(); + break; + } + return NOTIFY_DONE; +} +#endif /* CONFIG_PMAC_PBOOK */ + +int +adb_reset_bus(void) +{ + int ret, devs; + unsigned long flags; + + if (adb_controller == NULL) + return -ENXIO; + + ret = notifier_call_chain(&adb_client_list, ADB_MSG_PRE_RESET, NULL); + if (ret & NOTIFY_STOP_MASK) + return -EBUSY; + + save_flags(flags); + cli(); + memset(adb_handler, 0, sizeof(adb_handler)); + restore_flags(flags); + + if (adb_controller->reset_bus) + ret = adb_controller->reset_bus(); + else + ret = 0; + + if (!ret) + { + devs = adb_scan_bus(); + if (adb_controller->autopoll) + adb_controller->autopoll(devs); + } + + ret = notifier_call_chain(&adb_client_list, ADB_MSG_POST_RESET, NULL); + if (ret & NOTIFY_STOP_MASK) + return -EBUSY; + + return 1; +} + +void +adb_poll(void) +{ + if ((adb_controller == NULL)||(adb_controller->poll == NULL)) + return; + adb_controller->poll(); +} + + int adb_request(struct adb_request *req, void (*done)(struct adb_request *), int flags, int nbytes, ...) @@ -170,22 +258,34 @@ int i; struct adb_request sreq; + if ((adb_controller == NULL) || (adb_controller->send_request == NULL)) + return -ENXIO; + if (nbytes < 1) + return -EINVAL; + if (req == NULL) { req = &sreq; flags |= ADBREQ_SYNC; } - req->nbytes = nbytes; + req->nbytes = nbytes+1; req->done = done; req->reply_expected = flags & ADBREQ_REPLY; + req->data[0] = ADB_PACKET; va_start(list, nbytes); for (i = 0; i < nbytes; ++i) - req->data[i] = va_arg(list, int); + req->data[i+1] = va_arg(list, int); va_end(list); - return adb_send_request(req, flags & ADBREQ_SYNC); + + return adb_controller->send_request(req, flags & ADBREQ_SYNC); } -/* Ultimately this should return the number of devices with - the given default id. */ + /* Ultimately this should return the number of devices with + the given default id. + And it does it now ! Note: changed behaviour: This function + will now register if default_id _and_ handler_id both match + but handler_id can be left to 0 to match with default_id only. + When handler_id is set, this function will try to adjust + the handler_id id it doesn't match. */ int adb_register(int default_id, int handler_id, struct adb_ids *ids, void (*handler)(unsigned char *, int, struct pt_regs *, int)) @@ -194,18 +294,20 @@ ids->nids = 0; for (i = 1; i < 16; i++) { - if (adb_handler[i].original_address == default_id) { + if ((adb_handler[i].original_address == default_id) && + (!handler_id || (handler_id == adb_handler[i].handler_id) || + adb_try_handler_change(i, handler_id))) { if (adb_handler[i].handler != 0) { printk(KERN_ERR "Two handlers for ADB device %d\n", default_id); - return 0; + continue; } adb_handler[i].handler = handler; ids->id[ids->nids++] = i; } } - return 1; + return ids->nids; } void @@ -226,6 +328,41 @@ } } +/* Try to change handler to new_id. Will return 1 if successful */ +int +adb_try_handler_change(int address, int new_id) +{ + struct adb_request req; + + if (adb_handler[address].handler_id == new_id) + return 1; + adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1, + ADB_READREG(address,3)); + if (req.reply_len < 2) + return 0; + adb_request(&req, NULL, ADBREQ_SYNC, 3, + ADB_WRITEREG(address, 3), req.reply[1] & 0xF0, new_id); + adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1, + ADB_READREG(address, 3)); + if (req.reply_len < 2) + return 0; + if (req.reply[2] != new_id) + return 0; + adb_handler[address].handler_id = req.reply[2]; + + return 1; +} + +int +adb_get_infos(int address, int *original_address, int *handler_id) +{ + *original_address = adb_handler[address].original_address; + *handler_id = adb_handler[address].handler_id; + + return (*original_address != 0); +} + + /* * /dev/adb device driver. */ @@ -275,7 +412,7 @@ { struct adbdev_state *state; - if (MINOR(inode->i_rdev) > 0 || adb_hardware == ADB_NONE) + if (MINOR(inode->i_rdev) > 0 || (adb_controller == NULL)/*adb_hardware == ADB_NONE*/) return -ENXIO; state = kmalloc(sizeof(struct adbdev_state), GFP_KERNEL); if (state == 0) @@ -377,7 +514,7 @@ static ssize_t adb_write(struct file *file, const char *buf, size_t count, loff_t *ppos) { - int ret, i; + int ret/*, i*/; struct adbdev_state *state = file->private_data; struct adb_request *req; @@ -396,36 +533,26 @@ req->done = adb_write_done; req->arg = (void *) state; req->complete = 0; - + ret = -EFAULT; if (copy_from_user(req->data, buf, count)) goto out; atomic_inc(&state->n_pending); - switch (adb_hardware) { - case ADB_NONE: - ret = -ENXIO; - break; - case ADB_VIACUDA: - req->reply_expected = 1; - ret = cuda_send_request(req); - break; - case ADB_VIAPMU: - if (req->data[0] != ADB_PACKET) { - ret = pmu_send_request(req); - break; - } - /* else fall through */ - default: - ret = -EINVAL; - if (req->data[0] != ADB_PACKET) - break; - for (i = 0; i < req->nbytes-1; ++i) - req->data[i] = req->data[i+1]; - req->nbytes--; - req->reply_expected = ((req->data[0] & 0xc) == 0xc); - ret = adb_send_request(req, 0); - break; + + /* Special case for ADB_BUSRESET request, all others are sent to + the controller */ + if ((req->data[0] == ADB_PACKET)&&(count > 1) + &&(req->data[1] == ADB_BUSRESET)) + ret = adb_reset_bus(); + else + { + req->reply_expected = ((req->data[1] & 0xc) == 0xc); + + if (adb_controller && adb_controller->send_request) + ret = adb_controller->send_request(req, 0); + else + ret = -ENXIO; } if (ret != 0) { diff -ur --new-file old/linux/drivers/macintosh/mac_keyb.c new/linux/drivers/macintosh/mac_keyb.c --- old/linux/drivers/macintosh/mac_keyb.c Sun Nov 15 19:51:46 1998 +++ new/linux/drivers/macintosh/mac_keyb.c Thu Apr 29 21:53:48 1999 @@ -7,6 +7,27 @@ * (see that file for its authors and contributors). * * Copyright (C) 1996 Paul Mackerras. + * + * Adapted to ADB changes and support for more devices by + * Benjamin Herrenschmidt. Adapted from code in MkLinux + * and reworked. + * + * Supported devices: + * + * - Standard 1 button mouse + * - All standard Apple Extended protocol (handler ID 4) + * mice & trackballs + * - PowerBook Trackpad (default setup: enable tapping) + * - MicroSpeed mouse & trackball (needs testing) + * - CH Products Trackball Pro (needs testing) + * - Contour Design (Contour Mouse) + * - Hunter digital (NoHandsMouse) + * - Kensignton TurboMouse 5 (needs testing) + * + * To do: + * + * Improve Kensignton support, add MacX support as a dynamic + * option (not a compile-time option). */ #include @@ -22,6 +43,7 @@ #include #include #include +#include #include #include @@ -31,6 +53,41 @@ #define KEYB_LEDREG 2 /* register # for leds on ADB keyboard */ #define MOUSE_DATAREG 0 /* reg# for movement/button codes from mouse */ +static int adb_message_handler(struct notifier_block *, unsigned long, void *); +static struct notifier_block mackeyb_adb_notifier = { + adb_message_handler, + NULL, + 0 +}; + +/* this map indicates which keys shouldn't autorepeat. */ +static unsigned char dont_repeat[128] = { + 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, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* esc...option */ + 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, /* fn, num lock */ + 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, 1, 0, 0, 0, 0, /* scroll lock */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; + +/* Simple translation table for the SysRq keys */ + +#ifdef CONFIG_MAGIC_SYSRQ +unsigned char mackbd_sysrq_xlate[128] = + "asdfhgzxcv\000bqwer" /* 0x00 - 0x0f */ + "yt123465=97-80o]" /* 0x10 - 0x1f */ + "u[ip\rlj'k;\\,/nm." /* 0x20 - 0x2f */ + "\t `\177\000\033\000\000\000\000\000\000\000\000\000\000" + /* 0x30 - 0x3f */ + "\000\000\000*\000+\000\000\000\000\000/\r\000-\000" + /* 0x40 - 0x4f */ + "\000\0000123456789\000\000\000" /* 0x50 - 0x5f */ + "\205\206\207\203\210\211\000\213\000\215\000\000\000\000\000\212\000\214"; + /* 0x60 - 0x6f */ +#endif + static u_short macplain_map[NR_KEYS] __initdata = { 0xfb61, 0xfb73, 0xfb64, 0xfb66, 0xfb68, 0xfb67, 0xfb7a, 0xfb78, 0xfb63, 0xfb76, 0xf200, 0xfb62, 0xfb71, 0xfb77, 0xfb65, 0xfb72, @@ -169,11 +226,20 @@ static struct timer_list repeat_timer = { NULL, NULL, 0, 0, kbd_repeat }; static int last_keycode; +static void mackeyb_probe(void); + static void keyboard_input(unsigned char *, int, struct pt_regs *, int); static void input_keycode(int, int); static void leds_done(struct adb_request *); static void mac_put_queue(int); +static void buttons_input(unsigned char *, int, struct pt_regs *, int); + +static void init_trackpad(int id); +static void init_trackball(int id); +static void init_turbomouse(int id); +static void init_microspeed(int id); + #ifdef CONFIG_ADBMOUSE /* XXX: Hook for mouse driver */ void (*adb_mouse_interrupt_hook)(unsigned char *, int); @@ -187,22 +253,23 @@ extern struct kbd_struct kbd_table[]; extern struct wait_queue * keypress_wait; -extern void handle_scancode(unsigned char); +extern void handle_scancode(unsigned char, int); static struct adb_ids keyboard_ids; static struct adb_ids mouse_ids; +static struct adb_ids buttons_ids; -/* this map indicates which keys shouldn't autorepeat. */ -static unsigned char dont_repeat[128] = { - 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, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* esc...option */ - 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, /* num lock */ - 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, 1, 0, 0, 0, 0, /* scroll lock */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; +/* Kind of mouse */ +#define ADBMOUSE_STANDARD_100 0 /* Standard 100cpi mouse (handler 1) */ +#define ADBMOUSE_STANDARD_200 1 /* Standard 200cpi mouse (handler 2) */ +#define ADBMOUSE_EXTENDED 2 /* Apple Extended mouse (handler 4) */ +#define ADBMOUSE_TRACKBALL 3 /* TrackBall (handler 4) */ +#define ADBMOUSE_TRACKPAD 4 /* Apple's PowerBook trackpad (handler 4) */ +#define ADBMOUSE_TURBOMOUSE5 5 /* Turbomouse 5 (previously req. mousehack) */ +#define ADBMOUSE_MICROSPEED 6 /* Microspeed mouse (&trackball ?), MacPoint */ +#define ADBMOUSE_TRACKBALLPRO 7 /* Trackball Pro (special buttons) */ + +static int adb_mouse_kinds[16]; __openfirmware @@ -216,11 +283,6 @@ return -EINVAL; } -int mackbd_pretranslate(unsigned char scancode, char raw_mode) -{ - return 1; -} - int mackbd_translate(unsigned char keycode, unsigned char *keycodep, char raw_mode) { @@ -268,6 +330,10 @@ /* on the powerbook 3400, the power key gives code 0x7e */ if (keycode == 0x7e) keycode = 0x7f; + /* remap the "Fn" key of the PowerBook G3 Series to 0x48 + to avoid conflict with button emulation */ + if (keycode == 0x3f) + keycode = 0x48; if (!repeat) del_timer(&repeat_timer); @@ -320,8 +386,8 @@ switch (keycode) { /*case 0xb9:*/ case 0x39: - handle_scancode(0x39); - handle_scancode(0xb9); + handle_scancode(0x39, 1); + handle_scancode(0x39, 0); mark_bh(KEYBOARD_BH); return; case 0x47: @@ -331,7 +397,7 @@ } } - handle_scancode(keycode + up_flag); + handle_scancode(keycode, !up_flag); } static void @@ -423,6 +489,31 @@ */ struct kbd_struct *kbd; + /* If it's a trackpad, we alias the second button to the first. + NOTE: Apple sends an ADB flush command to the trackpad when + the first (the real) button is released. We could do + this here using async flush requests. + */ + switch (adb_mouse_kinds[(data[0]>>4) & 0xf]) + { + case ADBMOUSE_TRACKPAD: + data[1] = (data[1] & 0x7f) | ((data[1] & data[2]) & 0x80); + data[2] = data[2] | 0x80; + break; + case ADBMOUSE_MICROSPEED: + data[1] = (data[1] & 0x7f) | ((data[3] & 0x01) << 7); + data[2] = (data[2] & 0x7f) | ((data[3] & 0x02) << 6); + data[3] = (data[3] & 0x77) | ((data[3] & 0x04) << 5) + | (data[3] & 0x08); + break; + case ADBMOUSE_TRACKBALLPRO: + data[1] = (data[1] & 0x7f) | (((data[3] & 0x04) << 5) + & ((data[3] & 0x08) << 4)); + data[2] = (data[2] & 0x7f) | ((data[3] & 0x01) << 7); + data[3] = (data[3] & 0x77) | ((data[3] & 0x02) << 6); + break; + } + if (adb_mouse_interrupt_hook) adb_mouse_interrupt_hook(data, nb); @@ -450,7 +541,7 @@ } /* Macintosh 3-button mouse (handler 4). */ - if (nb == 4) { + if (nb >= 4) { static unsigned char uch_ButtonStateThird = 0x80; unsigned char uchButtonThird; @@ -467,6 +558,64 @@ } #endif /* CONFIG_ADBMOUSE */ +/* XXX Needs to get rid of this, see comments in pmu.c */ +extern int backlight_level; + +static void +buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int autopoll) +{ + /* + * XXX: Where is the contrast control for the passive? + * -- Cort + */ + + /* Ignore data from register other than 0 */ + if ((adb_hardware != ADB_VIAPMU) || (data[0] & 0x3) || (nb < 2)) + return; + + switch (data[1]&0xf ) + { + /* mute */ + case 0x8: + /* down event */ + if ( data[1] == (data[1]&0xf) ) { + } + break; + /* contrast decrease */ + case 0x7: + /* down event */ + if ( data[1] == (data[1]&0xf) ) { + } + break; + /* contrast increase */ + case 0x6: + /* down event */ + if ( data[1] == (data[1]&0xf) ) { + } + break; + /* brightness decrease */ + case 0xa: + /* down event */ + if ( data[1] == (data[1]&0xf) ) { + if (backlight_level > 2) + pmu_set_brightness(backlight_level-2); + else + pmu_set_brightness(0); + } + break; + /* brightness increase */ + case 0x9: + /* down event */ + if ( data[1] == (data[1]&0xf) ) { + if (backlight_level < 0x1e) + pmu_set_brightness(backlight_level+2); + else + pmu_set_brightness(0x1f); + } + break; + } +} + /* Map led flags as defined in kbd_kern.h to bits for Apple keyboard. */ static unsigned char mac_ledmap[8] = { 0, /* none */ @@ -527,9 +676,6 @@ __initfunc(void mackbd_init_hw(void)) { - struct adb_request req; - int i; - if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) ) return; @@ -545,66 +691,290 @@ #ifdef CONFIG_ADBMOUSE /* initialize mouse interrupt hook */ adb_mouse_interrupt_hook = NULL; +#endif + + led_request.complete = 1; + + mackeyb_probe(); + + notifier_chain_register(&adb_client_list, &mackeyb_adb_notifier); +} + +static int +adb_message_handler(struct notifier_block *this, unsigned long code, void *x) +{ + switch (code) { + case ADB_MSG_PRE_RESET: + case ADB_MSG_POWERDOWN: + /* Add unregister_keyboard when merging with Paul Mackerras */ + while(!led_request.complete) + adb_poll(); + break; + + case ADB_MSG_POST_RESET: + mackeyb_probe(); + break; + } + return NOTIFY_DONE; +} + +static void +mackeyb_probe(void) +{ + struct adb_request req; + int i; - adb_register(ADB_MOUSE, 1, &mouse_ids, mouse_input); +#ifdef CONFIG_ADBMOUSE + adb_register(ADB_MOUSE, 0, &mouse_ids, mouse_input); #endif /* CONFIG_ADBMOUSE */ - adb_register(ADB_KEYBOARD, 5, &keyboard_ids, keyboard_input); + adb_register(ADB_KEYBOARD, 0, &keyboard_ids, keyboard_input); + adb_register(0x07, 0x1F, &buttons_ids, buttons_input); - for(i = 0; i < keyboard_ids.nids; i++) { - /* turn off all leds */ - adb_request(&req, NULL, ADBREQ_SYNC, 3, - ADB_WRITEREG(keyboard_ids.id[i], KEYB_LEDREG), 0xff, 0xff); - } + for (i = 0; i < keyboard_ids.nids; i++) { + int id = keyboard_ids.id[i]; - /* get the keyboard to send separate codes for - left and right shift, control, option keys. */ - for(i = 0;i < keyboard_ids.nids; i++) { - /* get the keyboard to send separate codes for - left and right shift, control, option keys. */ - adb_request(&req, NULL, ADBREQ_SYNC, 3, - ADB_WRITEREG(keyboard_ids.id[i], 3), 0, 3); + /* turn off all leds */ + adb_request(&req, NULL, ADBREQ_SYNC, 3, + ADB_WRITEREG(id, KEYB_LEDREG), 0xff, 0xff); + + /* Enable full feature set of the keyboard + ->get it to send separate codes for left and right shift, + control, option keys */ + if (adb_try_handler_change(id, 5)) + printk("ADB keyboard at %d, handler set to 5\n", id); + else if (adb_try_handler_change(id, 3)) + printk("ADB keyboard at %d, handler set to 3\n", id); + else + printk("ADB keyboard at %d, handler 1\n", id); } - led_request.complete = 1; + /* Try to switch all mice to handler 4, or 2 for three-button + mode and full resolution. */ + for (i = 0; i < mouse_ids.nids; i++) { + int id = mouse_ids.id[i]; + if (adb_try_handler_change(id, 4)) { + printk("ADB mouse at %d, handler set to 4", id); + adb_mouse_kinds[id] = ADBMOUSE_EXTENDED; + } + else if (adb_try_handler_change(id, 2)) { + printk("ADB mouse at %d, handler set to 2", id); + adb_mouse_kinds[id] = ADBMOUSE_STANDARD_200; + } + else if (adb_try_handler_change(id, 0x2F)) { + printk("ADB mouse at %d, handler set to 0x2F", id); + adb_mouse_kinds[id] = ADBMOUSE_MICROSPEED; + } + else if (adb_try_handler_change(id, 0x42)) { + printk("ADB mouse at %d, handler set to 0x42", id); + adb_mouse_kinds[id] = ADBMOUSE_TRACKBALLPRO; + } + else if (adb_try_handler_change(id, 0x66)) { + printk("ADB mouse at %d, handler set to 0x66", id); + adb_mouse_kinds[id] = ADBMOUSE_MICROSPEED; + } + else if (adb_try_handler_change(id, 0x5F)) { + printk("ADB mouse at %d, handler set to 0x5F", id); + adb_mouse_kinds[id] = ADBMOUSE_MICROSPEED; + } + else { + printk("ADB mouse at %d, handler 1", id); + adb_mouse_kinds[id] = ADBMOUSE_STANDARD_100; + } - /* Try to switch the mouse (id 3) to handler 4, for three-button - mode. (0x20 is Service Request Enable, 0x03 is Device ID). */ - for(i = 0; i < mouse_ids.nids; i++) { - adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1, - ADB_READREG(mouse_ids.id[i], 1)); + if ((adb_mouse_kinds[id] == ADBMOUSE_TRACKBALLPRO) + || (adb_mouse_kinds[id] == ADBMOUSE_MICROSPEED)) { + init_microspeed(id); + } else if (adb_mouse_kinds[id] == ADBMOUSE_EXTENDED) { + /* + * Register 1 is usually used for device + * identification. Here, we try to identify + * a known device and call the appropriate + * init function. + */ + adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1, + ADB_READREG(id, 1)); + + if ((req.reply_len) && + (req.reply[1] == 0x9a) && (req.reply[2] == 0x21)) + init_trackball(id); + else if ((req.reply_len >= 4) && + (req.reply[1] == 0x74) && (req.reply[2] == 0x70) && + (req.reply[3] == 0x61) && (req.reply[4] == 0x64)) + init_trackpad(id); + else if ((req.reply_len >= 4) && + (req.reply[1] == 0x4b) && (req.reply[2] == 0x4d) && + (req.reply[3] == 0x4c) && (req.reply[4] == 0x31)) + init_turbomouse(id); + } + printk("\n"); + } +} - if ((req.reply_len) && - (req.reply[1] == 0x9a) && (req.reply[2] == 0x21)) { +static void +init_trackpad(int id) +{ + struct adb_request req; + unsigned char r1_buffer[8]; + + printk(" (trackpad)"); + + adb_mouse_kinds[id] = ADBMOUSE_TRACKPAD; + + adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1, + ADB_READREG(id,1)); + if (req.reply_len < 8) + printk("bad length for reg. 1\n"); + else + { + memcpy(r1_buffer, &req.reply[1], 8); + adb_request(&req, NULL, ADBREQ_SYNC, 9, + ADB_WRITEREG(id,1), + r1_buffer[0], + r1_buffer[1], + r1_buffer[2], + r1_buffer[3], + r1_buffer[4], + r1_buffer[5], + 0x0d, /*r1_buffer[6],*/ + r1_buffer[7]); + + adb_request(&req, NULL, ADBREQ_SYNC, 9, + ADB_WRITEREG(id,2), + 0x99, + 0x94, + 0x19, + 0xff, + 0xb2, + 0x8a, + 0x1b, + 0x50); + + adb_request(&req, NULL, ADBREQ_SYNC, 9, + ADB_WRITEREG(id,1), + r1_buffer[0], + r1_buffer[1], + r1_buffer[2], + r1_buffer[3], + r1_buffer[4], + r1_buffer[5], + 0x03, /*r1_buffer[6],*/ + r1_buffer[7]); + } +} - printk("aha, trackball found at %d\n", mouse_ids.id[i]); +static void +init_trackball(int id) +{ + struct adb_request req; + + printk(" (trackball)"); + + adb_mouse_kinds[id] = ADBMOUSE_TRACKBALL; - adb_request(&req, NULL, ADBREQ_SYNC, 3, - ADB_WRITEREG(mouse_ids.id[i], 3), 0x63, 4 ); + adb_request(&req, NULL, ADBREQ_SYNC, 3, + ADB_WRITEREG(id,1), 00,0x81); - adb_request(&req, NULL, ADBREQ_SYNC, 3, - ADB_WRITEREG(mouse_ids.id[i],1), 00,0x81); + adb_request(&req, NULL, ADBREQ_SYNC, 3, + ADB_WRITEREG(id,1), 01,0x81); - adb_request(&req, NULL, ADBREQ_SYNC, 3, - ADB_WRITEREG(mouse_ids.id[i],1), 01,0x81); + adb_request(&req, NULL, ADBREQ_SYNC, 3, + ADB_WRITEREG(id,1), 02,0x81); - adb_request(&req, NULL, ADBREQ_SYNC, 3, - ADB_WRITEREG(mouse_ids.id[i],1), 02,0x81); + adb_request(&req, NULL, ADBREQ_SYNC, 3, + ADB_WRITEREG(id,1), 03,0x38); - adb_request(&req, NULL, ADBREQ_SYNC, 3, - ADB_WRITEREG(mouse_ids.id[i],1), 03,0x38); + adb_request(&req, NULL, ADBREQ_SYNC, 3, + ADB_WRITEREG(id,1), 00,0x81); - adb_request(&req, NULL, ADBREQ_SYNC, 3, - ADB_WRITEREG(mouse_ids.id[i],1), 00,0x81); + adb_request(&req, NULL, ADBREQ_SYNC, 3, + ADB_WRITEREG(id,1), 01,0x81); - adb_request(&req, NULL, ADBREQ_SYNC, 3, - ADB_WRITEREG(mouse_ids.id[i],1), 01,0x81); + adb_request(&req, NULL, ADBREQ_SYNC, 3, + ADB_WRITEREG(id,1), 02,0x81); - adb_request(&req, NULL, ADBREQ_SYNC, 3, - ADB_WRITEREG(mouse_ids.id[i],1), 02,0x81); + adb_request(&req, NULL, ADBREQ_SYNC, 3, + ADB_WRITEREG(id,1), 03,0x38); +} - adb_request(&req, NULL, ADBREQ_SYNC, 3, - ADB_WRITEREG(mouse_ids.id[i],1), 03,0x38); - } - } +static void +init_turbomouse(int id) +{ + struct adb_request req; + + printk(" (TurboMouse 5)"); + + adb_mouse_kinds[id] = ADBMOUSE_TURBOMOUSE5; + + adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id)); + + adb_request(&req, NULL, ADBREQ_SYNC, 3, + ADB_WRITEREG(id,3), 0x20 | id, 4); + + adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id)); + + adb_request(&req, NULL, ADBREQ_SYNC, 9, + ADB_WRITEREG(id,2), + 0xe7, + 0x8c, + 0, + 0, + 0, + 0xff, + 0xff, + 0x94); + + adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id)); + + adb_request(&req, NULL, ADBREQ_SYNC, 9, + ADB_WRITEREG(id,2), + 0xa5, + 0x14, + 0, + 0, + 0x69, + 0xff, + 0xff, + 0x27); } + +static void +init_microspeed(int id) +{ + struct adb_request req; + + printk(" (Microspeed/MacPoint or compatible)"); + + adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id)); + + /* This will initialize mice using the Microspeed, MacPoint and + other compatible firmware. Bit 12 enables extended protocol. + + Register 1 Listen (4 Bytes) + 0 - 3 Button is mouse (set also for double clicking!!!) + 4 - 7 Button is locking (affects change speed also) + 8 - 11 Button changes speed + 12 1 = Extended mouse mode, 0 = normal mouse mode + 13 - 15 unused 0 + 16 - 23 normal speed + 24 - 31 changed speed + + Register 1 talk holds version and product identification information. + Register 1 Talk (4 Bytes): + 0 - 7 Product code + 8 - 23 undefined, reserved + 24 - 31 Version number + + Speed 0 is max. 1 to 255 set speed in increments of 1/256 of max. + */ + adb_request(&req, NULL, ADBREQ_SYNC, 5, + ADB_WRITEREG(id,1), + 0x20, /* alt speed = 0x20 (rather slow) */ + 0x00, /* norm speed = 0x00 (fastest) */ + 0x10, /* extended protocol, no speed change */ + 0x07); /* all buttons enabled as mouse buttons, no locking */ + + + adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id)); +} + diff -ur --new-file old/linux/drivers/macintosh/macio-adb.c new/linux/drivers/macintosh/macio-adb.c --- old/linux/drivers/macintosh/macio-adb.c Sun Nov 15 19:51:46 1998 +++ new/linux/drivers/macintosh/macio-adb.c Thu Apr 29 21:53:48 1999 @@ -63,9 +63,17 @@ static int macio_adb_send_request(struct adb_request *req, int sync); static int macio_adb_autopoll(int devs); static void macio_adb_poll(void); -static int macio_reset_bus(void); +static int macio_adb_reset_bus(void); static void completed(void); +static struct adb_controller macio_controller = { + ADB_MACIO, + macio_adb_send_request, + macio_adb_autopoll, + macio_adb_reset_bus, + macio_adb_poll +}; + __openfirmware void macio_adb_init(void) @@ -106,10 +114,12 @@ out_8(&adb->autopoll.r, APE); out_8(&adb->intr_enb.r, DFB | TAG); - adb_hardware = ADB_MACIO; - adb_send_request = macio_adb_send_request; - adb_autopoll = macio_adb_autopoll; - adb_reset_bus = macio_reset_bus; + adb_controller = &macio_controller; +// adb_hardware = ADB_MACIO; + +// adb_send_request = macio_adb_send_request; +// adb_autopoll = macio_adb_autopoll; +// adb_reset_bus = macio_reset_bus; } static int macio_adb_autopoll(int devs) @@ -120,7 +130,7 @@ return 0; } -static int macio_reset_bus(void) +static int macio_adb_reset_bus(void) { int timeout = 1000000; @@ -138,7 +148,15 @@ static int macio_adb_send_request(struct adb_request *req, int sync) { unsigned long mflags; - + int i; + + if (req->data[0] != ADB_PACKET) + return -EINVAL; + + for (i = 0; i < req->nbytes - 1; ++i) + req->data[i] = req->data[i+1]; + --req->nbytes; + req->next = 0; req->sent = 0; req->complete = 0; diff -ur --new-file old/linux/drivers/macintosh/macserial.c new/linux/drivers/macintosh/macserial.c --- old/linux/drivers/macintosh/macserial.c Wed Dec 23 18:44:41 1998 +++ new/linux/drivers/macintosh/macserial.c Thu Apr 29 21:53:48 1999 @@ -34,6 +34,8 @@ #include #include #include +#include +#include #ifdef CONFIG_KGDB #include #endif @@ -62,6 +64,8 @@ struct tty_struct zs_ttys[NUM_CHANNELS]; +static int is_powerbook; + #ifdef CONFIG_SERIAL_CONSOLE static struct console sercons; #endif @@ -99,6 +103,10 @@ #undef SERIAL_DEBUG_INTR #undef SERIAL_DEBUG_OPEN #undef SERIAL_DEBUG_FLOW +#undef SERIAL_DEBUG_POWER +#undef SERIAL_DEBUG_THROTTLE +#undef SERIAL_DEBUG_STOP +#undef SERIAL_DEBUG_BAUDS #define RS_STROBE_TIME 10 #define RS_ISR_PASS_LIMIT 256 @@ -106,8 +114,10 @@ #define _INLINE_ inline static void probe_sccs(void); -static void change_speed(struct mac_serial *info); +static void change_speed(struct mac_serial *info, struct termios *old); static void rs_wait_until_sent(struct tty_struct *tty, int timeout); +static void set_scc_power(struct mac_serial * info, int state); +static int setup_scc(struct mac_serial * info); static struct tty_struct *serial_table[NUM_CHANNELS]; static struct termios *serial_termios[NUM_CHANNELS]; @@ -152,13 +162,6 @@ 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, 115200, 230400, 0 }; - /* * Reading and writing Z8530 registers. */ @@ -320,12 +323,14 @@ #endif if (!tty) continue; - tty_flip_buffer_push(tty); - + if (tty->flip.count >= TTY_FLIPBUF_SIZE) + tty_flip_buffer_push(tty); + if (tty->flip.count >= TTY_FLIPBUF_SIZE) { static int flip_buf_ovf; ++flip_buf_ovf; - continue; + printk("FB. overflow: %d\n", flip_buf_ovf); + break; } tty->flip.count++; { @@ -347,6 +352,8 @@ *tty->flip.flag_buf_ptr++ = flag; *tty->flip.char_buf_ptr++ = ch; } + if (tty) + tty_flip_buffer_push(tty); } static void transmit_chars(struct mac_serial *info) @@ -407,11 +414,17 @@ */ if ((status & CTS) == 0) { if (info->tx_stopped) { +#ifdef SERIAL_DEBUG_FLOW + printk("CTS up\n"); +#endif info->tx_stopped = 0; if (!info->tx_active) transmit_chars(info); } } else { +#ifdef SERIAL_DEBUG_FLOW + printk("CTS down\n"); +#endif info->tx_stopped = 1; } } @@ -446,12 +459,17 @@ for (;;) { zs_intreg = read_zsreg(info->zs_chan_a, 3) >> shift; #ifdef SERIAL_DEBUG_INTR -// printk("rs_interrupt: irq %d, zs_intreg 0x%x\n", irq, (int)zs_intreg); + printk("rs_interrupt: irq %d, zs_intreg 0x%x\n", irq, (int)zs_intreg); #endif if ((zs_intreg & CHAN_IRQMASK) == 0) break; + if (!(info->flags & ZILOG_INITIALIZED)) { + printk("rs_interrupt: irq %d, port not initialized\n", irq); + break; + } + if (zs_intreg & CHBRxIP) receive_chars(info, regs); if (zs_intreg & CHBTxIP) @@ -478,6 +496,11 @@ { struct mac_serial *info = (struct mac_serial *)tty->driver_data; +#ifdef SERIAL_DEBUG_STOP + printk("rs_stop %ld....\n", + tty->ldisc.chars_in_buffer(tty)); +#endif + if (serial_paranoia_check(info, tty->device, "rs_stop")) return; @@ -497,6 +520,11 @@ struct mac_serial *info = (struct mac_serial *)tty->driver_data; unsigned long flags; +#ifdef SERIAL_DEBUG_STOP + printk("rs_start %ld....\n", + tty->ldisc.chars_in_buffer(tty)); +#endif + if (serial_paranoia_check(info, tty->device, "rs_start")) return; @@ -552,10 +580,16 @@ static int startup(struct mac_serial * info) { - unsigned long flags; - - if (info->flags & ZILOG_INITIALIZED) - return 0; +#ifdef SERIAL_DEBUG_OPEN + printk("startup() (ttyS%d, irq %d)\n", info->line, info->irq); +#endif + + if (info->flags & ZILOG_INITIALIZED) { +#ifdef SERIAL_DEBUG_OPEN + printk(" -> already inited\n"); +#endif + return 0; + } if (!info->xmit_buf) { info->xmit_buf = (unsigned char *) get_free_page(GFP_KERNEL); @@ -563,12 +597,42 @@ return -ENOMEM; } - save_flags(flags); cli(); +#ifdef SERIAL_DEBUG_OPEN + printk("starting up ttyS%d (irq %d)...\n", info->line, info->irq); +#endif + + set_scc_power(info, 1); + + setup_scc(info); #ifdef SERIAL_DEBUG_OPEN - printk("starting up ttyS%d (irq %d)...", info->line, info->irq); + printk("enabling IRQ on ttyS%d (irq %d)...\n", info->line, info->irq); #endif + info->flags |= ZILOG_INITIALIZED; + enable_irq(info->irq); + + return 0; +} + +static int setup_scc(struct mac_serial * info) +{ + unsigned long flags; + +#ifdef SERIAL_DEBUG_OPEN + printk("setting up ttys%d SCC...\n", info->line); +#endif + + save_flags(flags); cli(); /* Disable interrupts */ + + /* + * Reset the chip. + */ + write_zsreg(info->zs_channel, 9, + (info->zs_channel == info->zs_chan_a? CHRA: CHRB)); + udelay(10); + write_zsreg(info->zs_channel, 9, 0); + /* * Clear the receive FIFO. */ @@ -608,13 +672,13 @@ /* * Set the speed of the serial port */ - change_speed(info); + change_speed(info, 0); /* 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; } @@ -624,22 +688,20 @@ */ static void shutdown(struct mac_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, + printk("Shutting down serial port %d (irq %d)....\n", info->line, info->irq); #endif - save_flags(flags); cli(); /* Disable interrupts */ + if (!(info->flags & ZILOG_INITIALIZED)) { +#ifdef SERIAL_DEBUG_OPEN + printk("(already shutdown)\n"); +#endif - if (info->xmit_buf) { - free_page((unsigned long) info->xmit_buf); - info->xmit_buf = 0; + return; } + + disable_irq(info->irq); info->pendregs[1] = info->curregs[1] = 0; write_zsreg(info->zs_channel, 1, 0); /* no interrupts */ @@ -657,34 +719,156 @@ if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags); + set_scc_power(info, 0); + + if (info->xmit_buf) { + free_page((unsigned long) info->xmit_buf); + info->xmit_buf = 0; + } + + memset(info->curregs, 0, sizeof(info->curregs)); + memset(info->curregs, 0, sizeof(info->pendregs)); + info->flags &= ~ZILOG_INITIALIZED; - restore_flags(flags); } +static void set_scc_power(struct mac_serial * info, int state) +{ + if (feature_test(info->dev_node, FEATURE_Serial_enable) < 0) + return; /* don't have serial power control */ + + /* The timings looks strange but that's the ones MacOS seems + to use for the internal modem. I think we can use a lot faster + ones, at least whe not using the modem, this should be tested. + */ + if (state) { +#ifdef SERIAL_DEBUG_POWER + printk(KERN_INFO "ttyS%02d: powering up hardware\n", info->line); +#endif + if (feature_test(info->dev_node, FEATURE_Serial_enable) == 0) { + feature_clear(info->dev_node, FEATURE_Serial_reset); + mdelay(5); + feature_set(info->dev_node, FEATURE_Serial_enable); + } + if (info->zs_chan_a == info->zs_channel) + feature_set(info->dev_node, FEATURE_Serial_IO_A); + else + feature_set(info->dev_node, FEATURE_Serial_IO_B); + mdelay(1); + + if (info->is_cobalt_modem){ + feature_set(info->dev_node, FEATURE_Modem_Reset); + mdelay(15); + feature_clear(info->dev_node, FEATURE_Modem_Reset); + /* XXX Note the big 250ms, we should probably replace this + by something better since we have irqs disabled here + */ + mdelay(250); + } + if (info->is_pwbk_ir) + pmu_enable_irled(1); + } else { +#ifdef SERIAL_DEBUG_POWER + printk(KERN_INFO "ttyS%02d: shutting down hardware\n", info->line); +#endif +#ifdef CONFIG_KGDB + if (info->kgdb_channel) { +#ifdef SERIAL_DEBUG_POWER + printk(KERN_INFO " (canceled by KGDB)\n"); +#endif + return; + } +#endif +#ifdef CONFIG_XMON + if (!info->is_cobalt_modem) { +#ifdef SERIAL_DEBUG_POWER + printk(KERN_INFO " (canceled by XMON)\n"); +#endif + return; + } +#endif + if (info->is_cobalt_modem) { +#ifdef SERIAL_DEBUG_POWER + printk(KERN_INFO "ttyS%02d: shutting down modem\n", info->line); +#endif + feature_set(info->dev_node, FEATURE_Modem_Reset); + mdelay(15); + feature_clear(info->dev_node, FEATURE_Modem_Reset); + mdelay(25); + } + if (info->is_pwbk_ir) + pmu_enable_irled(0); + + if (info->zs_chan_a == info->zs_channel) { +#ifdef SERIAL_DEBUG_POWER + printk(KERN_INFO "ttyS%02d: shutting down SCC channel A\n", info->line); +#endif + feature_clear(info->dev_node, FEATURE_Serial_IO_A); + } else { +#ifdef SERIAL_DEBUG_POWER + printk(KERN_INFO "ttyS%02d: shutting down SCC channel B\n", info->line); +#endif + feature_clear(info->dev_node, FEATURE_Serial_IO_B); + } + /* XXX for now, shut down SCC core only on powerbooks */ + if (is_powerbook + && !(feature_test(info->dev_node, FEATURE_Serial_IO_A) || + feature_test(info->dev_node, FEATURE_Serial_IO_B))) { +#ifdef SERIAL_DEBUG_POWER + printk(KERN_INFO "ttyS%02d: shutting down SCC core\n", info->line); +#endif + feature_set(info->dev_node, FEATURE_Serial_reset); + mdelay(10); + feature_clear(info->dev_node, FEATURE_Serial_enable); + mdelay(5); + } + } +} + + /* * 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 mac_serial *info) +static void change_speed(struct mac_serial *info, struct termios *old_termios) { unsigned short port; unsigned cflag; - int i; - int brg; + int bits; + int brg, baud; unsigned long flags; if (!info->tty || !info->tty->termios) return; - cflag = info->tty->termios->c_cflag; if (!(port = info->port)) return; - i = cflag & CBAUD; + + cflag = info->tty->termios->c_cflag; + baud = tty_get_baud_rate(info->tty); + if (baud == 0) { + if (old_termios) { + info->tty->termios->c_cflag &= ~CBAUD; + info->tty->termios->c_cflag |= (old_termios->c_cflag & CBAUD); + cflag = info->tty->termios->c_cflag; + baud = tty_get_baud_rate(info->tty); + } + else + baud = info->zs_baud; + } + if (baud > 230400) + baud = 230400; + else if (baud == 0) + baud = 38400; save_flags(flags); cli(); - info->zs_baud = baud_table[i]; + info->zs_baud = baud; info->clk_divisor = 16; - switch (info->zs_baud) { +#ifdef SERIAL_DEBUG_BAUDS + printk("set speed to %d bds, ", baud); +#endif + + switch (baud) { case ZS_CLOCK/16: /* 230400 */ info->curregs[4] = X16CLK; info->curregs[11] = 0; @@ -696,7 +880,7 @@ default: info->curregs[4] = X16CLK; info->curregs[11] = TCBR | RCBR; - brg = BPS_TO_BRG(info->zs_baud, ZS_CLOCK/info->clk_divisor); + brg = BPS_TO_BRG(baud, ZS_CLOCK/info->clk_divisor); info->curregs[12] = (brg & 255); info->curregs[13] = ((brg >> 8) & 255); info->curregs[14] = BRENABL; @@ -709,19 +893,35 @@ case CS5: info->curregs[3] |= Rx5; info->curregs[5] |= Tx5; +#ifdef SERIAL_DEBUG_BAUDS + printk("5 bits, "); +#endif + bits = 7; break; case CS6: info->curregs[3] |= Rx6; info->curregs[5] |= Tx6; +#ifdef SERIAL_DEBUG_BAUDS + printk("6 bits, "); +#endif + bits = 8; break; case CS7: info->curregs[3] |= Rx7; info->curregs[5] |= Tx7; +#ifdef SERIAL_DEBUG_BAUDS + printk("7 bits, "); +#endif + bits = 9; break; case CS8: default: /* defaults to 8 bits */ info->curregs[3] |= Rx8; info->curregs[5] |= Tx8; +#ifdef SERIAL_DEBUG_BAUDS + printk("8 bits, "); +#endif + bits = 10; break; } info->pendregs[3] = info->curregs[3]; @@ -730,11 +930,22 @@ info->curregs[4] &= ~(SB_MASK | PAR_ENA | PAR_EVEN); if (cflag & CSTOPB) { info->curregs[4] |= SB2; + bits++; +#ifdef SERIAL_DEBUG_BAUDS + printk("2 stop, "); +#endif } else { info->curregs[4] |= SB1; +#ifdef SERIAL_DEBUG_BAUDS + printk("1 stop, "); +#endif } if (cflag & PARENB) { - info->curregs[4] |= PAR_ENA; + bits++; + info->curregs[4] |= PAR_ENA; +#ifdef SERIAL_DEBUG_BAUDS + printk("parity, "); +#endif } if (!(cflag & PARODD)) { info->curregs[4] |= PAR_EVEN; @@ -757,6 +968,17 @@ } info->pendregs[15] = info->curregs[15]; + /* Calc timeout value. This is pretty broken with high baud rates with HZ=100. + This code would love a larger HZ and a >1 fifo size, but this is not + a priority. The resulting value must be >HZ/2 + */ + info->timeout = ((info->xmit_fifo_size*HZ*bits) / baud); + info->timeout += HZ/50+1; /* Add .02 seconds of slop */ + +#ifdef SERIAL_DEBUG_BAUDS + printk("timeout=%d/%ds, base:%d\n", (int)info->timeout, (int)HZ, (int)info->baud_base); +#endif + /* Load up the new values */ load_zsregs(info->zs_channel, info->curregs); @@ -877,8 +1099,7 @@ #ifdef SERIAL_DEBUG_THROTTLE char buf[64]; - printk("throttle %s: %d....\n", _tty_name(tty, buf), - tty->ldisc.chars_in_buffer(tty)); + printk("throttle %ld....\n",tty->ldisc.chars_in_buffer(tty)); #endif if (serial_paranoia_check(info, tty->device, "rs_throttle")) @@ -915,8 +1136,7 @@ #ifdef SERIAL_DEBUG_THROTTLE char buf[64]; - printk("unthrottle %s: %d....\n", _tty_name(tty, buf), - tty->ldisc.chars_in_buffer(tty)); + printk("unthrottle %s: %d....\n",tty->ldisc.chars_in_buffer(tty)); #endif if (serial_paranoia_check(info, tty->device, "rs_unthrottle")) @@ -1011,7 +1231,8 @@ info->closing_wait = new_serial.closing_wait; check_and_exit: - retval = startup(info); + if (info->flags & ZILOG_INITIALIZED) + retval = setup_scc(info); return retval; } @@ -1180,10 +1401,12 @@ return; was_stopped = info->tx_stopped; - change_speed(info); + change_speed(info, old_termios); - if (was_stopped && !info->tx_stopped) + if (was_stopped && !info->tx_stopped) { + tty->hw_stopped = 0; rs_start(tty); + } } /* @@ -1246,6 +1469,9 @@ * Now we wait for the transmit buffer to clear; and we notify * the line discipline to only process XON/XOFF characters. */ +#ifdef SERIAL_DEBUG_OPEN + printk("waiting end of Tx... (timeout:%d)\n", info->closing_wait); +#endif tty->closing = 1; if (info->closing_wait != ZILOG_CLOSING_WAIT_NONE) tty_wait_until_sent(tty, info->closing_wait); @@ -1265,10 +1491,17 @@ * Before we drop DTR, make sure the SCC transmitter * has completely drained. */ +#ifdef SERIAL_DEBUG_OPEN + printk("waiting end of Rx...\n"); +#endif rs_wait_until_sent(tty, info->timeout); } shutdown(info); + /* restore flags now since shutdown() will have disabled this port's + specific irqs */ + restore_flags(flags); + if (tty->driver.flush_buffer) tty->driver.flush_buffer(tty); if (tty->ldisc.flush_buffer) @@ -1277,14 +1510,6 @@ info->event = 0; info->tty = 0; - if (info->is_cobalt_modem) { - /* Power down modem */ - feature_set(info->dev_node, FEATURE_Modem_Reset); - mdelay(15); - feature_clear(info->dev_node, FEATURE_Modem_PowerOn); - mdelay(15); - } - if (info->blocked_open) { if (info->close_delay) { current->state = TASK_INTERRUPTIBLE; @@ -1295,8 +1520,6 @@ info->flags &= ~(ZILOG_NORMAL_ACTIVE|ZILOG_CALLOUT_ACTIVE| ZILOG_CLOSING); wake_up_interruptible(&info->close_wait); - - restore_flags(flags); } /* @@ -1310,15 +1533,26 @@ if (serial_paranoia_check(info, tty->device, "rs_wait_until_sent")) return; +/* printk("rs_wait_until_sent, timeout:%d, tty_stopped:%d, tx_stopped:%d\n", + timeout, tty->stopped, info->tx_stopped); +*/ 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. */ + if (info->timeout <= HZ/50) { + printk("macserial: invalid info->timeout=%d\n", info->timeout); + info->timeout = HZ/50+1; + } + char_time = (info->timeout - HZ/50) / info->xmit_fifo_size; char_time = char_time / 5; - if (char_time == 0) + if (char_time > HZ) { + printk("macserial: char_time %ld >HZ !!!\n", char_time); + char_time = 1; + } else if (char_time == 0) char_time = 1; if (timeout) char_time = MIN(char_time, timeout); @@ -1534,38 +1768,16 @@ * Start up serial port */ - if (info->is_cobalt_modem) { - /* Power up modem */ - feature_set(info->dev_node, FEATURE_Modem_PowerOn); - mdelay(250); - feature_clear(info->dev_node, FEATURE_Modem_Reset); - mdelay(10); - } retval = startup(info); - if (retval) { - if (info->is_cobalt_modem) { - /* Power down modem */ - feature_set(info->dev_node, FEATURE_Modem_Reset); - mdelay(15); - feature_clear(info->dev_node, FEATURE_Modem_PowerOn); - mdelay(15); - } + 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); + retval); #endif - if (info->is_cobalt_modem) { - /* Power down modem */ - feature_set(info->dev_node, FEATURE_Modem_Reset); - mdelay(15); - feature_clear(info->dev_node, FEATURE_Modem_PowerOn); - mdelay(15); - } return retval; } @@ -1574,13 +1786,13 @@ *tty->termios = info->normal_termios; else *tty->termios = info->callout_termios; - change_speed(info); + change_speed(info, 0); } #ifdef CONFIG_SERIAL_CONSOLE if (sercons.cflag && sercons.index == line) { tty->termios->c_cflag = sercons.cflag; sercons.cflag = 0; - change_speed(info); + change_speed(info, 0); } #endif @@ -1588,7 +1800,7 @@ info->pgrp = current->pgrp; #ifdef SERIAL_DEBUG_OPEN - printk("rs_open ttys%d successful...", info->line); + printk("rs_open ttys%d successful...\n", info->line); #endif return 0; } @@ -1597,7 +1809,7 @@ static void show_serial_version(void) { - printk("PowerMac Z8530 serial driver version 1.00\n"); + printk("PowerMac Z8530 serial driver version 1.01\n"); } /* Ask the PROM how many Z8530s we have and initialize their zs_channels */ @@ -1606,7 +1818,7 @@ { struct device_node *dev, *ch; struct mac_serial **pp; - int n; + int n, lenp; n = 0; pp = &zs_chain; @@ -1616,12 +1828,6 @@ dev->full_name); continue; } - feature_clear(dev, FEATURE_Serial_reset); - mdelay(5); - feature_set(dev, FEATURE_Serial_enable); - feature_set(dev, FEATURE_Serial_IO_A); - feature_set(dev, FEATURE_Serial_IO_B); - mdelay(5); for (ch = dev->child; ch != 0; ch = ch->sibling) { if (ch->n_addrs < 1 || (ch ->n_intrs < 1)) { printk("Can't use %s: %d addrs %d intrs\n", @@ -1630,21 +1836,17 @@ } zs_channels[n].control = (volatile unsigned char *) ioremap(ch->addrs[0].address, 0x1000); - zs_channels[n].data = zs_channels[n].control - + ch->addrs[0].size / 2; + zs_channels[n].data = zs_channels[n].control + 0x10; spin_lock_init(&zs_channels[n].lock); zs_soft[n].zs_channel = &zs_channels[n]; zs_soft[n].dev_node = ch; zs_soft[n].irq = ch->intrs[0].line; + zs_soft[n].zs_channel->parent = &zs_soft[n]; zs_soft[n].is_cobalt_modem = device_is_compatible(ch, "cobalt"); - if (zs_soft[n].is_cobalt_modem) - { - /* Just in case the modem is up, shut it down */ - feature_set(ch, FEATURE_Modem_Reset); - mdelay(15); - feature_clear(ch, FEATURE_Modem_PowerOn); - mdelay(15); - } + + /* XXX tested only with wallstreet PowerBook, should do no harm anyway */ + zs_soft[n].is_pwbk_ir = (strcmp(get_property(ch, "AAPL,connector", + &lenp), "infrared") == 0); /* XXX this assumes the prom puts chan A before B */ if (n & 1) @@ -1677,13 +1879,19 @@ if (zs_chain == 0) probe_sccs(); + /* XXX assume it's a powerbook if we have a via-pmu */ + is_powerbook = find_devices("via-pmu") != 0; + /* Register the interrupt handler for each one */ + save_flags(flags); cli(); for (i = 0; i < zs_channels_found; ++i) { if (request_irq(zs_soft[i].irq, rs_interrupt, 0, "SCC", &zs_soft[i])) printk(KERN_ERR "macserial: can't get irq %d\n", zs_soft[i].irq); + disable_irq(zs_soft[i].irq); } + restore_flags(flags); show_serial_version(); @@ -1739,8 +1947,6 @@ 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) { @@ -1749,10 +1955,15 @@ } #endif zs_soft[channel].clk_divisor = 16; - zs_soft[channel].zs_baud = get_zsbaud(&zs_soft[channel]); +/* -- we are not sure the SCC is powered ON at this point + zs_soft[channel].zs_baud = get_zsbaud(&zs_soft[channel]); +*/ + zs_soft[channel].zs_baud = 38400; /* If console serial line, then enable interrupts. */ if (zs_soft[channel].is_cons) { + printk("macserial: console line, enabling interrupt %d\n", zs_soft[channel].irq); + panic("macserial: console not supported yet !"); write_zsreg(zs_soft[channel].zs_channel, R1, (EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB)); write_zsreg(zs_soft[channel].zs_channel, R9, @@ -1775,6 +1986,7 @@ info->line = i; info->tty = 0; info->custom_divisor = 16; + info->timeout = 0; info->close_delay = 50; info->closing_wait = 3000; info->x_char = 0; @@ -1787,6 +1999,7 @@ info->normal_termios = serial_driver.init_termios; info->open_wait = 0; info->close_wait = 0; + info->timeout = HZ; printk("tty%02d at 0x%08x (irq = %d)", info->line, info->port, info->irq); printk(" is a Z8530 ESCC"); @@ -1795,10 +2008,21 @@ printk(", port = %s", connector); if (info->is_cobalt_modem) printk(" (cobalt modem)"); + if (info->is_pwbk_ir) + printk(" (powerbook IR)"); printk("\n"); - } - restore_flags(flags); +#ifdef CONFIG_KGDB + if (info->kgdb_channel) + continue; +#endif +#ifdef CONFIG_XMON + if (!info->is_cobalt_modem) + continue; +#endif + /* By default, disable the port */ + set_scc_power(info, 0); + } return 0; } @@ -1835,6 +2059,32 @@ static void serial_console_write(struct console *co, const char *s, unsigned count) { + struct mac_serial *info = zs_soft + co->index; + int i; + + /* Turn of interrupts and enable the transmitter. */ + write_zsreg(info->zs_channel, R1, info->curregs[1] & ~TxINT_ENAB); + write_zsreg(info->zs_channel, R5, info->curregs[5] | TxENAB | RTS | DTR); + + for (i=0; izs_channel, 0) & Tx_BUF_EMP) == 0) { + eieio(); + } + + write_zsdata(info->zs_channel, s[i]); + if (s[i] == 10) { + while ((read_zsreg(info->zs_channel, 0) & Tx_BUF_EMP) + == 0) + eieio(); + + write_zsdata(info->zs_channel, 13); + } + } + + /* Restore the values in the registers. */ + write_zsreg(info->zs_channel, R1, info->curregs[1]); + /* Don't disable the transmitter. */ } /* @@ -1842,7 +2092,23 @@ */ static int serial_console_wait_key(struct console *co) { - return 0; + struct mac_serial *info = zs_soft + co->index; + int val; + + /* Turn of interrupts and enable the transmitter. */ + write_zsreg(info->zs_channel, R1, info->curregs[1] & ~INT_ALL_Rx); + write_zsreg(info->zs_channel, R3, info->curregs[3] | RxENABLE); + + /* Wait for something in the receive buffer. */ + while((read_zsreg(info->zs_channel, 0) & Rx_CH_AV) == 0) + eieio(); + val = read_zsdata(info->zs_channel); + + /* Restore the values in the registers. */ + write_zsreg(info->zs_channel, R1, info->curregs[1]); + write_zsreg(info->zs_channel, R3, info->curregs[3]); + + return val; } static kdev_t serial_console_device(struct console *c) @@ -1858,14 +2124,24 @@ */ __initfunc(static int serial_console_setup(struct console *co, char *options)) { - struct serial_state *ser; - unsigned cval; - int baud = 9600; + struct mac_serial *info = zs_soft + co->index; + int baud = 38400; int bits = 8; int parity = 'n'; int cflag = CREAD | HUPCL | CLOCAL; - int quot = 0; + int brg; char *s; + long flags; + + /* Find out how many Z8530 SCCs we have */ + if (zs_chain == 0) + probe_sccs(); + + if (zs_chain == 0) + return -1; + + /* Reset the channel */ + write_zsreg(info->zs_channel, R9, CHRA); if (options) { baud = simple_strtoul(options, NULL, 10); @@ -1891,21 +2167,21 @@ case 4800: cflag |= B4800; break; + case 9600: + cflag |= B9600; + break; case 19200: cflag |= B19200; break; - case 38400: - cflag |= B38400; - break; case 57600: cflag |= B57600; break; case 115200: cflag |= B115200; break; - case 9600: + case 38400: default: - cflag |= B9600; + cflag |= B38400; break; } switch(bits) { @@ -1919,7 +2195,7 @@ } switch(parity) { case 'o': case 'O': - cflag |= PARODD; + cflag |= PARENB | PARODD; break; case 'e': case 'E': cflag |= PARENB; @@ -1927,6 +2203,90 @@ } co->cflag = cflag; + save_flags(flags); cli(); + memset(info->curregs, 0, sizeof(info->curregs)); + + info->zs_baud = baud; + info->clk_divisor = 16; + switch (info->zs_baud) { + case ZS_CLOCK/16: /* 230400 */ + info->curregs[4] = X16CLK; + info->curregs[11] = 0; + break; + case ZS_CLOCK/32: /* 115200 */ + info->curregs[4] = X32CLK; + info->curregs[11] = 0; + break; + default: + info->curregs[4] = X16CLK; + info->curregs[11] = TCBR | RCBR; + brg = BPS_TO_BRG(info->zs_baud, ZS_CLOCK/info->clk_divisor); + info->curregs[12] = (brg & 255); + info->curregs[13] = ((brg >> 8) & 255); + info->curregs[14] = BRENABL; + } + + /* byte size and parity */ + info->curregs[3] &= ~RxNBITS_MASK; + info->curregs[5] &= ~TxNBITS_MASK; + switch (cflag & CSIZE) { + case CS5: + info->curregs[3] |= Rx5; + info->curregs[5] |= Tx5; + break; + case CS6: + info->curregs[3] |= Rx6; + info->curregs[5] |= Tx6; + break; + case CS7: + info->curregs[3] |= Rx7; + info->curregs[5] |= Tx7; + break; + case CS8: + default: /* defaults to 8 bits */ + info->curregs[3] |= Rx8; + info->curregs[5] |= Tx8; + break; + } + info->curregs[5] |= TxENAB | RTS | DTR; + info->pendregs[3] = info->curregs[3]; + info->pendregs[5] = info->curregs[5]; + + info->curregs[4] &= ~(SB_MASK | PAR_ENA | PAR_EVEN); + if (cflag & CSTOPB) { + info->curregs[4] |= SB2; + } else { + info->curregs[4] |= SB1; + } + if (cflag & PARENB) { + info->curregs[4] |= PAR_ENA; + if (!(cflag & PARODD)) { + info->curregs[4] |= PAR_EVEN; + } + } + info->pendregs[4] = info->curregs[4]; + + if (!(cflag & CLOCAL)) { + if (!(info->curregs[15] & DCDIE)) + info->read_reg_zero = read_zsreg(info->zs_channel, 0); + info->curregs[15] |= DCDIE; + } else + info->curregs[15] &= ~DCDIE; + if (cflag & CRTSCTS) { + info->curregs[15] |= CTSIE; + if ((read_zsreg(info->zs_channel, 0) & CTS) != 0) + info->tx_stopped = 1; + } else { + info->curregs[15] &= ~CTSIE; + info->tx_stopped = 0; + } + info->pendregs[15] = info->curregs[15]; + + /* Load up the new values */ + load_zsregs(info->zs_channel, info->curregs); + + restore_flags(flags); + return 0; } @@ -1947,9 +2307,10 @@ /* * Register console. */ -__initfunc (void serial_console_init(void)) +__initfunc (long serial_console_init(long kmem_start, long kmem_end)) { register_console(&sercons); + return kmem_start; } #endif /* ifdef CONFIG_SERIAL_CONSOLE */ @@ -2022,6 +2383,8 @@ if (zs_chain == 0) probe_sccs(); + set_scc_power(&zs_soft[n], 1); + zs_kgdbchan = zs_soft[tty_num].zs_channel; zs_soft[tty_num].change_needed = 0; zs_soft[tty_num].clk_divisor = 16; diff -ur --new-file old/linux/drivers/macintosh/macserial.h new/linux/drivers/macintosh/macserial.h --- old/linux/drivers/macintosh/macserial.h Sun Nov 15 19:51:47 1998 +++ new/linux/drivers/macintosh/macserial.h Thu Mar 11 06:48:46 1999 @@ -38,27 +38,27 @@ /* * 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 */ +#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 */ @@ -81,10 +81,14 @@ * For definitions of the flags field, see tty.h */ +struct mac_serial; + struct mac_zschannel { - volatile unsigned char *control; - volatile unsigned char *data; - spinlock_t lock; + volatile unsigned char* control; + volatile unsigned char* data; + spinlock_t lock; + /* Used for debugging */ + struct mac_serial* parent; }; struct mac_serial { @@ -99,6 +103,7 @@ char kgdb_channel; /* Kgdb is running on this channel */ char is_cons; /* Is this our console. */ char is_cobalt_modem; /* is a gatwick-based cobalt modem */ + char is_pwbk_ir; /* is connected to an IR led on powerbooks */ unsigned char tx_active; /* character is being xmitted */ unsigned char tx_stopped; /* output is suspended */ diff -ur --new-file old/linux/drivers/macintosh/nvram.c new/linux/drivers/macintosh/nvram.c --- old/linux/drivers/macintosh/nvram.c Mon Aug 24 22:14:09 1998 +++ new/linux/drivers/macintosh/nvram.c Thu Apr 29 21:53:48 1999 @@ -1,6 +1,11 @@ /* * /dev/nvram driver for Power Macintosh. */ + +#define NVRAM_VERSION "1.0" + +#include + #include #include #include @@ -9,11 +14,14 @@ #include #include #include -#include #define NVRAM_SIZE 8192 +/* when building as a module, __openfirmware is both unavailable + * and unnecessary. */ +#ifndef MODULE __openfirmware +#endif static long long nvram_llseek(struct file *file, loff_t offset, int origin) { @@ -70,6 +78,13 @@ static int nvram_open(struct inode *inode, struct file *file) { + MOD_INC_USE_COUNT; + return 0; +} + +static int nvram_release(struct inode *inode, struct file *file) +{ + MOD_DEC_USE_COUNT; return 0; } @@ -83,7 +98,7 @@ NULL, /* nvram_mmap */ nvram_open, NULL, /* flush */ - NULL, /* no special release code */ + nvram_release, NULL /* fsync */ }; @@ -95,6 +110,19 @@ __initfunc(int nvram_init(void)) { + printk(KERN_INFO "Macintosh non-volatile memory driver v%s\n", + NVRAM_VERSION); misc_register(&nvram_dev); return 0; } +#ifdef MODULE +int init_module (void) +{ + return( nvram_init() ); +} + +void cleanup_module (void) +{ + misc_deregister( &nvram_dev ); +} +#endif diff -ur --new-file old/linux/drivers/macintosh/via-cuda.c new/linux/drivers/macintosh/via-cuda.c --- old/linux/drivers/macintosh/via-cuda.c Sun Nov 15 19:51:47 1998 +++ new/linux/drivers/macintosh/via-cuda.c Thu Apr 29 21:53:48 1999 @@ -74,6 +74,7 @@ static int reading_reply; static int data_index; static struct device_node *vias; +static int cuda_fully_inited = 0; static int init_via(void); static void cuda_start(void); @@ -81,7 +82,17 @@ static void cuda_input(unsigned char *buf, int nb, struct pt_regs *regs); static int cuda_adb_send_request(struct adb_request *req, int sync); static int cuda_adb_autopoll(int devs); -static int cuda_reset_bus(void); +static int cuda_adb_reset_bus(void); +static int cuda_send_request(struct adb_request *req); + + +static struct adb_controller cuda_controller = { + ADB_VIACUDA, + cuda_adb_send_request, + cuda_adb_autopoll, + cuda_adb_reset_bus, + cuda_poll +}; __openfirmware @@ -121,7 +132,7 @@ via = NULL; } - adb_hardware = ADB_VIACUDA; + adb_controller = &cuda_controller; } void @@ -139,10 +150,7 @@ via[IFR] = 0x7f; eieio(); /* clear interrupts by writing 1s */ via[IER] = IER_SET|SR_INT; eieio(); /* enable interrupt from SR */ - /* Set function pointers */ - adb_send_request = cuda_adb_send_request; - adb_autopoll = cuda_adb_autopoll; - adb_reset_bus = cuda_reset_bus; + cuda_fully_inited = 1; } #define WAIT_FOR(cond, what) \ @@ -201,14 +209,17 @@ { int i; - for (i = req->nbytes; i > 0; --i) - req->data[i] = req->data[i-1]; - req->data[0] = ADB_PACKET; - ++req->nbytes; + if ((via == NULL) || !cuda_fully_inited) { + req->complete = 1; + return -ENXIO; + } + req->reply_expected = 1; + i = cuda_send_request(req); if (i) return i; + if (sync) { while (!req->complete) cuda_poll(); @@ -216,12 +227,16 @@ return 0; } + /* Enable/disable autopolling */ static int cuda_adb_autopoll(int devs) { struct adb_request req; + if ((via == NULL) || !cuda_fully_inited) + return -ENXIO; + cuda_request(&req, NULL, 3, CUDA_PACKET, CUDA_AUTOPOLL, (devs? 1: 0)); while (!req.complete) cuda_poll(); @@ -230,10 +245,13 @@ /* Reset adb bus - how do we do this?? */ static int -cuda_reset_bus(void) +cuda_adb_reset_bus(void) { struct adb_request req; + if ((via == NULL) || !cuda_fully_inited) + return -ENXIO; + cuda_request(&req, NULL, 2, ADB_PACKET, 0); /* maybe? */ while (!req.complete) cuda_poll(); @@ -248,6 +266,11 @@ va_list list; int i; + if (via == NULL) { + req->complete = 1; + return -ENXIO; + } + req->nbytes = nbytes; req->done = done; va_start(list, nbytes); @@ -258,15 +281,11 @@ return cuda_send_request(req); } -int +static int cuda_send_request(struct adb_request *req) { unsigned long flags; - if (via == NULL) { - req->complete = 1; - return -ENXIO; - } if (req->nbytes < 2 || req->data[0] > CUDA_PACKET) { req->complete = 1; return -EINVAL; @@ -472,3 +491,9 @@ printk("\n"); } } + +int +cuda_present(void) +{ + return (adb_controller && (adb_controller->kind == ADB_VIACUDA) && via); +} \ No newline at end of file diff -ur --new-file old/linux/drivers/macintosh/via-pmu.c new/linux/drivers/macintosh/via-pmu.c --- old/linux/drivers/macintosh/via-pmu.c Wed Dec 23 18:44:41 1998 +++ new/linux/drivers/macintosh/via-pmu.c Thu Apr 29 21:53:48 1999 @@ -31,6 +31,7 @@ #include #include #include +#include /* Misc minor number allocated for /dev/pmu */ #define PMU_MINOR 154 @@ -89,8 +90,10 @@ static int adb_int_pending; static int pmu_adb_flags; static int adb_dev_map = 0; -static struct adb_request bright_req_1, bright_req_2; +static struct adb_request bright_req_1, bright_req_2, bright_req_3; static struct device_node *vias; +static int pmu_kind = PMU_UNKNOWN; +static int pmu_fully_inited = 0; int asleep; struct notifier_block *sleep_notifier_list; @@ -101,16 +104,23 @@ static void via_pmu_interrupt(int irq, void *arg, struct pt_regs *regs); static int pmu_adb_send_request(struct adb_request *req, int sync); static int pmu_adb_autopoll(int devs); -static int pmu_reset_bus(void); +static int pmu_adb_reset_bus(void); static void send_byte(int x); static void recv_byte(void); static void pmu_sr_intr(struct pt_regs *regs); static void pmu_done(struct adb_request *req); static void pmu_handle_data(unsigned char *data, int len, struct pt_regs *regs); -static void set_brightness(int level); static void set_volume(int level); +static struct adb_controller pmu_controller = { + ADB_VIAPMU, + pmu_adb_send_request, + pmu_adb_autopoll, + pmu_adb_reset_bus, + pmu_poll +}; + /* * This table indicates for each PMU opcode: * - the number of data bytes to be sent with the command, or -1 @@ -118,24 +128,24 @@ * - the number of response bytes which the PMU will return, or * -1 if it will send a length byte. */ -static s8 pmu_data_len[256][2] = { +static s8 pmu_data_len[256][2] __openfirmwaredata = { /* 0 1 2 3 4 5 6 7 */ /*00*/ {-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0}, /*08*/ {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, /*10*/ { 1, 0},{ 1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0}, /*18*/ { 0, 1},{ 0, 1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{ 0, 0}, /*20*/ {-1, 0},{ 0, 0},{ 2, 0},{ 1, 0},{ 1, 0},{-1, 0},{-1, 0},{-1, 0}, -/*28*/ { 0,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, -/*30*/ { 4, 0},{20, 0},{ 2, 0},{ 3, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0}, -/*38*/ { 0, 4},{ 0,20},{ 1, 1},{ 2, 1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, +/*28*/ { 0,-1},{ 0,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{ 0,-1}, +/*30*/ { 4, 0},{20, 0},{-1, 0},{ 3, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0}, +/*38*/ { 0, 4},{ 0,20},{ 2,-1},{ 2, 1},{ 3,-1},{-1,-1},{-1,-1},{ 4, 0}, /*40*/ { 1, 0},{ 1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0}, -/*48*/ { 0, 1},{ 0, 1},{-1,-1},{-1,-1},{ 1, 0},{-1,-1},{-1,-1},{-1,-1}, +/*48*/ { 0, 1},{ 0, 1},{-1,-1},{ 1, 0},{ 1, 0},{-1,-1},{-1,-1},{-1,-1}, /*50*/ { 1, 0},{ 0, 0},{ 2, 0},{ 2, 0},{-1, 0},{ 1, 0},{ 3, 0},{ 1, 0}, /*58*/ { 0, 1},{ 1, 0},{ 0, 2},{ 0, 2},{ 0,-1},{-1,-1},{-1,-1},{-1,-1}, -/*60*/ { 2, 0},{-1, 0},{ 2, 0},{ 0, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0}, +/*60*/ { 2, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0}, /*68*/ { 0, 3},{ 0, 3},{ 0, 2},{ 0, 8},{ 0,-1},{ 0,-1},{-1,-1},{-1,-1}, /*70*/ { 1, 0},{ 1, 0},{ 1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0}, -/*78*/ { 0,-1},{ 0,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{ 4, 1},{ 4, 1}, +/*78*/ { 0,-1},{ 0,-1},{-1,-1},{-1,-1},{-1,-1},{ 5, 1},{ 4, 1},{ 4, 1}, /*80*/ { 4, 0},{-1, 0},{ 0, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0}, /*88*/ { 0, 5},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, /*90*/ { 1, 0},{ 2, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0}, @@ -148,15 +158,14 @@ /*c8*/ {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, /*d0*/ { 0, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0}, /*d8*/ { 1, 1},{ 1, 1},{-1,-1},{-1,-1},{ 0, 1},{ 0,-1},{-1,-1},{-1,-1}, -/*e0*/ {-1, 0},{ 4, 0},{ 0, 1},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0}, +/*e0*/ {-1, 0},{ 4, 0},{ 0, 1},{-1, 0},{-1, 0},{ 4, 0},{-1, 0},{-1, 0}, /*e8*/ { 3,-1},{-1,-1},{ 0, 1},{-1,-1},{ 0,-1},{-1,-1},{-1,-1},{ 0, 0}, /*f0*/ {-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0}, /*f8*/ {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }; -__openfirmware -void +void __openfirmware find_via_pmu() { vias = find_devices("via-pmu"); @@ -185,6 +194,15 @@ if (vias->n_addrs < 1 || vias->n_intrs < 1) return; } + + if (vias->parent->name && ((strcmp(vias->parent->name, "ohare") == 0) + || device_is_compatible(vias->parent, "ohare"))) + pmu_kind = PMU_OHARE_BASED; + else if (device_is_compatible(vias->parent, "heathrow")) + pmu_kind = PMU_HEATHROW_BASED; + else + pmu_kind = PMU_UNKNOWN; + via = (volatile unsigned char *) ioremap(vias->addrs->address, 0x2000); out_8(&via[IER], IER_CLR | 0x7f); /* disable all intrs */ @@ -194,10 +212,16 @@ if (!init_pmu()) via = NULL; - adb_hardware = ADB_VIAPMU; + adb_controller = &pmu_controller; + + if (via) + printk(KERN_INFO "PMU driver initialized for %s\n", + (pmu_kind == PMU_OHARE_BASED) ? "PowerBook 2400/3400/3500(G3)" : + ((pmu_kind == PMU_HEATHROW_BASED) ? "PowerBook G3 Series" : + "Unknown PowerBook")); } -void +void __openfirmware via_pmu_init(void) { if (vias == NULL) @@ -205,6 +229,7 @@ bright_req_1.complete = 1; bright_req_2.complete = 1; + bright_req_3.complete = 1; if (request_irq(vias->intrs[0].line, via_pmu_interrupt, 0, "VIA-PMU", (void *)0)) { @@ -216,13 +241,13 @@ /* Enable interrupts */ out_8(&via[IER], IER_SET | SR_INT | CB1_INT); - /* Set function pointers */ - adb_send_request = pmu_adb_send_request; - adb_autopoll = pmu_adb_autopoll; - adb_reset_bus = pmu_reset_bus; + pmu_fully_inited = 1; + + /* Enable backlight */ + pmu_enable_backlight(1); } -static int +static int __openfirmware init_pmu() { int timeout; @@ -232,7 +257,7 @@ out_8(&via[DIRB], (via[DIRB] | TREQ) & ~TACK); /* TACK in, TREQ out */ pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0xff); - timeout = 100000; + timeout = 100000; while (!req.complete) { if (--timeout < 0) { printk(KERN_ERR "init_pmu: no response from PMU\n"); @@ -259,37 +284,102 @@ return 1; } +int +pmu_get_model(void) +{ + return pmu_kind; +} + /* Send an ADB command */ -static int +static int __openfirmware pmu_adb_send_request(struct adb_request *req, int sync) { - int i; + int i, ret; - for (i = req->nbytes - 1; i > 0; --i) - req->data[i+3] = req->data[i]; - req->data[3] = req->nbytes - 1; - req->data[2] = pmu_adb_flags; - req->data[1] = req->data[0]; - req->data[0] = PMU_ADB_CMD; - req->nbytes += 3; - req->reply_expected = 1; - req->reply_len = 0; - i = pmu_queue_request(req); - if (i) - return i; - if (sync) { - while (!req->complete) - pmu_poll(); - } - return 0; + if ((vias == NULL) || (!pmu_fully_inited)) + { + req->complete = 1; + return -ENXIO; + } + + ret = -EINVAL; + + switch (req->data[0]) { + case PMU_PACKET: + for (i = 0; i < req->nbytes - 1; ++i) + req->data[i] = req->data[i+1]; + --req->nbytes; + if (pmu_data_len[req->data[0]][1] != 0) { + req->reply[0] = ADB_RET_OK; + req->reply_len = 1; + } else + req->reply_len = 0; + ret = pmu_queue_request(req); + break; + case CUDA_PACKET: + switch (req->data[1]) { + case CUDA_GET_TIME: + if (req->nbytes != 2) + break; + req->data[0] = PMU_READ_RTC; + req->nbytes = 1; + req->reply_len = 3; + req->reply[0] = CUDA_PACKET; + req->reply[1] = 0; + req->reply[2] = CUDA_GET_TIME; + ret = pmu_queue_request(req); + break; + case CUDA_SET_TIME: + if (req->nbytes != 6) + break; + req->data[0] = PMU_SET_RTC; + req->nbytes = 5; + for (i = 1; i <= 4; ++i) + req->data[i] = req->data[i+1]; + req->reply_len = 3; + req->reply[0] = CUDA_PACKET; + req->reply[1] = 0; + req->reply[2] = CUDA_SET_TIME; + ret = pmu_queue_request(req); + break; + } + break; + case ADB_PACKET: + for (i = req->nbytes - 1; i > 1; --i) + req->data[i+2] = req->data[i]; + req->data[3] = req->nbytes - 2; + req->data[2] = pmu_adb_flags; + /*req->data[1] = req->data[1];*/ + req->data[0] = PMU_ADB_CMD; + req->nbytes += 2; + req->reply_expected = 1; + req->reply_len = 0; + ret = pmu_queue_request(req); + break; + } + if (ret) + { + req->complete = 1; + return ret; + } + + if (sync) { + while (!req->complete) + pmu_poll(); + } + + return 0; } /* Enable/disable autopolling */ -static int +static int __openfirmware pmu_adb_autopoll(int devs) { struct adb_request req; + if ((vias == NULL) || (!pmu_fully_inited)) + return -ENXIO; + if (devs) { adb_dev_map = devs; pmu_request(&req, NULL, 5, PMU_ADB_CMD, 0, 0x86, @@ -305,13 +395,16 @@ } /* Reset the ADB bus */ -static int -pmu_reset_bus(void) +static int __openfirmware +pmu_adb_reset_bus(void) { struct adb_request req; long timeout; int save_autopoll = adb_dev_map; + if ((vias == NULL) || (!pmu_fully_inited)) + return -ENXIO; + /* anyone got a better idea?? */ pmu_adb_autopoll(0); @@ -319,23 +412,23 @@ req.done = NULL; req.data[0] = PMU_ADB_CMD; req.data[1] = 0; - req.data[2] = 3; + req.data[2] = 3; /* ADB_BUSRESET ??? */ req.data[3] = 0; req.data[4] = 0; req.reply_len = 0; req.reply_expected = 1; if (pmu_queue_request(&req) != 0) { - printk(KERN_ERR "pmu_reset_bus: pmu_queue_request failed\n"); - return 0; + printk(KERN_ERR "pmu_adb_reset_bus: pmu_queue_request failed\n"); + return -EIO; } while (!req.complete) pmu_poll(); timeout = 100000; while (!req.complete) { if (--timeout < 0) { - printk(KERN_ERR "pmu_reset_bus (reset): no response from PMU\n"); - return 0; + printk(KERN_ERR "pmu_adb_reset_bus (reset): no response from PMU\n"); + return -EIO; } udelay(10); pmu_poll(); @@ -344,17 +437,20 @@ if (save_autopoll != 0) pmu_adb_autopoll(save_autopoll); - return 1; + return 0; } /* Construct and send a pmu request */ -int +int __openfirmware pmu_request(struct adb_request *req, void (*done)(struct adb_request *), int nbytes, ...) { va_list list; int i; + if (vias == NULL) + return -ENXIO; + if (nbytes < 0 || nbytes > 32) { printk(KERN_ERR "pmu_request: bad nbytes (%d)\n", nbytes); req->complete = 1; @@ -375,58 +471,7 @@ return pmu_queue_request(req); } -/* - * This procedure handles requests written to /dev/adb where the - * first byte is CUDA_PACKET or PMU_PACKET. For CUDA_PACKET, we - * emulate a few CUDA requests. - */ -int -pmu_send_request(struct adb_request *req) -{ - int i; - - switch (req->data[0]) { - case PMU_PACKET: - for (i = 0; i < req->nbytes - 1; ++i) - req->data[i] = req->data[i+1]; - --req->nbytes; - if (pmu_data_len[req->data[0]][1] != 0) { - req->reply[0] = ADB_RET_OK; - req->reply_len = 1; - } else - req->reply_len = 0; - return pmu_queue_request(req); - case CUDA_PACKET: - switch (req->data[1]) { - case CUDA_GET_TIME: - if (req->nbytes != 2) - break; - req->data[0] = PMU_READ_RTC; - req->nbytes = 1; - req->reply_len = 3; - req->reply[0] = CUDA_PACKET; - req->reply[1] = 0; - req->reply[2] = CUDA_GET_TIME; - return pmu_queue_request(req); - case CUDA_SET_TIME: - if (req->nbytes != 6) - break; - req->data[0] = PMU_SET_RTC; - req->nbytes = 5; - for (i = 1; i <= 4; ++i) - req->data[i] = req->data[i+1]; - req->reply_len = 3; - req->reply[0] = CUDA_PACKET; - req->reply[1] = 0; - req->reply[2] = CUDA_SET_TIME; - return pmu_queue_request(req); - } - break; - } - return -EINVAL; -} - -int +int __openfirmware pmu_queue_request(struct adb_request *req) { unsigned long flags; @@ -465,7 +510,7 @@ return 0; } -static void +static void __openfirmware send_byte(int x) { out_8(&via[ACR], 0x1c); @@ -473,7 +518,7 @@ out_8(&via[B], via[B] & ~0x10); /* assert TREQ */ } -static void +static void __openfirmware recv_byte() { out_8(&via[ACR], 0x0c); @@ -481,7 +526,7 @@ out_8(&via[B], via[B] & ~0x10); } -static void +static void __openfirmware pmu_start() { unsigned long flags; @@ -506,7 +551,7 @@ restore_flags(flags); } -void +void __openfirmware pmu_poll() { int ie; @@ -517,7 +562,7 @@ _enable_interrupts(ie); } -static void +static void __openfirmware via_pmu_interrupt(int irq, void *arg, struct pt_regs *regs) { int intr; @@ -553,7 +598,7 @@ } } -static void +static void __openfirmware pmu_sr_intr(struct pt_regs *regs) { struct adb_request *req; @@ -649,7 +694,7 @@ } } -static void +static void __openfirmware pmu_done(struct adb_request *req) { req->complete = 1; @@ -658,7 +703,7 @@ } /* Interrupt data could be the result data from an ADB cmd */ -static void +static void __openfirmware pmu_handle_data(unsigned char *data, int len, struct pt_regs *regs) { static int show_pmu_ints = 1; @@ -689,7 +734,7 @@ } else { if (data[0] == 0x08 && len == 3) { /* sound/brightness buttons pressed */ - set_brightness(data[1]); + pmu_set_brightness(data[1] >> 3); set_volume(data[2]); } else if (show_pmu_ints && !(data[0] == PMU_INT_TICK && len == 1)) { @@ -702,54 +747,101 @@ } } -int backlight_bright = -1; +int backlight_level = -1; int backlight_enabled = 0; -#define LEVEL_TO_BRIGHT(lev) ((lev) < 8? 0x7f: 0x4a - ((lev) >> 2)) +#define LEVEL_TO_BRIGHT(lev) ((lev) < 1? 0x7f: 0x4a - ((lev) << 1)) -void +void __openfirmware pmu_enable_backlight(int on) { struct adb_request req; + if (vias == NULL) + return ; + if (on) { - if (backlight_bright < 0) { + /* first call: get current backlight value */ + if (backlight_level < 0) { + switch(pmu_kind) { + case PMU_OHARE_BASED: pmu_request(&req, NULL, 2, 0xd9, 0); while (!req.complete) pmu_poll(); - backlight_bright = LEVEL_TO_BRIGHT(req.reply[1]); + backlight_level = req.reply[1] >> 3; + printk(KERN_DEBUG "pmu: controls returned bright: %d\n", (int)req.reply[1]); + break; + case PMU_HEATHROW_BASED: + pmu_request(&req, NULL, 3, PMU_READ_NVRAM, 0x14, 0xe); + while (!req.complete) + pmu_poll(); + printk(KERN_DEBUG "pmu: nvram returned bright: %d\n", (int)req.reply[1]); + backlight_level = req.reply[1]; + break; + default: + backlight_enabled = 0; + return; } - pmu_request(&req, NULL, 2, PMU_BACKLIGHT_BRIGHT, - backlight_bright); - while (!req.complete) - pmu_poll(); + } + pmu_request(&req, NULL, 2, PMU_BACKLIGHT_BRIGHT, + LEVEL_TO_BRIGHT(backlight_level)); + while (!req.complete) + pmu_poll(); } - pmu_request(&req, NULL, 2, PMU_BACKLIGHT_CTRL, on? 0x81: 1); + pmu_request(&req, NULL, 2, PMU_POWER_CTRL, + PMU_POW_BACKLIGHT | (on ? PMU_POW_ON : PMU_POW_OFF)); while (!req.complete) pmu_poll(); backlight_enabled = on; } -static void -set_brightness(int level) +void __openfirmware +pmu_set_brightness(int level) { - backlight_bright = LEVEL_TO_BRIGHT(level); + int bright; + + if (vias == NULL) + return ; + + backlight_level = level; + bright = LEVEL_TO_BRIGHT(level); if (!backlight_enabled) return; if (bright_req_1.complete) pmu_request(&bright_req_1, NULL, 2, PMU_BACKLIGHT_BRIGHT, - backlight_bright); + bright); if (bright_req_2.complete) - pmu_request(&bright_req_2, NULL, 2, PMU_BACKLIGHT_CTRL, - backlight_bright < 0x7f? 0x81: 1); + pmu_request(&bright_req_2, NULL, 2, PMU_POWER_CTRL, + PMU_POW_BACKLIGHT | (bright < 0x7f ? PMU_POW_ON : PMU_POW_OFF)); + + /* XXX nvram address is hard-coded and looks ok on wallstreet, please + test on your machine. Note that newer MacOS system software may break + the nvram layout. */ + if ((pmu_kind == PMU_HEATHROW_BASED) && bright_req_3.complete) + pmu_request(&bright_req_3, NULL, 4, PMU_WRITE_NVRAM, + 0x14, 0xe, level); +} + +void __openfirmware +pmu_enable_irled(int on) +{ + struct adb_request req; + + if (vias == NULL) + return ; + + pmu_request(&req, NULL, 2, PMU_POWER_CTRL, PMU_POW_IRLED | + (on ? PMU_POW_ON : PMU_POW_OFF)); + while (!req.complete) + pmu_poll(); } -static void +static void __openfirmware set_volume(int level) { } -void +void __openfirmware pmu_restart(void) { struct adb_request req; @@ -768,7 +860,7 @@ ; } -void +void __openfirmware pmu_shutdown(void) { struct adb_request req; @@ -788,6 +880,11 @@ ; } +int +pmu_present(void) +{ + return (adb_controller && (adb_controller->kind == ADB_VIAPMU) && vias); +} #ifdef CONFIG_PMAC_PBOOK @@ -802,7 +899,7 @@ } *pbook_pci_saves; static int n_pbook_pci_saves; -static inline void +static inline void __openfirmware pbook_pci_save(void) { int npci; @@ -829,7 +926,7 @@ } } -static inline void +static inline void __openfirmware pbook_pci_restore(void) { u16 cmd; @@ -868,7 +965,7 @@ #define IRQ_ENABLE ((unsigned int *)0xf3000024) #define MEM_CTRL ((unsigned int *)0xf8000070) -int powerbook_sleep(void) +int __openfirmware powerbook_sleep(void) { int ret, i, x; static int save_backlight; @@ -967,29 +1064,44 @@ /* * Support for /dev/pmu device */ -static int pmu_open(struct inode *inode, struct file *file) +static int __openfirmware pmu_open(struct inode *inode, struct file *file) { return 0; } -static ssize_t pmu_read(struct file *file, char *buf, +static ssize_t __openfirmware pmu_read(struct file *file, char *buf, size_t count, loff_t *ppos) { return 0; } -static ssize_t pmu_write(struct file *file, const char *buf, +static ssize_t __openfirmware pmu_write(struct file *file, const char *buf, size_t count, loff_t *ppos) { return 0; } -static int pmu_ioctl(struct inode * inode, struct file *filp, +/* Note: removed __openfirmware here since it causes link errors */ +static int /*__openfirmware*/ pmu_ioctl(struct inode * inode, struct file *filp, u_int cmd, u_long arg) { + int error; + __u32 value; + switch (cmd) { - case PMU_IOC_SLEEP: + case PMU_IOC_SLEEP: + if (pmu_kind != PMU_OHARE_BASED) + return -ENOSYS; return powerbook_sleep(); + case PMU_IOC_GET_BACKLIGHT: + return put_user(backlight_level, (__u32 *)arg); + case PMU_IOC_SET_BACKLIGHT: + error = get_user(value, (__u32 *)arg); + if (!error) + pmu_set_brightness(value); + return error; + case PMU_IOC_GET_MODEL: + return put_user(pmu_kind, (__u32 *)arg); } return -EINVAL; } @@ -1017,3 +1129,4 @@ misc_register(&pmu_device); } #endif /* CONFIG_PMAC_PBOOK */ + diff -ur --new-file old/linux/drivers/misc/Makefile new/linux/drivers/misc/Makefile --- old/linux/drivers/misc/Makefile Thu Jan 7 17:46:59 1999 +++ new/linux/drivers/misc/Makefile Tue May 11 18:55:49 1999 @@ -34,6 +34,27 @@ M_OBJS += parport_ax.o endif endif + ifeq ($(CONFIG_PARPORT_AMIGA),y) + LX_OBJS += parport_amiga.o + else + ifeq ($(CONFIG_PARPORT_AMIGA),m) + M_OBJS += parport_amiga.o + endif + endif + ifeq ($(CONFIG_PARPORT_MFC3),y) + LX_OBJS += parport_mfc3.o + else + ifeq ($(CONFIG_PARPORT_MFC3),m) + M_OBJS += parport_mfc3.o + endif + endif + ifeq ($(CONFIG_PARPORT_ATARI),y) + LX_OBJS += parport_atari.o + else + ifeq ($(CONFIG_PARPORT_ATARI),m) + M_OBJS += parport_atari.o + endif + endif LX_OBJS += parport_init.o else ifeq ($(CONFIG_PARPORT),m) @@ -49,6 +70,15 @@ endif ifeq ($(CONFIG_PARPORT_AX),m) M_OBJS += parport_ax.o + endif + ifeq ($(CONFIG_PARPORT_AMIGA),m) + M_OBJS += parport_amiga.o + endif + ifeq ($(CONFIG_PARPORT_MFC3),m) + M_OBJS += parport_mfc3.o + endif + ifeq ($(CONFIG_PARPORT_ATARI),m) + M_OBJS += parport_atari.o endif endif diff -ur --new-file old/linux/drivers/misc/multiface.h new/linux/drivers/misc/multiface.h --- old/linux/drivers/misc/multiface.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/misc/multiface.h Tue May 11 18:55:49 1999 @@ -0,0 +1,20 @@ +#ifndef _MULTIFACE_H_ +#define _MULTIFACE_H_ + +/* + * Defines for SerialMaster, Multiface Card II and Multiface Card III + * The addresses given below are offsets to the board base address + * + * 6.11.95 Joerg Dorchain (dorchain@mpi-sb.mpg.de) + * + */ + +#define PIA_REG_PADWIDTH 255 + +#define DUARTBASE 0x0000 +#define PITBASE 0x0100 +#define ROMBASE 0x0200 +#define PIABASE 0x4000 + +#endif + diff -ur --new-file old/linux/drivers/misc/parport_amiga.c new/linux/drivers/misc/parport_amiga.c --- old/linux/drivers/misc/parport_amiga.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/misc/parport_amiga.c Tue May 11 18:55:49 1999 @@ -0,0 +1,322 @@ +/* Low-level parallel port routines for the Amiga buildin port + * + * Author: Joerg Dorchain + * + * This is a complete rewrite of the code, but based heaviy upon the old + * lp_intern. code. + * + * The built-in Amiga parallel port provides one port at a fixed address + * with 8 bisdirecttional data lines (D0 - D7) and 3 bidirectional status + * lines (BUSY, POUT, SEL), 1 output control line /STROBE (raised automatically in + * hardware when the data register is accessed), and 1 input control line + * /ACK, able to cause an interrupt, but both not directly settable by + * software. + */ + +#include +#include +#include +#include +#include +#include +#include + +#undef DEBUG +#ifdef DEBUG +#define DPRINTK printk +#else +static inline int DPRINTK() {return 0;} +#endif + +static struct parport *this_port = NULL; + +static void amiga_write_data(struct parport *p, unsigned char data) +{ +DPRINTK("write_data %c\n",data); + /* Triggers also /STROBE. This behavior cannot be changed */ + ciaa.prb = data; +} + +static unsigned char amiga_read_data(struct parport *p) +{ + /* Triggers also /STROBE. This behavior cannot be changed */ + return ciaa.prb; +} + +#if 0 +static unsigned char control_pc_to_amiga(unsigned char control) +{ + unsigned char ret = 0; + + if (control & PARPORT_CONTROL_DIRECTION) /* XXX: What is this? */ + ; + if (control & PARPORT_CONTROL_INTEN) /* XXX: What is INTEN? */ + ; + if (control & PARPORT_CONTROL_SELECT) /* XXX: What is SELECP? */ + ; + if (control & PARPORT_CONTROL_INIT) /* INITP */ + /* reset connected to cpu reset pin */; + if (control & PARPORT_CONTROL_AUTOFD) /* AUTOLF */ + /* Not connected */; + if (control & PARPORT_CONTROL_STROBE) /* Strobe */ + /* Handled only directly by hardware */; + return ret; +} +#endif + +static unsigned char control_amiga_to_pc(unsigned char control) +{ + return PARPORT_CONTROL_INTEN | PARPORT_CONTROL_SELECT | + PARPORT_CONTROL_AUTOFD | PARPORT_CONTROL_STROBE; + /* fake value: interrupt enable, select in, no reset, + no autolf, no strobe - seems to be closest the wiring diagram */ +} + +static void amiga_write_control(struct parport *p, unsigned char control) +{ +DPRINTK("write_control %02x\n",control); + /* No implementation possible */ +} + +static unsigned char amiga_read_control( struct parport *p) +{ +DPRINTK("read_control \n"); + return control_amiga_to_pc(0); +} + +static unsigned char amiga_frob_control( struct parport *p, unsigned char mask, unsigned char val) +{ + unsigned char old; + +DPRINTK("frob_control mask %02x, value %02x\n",mask,val); + old = amiga_read_control(p); + amiga_write_control(p, (old & ~mask) ^ val); + return old; +} + + +static unsigned char status_pc_to_amiga(unsigned char status) +{ + unsigned char ret = 1; + + if (status & PARPORT_STATUS_BUSY) /* Busy */ + ret &= ~1; + if (status & PARPORT_STATUS_ACK) /* Ack */ + /* handled in hardware */; + if (status & PARPORT_STATUS_PAPEROUT) /* PaperOut */ + ret |= 2; + if (status & PARPORT_STATUS_SELECT) /* select */ + ret |= 4; + if (status & PARPORT_STATUS_ERROR) /* error */ + /* not connected */; + return ret; +} + +static unsigned char status_amiga_to_pc(unsigned char status) +{ + unsigned char ret = PARPORT_STATUS_BUSY | PARPORT_STATUS_ACK | PARPORT_STATUS_ERROR; + + if (status & 1) /* Busy */ + ret &= ~PARPORT_STATUS_BUSY; + if (status & 2) /* PaperOut */ + ret |= PARPORT_STATUS_PAPEROUT; + if (status & 4) /* Selected */ + ret |= PARPORT_STATUS_SELECT; + /* the rest is not connected or handled autonomously in hardware */ + + return ret; +} + +static void amiga_write_status( struct parport *p, unsigned char status) +{ +DPRINTK("write_status %02x\n",status); + ciab.pra |= (ciab.pra & 0xf8) | status_pc_to_amiga(status); +} + +static unsigned char amiga_read_status(struct parport *p) +{ + unsigned char status; + + status = status_amiga_to_pc(ciab.pra & 7); +DPRINTK("read_status %02x\n", status); + return status; +} + +static void amiga_change_mode( struct parport *p, int m) +{ + /* XXX: This port only has one mode, and I am + not sure about the corresponding PC-style mode*/ +} + +/* as this ports irq handling is already done, we use a generic funktion */ +static void amiga_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + parport_generic_irq(irq, (struct parport *) dev_id, regs); +} + + +static void amiga_release_resources(struct parport *p) +{ +DPRINTK("realease_resources\n"); + if (p->irq != PARPORT_IRQ_NONE) + free_irq(IRQ_AMIGA_CIAA_FLG, p); +} + +static int amiga_claim_resources(struct parport *p) +{ +DPRINTK("claim_resources\n"); + return request_irq(IRQ_AMIGA_CIAA_FLG, amiga_interrupt, 0, p->name, p); +} + +static void amiga_init_state(struct parport_state *s) +{ + s->u.amiga.data = 0; + s->u.amiga.datadir = 255; + s->u.amiga.status = 0; + s->u.amiga.statusdir = 0; +} + +static void amiga_save_state(struct parport *p, struct parport_state *s) +{ + s->u.amiga.data = ciaa.prb; + s->u.amiga.datadir = ciaa.ddrb; + s->u.amiga.status = ciab.pra & 7; + s->u.amiga.statusdir = ciab.ddra & 7; +} + +static void amiga_restore_state(struct parport *p, struct parport_state *s) +{ + ciaa.prb = s->u.amiga.data; + ciaa.ddrb = s->u.amiga.datadir; + ciab.pra |= (ciab.pra & 0xf8) | s->u.amiga.status; + ciab.ddra |= (ciab.ddra & 0xf8) | s->u.amiga.statusdir; +} + +static void amiga_enable_irq(struct parport *p) +{ + enable_irq(IRQ_AMIGA_CIAA_FLG); +} + +static void amiga_disable_irq(struct parport *p) +{ + disable_irq(IRQ_AMIGA_CIAA_FLG); +} + +static void amiga_inc_use_count(void) +{ + MOD_INC_USE_COUNT; +} + +static void amiga_dec_use_count(void) +{ + MOD_DEC_USE_COUNT; +} + +static void amiga_fill_inode(struct inode *inode, int fill) +{ +#ifdef MODULE + if (fill) + MOD_INC_USE_COUNT; + else + MOD_DEC_USE_COUNT; +#endif +} + +static struct parport_operations pp_amiga_ops = { + amiga_write_data, + amiga_read_data, + + amiga_write_control, + amiga_read_control, + amiga_frob_control, + + NULL, /* write_econtrol */ + NULL, /* read_econtrol */ + NULL, /* frob_econtrol */ + + amiga_write_status, + amiga_read_status, + + NULL, /* write fifo */ + NULL, /* read fifo */ + + amiga_change_mode, + + + amiga_release_resources, + amiga_claim_resources, + + + NULL, /* epp_write_data */ + NULL, /* epp_read_data */ + NULL, /* epp_write_addr */ + NULL, /* epp_read_addr */ + NULL, /* epp_check_timeout */ + + NULL, /* epp_write_block */ + NULL, /* epp_read_block */ + + NULL, /* ecp_write_block */ + NULL, /* ecp_read_block */ + + amiga_init_state, + amiga_save_state, + amiga_restore_state, + + amiga_enable_irq, + amiga_disable_irq, + amiga_interrupt, + + amiga_inc_use_count, + amiga_dec_use_count, + amiga_fill_inode +}; + +/* ----------- Initialisation code --------------------------------- */ + +__initfunc(int parport_amiga_init(void)) +{ + struct parport *p; + + if (MACH_IS_AMIGA && AMIGAHW_PRESENT(AMI_PARALLEL)) { + ciaa.ddrb = 0xff; + ciab.ddra &= 0xf8; + if (!(p = parport_register_port((unsigned long)&ciaa.prb, + IRQ_AMIGA_CIAA_FLG, PARPORT_DMA_NONE, + &pp_amiga_ops))) + return 0; + this_port = p; + printk(KERN_INFO "%s: Amiga built-in port using irq\n", p->name); + /* XXX: set operating mode */ + parport_proc_register(p); + p->flags |= PARPORT_FLAG_COMA; + + if (parport_probe_hook) + (*parport_probe_hook)(p); + return 1; + + } + return 0; +} + +#ifdef MODULE + +MODULE_AUTHOR("Joerg Dorchain"); +MODULE_DESCRIPTION("Parport Driver for Amiga builtin Port"); +MODULE_SUPPORTED_DEVICE("Amiga builtin Parallel Port"); + +int init_module(void) +{ + return ! parport_amiga_init(); +} + +void cleanup_module(void) +{ + if (!(this_port->flags & PARPORT_FLAG_COMA)) + parport_quiesce(this_port); + parport_proc_unregister(this_port); + parport_unregister_port(this_port); +} +#endif + + diff -ur --new-file old/linux/drivers/misc/parport_atari.c new/linux/drivers/misc/parport_atari.c --- old/linux/drivers/misc/parport_atari.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/misc/parport_atari.c Tue May 11 18:55:49 1999 @@ -0,0 +1,263 @@ +/* Low-level parallel port routines for the Atari builtin port + * + * Author: Andreas Schwab + * + * Based on parport_amiga.c. + * + * The built-in Atari parallel port provides one port at a fixed address + * with 8 output data lines (D0 - D7), 1 output control line (STROBE) + * and 1 input status line (BUSY) able to cause an interrupt. + */ + +#include +#include +#include +#include +#include +#include +#include + +static struct parport *this_port = NULL; + +static unsigned char +parport_atari_read_data(struct parport *p) +{ + unsigned long flags; + unsigned char data; + + save_flags(flags); + cli(); + sound_ym.rd_data_reg_sel = 15; + data = sound_ym.rd_data_reg_sel; + restore_flags(flags); + return data; +} + +static void +parport_atari_write_data(struct parport *p, unsigned char data) +{ + unsigned long flags; + + save_flags(flags); + cli(); + sound_ym.rd_data_reg_sel = 15; + sound_ym.wd_data = data; + restore_flags(flags); +} + +static unsigned char +parport_atari_read_control(struct parport *p) +{ + unsigned long flags; + unsigned char control = 0; + + save_flags(flags); + cli(); + sound_ym.rd_data_reg_sel = 14; + if (!(sound_ym.rd_data_reg_sel & (1 << 5))) + control = PARPORT_CONTROL_STROBE; + restore_flags(flags); + return control; +} + +static void +parport_atari_write_control(struct parport *p, unsigned char control) +{ + unsigned long flags; + + save_flags(flags); + cli(); + sound_ym.rd_data_reg_sel = 14; + if (control & PARPORT_CONTROL_STROBE) + sound_ym.wd_data = sound_ym.rd_data_reg_sel & ~(1 << 5); + else + sound_ym.wd_data = sound_ym.rd_data_reg_sel | (1 << 5); + restore_flags(flags); +} + +static unsigned char +parport_atari_frob_control(struct parport *p, unsigned char mask, + unsigned char val) +{ + unsigned char old = parport_atari_read_control(p); + parport_atari_write_control(p, (old & ~mask) ^ val); + return old; +} + +static unsigned char +parport_atari_read_status(struct parport *p) +{ + return ((mfp.par_dt_reg & 1 ? 0 : PARPORT_STATUS_BUSY) | + PARPORT_STATUS_SELECT | PARPORT_STATUS_ERROR); +} + +static void +parport_atari_write_status(struct parport *p, unsigned char status) +{ +} + +static void +parport_atari_init_state(struct parport_state *s) +{ +} + +static void +parport_atari_save_state(struct parport *p, struct parport_state *s) +{ +} + +static void +parport_atari_restore_state(struct parport *p, struct parport_state *s) +{ +} + +static void +parport_atari_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + parport_generic_irq(irq, (struct parport *) dev_id, regs); +} + +static void +parport_atari_release_resources(struct parport *p) +{ + if (p->irq != PARPORT_IRQ_NONE) + free_irq(IRQ_MFP_BUSY, p); +} + +static int +parport_atari_claim_resources(struct parport *p) +{ + return request_irq(IRQ_MFP_BUSY, parport_atari_interrupt, + IRQ_TYPE_SLOW, p->name, p); +} + +static void +parport_atari_inc_use_count(void) +{ + MOD_INC_USE_COUNT; +} + +static void +parport_atari_dec_use_count(void) +{ + MOD_DEC_USE_COUNT; +} + +static void +parport_atari_fill_inode(struct inode *inode, int fill) +{ +#ifdef MODULE + if (fill) + MOD_INC_USE_COUNT; + else + MOD_DEC_USE_COUNT; +#endif +} + +static struct parport_operations parport_atari_ops = { + parport_atari_write_data, + parport_atari_read_data, + + parport_atari_write_control, + parport_atari_read_control, + parport_atari_frob_control, + + NULL, /* write_econtrol */ + NULL, /* read_econtrol */ + NULL, /* frob_econtrol */ + + parport_atari_write_status, + parport_atari_read_status, + + NULL, /* write fifo */ + NULL, /* read fifo */ + + NULL, /* change_mode */ + + parport_atari_release_resources, + parport_atari_claim_resources, + + NULL, /* epp_write_data */ + NULL, /* epp_read_data */ + NULL, /* epp_write_addr */ + NULL, /* epp_read_addr */ + NULL, /* epp_check_timeout */ + + NULL, /* epp_write_block */ + NULL, /* epp_read_block */ + + NULL, /* ecp_write_block */ + NULL, /* ecp_read_block */ + + parport_atari_init_state, + parport_atari_save_state, + parport_atari_restore_state, + + NULL, /* enable_irq */ + NULL, /* disable_irq */ + parport_atari_interrupt, + + parport_atari_inc_use_count, + parport_atari_dec_use_count, + parport_atari_fill_inode +}; + + +int __init +parport_atari_init(void) +{ + struct parport *p; + unsigned long flags; + + if (MACH_IS_ATARI) { + save_flags(flags); + cli(); + /* Soundchip port A/B as output. */ + sound_ym.rd_data_reg_sel = 7; + sound_ym.wd_data = (sound_ym.rd_data_reg_sel & 0x3f) | 0xc0; + /* STROBE high. */ + sound_ym.rd_data_reg_sel = 14; + sound_ym.wd_data = sound_ym.rd_data_reg_sel | (1 << 5); + restore_flags(flags); + /* MFP port I0 as input. */ + mfp.data_dir &= ~1; + /* MFP port I0 interrupt on high->low edge. */ + mfp.active_edge &= ~1; + p = parport_register_port((unsigned long)&sound_ym.wd_data, + IRQ_MFP_BUSY, PARPORT_DMA_NONE, + &parport_atari_ops); + if (!p) + return 0; + this_port = p; + printk(KERN_INFO "%s: Atari built-in port using irq\n", p->name); + parport_proc_register(p); + p->flags |= PARPORT_FLAG_COMA; + + if (parport_probe_hook) + (*parport_probe_hook)(p); + return 1; + } + return 0; +} + +#ifdef MODULE + +MODULE_AUTHOR("Andreas Schwab"); +MODULE_DESCRIPTION("Parport Driver for Atari builtin Port"); +MODULE_SUPPORTED_DEVICE("Atari builtin Parallel Port"); + +int +init_module(void) +{ + return parport_atari_init() ? 0 : -ENODEV; +} + +void +cleanup_module(void) +{ + if (!(this_port->flags & PARPORT_FLAG_COMA)) + parport_quiesce(this_port); + parport_proc_unregister(this_port); + parport_unregister_port(this_port); +} +#endif diff -ur --new-file old/linux/drivers/misc/parport_ax.c new/linux/drivers/misc/parport_ax.c --- old/linux/drivers/misc/parport_ax.c Thu Jan 7 18:28:47 1999 +++ new/linux/drivers/misc/parport_ax.c Tue Mar 16 01:11:30 1999 @@ -1,4 +1,4 @@ -/* $Id: parport_ax.c,v 1.14 1998/11/16 04:48:02 davem Exp $ +/* $Id: parport_ax.c,v 1.17 1999/01/20 06:18:54 davem Exp $ * Parallel-port routines for Sun Ultra/AX architecture * * Author: Eddie C. Dost @@ -220,13 +220,13 @@ /* FIXME check that resources are free */ int err; - if (p->irq != PARPORT_IRQ_NONE) + if (p->irq != PARPORT_IRQ_NONE) { if ((err = request_irq(p->irq, parport_ax_interrupt, 0, p->name, p)) != 0) return err; else parport_ax_enable_irq(p); - + } request_region(p->base, p->size, p->name); if (p->modes & PARPORT_MODE_PCECR) request_region(p->base+0x400, 3, p->name); diff -ur --new-file old/linux/drivers/misc/parport_ieee1284.c new/linux/drivers/misc/parport_ieee1284.c --- old/linux/drivers/misc/parport_ieee1284.c Wed Jan 20 22:29:18 1999 +++ new/linux/drivers/misc/parport_ieee1284.c Mon May 10 19:26:31 1999 @@ -48,26 +48,24 @@ int parport_ieee1284_nibble_mode_ok(struct parport *port, unsigned char mode) { /* make sure it's a valid state, set nStrobe & nAutoFeed high */ - parport_write_control(port, (parport_read_control(port) \ - & ~1 ) & ~2); + parport_frob_control (port, (1|2), 0); udelay(1); parport_write_data(port, mode); - udelay(1); + udelay(400); /* nSelectIn high, nAutoFd low */ - parport_write_control(port, (parport_read_control(port) & ~8) | 2); + parport_frob_control(port, (2|8), 2); if (parport_wait_peripheral(port, 0x78, 0x38)) { - parport_write_control(port, - (parport_read_control(port) & ~2) | 8); + parport_frob_control(port, (2|8), 8); return 0; } /* nStrobe low */ - parport_write_control(port, parport_read_control(port) | 1); + parport_frob_control (port, 1, 1); udelay(1); /* Strobe wait */ /* nStrobe high, nAutoFeed low, last step before transferring * reverse data */ - parport_write_control(port, (parport_read_control(port) \ - & ~1) & ~2); + parport_frob_control (port, (1|2), 0); udelay(1); /* Data available? */ - return (parport_wait_peripheral(port, 0x20, 0))?1:2; + parport_wait_peripheral (port, PARPORT_STATUS_ACK, PARPORT_STATUS_ACK); + return (parport_read_status(port) & PARPORT_STATUS_ERROR)?1:2; } diff -ur --new-file old/linux/drivers/misc/parport_init.c new/linux/drivers/misc/parport_init.c --- old/linux/drivers/misc/parport_init.c Sun Jan 3 02:55:05 1999 +++ new/linux/drivers/misc/parport_init.c Tue May 11 18:55:49 1999 @@ -126,6 +126,15 @@ #ifdef CONFIG_PARPORT_AX parport_ax_init(); #endif +#ifdef CONFIG_PARPORT_AMIGA + parport_amiga_init(); +#endif +#ifdef CONFIG_PARPORT_MFC3 + parport_mfc3_init(); +#endif +#ifdef CONFIG_PARPORT_ATARI + parport_atari_init(); +#endif return 0; } #endif diff -ur --new-file old/linux/drivers/misc/parport_mfc3.c new/linux/drivers/misc/parport_mfc3.c --- old/linux/drivers/misc/parport_mfc3.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/misc/parport_mfc3.c Tue May 11 18:55:49 1999 @@ -0,0 +1,420 @@ +/* Low-level parallel port routines for the Multiface 3 card + * + * Author: Joerg Dorchain + * + * (C) The elitist m68k Users(TM) + * + * based on the existing parport_amiga and lp_mfc + * + * + * From the MFC3 documentation: + * + * Miscellaneous PIA Details + * ------------------------- + * + * The two open-drain interrupt outputs /IRQA and /IRQB are routed to + * /INT2 of the Z2 bus. + * + * The CPU data bus of the PIA (D0-D7) is connected to D8-D15 on the Z2 + * bus. This means that any PIA registers are accessed at even addresses. + * + * Centronics Pin Connections for the PIA + * -------------------------------------- + * + * The following table shows the connections between the PIA and the + * Centronics interface connector. These connections implement a single, but + * very complete, Centronics type interface. The Pin column gives the pin + * numbers of the PIA. The Centronics pin numbers can be found in the section + * "Parallel Connectors". + * + * + * Pin | PIA | Dir | Centronics Names + * -------+-----+-----+--------------------------------------------------------- + * 19 | CB2 | --> | /STROBE (aka /DRDY) + * 10-17 | PBx | <-> | DATA0 - DATA7 + * 18 | CB1 | <-- | /ACK + * 40 | CA1 | <-- | BUSY + * 3 | PA1 | <-- | PAPER-OUT (aka POUT) + * 4 | PA2 | <-- | SELECTED (aka SEL) + * 9 | PA7 | --> | /INIT (aka /RESET or /INPUT-PRIME) + * 6 | PA4 | <-- | /ERROR (aka /FAULT) + * 7 | PA5 | --> | DIR (aka /SELECT-IN) + * 8 | PA6 | --> | /AUTO-FEED-XT + * 39 | CA2 | --> | open + * 5 | PA3 | <-- | /ACK (same as CB1!) + * 2 | PA0 | <-- | BUSY (same as CA1!) + * -------+-----+-----+--------------------------------------------------------- + * + * Should be enough to understand some of the driver. + */ + +#include "multiface.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Maximum Number of Cards supported */ +#define MAX_MFC 5 + +#undef DEBUG +#ifdef DEBUG +#define DPRINTK printk +#else +static inline int DPRINTK() {return 0;} +#endif + +static struct parport *this_port[MAX_MFC] = {NULL, }; +static volatile int dummy; /* for trigger readds */ + +#define pia(dev) ((struct pia *)(dev->base)) +static struct parport_operations pp_mfc3_ops; + +static void mfc3_write_data(struct parport *p, unsigned char data) +{ +DPRINTK("write_data %c\n",data); + + dummy = pia(p)->pprb; /* clears irq bit */ + /* Triggers also /STROBE.*/ + pia(p)->pprb = data; +} + +static unsigned char mfc3_read_data(struct parport *p) +{ + /* clears interupt bit. Triggers also /STROBE. */ + return pia(p)->pprb; +} + +static unsigned char control_pc_to_mfc3(unsigned char control) +{ + unsigned char ret = 32|64; + + if (control & PARPORT_CONTROL_DIRECTION) /* XXX: What is this? */ + ; + if (control & PARPORT_CONTROL_INTEN) /* XXX: What is INTEN? */ + ; + if (control & PARPORT_CONTROL_SELECT) /* XXX: What is SELECP? */ + ret &= ~32; /* /SELECT_IN */ + if (control & PARPORT_CONTROL_INIT) /* INITP */ + ret |= 128; + if (control & PARPORT_CONTROL_AUTOFD) /* AUTOLF */ + ret &= ~64; + if (control & PARPORT_CONTROL_STROBE) /* Strobe */ + /* Handled directly by hardware */; + return ret; +} + +static unsigned char control_mfc3_to_pc(unsigned char control) +{ + unsigned char ret = PARPORT_CONTROL_INTEN | PARPORT_CONTROL_STROBE + | PARPORT_CONTROL_AUTOFD | PARPORT_CONTROL_SELECT; + + if (control & 128) /* /INITP */ + ret |= PARPORT_CONTROL_INIT; + if (control & 64) /* /AUTOLF */ + ret &= ~PARPORT_CONTROL_AUTOFD; + if (control & 32) /* /SELECT_IN */ + ret &= ~PARPORT_CONTROL_SELECT; + return ret; +} + +static void mfc3_write_control(struct parport *p, unsigned char control) +{ +DPRINTK("write_control %02x\n",control); + pia(p)->ppra = (pia(p)->ppra & 0x1f) | control_pc_to_mfc3(control); +} + +static unsigned char mfc3_read_control( struct parport *p) +{ +DPRINTK("read_control \n"); + return control_mfc3_to_pc(pia(p)->ppra & 0xe0); +} + +static unsigned char mfc3_frob_control( struct parport *p, unsigned char mask, unsigned char val) +{ + unsigned char old; + +DPRINTK("frob_control mask %02x, value %02x\n",mask,val); + old = mfc3_read_control(p); + mfc3_write_control(p, (old & ~mask) ^ val); + return old; +} + + +static unsigned char status_pc_to_mfc3(unsigned char status) +{ + unsigned char ret = 1; + + if (status & PARPORT_STATUS_BUSY) /* Busy */ + ret &= ~1; + if (status & PARPORT_STATUS_ACK) /* Ack */ + ret |= 8; + if (status & PARPORT_STATUS_PAPEROUT) /* PaperOut */ + ret |= 2; + if (status & PARPORT_STATUS_SELECT) /* select */ + ret |= 4; + if (status & PARPORT_STATUS_ERROR) /* error */ + ret |= 16; + return ret; +} + +static unsigned char status_mfc3_to_pc(unsigned char status) +{ + unsigned char ret = PARPORT_STATUS_BUSY; + + if (status & 1) /* Busy */ + ret &= ~PARPORT_STATUS_BUSY; + if (status & 2) /* PaperOut */ + ret |= PARPORT_STATUS_PAPEROUT; + if (status & 4) /* Selected */ + ret |= PARPORT_STATUS_SELECT; + if (status & 8) /* Ack */ + ret |= PARPORT_STATUS_ACK; + if (status & 16) /* /ERROR */ + ret |= PARPORT_STATUS_ERROR; + + return ret; +} + +static void mfc3_write_status( struct parport *p, unsigned char status) +{ +DPRINTK("write_status %02x\n",status); + pia(p)->ppra = (pia(p)->ppra & 0xe0) | status_pc_to_mfc3(status); +} + +static unsigned char mfc3_read_status(struct parport *p) +{ + unsigned char status; + + status = status_mfc3_to_pc(pia(p)->ppra & 0x1f); +DPRINTK("read_status %02x\n", status); + return status; +} + +static void mfc3_change_mode( struct parport *p, int m) +{ + /* XXX: This port only has one mode, and I am + not sure about the corresponding PC-style mode*/ +} + +static int use_cnt = 0; + +static void mfc3_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + int i; + + for( i = 0; i < MAX_MFC; i++) + if (this_port[i] != NULL) + if (pia(this_port[i])->crb & 128) { /* Board caused interrupt */ + dummy = pia(this_port[i])->pprb; /* clear irq bit */ + parport_generic_irq(irq, this_port[i], regs); + } +} + +static void mfc3_release_resources(struct parport *p) +{ +DPRINTK("realease_resources\n"); + if (p->irq != PARPORT_IRQ_NONE) + if (--use_cnt == 0) + free_irq(IRQ_AMIGA_PORTS, &pp_mfc3_ops); +} + +static int mfc3_claim_resources(struct parport *p) +{ +DPRINTK("claim_resources\n"); + if (p->irq != PARPORT_IRQ_NONE) + if (use_cnt++ == 0) + if (request_irq(IRQ_AMIGA_PORTS, mfc3_interrupt, 0, p->name, &pp_mfc3_ops)) + return use_cnt--; + return 0; +} + +static void mfc3_init_state(struct parport_state *s) +{ + s->u.amiga.data = 0; + s->u.amiga.datadir = 255; + s->u.amiga.status = 0; + s->u.amiga.statusdir = 0xe0; +} + +static void mfc3_save_state(struct parport *p, struct parport_state *s) +{ + s->u.amiga.data = pia(p)->pprb; + pia(p)->crb &= ~PIA_DDR; + s->u.amiga.datadir = pia(p)->pddrb; + pia(p)->crb |= PIA_DDR; + s->u.amiga.status = pia(p)->ppra; + pia(p)->cra &= ~PIA_DDR; + s->u.amiga.statusdir = pia(p)->pddrb; + pia(p)->cra |= PIA_DDR; +} + +static void mfc3_restore_state(struct parport *p, struct parport_state *s) +{ + pia(p)->pprb = s->u.amiga.data; + pia(p)->crb &= ~PIA_DDR; + pia(p)->pddrb = s->u.amiga.datadir; + pia(p)->crb |= PIA_DDR; + pia(p)->ppra = s->u.amiga.status; + pia(p)->cra &= ~PIA_DDR; + pia(p)->pddrb = s->u.amiga.statusdir; + pia(p)->cra |= PIA_DDR; +} + +static void mfc3_enable_irq(struct parport *p) +{ + pia(p)->crb |= PIA_C1_ENABLE_IRQ; +} + +static void mfc3_disable_irq(struct parport *p) +{ + pia(p)->crb &= ~PIA_C1_ENABLE_IRQ; +} + +static void mfc3_inc_use_count(void) +{ + MOD_INC_USE_COUNT; +} + +static void mfc3_dec_use_count(void) +{ + MOD_DEC_USE_COUNT; +} + +static void mfc3_fill_inode(struct inode *inode, int fill) +{ +#ifdef MODULE + if (fill) + MOD_INC_USE_COUNT; + else + MOD_DEC_USE_COUNT; +#endif +} + +static struct parport_operations pp_mfc3_ops = { + mfc3_write_data, + mfc3_read_data, + + mfc3_write_control, + mfc3_read_control, + mfc3_frob_control, + + NULL, /* write_econtrol */ + NULL, /* read_econtrol */ + NULL, /* frob_econtrol */ + + mfc3_write_status, + mfc3_read_status, + + NULL, /* write fifo */ + NULL, /* read fifo */ + + mfc3_change_mode, + + + mfc3_release_resources, + mfc3_claim_resources, + + + NULL, /* epp_write_data */ + NULL, /* epp_read_data */ + NULL, /* epp_write_addr */ + NULL, /* epp_read_addr */ + NULL, /* epp_check_timeout */ + + NULL, /* epp_write_block */ + NULL, /* epp_read_block */ + + NULL, /* ecp_write_block */ + NULL, /* ecp_read_block */ + + mfc3_init_state, + mfc3_save_state, + mfc3_restore_state, + + mfc3_enable_irq, + mfc3_disable_irq, + mfc3_interrupt, + + mfc3_inc_use_count, + mfc3_dec_use_count, + mfc3_fill_inode +}; + +/* ----------- Initialisation code --------------------------------- */ + +__initfunc(int parport_mfc3_init(void)) +{ + struct parport *p; + int pias = 0; + struct pia *pp; + unsigned int key = 0; + const struct ConfigDev *cd; + + if (MACH_IS_AMIGA) { + while ((key = zorro_find(ZORRO_PROD_BSC_MULTIFACE_III, 0, key))) { + cd = zorro_get_board(key); + pp = (struct pia *)ZTWO_VADDR((((u_char *)cd->cd_BoardAddr)+PIABASE)); + if (pias < MAX_MFC) { + pp->crb = 0; + pp->pddrb = 255; /* all data pins output */ + pp->crb = PIA_DDR|32|8; + dummy = pp->pddrb; /* reading clears interrupt */ + pp->cra = 0; + pp->pddra = 0xe0; /* /RESET, /DIR ,/AUTO-FEED output */ + pp->cra = PIA_DDR; + pp->ppra = 0; /* reset printer */ + udelay(10); + pp->ppra = 128; + if ((p = parport_register_port((unsigned long)pp, + IRQ_AMIGA_PORTS, PARPORT_DMA_NONE, + &pp_mfc3_ops))) { + this_port[pias++] = p; + printk(KERN_INFO "%s: Multiface III port using irq\n", p->name); + /* XXX: set operating mode */ + parport_proc_register(p); + p->flags |= PARPORT_FLAG_COMA; + if (parport_probe_hook) + (*parport_probe_hook)(p); + zorro_config_board(key, 0); + p->private_data = (void *)key; + } + } + } + } + return pias; +} + +#ifdef MODULE + +MODULE_AUTHOR("Joerg Dorchain"); +MODULE_DESCRIPTION("Parport Driver for Multiface 3 expansion cards Paralllel Port"); +MODULE_SUPPORTED_DEVICE("Multiface 3 Parallel Port"); + +int init_module(void) +{ + return ! parport_mfc3_init(); +} + +void cleanup_module(void) +{ + int i; + + for (i = 0; i < MAX_MFC; i++) + if (this_port[i] != NULL) { + if (!(this_port[i]->flags & PARPORT_FLAG_COMA)) + parport_quiesce(this_port[i]); + parport_proc_unregister(this_port[i]); + parport_unregister_port(this_port[i]); + zorro_unconfig_board((unsigned int)this_port[i]->private_data, 0); + } +} +#endif + + diff -ur --new-file old/linux/drivers/misc/parport_pc.c new/linux/drivers/misc/parport_pc.c --- old/linux/drivers/misc/parport_pc.c Sun Jan 3 02:55:05 1999 +++ new/linux/drivers/misc/parport_pc.c Mon May 10 19:26:31 1999 @@ -53,6 +53,8 @@ than PARPORT_MAX (in ). */ #define PARPORT_PC_MAX_PORTS 8 +static int user_specified = 0; + static void parport_pc_interrupt(int irq, void *dev_id, struct pt_regs *regs) { parport_generic_irq(irq, (struct parport *) dev_id, regs); @@ -103,19 +105,24 @@ void parport_pc_write_control(struct parport *p, unsigned char d) { + struct parport_pc_private *priv = p->private_data; + priv->ctr = d;/* update soft copy */ outb(d, p->base+CONTROL); } unsigned char parport_pc_read_control(struct parport *p) { - return inb(p->base+CONTROL); + struct parport_pc_private *priv = p->private_data; + return priv->ctr; } unsigned char parport_pc_frob_control(struct parport *p, unsigned char mask, unsigned char val) { - unsigned char old = inb(p->base+CONTROL); - outb(((old & ~mask) ^ val), p->base+CONTROL); - return old; + struct parport_pc_private *priv = p->private_data; + unsigned char ctr = priv->ctr; + ctr = (ctr & ~mask) ^ val; + outb (ctr, p->base+CONTROL); + return priv->ctr = ctr; /* update soft copy */ } void parport_pc_write_status(struct parport *p, unsigned char d) @@ -345,6 +352,8 @@ */ static int parport_SPP_supported(struct parport *pb) { + unsigned char r, w; + /* * first clear an eventually pending EPP timeout * I (sailer@ife.ee.ethz.ch) have an SMSC chipset @@ -354,14 +363,54 @@ parport_pc_epp_clear_timeout(pb); /* Do a simple read-write test to make sure the port exists. */ - parport_pc_write_control(pb, 0xc); - parport_pc_write_data(pb, 0xaa); - if (parport_pc_read_data(pb) != 0xaa) return 0; - - parport_pc_write_data(pb, 0x55); - if (parport_pc_read_data(pb) != 0x55) return 0; + w = 0xc; + parport_pc_write_control(pb, w); - return PARPORT_MODE_PCSPP; + /* Can we read from the control register? Some ports don't + * allow reads, so read_control just returns a software + * copy. Some ports _do_ allow reads, so bypass the software + * copy here. In addition, some bits aren't writable. */ + r = inb (pb->base+CONTROL); + if ((r & 0x3f) == w) { + w = 0xe; + parport_pc_write_control (pb, w); + r = inb (pb->base+CONTROL); + parport_pc_write_control (pb, 0xc); + if ((r & 0x3f) == w) + return PARPORT_MODE_PCSPP; + } + + if (user_specified) + /* That didn't work, but the user thinks there's a + * port here. */ + printk (KERN_DEBUG "0x%lx: CTR: wrote 0x%02x, read 0x%02x\n", + pb->base, w, r); + + /* Try the data register. The data lines aren't tri-stated at + * this stage, so we expect back what we wrote. */ + w = 0xaa; + parport_pc_write_data (pb, w); + r = parport_pc_read_data (pb); + if (r == w) { + w = 0x55; + parport_pc_write_data (pb, w); + r = parport_pc_read_data (pb); + if (r == w) + return PARPORT_MODE_PCSPP; + } + + if (user_specified) + /* Didn't work with 0xaa, but the user is convinced + * this is the place. */ + printk (KERN_DEBUG "0x%lx: DATA: wrote 0x%02x, read 0x%02x\n", + pb->base, w, r); + + /* It's possible that we can't read the control register or + the data register. In that case just believe the user. */ + if (user_specified) + return PARPORT_MODE_PCSPP; + + return 0; } /* Check for ECP @@ -378,34 +427,35 @@ */ static int parport_ECR_present(struct parport *pb) { - unsigned char r, octr = parport_pc_read_control(pb); - unsigned char oecr = parport_pc_read_econtrol(pb); - unsigned char tmp; + unsigned char r; + parport_pc_write_control (pb, 0xc); r = parport_pc_read_control(pb); if ((parport_pc_read_econtrol(pb) & 0x3) == (r & 0x3)) { parport_pc_write_control(pb, r ^ 0x2 ); /* Toggle bit 1 */ r = parport_pc_read_control(pb); - if ((parport_pc_read_econtrol(pb) & 0x2) == (r & 0x2)) { - parport_pc_write_control(pb, octr); - return 0; /* Sure that no ECR register exists */ - } + if ((parport_pc_read_econtrol(pb) & 0x2) == (r & 0x2)) + goto no_reg; /* Sure that no ECR register exists */ } if ((parport_pc_read_econtrol(pb) & 0x3 ) != 0x1) - return 0; + goto no_reg; parport_pc_write_econtrol(pb, 0x34); - tmp = parport_pc_read_econtrol(pb); + if (parport_pc_read_econtrol(pb) != 0x35) + goto no_reg; - parport_pc_write_econtrol(pb, oecr); - parport_pc_write_control(pb, octr); - - if (tmp != 0x35) - return 0; + parport_pc_write_control(pb, 0xc); + /* Go to mode 000; SPP, reset FIFO */ + parport_pc_frob_econtrol (pb, 0xe0, 0x00); + return PARPORT_MODE_PCECR; + + no_reg: + parport_pc_write_control (pb, 0xc); + return 0; } static int parport_ECP_supported(struct parport *pb) @@ -706,14 +756,20 @@ static int probe_one_port(unsigned long int base, int irq, int dma) { - struct parport tmpport, *p; + struct parport *p; int probedirq = PARPORT_IRQ_NONE; if (check_region(base, 3)) return 0; - tmpport.base = base; - tmpport.ops = &parport_pc_ops; - if (!(parport_SPP_supported(&tmpport))) return 0; - if (!(p = parport_register_port(base, irq, dma, &parport_pc_ops))) return 0; - p->modes = PARPORT_MODE_PCSPP | parport_PS2_supported(p); + if (!(p = parport_register_port(base, irq, dma, &parport_pc_ops))) + return 0; + p->private_data = kmalloc (sizeof (struct parport_pc_private), + GFP_KERNEL); + if (!p->private_data) { + /* Not enough memory. */ + printk (KERN_DEBUG "parport (0x%lx): no memory!\n", base); + parport_unregister_port (p); + return 0; + } + ((struct parport_pc_private *) (p->private_data))->ctr = 0xc; if (p->base != 0x3bc) { if (!check_region(base+0x400,3)) { p->modes |= parport_ECR_present(p); @@ -725,6 +781,13 @@ p->modes |= parport_ECPEPP_supported(p); } } + if (!parport_SPP_supported(p)) { + /* No port. */ + kfree (p->private_data); + parport_unregister_port (p); + return 0; + } + p->modes |= PARPORT_MODE_PCSPP | parport_PS2_supported(p); p->size = (p->modes & (PARPORT_MODE_PCEPP | PARPORT_MODE_PCECPEPP))?8:3; printk(KERN_INFO "%s: PC-style at 0x%lx", p->name, p->base); @@ -783,6 +846,7 @@ int count = 0, i = 0; if (io && *io) { /* Only probe the ports we were given. */ + user_specified = 1; do { count += probe_one_port(*(io++), *(irq++), *(dma++)); } while (*io && (++i < PARPORT_PC_MAX_PORTS)); @@ -825,6 +889,7 @@ if (!(p->flags & PARPORT_FLAG_COMA)) parport_quiesce(p); parport_proc_unregister(p); + kfree (p->private_data); parport_unregister_port(p); } p = tmp; diff -ur --new-file old/linux/drivers/net/3c507.c new/linux/drivers/net/3c507.c --- old/linux/drivers/net/3c507.c Tue Feb 10 21:56:43 1998 +++ new/linux/drivers/net/3c507.c Fri May 7 08:14:36 1999 @@ -40,6 +40,7 @@ info that the casual reader might think that it documents the i82586 :-<. */ +#include #include #include #include @@ -53,6 +54,7 @@ #include #include #include +#include #include #include @@ -123,6 +125,7 @@ ushort tx_head; ushort tx_cmd_link; ushort tx_reap; + spinlock_t lock; }; /* @@ -448,6 +451,7 @@ struct net_local *lp = (struct net_local *)dev->priv; int ioaddr = dev->base_addr; unsigned long shmem = dev->mem_start; + unsigned long flags; if (dev->tbusy) { @@ -487,7 +491,13 @@ lp->stats.tx_bytes+=length; /* Disable the 82586's input to the interrupt line. */ outb(0x80, ioaddr + MISC_CTRL); +#ifdef CONFIG_SMP + spin_lock_irqsave(&lp->lock, flags); hardware_send_packet(dev, buf, length); + spin_unlock_irqrestore(&lp->lock, flags); +#else + hardware_send_packet(dev, buf, length); +#endif dev->trans_start = jiffies; /* Enable the 82586 interrupt input. */ outb(0x84, ioaddr + MISC_CTRL); @@ -515,11 +525,14 @@ return; } dev->interrupt = 1; + ioaddr = dev->base_addr; lp = (struct net_local *)dev->priv; shmem = dev->mem_start; + spin_lock(&lp->lock); + status = readw(shmem+iSCB_STATUS); if (net_debug > 4) { @@ -598,6 +611,7 @@ /* Enable the 82586's interrupt input. */ outb(0x84, ioaddr + MISC_CTRL); + spin_unlock(&lp->lock); return; } diff -ur --new-file old/linux/drivers/net/3c509.c new/linux/drivers/net/3c509.c --- old/linux/drivers/net/3c509.c Thu Dec 17 18:03:57 1998 +++ new/linux/drivers/net/3c509.c Thu May 6 23:02:34 1999 @@ -1,8 +1,8 @@ /* 3c509.c: A 3c509 EtherLink3 ethernet driver for linux. */ /* - Written 1993-1997 by Donald Becker. + Written 1993-1998 by Donald Becker. - Copyright 1994-1997 by Donald Becker. + Copyright 1994-1998 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, @@ -35,19 +35,24 @@ other cleanups. -djb Andrea Arcangeli: Upgraded to Donald Becker's version 1.12. Rick Payne: Fixed SMP race condition + v1.13 9/8/97 Made 'max_interrupt_work' an insmod-settable variable -djb + v1.14 10/15/97 Avoided waiting..discard message for fast machines -djb + v1.15 1/31/98 Faster recovery for Tx errors. -djb + v1.16 2/3/98 Different ID port handling to avoid sound cards. -djb */ -static char *version = "3c509.c:1.12 6/4/97 becker@cesdis.gsfc.nasa.gov\n"; +static char *version = "3c509.c:1.16 (2.2) 2/3/98 becker@cesdis.gsfc.nasa.gov.\n"; /* A few values that may be tweaked. */ /* Time in jiffies before concluding the transmitter is hung. */ #define TX_TIMEOUT (400*HZ/1000) /* Maximum events (Rx packets, etc.) to handle at each interrupt. */ -#define INTR_WORK 10 +static int max_interrupt_work = 10; +#include #include -#include /* for CONFIG_MCA */ +#include #include #include #include @@ -129,12 +134,13 @@ /* skb send-queue */ int head, size; struct sk_buff *queue[SKB_QUEUE_SIZE]; + char mca_slot; }; -static int id_port = 0x100; +static int id_port = 0x110; /* Start with 0x110 to avoid new sound cards.*/ static struct device *el3_root_dev = NULL; static ushort id_read_eeprom(int index); -static ushort read_eeprom(short ioaddr, int index); +static ushort read_eeprom(int ioaddr, int index); static int el3_open(struct device *dev); static int el3_start_xmit(struct sk_buff *skb, struct device *dev); static void el3_interrupt(int irq, void *dev_id, struct pt_regs *regs); @@ -144,14 +150,29 @@ static int el3_close(struct device *dev); static void set_multicast_list(struct device *dev); - +#ifdef CONFIG_MCA +struct el3_mca_adapters_struct { + char* name; + int id; +}; + +struct el3_mca_adapters_struct el3_mca_adapters[] = { + { "3Com 3c529 EtherLink III (10base2)", 0x627c }, + { "3Com 3c529 EtherLink III (10baseT)", 0x627d }, + { "3Com 3c529 EtherLink III (test mode)", 0x62db }, + { "3Com 3c529 EtherLink III (TP or coax)", 0x62f6 }, + { "3Com 3c529 EtherLink III (TP)", 0x62f7 }, + { NULL, 0 }, +}; +#endif int el3_probe(struct device *dev) { short lrs_state = 0xff, i; - ushort ioaddr, irq, if_port; - short phys_addr[3]; + int ioaddr, irq, if_port; + u16 phys_addr[3]; static int current_tag = 0; + int mca_slot = -1; /* First check all slots of the EISA bus. The next slot address to probe is kept in 'eisa_addr' to support multiple probe() calls. */ @@ -182,69 +203,72 @@ } #ifdef CONFIG_MCA -#define MCA_NUMBER_OF_SLOTS 8 -#define MCA_PORT_POS_SEL 0x096 -#define MCA_PORT_ID_REG_0 0x100 -#define MCA_PORT_ID_REG_1 0x101 -#define MCA_SELECT_BIT 0x08 - if (MCA_bus) - { - u_int mca_id; - u_char posreg[4]; - int mca_slot; - - if (el3_debug > 2) - printk("3c529: probing...\n"); - /* This should probably be done once early on and read into - * a structure somewhere... */ - for (mca_slot = 0; mca_slot < MCA_NUMBER_OF_SLOTS; mca_slot++) - { - /* Select MCA slot i */ - outb_p(mca_slot | MCA_SELECT_BIT, MCA_PORT_POS_SEL); - mca_id = ((inb_p(MCA_PORT_ID_REG_1)<<8) - + inb_p(MCA_PORT_ID_REG_0)); - if (mca_id == 0x627C /* 10base2 */ - || mca_id == 0x627D /* 10baseT */ - || mca_id == 0x62DB /* Test mode */ - || mca_id == 0x62F6 /* TP or coax */ - || mca_id == 0x62F7) /* TP only */ - { - if (el3_debug > 1) - printk("3c529: Found with id 0x%x at slot %d\n", - mca_id, mca_slot); - posreg[0] = inb_p(0x102); posreg[1] = inb_p(0x103); - posreg[2] = inb_p(0x104); posreg[3] = inb_p(0x105); - break; + /* Based on Erik Nygren's (nygren@mit.edu) 3c529 patch, heavily + * modified by Chris Beauregard (cpbeaure@csclub.uwaterloo.ca) + * to support standard MCA probing. + * + * redone for multi-card detection by ZP Gu (zpg@castle.net) + * now works as a module + */ + + if( MCA_bus ) { + int slot, j; + u_char pos4, pos5; + + for( j = 0; el3_mca_adapters[j].name != NULL; j ++ ) { + slot = 0; + while( slot != MCA_NOTFOUND ) { + slot = mca_find_unused_adapter( + el3_mca_adapters[j].id, slot ); + if( slot == MCA_NOTFOUND ) break; + + /* if we get this far, an adapter has been + * detected and is enabled + */ + + printk("3c509: found %s at slot %d\n", + el3_mca_adapters[j].name, slot + 1 ); + + pos4 = mca_read_stored_pos( slot, 4 ); + pos5 = mca_read_stored_pos( slot, 5 ); + + ioaddr = ((short)((pos4&0xfc)|0x02)) << 8; + irq = pos5 & 0x0f; + + /* probing for a card at a particular IO/IRQ */ + if(dev && ((dev->irq >= 1 && dev->irq != irq) || + (dev->base_addr >= 1 && dev->base_addr != ioaddr))) { + slot++; /* probing next slot */ + continue; + } + + /* claim the slot */ + mca_set_adapter_name(slot, el3_mca_adapters[j].name); + mca_set_adapter_procfn(slot, NULL, NULL); + mca_mark_as_used(slot); + + if_port = pos4 & 0x03; + if (el3_debug > 2) { + printk("3c529: irq %d ioaddr 0x%x ifport %d\n", irq, ioaddr, if_port); + } + for (i = 0; i < 3; i++) { + phys_addr[i] = htons(read_eeprom(ioaddr, i)); + } + + mca_slot = slot; + + goto found; } - mca_id = 0xFFFF; - } - /* Read values from POS registers so now disable */ - outb(0,MCA_PORT_POS_SEL); - if (mca_id != 0xFFFF && !(posreg[0]&0x01)) - printk("3c529: Adapter found but disabled in slot %d\n", mca_slot); - else if (mca_id != 0xFFFF && posreg[0]&0x01) - { - /* Found and adapter is enabled */ - if (el3_debug > 2) - printk("3c529: pos registers 0:0x%x 1:0x%x 2:0x%x 3:0x%x\n", - posreg[0], posreg[1], posreg[2], posreg[3]); - ioaddr = ((short)((posreg[2]&0xfc)|0x02)) << 8; - irq = posreg[3] & 0x0f; - if_port = posreg[2] & 0x03; - if (el3_debug > 2) - printk("3c529: irq %d ioaddr 0x%x ifport %d\n", - irq, ioaddr, if_port); - for (i = 0; i < 3; i++) - phys_addr[i] = htons(read_eeprom(ioaddr, i)); - goto found; } + /* if we get here, we didn't find an MCA adapter */ + return -ENODEV; } #endif /* Reset the ISA PnP mechanism on 3c509b. */ outb(0x02, 0x279); /* Select PnP config control register. */ outb(0x02, 0xA79); /* Return to WaitForKey state. */ /* Select an open I/O location at 0x1*0 to do contention select. */ - for (id_port = 0x100; id_port < 0x200; id_port += 0x10) { + for ( ; id_port < 0x200; id_port += 0x10) { if (check_region(id_port, 1)) continue; outb(0x00, id_port); @@ -288,18 +312,23 @@ } { - unsigned short iobase = id_read_eeprom(8); + unsigned int iobase = id_read_eeprom(8); if_port = iobase >> 14; ioaddr = 0x200 + ((iobase & 0x1f) << 4); } - if (dev && dev->irq > 1 && dev->irq < 16) - irq = dev->irq; - else - irq = id_read_eeprom(9) >> 12; + irq = id_read_eeprom(9) >> 12; - if (dev && dev->base_addr != 0 - && dev->base_addr != (unsigned short)ioaddr) { - return -ENODEV; + if (dev) { /* Set passed-in IRQ or I/O Addr. */ + if (dev->irq > 1 && dev->irq < 16) + irq = dev->irq; + + if (dev->base_addr) { + if (dev->mem_end == 0x3c509 /* Magic key */ + && dev->base_addr >= 0x200 && dev->base_addr <= 0x3e0) + ioaddr = dev->base_addr & 0x3f0; + else if (dev->base_addr != ioaddr) + return -ENODEV; + } } /* Set the adaptor tag so that the next card can be found. */ @@ -342,7 +371,8 @@ if (dev->priv == NULL) return -ENOMEM; memset(dev->priv, 0, sizeof(struct el3_private)); - + + ((struct el3_private *)dev->priv)->mca_slot = mca_slot; ((struct el3_private *)dev->priv)->next_dev = el3_root_dev; el3_root_dev = dev; @@ -364,7 +394,7 @@ /* Read a word from the EEPROM using the regular EEPROM access register. Assume that we are in register window zero. */ -static ushort read_eeprom(short ioaddr, int index) +static ushort read_eeprom(int ioaddr, int index) { outw(EEPROM_READ + index, ioaddr + 10); /* Pause for at least 162 us. for the read to take place. */ @@ -394,7 +424,6 @@ } - static int el3_open(struct device *dev) { @@ -464,7 +493,7 @@ /* Ack all pending events, and set active indicator mask. */ outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq, ioaddr + EL3_CMD); - outw(SetIntrEnb | IntLatch | TxAvailable | RxComplete | StatsFull, + outw(SetIntrEnb | IntLatch|TxAvailable|TxComplete|RxComplete|StatsFull, ioaddr + EL3_CMD); if (el3_debug > 3) @@ -539,7 +568,7 @@ */ #ifdef __SMP__ - disable_irq(dev->irq); + disable_irq_nosync(dev->irq); spin_lock(&lp->lock); #endif @@ -589,7 +618,7 @@ struct device *dev = (struct device *)dev_id; struct el3_private *lp; int ioaddr, status; - int i = INTR_WORK; + int i = max_interrupt_work; if (dev == NULL) { printk ("el3_interrupt(): irq %d for unknown device.\n", irq); @@ -624,7 +653,7 @@ dev->tbusy = 0; mark_bh(NET_BH); } - if (status & (AdapterFailure | RxEarly | StatsFull)) { + if (status & (AdapterFailure | RxEarly | StatsFull | TxComplete)) { /* Handle all uncommon interrupts. */ if (status & StatsFull) /* Empty statistics. */ update_stats(dev); @@ -632,6 +661,18 @@ el3_rx(dev); outw(AckIntr | RxEarly, ioaddr + EL3_CMD); } + if (status & TxComplete) { /* Really Tx error. */ + struct el3_private *lp = (struct el3_private *)dev->priv; + short tx_status; + int i = 4; + + while (--i>0 && (tx_status = inb(ioaddr + TX_STATUS)) > 0) { + if (tx_status & 0x38) lp->stats.tx_aborted_errors++; + if (tx_status & 0x30) outw(TxReset, ioaddr + EL3_CMD); + if (tx_status & 0x3C) outw(TxEnable, ioaddr + EL3_CMD); + outb(0x00, ioaddr + TX_STATUS); /* Pop the status stack. */ + } + } if (status & AdapterFailure) { /* Adapter failure requires Rx reset and reinit. */ outw(RxReset, ioaddr + EL3_CMD); @@ -730,6 +771,8 @@ while ((rx_status = inw(ioaddr + RX_STATUS)) > 0) { if (rx_status & 0x4000) { /* Error, update stats. */ short error = rx_status & 0x3800; + + outw(RxDiscard, ioaddr + EL3_CMD); lp->stats.rx_errors++; switch (error) { case 0x0000: lp->stats.rx_over_errors++; break; @@ -761,19 +804,21 @@ (pkt_len + 3) >> 2); #endif + outw(RxDiscard, ioaddr + EL3_CMD); /* Pop top Rx packet. */ skb->protocol = eth_type_trans(skb,dev); netif_rx(skb); - outw(RxDiscard, ioaddr + EL3_CMD); /* Pop top Rx packet. */ lp->stats.rx_packets++; continue; - } else if (el3_debug) + } + outw(RxDiscard, ioaddr + EL3_CMD); + lp->stats.rx_dropped++; + if (el3_debug) printk("%s: Couldn't allocate a sk_buff of size %d.\n", dev->name, pkt_len); } - lp->stats.rx_dropped++; - outw(RxDiscard, ioaddr + EL3_CMD); + inw(ioaddr + EL3_STATUS); /* Delay. */ while (inw(ioaddr + EL3_STATUS) & 0x1000) - printk(" Waiting for 3c509 to discard packet, status %x.\n", + printk(KERN_DEBUG " Waiting for 3c509 to discard packet, status %x.\n", inw(ioaddr + EL3_STATUS) ); } @@ -786,7 +831,10 @@ static void set_multicast_list(struct device *dev) { - short ioaddr = dev->base_addr; + unsigned long flags; + struct el3_private *lp = (struct el3_private *)dev->priv; + int ioaddr = dev->base_addr; + if (el3_debug > 1) { static int old = 0; if (old != dev->mc_count) { @@ -794,6 +842,7 @@ printk("%s: Setting Rx mode to %d addresses.\n", dev->name, dev->mc_count); } } + spin_lock_irqsave(&lp->lock, flags); if (dev->flags&IFF_PROMISC) { outw(SetRxFilter | RxStation | RxMulticast | RxBroadcast | RxProm, ioaddr + EL3_CMD); @@ -803,6 +852,7 @@ } else outw(SetRxFilter | RxStation | RxBroadcast, ioaddr + EL3_CMD); + spin_unlock_irqrestore(&lp->lock, flags); } static int @@ -844,7 +894,7 @@ } #ifdef MODULE -/* Parameter that may be passed into the module. */ +/* Parameters that may be passed into the module. */ static int debug = -1; static int irq[] = {-1, -1, -1, -1, -1, -1, -1, -1}; static int xcvr[] = {-1, -1, -1, -1, -1, -1, -1, -1}; @@ -880,7 +930,12 @@ /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ while (el3_root_dev) { - next_dev = ((struct el3_private *)el3_root_dev->priv)->next_dev; + struct el3_private *lp = (struct el3_private *)el3_root_dev->priv; +#ifdef CONFIG_MCA + if(lp->mca_slot!=-1) + mca_mark_as_unused(lp->mca_slot); +#endif + next_dev = lp->next_dev; unregister_netdev(el3_root_dev); release_region(el3_root_dev->base_addr, EL3_IO_EXTENT); kfree(el3_root_dev); @@ -888,7 +943,7 @@ } } #endif /* MODULE */ - + /* * Local variables: * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c509.c" diff -ur --new-file old/linux/drivers/net/3c523.c new/linux/drivers/net/3c523.c --- old/linux/drivers/net/3c523.c Mon Jan 18 03:28:06 1999 +++ new/linux/drivers/net/3c523.c Sun Apr 25 02:49:37 1999 @@ -62,8 +62,8 @@ search the MCA slots until it finds a 3c523 with the specified parameters. - This driver should support multiple ethernet cards, but I can't test - that. If someone would I'd greatly appreciate it. + This driver does support multiple ethernet cards when used as a module + (up to MAX_3C523_CARDS, the default being 4) This has been tested with both BNC and TP versions, internal and external transceivers. Haven't tested with the 64K version (that I @@ -76,7 +76,12 @@ update to 1.3.59, incorporated multicast diffs from ni52.c Feb 15th, 1996 added shared irq support - + Apr 1999 + added support for multiple cards when used as a module + added option to disable multicast as is causes problems + Ganesh Sittampalam + Stuart Adamson + $Header: /fsys2/home/chrisb/linux-1.3.59-MCA/drivers/net/RCS/3c523.c,v 1.1 1996/02/05 01:53:46 chrisb Exp chrisb $ */ @@ -107,6 +112,7 @@ /*************************************************************************/ #define DEBUG /* debug on */ #define SYSBUSVAL 0 /* 1 = 8 Bit, 0 = 16 bit - 3c523 only does 16 bit */ +#undef ELMC_MULTICAST /* Disable multicast support as it is somewhat seriously broken at the moment */ #define make32(ptr16) (p->memtop + (short) (ptr16) ) #define make24(ptr32) ((char *) (ptr32) - p->base) @@ -180,7 +186,9 @@ static int elmc_close(struct device *dev); static int elmc_send_packet(struct sk_buff *, struct device *); static struct net_device_stats *elmc_get_stats(struct device *dev); +#ifdef ELMC_MULTICAST static void set_multicast_list(struct device *dev); +#endif /* helper-functions */ static int init586(struct device *dev); @@ -432,21 +440,19 @@ while (slot != -1) { status = mca_read_stored_pos(slot, 2); + dev->irq=irq_table[(status & ELMC_STATUS_IRQ_SELECT) >> 6]; + dev->base_addr=csr_table[(status & ELMC_STATUS_CSR_SELECT) >> 1]; + /* If we're trying to match a specified irq or IO address, we'll reject a match unless it's what we're looking for. + Also reject it if the card is already in use. */ - if (base_addr || irq) { - /* we're looking for a card at a particular place */ - if (irq && irq != irq_table[(status & ELMC_STATUS_IRQ_SELECT) >> 6]) { - slot = mca_find_adapter(ELMC_MCA_ID, slot + 1); - continue; - } - if (base_addr && base_addr != csr_table[(status & ELMC_STATUS_CSR_SELECT) >> 1]) { - slot = mca_find_adapter(ELMC_MCA_ID, slot + 1); - continue; - } + if((irq && irq != dev->irq) || (base_addr && base_addr != dev->base_addr) + || check_region(dev->base_addr,ELMC_IO_EXTENT)) { + slot = mca_find_adapter(ELMC_MCA_ID, slot + 1); + continue; } /* found what we're looking for... */ break; @@ -476,9 +482,6 @@ /* revision is stored in the first 4 bits of the revision register */ revision = inb(dev->base_addr + ELMC_REVISION) & 0xf; - /* figure out our irq */ - dev->irq = irq_table[(status & ELMC_STATUS_IRQ_SELECT) >> 6]; - /* according to docs, we read the interrupt and write it back to the IRQ select register, since the POST might not configure the IRQ properly. */ @@ -497,9 +500,6 @@ break; } - /* Our IO address? */ - dev->base_addr = csr_table[(status & ELMC_STATUS_CSR_SELECT) >> 1]; - request_region(dev->base_addr, ELMC_IO_EXTENT, "3c523"); dev->priv = (void *) kmalloc(sizeof(struct priv), GFP_KERNEL); @@ -565,7 +565,11 @@ dev->stop = &elmc_close; dev->get_stats = &elmc_get_stats; dev->hard_start_xmit = &elmc_send_packet; +#ifdef ELMC_MULTICAST dev->set_multicast_list = &set_multicast_list; +#else + dev->set_multicast_list = NULL; +#endif ether_setup(dev); @@ -577,6 +581,10 @@ That gets done in elmc_open(). I'm not sure that's such a good idea, but it works, so I'll go with it. */ +#ifndef ELMC_MULTICAST + dev->flags&=~IFF_MULTICAST; /* Multicast doesn't work */ +#endif + return 0; } @@ -1210,6 +1218,7 @@ * Set MC list .. */ +#ifdef ELMC_MULTICAST static void set_multicast_list(struct device *dev) { if (!dev->start) { @@ -1222,60 +1231,85 @@ startrecv586(dev); dev->start = 1; } +#endif /*************************************************************************/ #ifdef MODULE -static char devicename[9] = {0,}; +/* Increase if needed ;) */ +#define MAX_3C523_CARDS 4 +/* I'm not sure where this magic 9 comes from */ +#define NAMELEN 9 -static struct device dev_elmc = -{ - devicename /*"3c523" */ , 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, elmc_probe +static char devicenames[NAMELEN * MAX_3C523_CARDS] = {0,}; + +static struct device dev_elmc[MAX_3C523_CARDS] = +{ + { + NULL /*"3c523" */ , 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL + }, }; -static int irq = 0; -static int io = 0; -MODULE_PARM(irq, "i"); -MODULE_PARM(io, "i"); +static int irq[MAX_3C523_CARDS] = {0,}; +static int io[MAX_3C523_CARDS] = {0,}; +MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_3C523_CARDS) "i"); +MODULE_PARM(io, "1-" __MODULE_STRING(MAX_3C523_CARDS) "i"); int init_module(void) { - struct device *dev = &dev_elmc; + int this_dev,found = 0; - dev->base_addr = io; - dev->irq = irq; - if (register_netdev(dev) != 0) { - return -EIO; - } - return 0; + /* Loop until we either can't find any more cards, or we have MAX_3C523_CARDS */ + for(this_dev=0; this_devname=devicenames+(NAMELEN*this_dev); + dev->irq=irq[this_dev]; + dev->base_addr=io[this_dev]; + dev->init=elmc_probe; + if(register_netdev(dev)!=0) { + if(io[this_dev]==0) break; + printk(KERN_WARNING "3c523.c: No 3c523 card found at io=%#x\n",io[this_dev]); + } else found++; + } + + if(found==0) { + if(io[0]==0) printk(KERN_NOTICE "3c523.c: No 3c523 cards found\n"); + return -ENXIO; + } else return 0; } void cleanup_module(void) { - struct device *dev = &dev_elmc; + int this_dev; + for(this_dev=0; this_devirq != 0) { - /* this should be done by close, but if we failed to - initialize properly something may have gotten hosed. */ - free_irq(dev->irq, dev); - dev->irq = 0; - } - if (dev->base_addr != 0) { - release_region(dev->base_addr, ELMC_IO_EXTENT); - dev->base_addr = 0; - } - irq = 0; - io = 0; - unregister_netdev(dev); + struct device *dev = &dev_elmc[this_dev]; + if(dev->priv) { + /* shutdown interrupts on the card */ + elmc_id_reset586(); + if (dev->irq != 0) { + /* this should be done by close, but if we failed to + initialize properly something may have gotten hosed. */ + free_irq(dev->irq, dev); + dev->irq = 0; + } + if (dev->base_addr != 0) { + release_region(dev->base_addr, ELMC_IO_EXTENT); + dev->base_addr = 0; + } + irq[this_dev] = 0; + io[this_dev] = 0; + unregister_netdev(dev); - mca_set_adapter_procfn(((struct priv *) (dev->priv))->slot, + mca_set_adapter_procfn(((struct priv *) (dev->priv))->slot, NULL, NULL); - kfree_s(dev->priv, sizeof(struct priv)); - dev->priv = NULL; + kfree_s(dev->priv, sizeof(struct priv)); + dev->priv = NULL; + } + } } #endif /* MODULE */ diff -ur --new-file old/linux/drivers/net/3c527.c new/linux/drivers/net/3c527.c --- old/linux/drivers/net/3c527.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/net/3c527.c Sun Mar 21 16:11:36 1999 @@ -0,0 +1,1152 @@ +/* 3c527.c: 3Com Etherlink/MC32 driver for Linux + * + * (c) Copyright 1998 Red Hat Software Inc + * Written by Alan Cox. + * + * Based on skeleton.c written 1993-94 by Donald Becker and ne2.c + * (for the MCA stuff) written by Wim Dumon. + * + * Thanks to 3Com for making this possible by providing me with the + * documentation. + * + * This software may be used and distributed according to the terms + * of the GNU Public License, incorporated herein by reference. + * + */ + +static const char *version = + "3c527.c:v0.04 1999/03/16 Alan Cox (alan@redhat.com)\n"; + +/* + * Things you need + * o The databook. + * + * Traps for the unwary + * + * The diagram (Figure 1-1) and the POS summary disagree with the + * "Interrupt Level" section in the manual. + * + * The documentation in places seems to miss things. In actual fact + * I've always eventually found everything is documented, it just + * requires careful study. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "3c527.h" + +/* + * The name of the card. Is used for messages and in the requests for + * io regions, irqs and dma channels + */ +static const char* cardname = "3c527"; + +/* use 0 for production, 1 for verification, >2 for debug */ +#ifndef NET_DEBUG +#define NET_DEBUG 2 +#endif +static unsigned int mc32_debug = NET_DEBUG; + +/* The number of low I/O ports used by the ethercard. */ +#define NETCARD_IO_EXTENT 8 + + +struct mc32_mailbox +{ + u16 mbox __attribute((packed)); + u16 data[1] __attribute((packed)); +}; + +/* Information that need to be kept for each board. */ + +#define TX_RING_MAX 16 /* Typically the card supports 37 */ +#define RX_RING_MAX 32 /* " " " */ + +struct mc32_local +{ + struct net_device_stats net_stats; + int slot; + volatile struct mc32_mailbox *rx_box; + volatile struct mc32_mailbox *tx_box; + volatile struct mc32_mailbox *exec_box; + volatile u16 *stats; + u16 tx_chain; + u16 rx_chain; + u16 tx_len; + u16 rx_len; + u32 base; + u16 rx_halted; + u16 tx_halted; + u16 exec_pending; + u16 mc_reload_wait; /* a multicast load request is pending */ + atomic_t tx_count; /* buffers left */ + struct wait_queue *event; + struct sk_buff *tx_skb[TX_RING_MAX]; /* Transmit ring */ + u16 tx_skb_top; + u16 tx_skb_end; + struct sk_buff *rx_skb[RX_RING_MAX]; /* Receive ring */ + void *rx_ptr[RX_RING_MAX]; /* Data pointers */ +}; + +/* The station (ethernet) address prefix, used for a sanity check. */ +#define SA_ADDR0 0x02 +#define SA_ADDR1 0x60 +#define SA_ADDR2 0xAC + +struct mca_adapters_t { + unsigned int id; + char *name; +}; + +const struct mca_adapters_t mc32_adapters[] = { + { 0x0041, "3COM EtherLink MC/32" }, + { 0x8EF5, "IBM High Performance Lan Adapter" }, + { 0x0000, NULL } +}; + + +/* Index to functions, as function prototypes. */ + +extern int mc32_probe(struct device *dev); + +static int mc32_probe1(struct device *dev, int ioaddr); +static int mc32_open(struct device *dev); +static int mc32_send_packet(struct sk_buff *skb, struct device *dev); +static void mc32_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static int mc32_close(struct device *dev); +static struct net_device_stats *mc32_get_stats(struct device *dev); +static void mc32_set_multicast_list(struct device *dev); + +/* + * Check for a network adaptor of this type, and return '0' iff one exists. + * If dev->base_addr == 0, probe all likely locations. + * If dev->base_addr == 1, always return failure. + * If dev->base_addr == 2, allocate space for the device and return success + * (detachable devices only). + */ + +__initfunc(int mc32_probe(struct device *dev)) +{ + static int current_mca_slot = -1; + int i; + int adapter_found = 0; + + /* Do not check any supplied i/o locations. + POS registers usually don't fail :) */ + + /* MCA cards have POS registers. + Autodetecting MCA cards is extremely simple. + Just search for the card. */ + + for(i = 0; (mc32_adapters[i].name != NULL) && !adapter_found; i++) { + current_mca_slot = + mca_find_unused_adapter(mc32_adapters[i].id, 0); + + if((current_mca_slot != MCA_NOTFOUND) && !adapter_found) { + if(!mc32_probe1(dev, current_mca_slot)) + { + mca_set_adapter_name(current_mca_slot, + mc32_adapters[i].name); + mca_mark_as_used(current_mca_slot); + return 0; + } + + } + } + return -ENODEV; +} + +/* + * 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. + */ +__initfunc(static int mc32_probe1(struct device *dev, int slot)) +{ + static unsigned version_printed = 0; + int i; + u8 POS; + u32 base; + struct mc32_local *lp; + static u16 mca_io_bases[]={ + 0x7280,0x7290, + 0x7680,0x7690, + 0x7A80,0x7A90, + 0x7E80,0x7E90 + }; + static u32 mca_mem_bases[]={ + 0x00C0000, + 0x00C4000, + 0x00C8000, + 0x00CC000, + 0x00D0000, + 0x00D4000, + 0x00D8000, + 0x00DC000 + }; + static char *failures[]={ + "Processor instruction", + "Processor data bus", + "Processor data bus", + "Processor data bus", + "Adapter bus", + "ROM checksum", + "Base RAM", + "Extended RAM", + "82586 internal loopback", + "82586 initialisation failure", + "Adapter list configuration error" + }; + + /* Time to play MCA games */ + + if (mc32_debug && version_printed++ == 0) + printk(KERN_DEBUG "%s", version); + + printk(KERN_INFO "%s: %s found in slot %d:", dev->name, cardname, slot); + + POS = mca_read_stored_pos(slot, 2); + + if(!(POS&1)) + { + printk(" disabled.\n"); + return -ENODEV; + } + + /* Allocate a new 'dev' if needed. */ + if (dev == NULL) { + /* + * Don't allocate the private data here, it is done later + * This makes it easier to free the memory when this driver + * is used as a module. + */ + dev = init_etherdev(0, 0); + if (dev == NULL) + return -ENOMEM; + } + + /* Fill in the 'dev' fields. */ + dev->base_addr = mca_io_bases[(POS>>1)&7]; + dev->mem_start = mca_mem_bases[(POS>>4)&7]; + + POS = mca_read_stored_pos(slot, 4); + if(!(POS&1)) + { + printk("memory window disabled.\n"); + return -ENODEV; + } + + POS = mca_read_stored_pos(slot, 5); + + i=(POS>>4)&3; + if(i==3) + { + printk("invalid memory window.\n"); + return -ENODEV; + } + + i*=16384; + i+=16384; + + dev->mem_end=dev->mem_start + i; + + dev->irq = ((POS>>2)&3)+9; + + printk("io 0x%3lX irq %d mem 0x%lX (%dK)\n", + dev->base_addr, dev->irq, dev->mem_start, i/1024); + + + /* We ought to set the cache line size here.. */ + + + /* + * Go PROM browsing + */ + + printk("%s: Address ", dev->name); + + /* Retrieve and print the ethernet address. */ + for (i = 0; i < 6; i++) + { + mca_write_pos(slot, 6, i+12); + mca_write_pos(slot, 7, 0); + + printk(" %2.2x", dev->dev_addr[i] = mca_read_pos(slot,3)); + } + + mca_write_pos(slot, 6, 0); + mca_write_pos(slot, 7, 0); + + POS = mca_read_stored_pos(slot, 4); + + if(POS&2) + printk(" : BNC port selected.\n"); + else + printk(" : AUI port selected.\n"); + + POS=inb(dev->base_addr+HOST_CTRL); + POS|=HOST_CTRL_ATTN|HOST_CTRL_RESET; + POS&=~HOST_CTRL_INTE; + outb(POS, dev->base_addr+HOST_CTRL); + /* Reset adapter */ + udelay(100); + /* Reset off */ + POS&=~(HOST_CTRL_ATTN|HOST_CTRL_RESET); + outb(POS, dev->base_addr+HOST_CTRL); + + udelay(300); + + /* + * Grab the IRQ + */ + + if(request_irq(dev->irq, &mc32_interrupt, 0, cardname, dev)) + { + printk("%s: unable to get IRQ %d.\n", + dev->name, dev->irq); + return -EAGAIN; + } + + /* Initialize the device structure. */ + if (dev->priv == NULL) { + dev->priv = kmalloc(sizeof(struct mc32_local), GFP_KERNEL); + if (dev->priv == NULL) + { + free_irq(dev->irq, dev); + return -ENOMEM; + } + } + + memset(dev->priv, 0, sizeof(struct mc32_local)); + lp = (struct mc32_local *)dev->priv; + lp->slot = slot; + + i=0; + + base = inb(dev->base_addr); + + while(base==0xFF) + { + i++; + if(i==1000) + { + printk("%s: failed to boot adapter.\n", dev->name); + free_irq(dev->irq, dev); + return -ENODEV; + } + udelay(1000); + if(inb(dev->base_addr+2)&(1<<5)) + base = inb(dev->base_addr); + } + + if(base>0) + { + if(base < 0x0C) + printk("%s: %s%s.\n", dev->name, failures[base-1], + base<0x0A?" test failure":""); + else + printk("%s: unknown failure %d.\n", dev->name, base); + free_irq(dev->irq, dev); + return -ENODEV; + } + + base=0; + for(i=0;i<4;i++) + { + int n=0; + + while(!(inb(dev->base_addr+2)&(1<<5))) + { + n++; + udelay(50); + if(n>100) + { + printk(KERN_ERR "%s: mailbox read fail (%d).\n", dev->name, i); + free_irq(dev->irq, dev); + return -ENODEV; + } + } + + base|=(inb(dev->base_addr)<<(8*i)); + } + + lp->exec_box=bus_to_virt(dev->mem_start+base); + + base=lp->exec_box->data[1]<<16|lp->exec_box->data[0]; + + lp->base = dev->mem_start+base; + + lp->rx_box=bus_to_virt(lp->base + lp->exec_box->data[2]); + lp->tx_box=bus_to_virt(lp->base + lp->exec_box->data[3]); + + lp->stats = bus_to_virt(lp->base + lp->exec_box->data[5]); + + /* + * Descriptor chains (card relative) + */ + + lp->tx_chain = lp->exec_box->data[8]; + lp->rx_chain = lp->exec_box->data[10]; + lp->tx_len = lp->exec_box->data[9]; + lp->rx_len = lp->exec_box->data[11]; + + printk("%s: %d RX buffers, %d TX buffers. Base of 0x%08X.\n", + dev->name, lp->rx_len, lp->tx_len, lp->base); + + dev->open = mc32_open; + dev->stop = mc32_close; + dev->hard_start_xmit = mc32_send_packet; + dev->get_stats = mc32_get_stats; + dev->set_multicast_list = mc32_set_multicast_list; + + lp->rx_halted = 1; + lp->tx_halted = 1; + + /* Fill in the fields of the device structure with ethernet values. */ + ether_setup(dev); + return 0; +} + + +/* + * Polled command stuff + */ + +static void mc32_ring_poll(struct device *dev) +{ + int ioaddr = dev->base_addr; + while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR)); +} + + +/* + * Send exec commands + */ + +static int mc32_command(struct device *dev, u16 cmd, void *data, int len) +{ + struct mc32_local *lp = (struct mc32_local *)dev->priv; + int ioaddr = dev->base_addr; + unsigned long flags; + + while(lp->exec_pending) + sleep_on(&lp->event); + + lp->exec_pending=1; + lp->exec_box->mbox=0; + lp->exec_box->mbox=cmd; + memcpy((void *)lp->exec_box->data, data, len); + barrier(); /* the memcpy forgot the volatile so be sure */ + + /* Send the command */ + while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR)); + outb(1<<6, ioaddr+HOST_CMD); + + save_flags(flags); + cli(); + while(lp->exec_pending!=2) + sleep_on(&lp->event); + lp->exec_pending=0; + restore_flags(flags); + + /* + * A multicast set got blocked - do it now + */ + + if(lp->mc_reload_wait) + mc32_set_multicast_list(dev); + + if(lp->exec_box->data[0]&(1<<13)) + return -1; + return 0; +} + +/* + * RX abort + */ + +static void mc32_rx_abort(struct device *dev) +{ + struct mc32_local *lp = (struct mc32_local *)dev->priv; + int ioaddr = dev->base_addr; + + while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR)); + + lp->rx_box->mbox=0; + outb(3<<3, ioaddr+HOST_CMD); /* Suspend reception */ +} + + +/* + * RX enable + */ + +static void mc32_rx_begin(struct device *dev) +{ + struct mc32_local *lp = (struct mc32_local *)dev->priv; + int ioaddr = dev->base_addr; + + while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR)); + + lp->rx_box->mbox=0; + outb(1<<3, ioaddr+HOST_CMD); /* GO */ + mc32_ring_poll(dev); + + lp->rx_halted=0; +} + +static void mc32_tx_abort(struct device *dev) +{ + struct mc32_local *lp = (struct mc32_local *)dev->priv; + int ioaddr = dev->base_addr; + + while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR)); + + lp->tx_box->mbox=0; + outb(3, ioaddr+HOST_CMD); /* Suspend */ + + /* Ring empty */ + + atomic_set(&lp->tx_count, lp->tx_len); + + /* Flush */ + if(lp->tx_skb_top!=lp->tx_skb_end) + { + int i; + if(lp->tx_skb_top<=lp->tx_skb_end) + { + for(i=lp->tx_skb_top;itx_skb_end;i++) + { + dev_kfree_skb(lp->tx_skb[i]); + lp->tx_skb[i]=NULL; + } + } + else + { + for(i=lp->tx_skb_end;itx_skb[i]); + lp->tx_skb[i]=NULL; + } + for(i=0;itx_skb_top;i++) + { + dev_kfree_skb(lp->tx_skb[i]); + lp->tx_skb[i]=NULL; + } + } + } + lp->tx_skb_top=lp->tx_skb_end=0; +} + +/* + * TX enable + */ + +static void mc32_tx_begin(struct device *dev) +{ + struct mc32_local *lp = (struct mc32_local *)dev->priv; + int ioaddr = dev->base_addr; + + while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR)); + + lp->tx_box->mbox=0; +#if 0 + outb(5, ioaddr+HOST_CMD); /* GO */ + printk("TX=>5\n"); + mc32_ring_poll(dev); + if(lp->tx_box->mbox&(1<<13)) + printk("TX begin error!\n"); +#endif + lp->tx_halted=0; +} + + +/* + * Load the rx ring + */ + +static int mc32_load_rx_ring(struct device *dev) +{ + struct mc32_local *lp = (struct mc32_local *)dev->priv; + int i; + u16 base; + volatile struct skb_header *p; + + base = lp->rx_box->data[0]; + + /* Fix me - should use card size - also fix flush ! */ + + for(i=0;irx_skb[i]=alloc_skb(1532, GFP_KERNEL); + if(lp->rx_skb[i]==NULL) + { + for(;i>=0;i--) + kfree_skb(lp->rx_skb[i]); + return -ENOBUFS; + } + lp->rx_ptr[i]=lp->rx_skb[i]->data+18; + + p=bus_to_virt(lp->base+base); + p->control=0; + p->data = virt_to_bus(lp->rx_ptr[i]); + p->status=0; + p->length = 1532; + base = p->next; + } + p->control = (1<<6); + lp->rx_box->mbox = 0; + return 0; +} + +static void mc32_flush_rx_ring(struct mc32_local *lp) +{ + int i; + for(i=0;irx_skb[i]); +} + +static void mc32_flush_tx_ring(struct mc32_local *lp) +{ + int i; + + if(lp->tx_skb_top <= lp->tx_skb_end) + { + for(i=lp->tx_skb_top;itx_skb_end;i++) + dev_kfree_skb(lp->tx_skb[i]); + } + else + { + for(i=0;itx_skb_end;i++) + dev_kfree_skb(lp->tx_skb[i]); + for(i=lp->tx_skb_top;itx_skb[i]); + } +} + +/* + * Open/initialize the board. This is called (in the current kernel) + * sometime after booting when the 'ifconfig' program is run. + */ + +static int mc32_open(struct device *dev) +{ + int ioaddr = dev->base_addr; + u16 zero_word=0; + u8 one=1; + u8 regs; + + dev->tbusy = 0; + dev->interrupt = 0; + dev->start = 1; + + /* + * Interrupts enabled + */ + + regs=inb(ioaddr+HOST_CTRL); + regs|=HOST_CTRL_INTE; + outb(regs, ioaddr+HOST_CTRL); + + + /* + * Send the indications on command + */ + + mc32_command(dev, 4, &one, 2); + + + /* + * Send the command sequence "abort, resume" for RX and TX. + * The abort cleans up the buffer chains if needed. + */ + + mc32_rx_abort(dev); + mc32_tx_abort(dev); + + /* Set Network Address */ + mc32_command(dev, 1, dev->dev_addr, 6); + + /* Set the filters */ + mc32_set_multicast_list(dev); + + /* Issue the 82586 workaround command - this is for "busy lans", + but basically means for all lans now days - has a performance + cost but best set */ + + mc32_command(dev, 0x0D, &zero_word, 2); /* 82586 bug workaround on */ + + /* Load the ring we just initialised */ + + if(mc32_load_rx_ring(dev)) + { + mc32_close(dev); + return -ENOBUFS; + } + + /* And the resume command goes last */ + + mc32_rx_begin(dev); + mc32_tx_begin(dev); + + MOD_INC_USE_COUNT; + + return 0; +} + +static int mc32_send_packet(struct sk_buff *skb, struct device *dev) +{ + struct mc32_local *lp = (struct mc32_local *)dev->priv; + + if (dev->tbusy) { + /* + * If we get here, some higher level has decided we are broken. + * There should really be a "kick me" function call instead. + */ + int tickssofar = jiffies - dev->trans_start; + if (tickssofar < 5) + return 1; + printk(KERN_WARNING "%s: transmit timed out?\n", dev->name); + /* Try to restart the adaptor. */ + dev->tbusy=0; + dev->trans_start = jiffies; + } + + /* + * 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_WARNING "%s: Transmitter access conflict.\n", dev->name); + dev_kfree_skb(skb); + } + else + { + unsigned long flags; + + u16 tx_head; + volatile struct skb_header *p, *np; + + save_flags(flags); + cli(); + + if(atomic_read(&lp->tx_count)==0) + { + dev->tbusy=1; + restore_flags(flags); + return 1; + } + + tx_head = lp->tx_box->data[0]; + atomic_dec(&lp->tx_count); + + /* We will need this to flush the buffer out */ + + lp->tx_skb[lp->tx_skb_end] = skb; + lp->tx_skb_end++; + lp->tx_skb_end&=(TX_RING_MAX-1); + + /* P is the last sending/sent buffer as a pointer */ + p=(struct skb_header *)bus_to_virt(lp->base+tx_head); + + /* NP is the buffer we will be loading */ + np=(struct skb_header *)bus_to_virt(lp->base+p->next); + + np->control |= (1<<6); /* EOL */ + wmb(); + + np->length = skb->len; + np->data = virt_to_bus(skb->data); + np->status = 0; + np->control = (1<<7)|(1<<6); /* EOP EOL */ + wmb(); + + p->status = 0; + p->control &= ~(1<<6); + + dev->tbusy = 0; /* Keep feeding me */ + + lp->tx_box->mbox=0; + restore_flags(flags); + } + return 0; +} + +static void mc32_update_stats(struct device *dev) +{ +} + + +static void mc32_rx_ring(struct device *dev) +{ + struct mc32_local *lp=dev->priv; + int ioaddr = dev->base_addr; + int x=0; + volatile struct skb_header *p; + u16 base; + u16 top; + + top = base = lp->rx_box->data[0]; + do + { + p=(struct skb_header *)bus_to_virt(base+lp->base); + if(!(p->status & (1<<7))) + break; + if(p->status & (1<<6)) + { + u16 length = p->length; + struct sk_buff *skb=dev_alloc_skb(length+2); + if(skb!=NULL) + { + skb_reserve(skb,2); + /*printk("Frame at %p\n", bus_to_virt(p->data)); */ + memcpy(skb_put(skb, length), + bus_to_virt(p->data), length); + skb->protocol=eth_type_trans(skb,dev); + skb->dev=dev; + lp->net_stats.rx_packets++; + lp->net_stats.rx_bytes+=skb->len; + netif_rx(skb); + } + else + lp->net_stats.rx_dropped++; + } + else + { + lp->net_stats.rx_errors++; + switch(p->status&0x0F) + { + case 1: + lp->net_stats.rx_crc_errors++;break; + case 2: + lp->net_stats.rx_fifo_errors++;break; + case 3: + lp->net_stats.rx_frame_errors++;break; + case 4: + lp->net_stats.rx_missed_errors++;break; + case 5: + lp->net_stats.rx_length_errors++;break; + } + } + p->length = 1532; + p->control &= ~(1<<6); + p->status = 0; + base = p->next; + } + while(x++<48); + + /* + * This is curious. It seems the receive stop and receive continue + * commands race against each other, even though we poll for + * command ready to be issued. The delay is hackish but is a workaround + * while I investigate in depth + */ + + while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR)); + lp->rx_box->mbox=0; + lp->rx_box->data[0] = top; + outb(1<<3, ioaddr+HOST_CMD); +} + + +/* + * The typical workload of the driver: + * Handle the network interface interrupts. + */ +static void mc32_interrupt(int irq, void *dev_id, struct pt_regs * regs) +{ + struct device *dev = dev_id; + struct mc32_local *lp; + int ioaddr, status, boguscount = 0; + int rx_event = 0; + + if (dev == NULL) { + printk(KERN_WARNING "%s: irq %d for unknown device.\n", cardname, irq); + return; + } + dev->interrupt = 1; + + ioaddr = dev->base_addr; + lp = (struct mc32_local *)dev->priv; + + /* See whats cooking */ + + while((inb(ioaddr+2)&(1<<5)) && boguscount++<2000) + { + status=inb(ioaddr+HOST_CMD); + +#ifdef DEBUG_IRQ + printk("Status TX%d RX%d EX%d OV%d\n", + (status&7), (status>>3)&7, (status>>6)&1, + (status>>7)&1); +#endif + + switch(status&7) + { + case 0: + break; + case 6: /* TX fail */ + lp->net_stats.tx_errors++; + case 2: /* TX ok */ + lp->net_stats.tx_packets++; + /* Packets are sent in order - this is + basically a FIFO queue of buffers matching + the card ring */ + lp->net_stats.tx_bytes+=lp->tx_skb[lp->tx_skb_top]->len; + dev_kfree_skb(lp->tx_skb[lp->tx_skb_top]); + lp->tx_skb[lp->tx_skb_top]=NULL; + lp->tx_skb_top++; + lp->tx_skb_top&=(TX_RING_MAX-1); + atomic_inc(&lp->tx_count); + dev->tbusy=0; + mark_bh(NET_BH); + break; + case 3: /* Halt */ + case 4: /* Abort */ + lp->tx_halted=1; + wake_up(&lp->event); + break; + case 5: + lp->tx_halted=0; + wake_up(&lp->event); + break; + default: + printk("%s: strange tx ack %d\n", + dev->name, status&7); + } + status>>=3; + switch(status&7) + { + case 0: + break; + case 2: /* RX */ + rx_event=1; + break; + case 3: + case 4: + lp->rx_halted=1; + wake_up(&lp->event); + break; + case 5: + lp->rx_halted=0; + wake_up(&lp->event); + break; + case 6: + /* Out of RX buffers stat */ + /* Must restart */ + lp->net_stats.rx_dropped++; + rx_event = 1; /* To restart */ + break; + default: + printk("%s: strange rx ack %d\n", + dev->name, status&7); + + } + status>>=3; + if(status&1) + { + /* 0=no 1=yes 2=reply clearing */ + lp->exec_pending=2; + wake_up(&lp->event); + } + if(status&2) + { + /* + * Update the stats as soon as + * we have it flagged and can + * send an immediate reply (CRR set) + */ + + if(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR) + { + mc32_update_stats(dev); + outb(0, ioaddr+HOST_CMD); + } + } + } + + /* + * Process and restart the receive ring. + */ + + if(rx_event) + mc32_rx_ring(dev); + dev->interrupt = 0; + return; +} + + +/* The inverse routine to mc32_open(). */ + +static int mc32_close(struct device *dev) +{ + struct mc32_local *lp = (struct mc32_local *)dev->priv; + int ioaddr = dev->base_addr; + u8 regs; + u16 one=1; + + /* + * Send the indications on command (handy debug check) + */ + + mc32_command(dev, 4, &one, 2); + + /* Abort RX and Abort TX */ + + mc32_rx_abort(dev); + mc32_tx_abort(dev); + + /* Catch any waiting commands */ + + while(lp->exec_pending==1) + sleep_on(&lp->event); + + /* Ok the card is now stopping */ + + regs=inb(ioaddr+HOST_CTRL); + regs&=~HOST_CTRL_INTE; + outb(regs, ioaddr+HOST_CTRL); + + mc32_flush_rx_ring(lp); + mc32_flush_tx_ring(lp); + + dev->tbusy = 1; + dev->start = 0; + + /* Update the statistics here. */ + + MOD_DEC_USE_COUNT; + + return 0; + +} + +/* + * Get the current statistics. + * This may be called with the card open or closed. + */ + +static struct net_device_stats *mc32_get_stats(struct device *dev) +{ + struct mc32_local *lp = (struct mc32_local *)dev->priv; + return &lp->net_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 mc32_set_multicast_list(struct device *dev) +{ + u16 filt; + if (dev->flags&IFF_PROMISC) + { + /* Enable promiscuous mode */ + filt = 1; + mc32_command(dev, 0, &filt, 2); + } + else if((dev->flags&IFF_ALLMULTI) || dev->mc_count > 10) + { + dev->flags|=IFF_PROMISC; + filt = 1; + mc32_command(dev, 0, &filt, 2); + } + else if(dev->mc_count) + { + unsigned char block[62]; + unsigned char *bp; + struct dev_mc_list *dmc=dev->mc_list; + + int i; + + filt = 0; + block[1]=0; + block[0]=dev->mc_count; + bp=block+2; + + for(i=0;imc_count;i++) + { + memcpy(bp, dmc->dmi_addr, 6); + bp+=6; + dmc=dmc->next; + } + mc32_command(dev, 2, block, 2+6*dev->mc_count); + mc32_command(dev, 0, &filt, 2); + } + else + { + filt = 0; + mc32_command(dev, 0, &filt, 2); + } +} + +#ifdef MODULE + +static char devicename[9] = { 0, }; +static struct device this_device = { + devicename, /* will be inserted by linux/drivers/net/mc32_init.c */ + 0, 0, 0, 0, + 0, 0, /* I/O address, IRQ */ + 0, 0, 0, NULL, mc32_probe }; + +int init_module(void) +{ + int result; + + if ((result = register_netdev(&this_device)) != 0) + return result; + + return 0; +} + +void cleanup_module(void) +{ + int slot; + + /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ + unregister_netdev(&this_device); + + /* + * If we don't do this, we can't re-insmod it later. + * Release irq/dma here, when you have jumpered versions and + * allocate them in mc32_probe1(). + */ + + if (this_device.priv) + { + struct mc32_local *lp=this_device.priv; + slot = lp->slot; + mca_mark_as_unused(slot); + mca_set_adapter_name(slot, NULL); + kfree_s(this_device.priv, sizeof(struct mc32_local)); + } + free_irq(this_device.irq, &this_device); +} + +#endif /* MODULE */ diff -ur --new-file old/linux/drivers/net/3c527.h new/linux/drivers/net/3c527.h --- old/linux/drivers/net/3c527.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/net/3c527.h Sun Mar 21 16:11:36 1999 @@ -0,0 +1,40 @@ +/* + * 3COM "EtherLink MC/32" Descriptions + */ + +/* + * Registers + */ + +#define HOST_CMD 0 + +#define HOST_STATUS 2 +#define HOST_STATUS_CRR (1<<6) +#define HOST_STATUS_CWR (1<<5) + +#define HOST_CTRL 6 +#define HOST_CTRL_ATTN (1<<7) +#define HOST_CTRL_RESET (1<<6) +#define HOST_CTRL_INTE (1<<2) + +#define HOST_RAMPAGE 8 + +struct skb_header +{ + u8 status __attribute((packed)); + u8 control __attribute((packed)); + u16 next __attribute((packed)); /* Do not change! */ + u16 length __attribute((packed)); + u32 data __attribute((packed)); +}; + +#define STATUS_MASK 0x0F +#define COMPLETED 0x80 +#define COMPLETED_OK 0x40 +#define BUFFER_BUSY 0x20 + +#define CONTROL_EOP 0x80 /* End Of Packet */ +#define CONTROL_EL 0x40 /* End of List */ + + +#define MCA_MC32_ID 0x0041 /* Our MCA ident */ \ No newline at end of file diff -ur --new-file old/linux/drivers/net/8390.c new/linux/drivers/net/8390.c --- old/linux/drivers/net/8390.c Fri Jan 15 09:39:37 1999 +++ new/linux/drivers/net/8390.c Thu May 6 23:02:34 1999 @@ -165,8 +165,10 @@ spin_lock_irqsave(&ei_local->page_lock, flags); NS8390_init(dev, 1); - spin_unlock_irqrestore(&ei_local->page_lock, flags); + /* Set the flag before we drop the lock, That way the IRQ arrives + after its set and we get no silly warnings */ dev->start = 1; + spin_unlock_irqrestore(&ei_local->page_lock, flags); ei_local->irqlock = 0; return 0; } @@ -255,8 +257,7 @@ /* Ugly but a reset can be slow, yet must be protected */ - disable_irq(dev->irq); - synchronize_irq(); + disable_irq_nosync(dev->irq); spin_lock(&ei_local->page_lock); /* Try to restart the card. Perhaps the user has fixed something. */ @@ -284,8 +285,7 @@ * Slow phase with lock held. */ - disable_irq(dev->irq); - synchronize_irq(); + disable_irq_nosync(dev->irq); spin_lock(&ei_local->page_lock); diff -ur --new-file old/linux/drivers/net/Config.in new/linux/drivers/net/Config.in --- old/linux/drivers/net/Config.in Tue Jan 19 19:13:13 1999 +++ new/linux/drivers/net/Config.in Mon Mar 22 17:08:11 1999 @@ -32,8 +32,8 @@ fi fi if [ "$CONFIG_PPC" = "y" ]; then - bool 'MACE (Power Mac ethernet) support' CONFIG_MACE - bool 'BMAC (G3 ethernet) support' CONFIG_BMAC + tristate 'MACE (Power Mac ethernet) support' CONFIG_MACE + tristate 'BMAC (G3 ethernet) support' CONFIG_BMAC fi if [ "$CONFIG_ZORRO" = "y" ]; then tristate 'Ariadne support' CONFIG_ARIADNE @@ -53,6 +53,7 @@ tristate '3c507 support' CONFIG_EL16 if [ "$CONFIG_MCA" = "y" ]; then tristate '3c523 support' CONFIG_ELMC + tristate '3c527 support' CONFIG_ELMC_II fi fi tristate '3c509/3c579 support' CONFIG_EL3 @@ -81,7 +82,7 @@ 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 Gigabit support' CONFIG_ACENIC + 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 diff -ur --new-file old/linux/drivers/net/Makefile new/linux/drivers/net/Makefile --- old/linux/drivers/net/Makefile Fri Jan 15 07:58:47 1999 +++ new/linux/drivers/net/Makefile Thu Apr 15 14:42:40 1999 @@ -430,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 @@ -478,6 +486,14 @@ endif endif +ifeq ($(CONFIG_ELMC_II),y) +L_OBJS += 3c527.o +else + ifeq ($(CONFIG_ELMC_II),m) + M_OBJS += 3c527.o + endif +endif + ifeq ($(CONFIG_EL3),y) L_OBJS += 3c509.o else @@ -989,10 +1005,18 @@ ifeq ($(CONFIG_MACE),y) L_OBJS += mace.o +else + ifeq ($(CONFIG_MACE),m) + M_OBJS += mace.o + endif endif ifeq ($(CONFIG_BMAC),y) L_OBJS += bmac.o +else + ifeq ($(CONFIG_BMAC),m) + M_OBJS += bmac.o + endif endif ifeq ($(CONFIG_VENDOR_SANGOMA),y) @@ -1046,9 +1070,10 @@ ifeq ($(CONFIG_IRDA),y) SUB_DIRS += irda +MOD_IN_SUB_DIRS += irda else ifeq ($(CONFIG_IRDA),m) - MOD_SUB_DIRS += irda + MOD_IN_SUB_DIRS += irda endif endif diff -ur --new-file old/linux/drivers/net/Space.c new/linux/drivers/net/Space.c --- old/linux/drivers/net/Space.c Fri Jan 15 23:36:21 1999 +++ new/linux/drivers/net/Space.c Tue Mar 16 01:11:30 1999 @@ -87,6 +87,7 @@ extern int sparc_lance_probe(struct device *); extern int happy_meal_probe(struct device *); extern int qec_probe(struct device *); +extern int bigmac_probe(struct device *); extern int myri_sbus_probe(struct device *); extern int sgiseeq_probe(struct device *); extern int atarilance_probe(struct device *); @@ -247,6 +248,9 @@ #ifdef CONFIG_SUNQE {qec_probe, 0}, #endif +#ifdef CONFIG_SUNBMAC + {bigmac_probe, 0}, +#endif #ifdef CONFIG_MYRI_SBUS {myri_sbus_probe, 0}, #endif @@ -518,7 +522,7 @@ && dfx_probe(dev) #endif #ifdef CONFIG_APFDDI - && apfddi_init(dev); + && apfddi_init(dev) #endif && 1 ) { return 1; /* -ENODEV or -EAGAIN would be more accurate. */ diff -ur --new-file old/linux/drivers/net/a2065.c new/linux/drivers/net/a2065.c --- old/linux/drivers/net/a2065.c Sun Oct 4 19:21:00 1998 +++ new/linux/drivers/net/a2065.c Sun Mar 21 16:22:00 1999 @@ -135,6 +135,7 @@ struct Linux_SBus_DMA *ledma; /* if set this points to ledma and arch=4m */ int burst_sizes; /* ledma SBus burst sizes */ #endif + struct timer_list multicast_timer; }; #define TX_BUFFS_AVAIL ((lp->tx_old<=lp->tx_new)?\ @@ -527,6 +528,7 @@ dev->start = 0; dev->tbusy = 1; + del_timer(&lp->multicast_timer); /* Stop the card */ ll->rap = LE_CSR0; @@ -706,12 +708,20 @@ volatile struct lance_init_block *ib = lp->init_block; volatile struct lance_regs *ll = lp->ll; - while (dev->tbusy) - schedule(); + if (!dev->start) + return; + + if (dev->tbusy) { + mod_timer(&lp->multicast_timer, jiffies + 2); + return; + } set_bit (0, (void *) &dev->tbusy); - while (lp->tx_old != lp->tx_new) - schedule(); + if (lp->tx_old != lp->tx_new) { + mod_timer(&lp->multicast_timer, jiffies + 4); + dev->tbusy = 0; + return; + } ll->rap = LE_CSR0; ll->rdp = LE_C0_STOP; @@ -726,6 +736,7 @@ load_csrs (lp); init_restart_lance (lp); dev->tbusy = 0; + mark_bh(NET_BH); } @@ -767,6 +778,8 @@ dev->priv = kmalloc(sizeof(struct lance_private), GFP_KERNEL); + if (dev->priv == NULL) + return -ENOMEM; priv = (struct lance_private *)dev->priv; memset(priv, 0, sizeof(struct lance_private)); @@ -793,6 +806,11 @@ dev->dma = 0; ether_setup(dev); + init_timer(&priv->multicast_timer); + priv->multicast_timer.data = (unsigned long) dev; + priv->multicast_timer.function = + (void (*)(unsigned long)) &lance_set_multicast; + zorro_config_board(key, 0); return(0); } diff -ur --new-file old/linux/drivers/net/acenic.c new/linux/drivers/net/acenic.c --- old/linux/drivers/net/acenic.c Mon Jan 18 03:28:06 1999 +++ new/linux/drivers/net/acenic.c Mon Mar 22 17:08:12 1999 @@ -16,6 +16,9 @@ * 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. + * + * Additional work by Pete Wyckoff for initial + * Alpha and trace dump support. */ #define PKT_COPY_THRESHOLD 300 @@ -40,6 +43,7 @@ #include #include #include +#include #include "acenic.h" @@ -52,10 +56,23 @@ #include "acenic_firmware.h" +#ifndef PCI_VENDOR_ID_ALTEON +#define PCI_VENDOR_ID_ALTEON 0x12ae +#define PCI_DEVICE_ID_ALTEON_ACENIC 0x0001 +#endif +#ifndef PCI_DEVICE_ID_3COM_3C985 +#define PCI_DEVICE_ID_3COM_3C985 0x0001 +#endif +#ifndef PCI_VENDOR_ID_NETGEAR +#define PCI_VENDOR_ID_NETGEAR 0x1385 +#define PCI_DEVICE_ID_NETGEAR_GA620 0x620a +#endif /* * This driver currently supports Tigon I and Tigon II based cards - * including the Alteon AceNIC and the 3Com 3C985. + * including the Alteon AceNIC and the 3Com 3C985. The driver should + * also work on the NetGear GA620, however I have not been able to + * test that myself. * * This card is really neat, it supports receive hardware checksumming * and jumbo frames (up to 9000 bytes) and does a lot of work in the @@ -114,16 +131,37 @@ * max_rx_desc= - maximum number of receive descriptors * (packets) received before interrupting the host. * + * tx_ratio= - 7 bit value (0 - 63) specifying the split in 64th + * increments of the NIC's on board memory to be used for + * transmit and receive buffers. For the 1MB NIC app. 800KB + * is available, on the 1/2MB NIC app. 300KB is available. + * 68KB will always be available as a minimum for both + * directions. The default value is a 50/50 split. + * * If you use more than one NIC, specify the parameters for the * individual NICs with a comma, ie. trace=0,0x00001fff,0 you want to * run tracing on NIC #2 but not on NIC #1 and #3. * * TODO: * - * - Add multicast support. + * - Proper multicast support. * - NIC dump support. * - More tuning parameters. + * + * The mini ring is not used under Linux and I am not sure it makes sense + * to actually use it. + */ + +/* + * Default values for tuning parameters */ +#define DEF_TX_RATIO 31 +#define DEF_TX_COAL TICKS_PER_SEC / 500 +#define DEF_TX_MAX_DESC 7 +#define DEF_RX_COAL TICKS_PER_SEC / 10000 +#define DEF_RX_MAX_DESC 2 +#define DEF_TRACE 0 +#define DEF_STAT 2 * TICKS_PER_SEC static int link[8] = {0, }; static int trace[8] = {0, }; @@ -131,13 +169,12 @@ static int rx_coal_tick[8] = {0, }; static int max_tx_desc[8] = {0, }; static int max_rx_desc[8] = {0, }; +static int tx_ratio[8] = {0, }; -static const char *version = "acenic.c: v0.24 01/13/99 Jes Sorensen (Jes.Sorensen@cern.ch)\n"; +static const char __initdata *version = "acenic.c: v0.32 03/15/99 Jes Sorensen (Jes.Sorensen@cern.ch)\n"; static struct device *root_dev = NULL; -static int ace_load_firmware(struct device *dev); - static int probed __initdata = 0; __initfunc(int acenic_probe (struct device *dev)) @@ -163,13 +200,15 @@ version_disp = 0; - while((pdev = pci_find_class(PCI_CLASS_NETWORK_ETHERNET << 8, pdev))) - { + while ((pdev = pci_find_class(PCI_CLASS_NETWORK_ETHERNET<<8, pdev))){ dev = NULL; - if ((pdev->vendor != PCI_VENDOR_ID_ALTEON) && + if (!((pdev->vendor == PCI_VENDOR_ID_ALTEON) && + (pdev->device == PCI_DEVICE_ID_ALTEON_ACENIC)) && !((pdev->vendor == PCI_VENDOR_ID_3COM) && - (pdev->device == PCI_DEVICE_ID_3COM_3C985))) + (pdev->device == PCI_DEVICE_ID_3COM_3C985)) && + !((pdev->vendor == PCI_VENDOR_ID_NETGEAR) && + (pdev->device == PCI_DEVICE_ID_NETGEAR_GA620))) continue; dev = init_etherdev(dev, sizeof(struct ace_private)); @@ -182,6 +221,8 @@ if (!dev->priv) dev->priv = kmalloc(sizeof(*ap), GFP_KERNEL); + if (!dev->priv) + return -ENOMEM; ap = dev->priv; ap->pdev = pdev; @@ -197,6 +238,9 @@ dev->stop = &ace_close; dev->get_stats = &ace_get_stats; dev->set_multicast_list = &ace_set_multicast_list; +#if 0 + dev->do_ioctl = &ace_ioctl; +#endif dev->set_mac_address = &ace_set_mac_addr; dev->change_mtu = &ace_change_mtu; @@ -234,6 +278,10 @@ sprintf(ap->name, "3Com 3C985 Gigabit Ethernet"); printk(KERN_INFO "%s: 3Com 3C985 ", dev->name); break; + case PCI_VENDOR_ID_NETGEAR: + sprintf(ap->name, "NetGear GA620 Gigabit Ethernet"); + printk(KERN_INFO "%s: NetGear GA620 ", dev->name); + break; default: sprintf(ap->name, "Unknown AceNIC based Gigabit Ethernet"); printk(KERN_INFO "%s: Unknown AceNIC ", dev->name); @@ -256,9 +304,11 @@ } #ifdef MODULE - ace_init(dev, boards_found); + if (ace_init(dev, boards_found)) + continue; #else - ace_init(dev, -1); + if (ace_init(dev, -1)) + continue; #endif boards_found++; @@ -317,17 +367,18 @@ short i; unsigned long flags; - while (root_dev) { + while (root_dev){ next = ((struct ace_private *)root_dev->priv)->next; ap = (struct ace_private *)root_dev->priv; regs = ap->regs; spin_lock_irqsave(&ap->lock, flags); - regs->CpuCtrl |= CPU_HALT; + writel(readl(®s->CpuCtrl) | CPU_HALT, ®s->CpuCtrl); if (ap->version == 2) - regs->CpuBCtrl |= CPU_HALT; - regs->Mb0Lo = 0; + writel(readl(®s->CpuBCtrl) | CPU_HALT, + ®s->CpuBCtrl); + writel(0, ®s->Mb0Lo); spin_unlock_irqrestore(&ap->lock, flags); @@ -337,7 +388,7 @@ for (i = 0; i < RX_STD_RING_ENTRIES; i++) { if (ap->rx_std_skbuff[i]) { ap->rx_std_ring[i].size = 0; - ap->rx_std_ring[i].addr = 0; + set_aceaddr_bus(&ap->rx_std_ring[i].addr, 0); dev_kfree_skb(ap->rx_std_skbuff[i]); } } @@ -363,12 +414,12 @@ { u32 idx; - idx = regs->CmdPrd; + idx = readl(®s->CmdPrd); - regs->CmdRng[idx] = *(u32 *)(cmd); + writel(*(u32 *)(cmd), ®s->CmdRng[idx]); idx = (idx + 1) % CMD_RING_ENTRIES; - regs->CmdPrd = idx; + writel(idx, ®s->CmdPrd); } @@ -384,51 +435,42 @@ ap = dev->priv; regs = ap->regs; -#if 0 - regs->HostCtrl |= 0x08; - regs->CpuCtrl = CPU_RESET; - regs->CpuBCtrl = CPU_RESET; - - { - long myjif = jiffies + HZ; - while (time_before(jiffies, myjif)); - } -#endif - /* * Don't access any other registes before this point! */ #ifdef __BIG_ENDIAN - regs->HostCtrl = ((BYTE_SWAP | WORD_SWAP | CLR_INT) | - ((BYTE_SWAP | WORD_SWAP | CLR_INT) << 24)); + writel(((BYTE_SWAP | WORD_SWAP | CLR_INT) | + ((BYTE_SWAP | WORD_SWAP | CLR_INT) << 24)), + ®s->HostCtrl); #else - regs->HostCtrl = (CLR_INT | WORD_SWAP | - ((CLR_INT | WORD_SWAP) << 24)); + writel((CLR_INT | WORD_SWAP | ((CLR_INT | WORD_SWAP) << 24)), + ®s->HostCtrl); #endif + mb(); /* * Stop the NIC CPU and clear pending interrupts */ - regs->CpuCtrl |= CPU_HALT; - regs->Mb0Lo = 0; + writel(readl(®s->CpuCtrl) | CPU_HALT, ®s->CpuCtrl); + writel(0, ®s->Mb0Lo); - tig_ver = regs->HostCtrl >> 28; + tig_ver = readl(®s->HostCtrl) >> 28; switch(tig_ver){ case 4: printk(KERN_INFO" Tigon I (Rev. 4), Firmware: %i.%i.%i, ", tigonFwReleaseMajor, tigonFwReleaseMinor, tigonFwReleaseFix); - regs->LocalCtrl = 0; + writel(0, ®s->LocalCtrl); ap->version = 1; break; case 6: printk(KERN_INFO" Tigon II (Rev. %i), Firmware: %i.%i.%i, ", tig_ver, tigon2FwReleaseMajor, tigon2FwReleaseMinor, tigon2FwReleaseFix); - regs->CpuBCtrl |= CPU_HALT; - regs->LocalCtrl = SRAM_BANK_512K; - regs->MiscCfg = SYNC_SRAM_TIMING; + writel(readl(®s->CpuBCtrl) | CPU_HALT, ®s->CpuBCtrl); + writel(SRAM_BANK_512K, ®s->LocalCtrl); + writel(SYNC_SRAM_TIMING, ®s->MiscCfg); ap->version = 2; break; default: @@ -445,8 +487,8 @@ * `Firmware not running' problem on the Tigon II. */ #ifdef __LITTLE_ENDIAN - regs->ModeStat = ACE_BYTE_SWAP_DATA | ACE_WARN | ACE_FATAL - | ACE_WORD_SWAP; + writel(ACE_BYTE_SWAP_DATA | ACE_WARN | ACE_FATAL | + ACE_WORD_SWAP | ACE_NO_JUMBO_FRAG, ®s->ModeStat); #else #error "this driver doesn't run on big-endian machines yet!" #endif @@ -462,8 +504,8 @@ mac2 |= read_eeprom_byte(regs, 0x8c+i); } - regs->MacAddrHi = mac1; - regs->MacAddrLo = mac2; + writel(mac1, ®s->MacAddrHi); + writel(mac2, ®s->MacAddrLo); printk("MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", (mac1 >> 8) & 0xff, mac1 & 0xff, (mac2 >> 24) &0xff, @@ -514,10 +556,9 @@ } } } - regs->PciState = tmp; + writel(tmp, ®s->PciState); - if (request_irq(dev->irq, ace_interrupt, SA_SHIRQ, ap->name, dev)) - { + if (request_irq(dev->irq, ace_interrupt, SA_SHIRQ, ap->name, dev)) { printk(KERN_WARNING "%s: Requested IRQ %d is busy\n", dev->name, dev->irq); return -EAGAIN; @@ -548,150 +589,149 @@ tmp_ptr = virt_to_bus((void *)info); #if (BITS_PER_LONG == 64) - regs->InfoPtrHi = (tmp_ptr >> 32); + writel(tmp_ptr >> 32, ®s->InfoPtrHi); #else - regs->InfoPtrHi = 0; + writel(0, ®s->InfoPtrHi); #endif - regs->InfoPtrLo = ((tmp_ptr) & 0xffffffff); + writel(tmp_ptr & 0xffffffff, ®s->InfoPtrLo); memset(ap->evt_ring, 0, EVT_RING_ENTRIES * sizeof(struct event)); - info->evt_ctrl.rngptr = virt_to_bus(ap->evt_ring); + set_aceaddr(&info->evt_ctrl.rngptr, ap->evt_ring); info->evt_ctrl.flags = 0; - info->evt_prd_ptr = virt_to_bus(&ap->evt_prd); + set_aceaddr(&info->evt_prd_ptr, &ap->evt_prd); ap->evt_prd = 0; - regs->EvtCsm = 0; + writel(0, ®s->EvtCsm); info->cmd_ctrl.flags = 0; - info->cmd_ctrl.rngptr = 0x100; + set_aceaddr_bus(&info->cmd_ctrl.rngptr, (void *)0x100); info->cmd_ctrl.max_len = 0; - for (i = 0; i < CMD_RING_ENTRIES; i++) { - regs->CmdRng[i] = 0; - } + for (i = 0; i < CMD_RING_ENTRIES; i++) + writel(0, ®s->CmdRng[i]); - regs->CmdPrd = 0; - regs->CmdCsm = 0; + writel(0, ®s->CmdPrd); + writel(0, ®s->CmdCsm); - info->stats2_ptr = virt_to_bus(&info->s.stats); + set_aceaddr(&info->stats2_ptr, &info->s.stats); info->rx_std_ctrl.max_len = ACE_STD_MTU + ETH_HLEN + 4; - info->rx_std_ctrl.rngptr = virt_to_bus(ap->rx_std_ring); - info->rx_std_ctrl.flags = RX_TCP_UDP_SUM; + set_aceaddr(&info->rx_std_ctrl.rngptr, ap->rx_std_ring); + info->rx_std_ctrl.flags = FLG_RX_TCP_UDP_SUM; memset(ap->rx_std_ring, 0, RX_STD_RING_ENTRIES * sizeof(struct rx_desc)); info->rx_jumbo_ctrl.max_len = 0; - info->rx_jumbo_ctrl.rngptr = virt_to_bus(ap->rx_jumbo_ring); - info->rx_jumbo_ctrl.flags = RX_TCP_UDP_SUM; + set_aceaddr(&info->rx_jumbo_ctrl.rngptr, ap->rx_jumbo_ring); + info->rx_jumbo_ctrl.flags = FLG_RX_TCP_UDP_SUM; memset(ap->rx_jumbo_ring, 0, RX_JUMBO_RING_ENTRIES * sizeof(struct rx_desc)); - info->rx_return_ctrl.max_len = 0; - info->rx_return_ctrl.rngptr = virt_to_bus(ap->rx_return_ring); + info->rx_mini_ctrl.max_len = 0; +#if 0 + set_aceaddr(&info->rx_mini_ctrl.rngptr, ap->rx_mini_ring); +#else + set_aceaddr_bus(&info->rx_mini_ctrl.rngptr, 0); +#endif + info->rx_mini_ctrl.flags = FLG_RNG_DISABLED; + +#if 0 + memset(ap->rx_mini_ring, 0, + RX_MINI_RING_ENTRIES * sizeof(struct rx_desc)); +#endif + + set_aceaddr(&info->rx_return_ctrl.rngptr, ap->rx_return_ring); info->rx_return_ctrl.flags = 0; + info->rx_return_ctrl.max_len = RX_RETURN_RING_ENTRIES; memset(ap->rx_return_ring, 0, RX_RETURN_RING_ENTRIES * sizeof(struct rx_desc)); - info->rx_ret_prd_ptr = virt_to_bus(&ap->rx_ret_prd); + set_aceaddr(&info->rx_ret_prd_ptr, &ap->rx_ret_prd); - regs->WinBase = TX_RING_BASE; + writel(TX_RING_BASE, ®s->WinBase); ap->tx_ring = (struct tx_desc *)regs->Window; - memset(ap->tx_ring, 0, TX_RING_ENTRIES * sizeof(struct tx_desc)); + for (i = 0; i < (TX_RING_ENTRIES * sizeof(struct tx_desc) / 4); i++){ + writel(0, (unsigned long)ap->tx_ring + i * 4); + } info->tx_ctrl.max_len = TX_RING_ENTRIES; info->tx_ctrl.flags = 0; -#if (BITS_PER_LONG == 64) && defined(__BIG_ENDIAN) - info->tx_ctrl.rngptr = TX_RING_BASE << 32; -#else - info->tx_ctrl.rngptr = TX_RING_BASE; -#endif + set_aceaddr_bus(&info->tx_ctrl.rngptr, (void *)TX_RING_BASE); - info->tx_csm_ptr = virt_to_bus(&ap->tx_csm); + set_aceaddr(&info->tx_csm_ptr, &ap->tx_csm); /* * Potential item for tuning parameter */ - regs->DmaReadCfg = DMA_THRESH_8W; - regs->DmaWriteCfg = DMA_THRESH_8W; - - regs->MaskInt = 0; - regs->IfIdx = 1; - - regs->AssistState = 1; -#if 0 -{ - u32 tmp; - - tmp = regs->MacRxState; - tmp &= ~4; - regs->MacRxState = tmp; -} -#endif + writel(DMA_THRESH_8W, ®s->DmaReadCfg); + writel(DMA_THRESH_8W, ®s->DmaWriteCfg); - regs->TuneStatTicks = 2 * TICKS_PER_SEC; + writel(0, ®s->MaskInt); + writel(1, ®s->IfIdx); + writel(1, ®s->AssistState); + + writel(DEF_STAT, ®s->TuneStatTicks); + + writel(DEF_TX_COAL, ®s->TuneTxCoalTicks); + writel(DEF_TX_MAX_DESC, ®s->TuneMaxTxDesc); + writel(DEF_RX_COAL, ®s->TuneRxCoalTicks); + writel(DEF_RX_MAX_DESC, ®s->TuneMaxRxDesc); + writel(DEF_TRACE, ®s->TuneTrace); + writel(DEF_TX_RATIO, ®s->TxBufRat); + + if (board_idx >= 8) { + printk(KERN_WARNING "%s: more then 8 NICs detected, " + "ignoring module parameters!\n", dev->name); + board_idx = -1; + } if (board_idx >= 0) { - if ((board_idx < 8) && tx_coal_tick[board_idx]) - regs->TuneTxCoalTicks = tx_coal_tick[board_idx] * - TICKS_PER_SEC / 1000; - else - regs->TuneTxCoalTicks = TICKS_PER_SEC / 500; - if ((board_idx < 8) && max_tx_desc[board_idx]) - regs->TuneMaxTxDesc = max_tx_desc[board_idx]; - else - regs->TuneMaxTxDesc = 7; + if (tx_coal_tick[board_idx]) + writel(tx_coal_tick[board_idx], + ®s->TuneTxCoalTicks); + if (max_tx_desc[board_idx]) + writel(max_tx_desc[board_idx], ®s->TuneMaxTxDesc); + + if (rx_coal_tick[board_idx]) + writel(rx_coal_tick[board_idx], + ®s->TuneRxCoalTicks); + if (max_rx_desc[board_idx]) + writel(max_rx_desc[board_idx], ®s->TuneMaxRxDesc); - if ((board_idx < 8) && rx_coal_tick[board_idx]) - regs->TuneRxCoalTicks = rx_coal_tick[board_idx] * - TICKS_PER_SEC / 1000; - else - regs->TuneRxCoalTicks = TICKS_PER_SEC / 10000; - if ((board_idx < 8) && max_rx_desc[board_idx]) - regs->TuneMaxRxDesc = max_rx_desc[board_idx]; - else - regs->TuneMaxRxDesc = 2; + if (trace[board_idx]) + writel(trace[board_idx], ®s->TuneTrace); - if (board_idx < 8) - regs->TuneTrace = trace[board_idx]; - else - regs->TuneTrace = 0; - }else{ - regs->TuneTxCoalTicks = TICKS_PER_SEC / 500; - regs->TuneMaxTxDesc = 7; - regs->TuneRxCoalTicks = TICKS_PER_SEC / 10000; - regs->TuneMaxRxDesc = 2; - regs->TuneTrace = 0; + if ((tx_ratio[board_idx] >= 0) && (tx_ratio[board_idx] < 64)) + writel(tx_ratio[board_idx], ®s->TxBufRat); } - tmp = LNK_ENABLE; - - if ((board_idx > 7) || (board_idx < 0) || !(link[board_idx])){ - if (board_idx > 7) - printk(KERN_WARNING "%s: more then 8 NICs detected, " - "ignoring link options!\n", dev->name); - /* - * No link options specified, we go for the defaults - */ - tmp |= LNK_FULL_DUPLEX | LNK_1000MB | LNK_100MB | LNK_10MB | - LNK_RX_FLOW_CTL_Y | LNK_NEG_FCTL | LNK_NEGOTIATE; + /* + * Default link parameters + */ + tmp = LNK_ENABLE | LNK_FULL_DUPLEX | LNK_1000MB | LNK_100MB | + LNK_10MB | LNK_RX_FLOW_CTL_Y | LNK_NEG_FCTL | LNK_NEGOTIATE; + if(ap->version == 2) + tmp |= LNK_TX_FLOW_CTL_Y; - if(ap->version == 2) - tmp |= LNK_TX_FLOW_CTL_Y; - } else { + /* + * Override link default parameters + */ + if ((board_idx >= 0) && link[board_idx]) { int option = link[board_idx]; + tmp = LNK_ENABLE; + if (option & 0x01){ printk(KERN_INFO "%s: Setting half duplex link\n", dev->name); - tmp |= LNK_FULL_DUPLEX; + tmp &= ~LNK_FULL_DUPLEX; } - if ((option & 0x02) == 0) - tmp |= LNK_NEGOTIATE; + if (option & 0x02) + tmp &= ~LNK_NEGOTIATE; if (option & 0x10) tmp |= LNK_10MB; if (option & 0x20) @@ -718,22 +758,22 @@ } } - regs->TuneLink = tmp; + writel(tmp, ®s->TuneLink); if (ap->version == 2) - regs->TuneFastLink = tmp; + writel(tmp, ®s->TuneFastLink); if (ap->version == 1) - regs->Pc = tigonFwStartAddr; + writel(tigonFwStartAddr, ®s->Pc); else if (ap->version == 2) - regs->Pc = tigon2FwStartAddr; + writel(tigon2FwStartAddr, ®s->Pc); - regs->Mb0Lo = 0; + writel(0, ®s->Mb0Lo); /* * Start the NIC CPU */ - regs->CpuCtrl = (regs->CpuCtrl & ~(CPU_HALT | CPU_TRACE)); + writel(readl(®s->CpuCtrl) & ~(CPU_HALT|CPU_TRACE), ®s->CpuCtrl); /* * Wait for the firmware to spin up - max 3 seconds. @@ -743,7 +783,7 @@ if (!ap->fw_running){ printk(KERN_ERR "%s: Firmware NOT running!\n", dev->name); ace_dump_trace(ap); - regs->CpuCtrl |= CPU_HALT; + writel(readl(®s->CpuCtrl) | CPU_HALT, ®s->CpuCtrl); return -EBUSY; } @@ -773,7 +813,7 @@ */ if (ap->tx_csm != ap->tx_ret_csm){ printk(KERN_WARNING "%s: Transmitter is stuck, %08x\n", - dev->name, regs->HostCtrl); + dev->name, (unsigned int)readl(®s->HostCtrl)); } ap->timer.expires = jiffies + (5/2*HZ); @@ -786,9 +826,11 @@ */ static void ace_dump_trace(struct ace_private *ap) { +#if 0 if (!ap->trace_buf) if (!(ap->trace_buf = kmalloc(ACE_TRACE_SIZE, GFP_KERNEL))); return; +#endif } @@ -819,7 +861,7 @@ ap->tx_full = 0; ap->cur_rx = ap->dirty_rx = 0; ap->tx_prd = ap->tx_csm = ap->tx_ret_csm = 0; - regs->RxRetCsm = 0; + writel(0, ®s->RxRetCsm); for (i = 0; i < RX_RING_THRESH; i++) { struct sk_buff *skb; @@ -833,7 +875,7 @@ */ skb_reserve(skb, 2); - ap->rx_std_ring[i].addr = virt_to_bus(skb->data); + set_aceaddr(&ap->rx_std_ring[i].addr, skb->data); ap->rx_std_ring[i].size = ACE_STD_MTU + ETH_HLEN + 4; ap->rx_std_ring[i].flags = 0; @@ -877,7 +919,7 @@ spin_lock_irqsave(&ap->lock, flags); - for (i = 0; i < RX_RING_THRESH; i++) { + for (i = 0; i < RX_RING_JUMBO_THRESH; i++) { struct sk_buff *skb; ap->rx_jumbo_ring[i].flags = 0; @@ -889,10 +931,10 @@ */ skb_reserve(skb, 2); - ap->rx_jumbo_ring[i].addr = virt_to_bus(skb->data); + set_aceaddr(&ap->rx_jumbo_ring[i].addr, skb->data); ap->rx_jumbo_ring[i].size = ACE_JUMBO_MTU + ETH_HLEN + 4; - ap->rx_jumbo_ring[i].flags = JUMBO_FLAG; + ap->rx_jumbo_ring[i].flags = DFLG_RX_JUMBO; ap->rx_jumbo_ring[i].type = DESC_RX; ap->rx_jumbo_ring[i].idx = i; @@ -939,7 +981,7 @@ for (i = 0; i < RX_JUMBO_RING_ENTRIES; i++) { if (ap->rx_jumbo_skbuff[i]) { ap->rx_jumbo_ring[i].size = 0; - ap->rx_jumbo_ring[i].addr = 0; + set_aceaddr_bus(&ap->rx_jumbo_ring[i].addr, 0); dev_kfree_skb(ap->rx_jumbo_skbuff[i]); } } @@ -959,10 +1001,8 @@ static u32 ace_handle_event(struct device *dev, u32 evtcsm, u32 evtprd) { struct ace_private *ap; - struct ace_regs *regs; ap = (struct ace_private *)dev->priv; - regs = ap->regs; while (evtcsm != evtprd){ switch (ap->evt_ring[evtcsm].evt){ @@ -1019,24 +1059,24 @@ } -static int rx_int(struct device *dev, u32 rxretprd, u32 rxretcsm) +static int ace_rx_int(struct device *dev, u32 rxretprd, u32 rxretcsm) { struct ace_private *ap = (struct ace_private *)dev->priv; - u32 idx, oldidx; struct ace_regs *regs = ap->regs; + u32 idx, oldidx; idx = rxretcsm; - while(idx != rxretprd){ + while (idx != rxretprd){ struct sk_buff *skb, *newskb, *oldskb; struct rx_desc *newrxdesc, *oldrxdesc; u32 prdidx, size; - unsigned long addr; + void *addr; u16 csum; int jumbo; oldidx = ap->rx_return_ring[idx].idx; - jumbo = ap->rx_return_ring[idx].flags & JUMBO_FLAG; + jumbo = ap->rx_return_ring[idx].flags & DFLG_RX_JUMBO; if (jumbo){ oldskb = ap->rx_jumbo_skbuff[oldidx]; @@ -1065,7 +1105,7 @@ skb_reserve(skb, 2); memcpy(skb_put(skb, size), oldskb->data, size); - addr = oldrxdesc->addr; + addr = get_aceaddr_bus(&oldrxdesc->addr); newskb = oldskb; }else{ skb = oldskb; @@ -1084,21 +1124,21 @@ * aligned receive buffers */ skb_reserve(newskb, 2); - addr = virt_to_bus(newskb->data); + addr = (void *)virt_to_bus(newskb->data); } - newrxdesc->addr = addr; + set_aceaddr_bus(&newrxdesc->addr, addr); newrxdesc->size = size; newrxdesc->flags = oldrxdesc->flags; newrxdesc->idx = prdidx; newrxdesc->type = DESC_RX; #if (BITS_PER_LONG == 32) - newrxdesc->zero = 0; + newrxdesc->addr.addrhi = 0; #endif oldrxdesc->size = 0; - oldrxdesc->addr = 0; + set_aceaddr_bus(&oldrxdesc->addr, 0); if (jumbo){ ap->rx_jumbo_skbuff[oldidx] = NULL; @@ -1152,7 +1192,11 @@ idx = (idx + 1) % RX_RETURN_RING_ENTRIES; } out: - regs->RxRetCsm = idx; + /* + * According to the documentation RxRetCsm is obsolete with + * the 12.3.x Firmware - my Tigon I NIC's seem to disagree! + */ + writel(idx, ®s->RxRetCsm); ap->cur_rx = idx; return idx; @@ -1180,7 +1224,7 @@ * we want to make sure it is actually our interrupt before * spending any time in here. */ - if (!(regs->HostCtrl & IN_INT)){ + if (!(readl(®s->HostCtrl) & IN_INT)){ spin_unlock(&ap->lock); return; } @@ -1188,7 +1232,16 @@ /* * Tell the card not to generate interrupts while we are in here. */ - regs->Mb0Lo = 1; + writel(1, ®s->Mb0Lo); + + /* + * Service RX ints before TX + */ + rxretprd = ap->rx_ret_prd; + rxretcsm = ap->cur_rx; + + if (rxretprd != rxretcsm) + rxretprd = ace_rx_int(dev, rxretprd, rxretcsm); txcsm = ap->tx_csm; if (txcsm != ap->tx_ret_csm) { @@ -1201,9 +1254,11 @@ ap->tx_skbuff[idx] = NULL; - ap->tx_ring[idx].size = 0; - ap->tx_ring[idx].addr = 0; - ap->tx_ring[idx].flags = 0; +#if (BITS_PER_LONG == 64) + writel(0, &ap->tx_ring[idx].addr.addrhi); +#endif + writel(0, &ap->tx_ring[idx].addr.addrlo); + writel(0, &ap->tx_ring[idx].flagsize); idx = (idx + 1) % TX_RING_ENTRIES; } while (idx != txcsm); @@ -1224,21 +1279,15 @@ ap->tx_ret_csm = txcsm; } - rxretprd = ap->rx_ret_prd; - rxretcsm = ap->cur_rx; - - if (rxretprd != rxretcsm) - rxretprd = rx_int(dev, rxretprd, rxretcsm); - - evtcsm = regs->EvtCsm; + evtcsm = readl(®s->EvtCsm); evtprd = ap->evt_prd; if (evtcsm != evtprd){ evtcsm = ace_handle_event(dev, evtcsm, evtprd); } - regs->EvtCsm = evtcsm; - regs->Mb0Lo = 0; + writel(evtcsm, ®s->EvtCsm); + writel(0, ®s->Mb0Lo); spin_unlock(&ap->lock); } @@ -1258,7 +1307,7 @@ return -EBUSY; } - regs->IfMtu = dev->mtu + ETH_HLEN + 4; + writel(dev->mtu + ETH_HLEN + 4, ®s->IfMtu); cmd.evt = C_HOST_STATE; cmd.code = C_C_STACK_UP; @@ -1277,6 +1326,7 @@ ap->promisc = 1; }else ap->promisc = 0; + ap->mcast_all = 0; #if 0 { long myjif = jiffies + HZ; @@ -1338,8 +1388,9 @@ for (i = 0; i < TX_RING_ENTRIES; i++) { if (ap->tx_skbuff[i]) { - ap->tx_ring[i].size = 0; - ap->tx_ring[i].addr = 0; + writel(0, &ap->tx_ring[i].addr.addrhi); + writel(0, &ap->tx_ring[i].addr.addrlo); + writel(0, &ap->tx_ring[i].flagsize); dev_kfree_skb(ap->tx_skbuff[i]); } } @@ -1359,30 +1410,37 @@ struct ace_private *ap = (struct ace_private *)dev->priv; struct ace_regs *regs = ap->regs; unsigned long flags; - u32 idx; + unsigned long addr; + u32 idx, flagsize; spin_lock_irqsave(&ap->lock, flags); idx = ap->tx_prd; ap->tx_skbuff[idx] = skb; - ap->tx_ring[idx].addr = virt_to_bus(skb->data); - ap->tx_ring[idx].size = skb->len; - ap->tx_ring[idx].flags = DESC_END; + addr = virt_to_bus(skb->data); +#if (BITS_PER_LONG == 64) + writel(addr >> 32, &ap->tx_ring[idx].addr.addrhi); +#endif + writel(addr & 0xffffffff, &ap->tx_ring[idx].addr.addrlo); + flagsize = (skb->len << 16) | (DESC_END) ; + writel(flagsize, &ap->tx_ring[idx].flagsize); + mb(); idx = (idx + 1) % TX_RING_ENTRIES; ap->tx_prd = idx; - regs->TxPrd = idx; + writel(idx, ®s->TxPrd); if ((idx + 1) % TX_RING_ENTRIES == ap->tx_ret_csm){ ap->tx_full = 1; set_bit(0, (void*)&dev->tbusy); /* * Queue is full, add timer to detect whether the - * transmitter is stuck. + * transmitter is stuck. Use mod_timer as we can get + * into the situation where we risk adding several + * timers. */ - ap->timer.expires = jiffies + (3 * HZ); - add_timer(&ap->timer); + mod_timer(&ap->timer, jiffies + (3 * HZ)); } spin_unlock_irqrestore(&ap->lock, flags); @@ -1400,7 +1458,7 @@ if ((new_mtu < 68) || (new_mtu > ACE_JUMBO_MTU)) return -EINVAL; - regs->IfMtu = new_mtu + ETH_HLEN + 4; + writel(new_mtu + ETH_HLEN + 4, ®s->IfMtu); dev->mtu = new_mtu; if (new_mtu > ACE_STD_MTU){ @@ -1442,8 +1500,8 @@ da = (u16 *)dev->dev_addr; regs = ((struct ace_private *)dev->priv)->regs; - regs->MacAddrHi = da[0]; - regs->MacAddrLo = (da[1] << 16) | da[2]; + writel(da[0], ®s->MacAddrHi); + writel((da[1] << 16) | da[2], ®s->MacAddrLo); cmd.evt = C_SET_MAC_ADDR; cmd.code = 0; @@ -1460,21 +1518,51 @@ struct ace_regs *regs = ap->regs; struct cmd cmd; + if ((dev->flags & IFF_ALLMULTI) && !(ap->mcast_all)) { + cmd.evt = C_SET_MULTICAST_MODE; + cmd.code = C_C_MCAST_ENABLE; + cmd.idx = 0; + ace_issue_cmd(regs, &cmd); + ap->mcast_all = 1; + } else if (ap->mcast_all){ + cmd.evt = C_SET_MULTICAST_MODE; + cmd.code = C_C_MCAST_ENABLE; + cmd.idx = 0; + ace_issue_cmd(regs, &cmd); + ap->mcast_all = 0; + } + if ((dev->flags & IFF_PROMISC) && !(ap->promisc)) { cmd.evt = C_SET_PROMISC_MODE; cmd.code = C_C_PROMISC_ENABLE; cmd.idx = 0; ace_issue_cmd(regs, &cmd); - ap->promisc = 1; }else if (!(dev->flags & IFF_PROMISC) && (ap->promisc)){ cmd.evt = C_SET_PROMISC_MODE; cmd.code = C_C_PROMISC_DISABLE; cmd.idx = 0; ace_issue_cmd(regs, &cmd); - ap->promisc = 0; } + + /* + * For the time being multicast relies on the upper layers + * filtering it properly. The Firmware does not allow one to + * set the entire multicast list at a time and keeping track of + * it here is going to be messy. + */ + if ((dev->mc_count) && !(ap->mcast_all)) { + cmd.evt = C_SET_MULTICAST_MODE; + cmd.code = C_C_MCAST_ENABLE; + cmd.idx = 0; + ace_issue_cmd(regs, &cmd); + }else if (!ap->mcast_all) { + cmd.evt = C_SET_MULTICAST_MODE; + cmd.code = C_C_MCAST_DISABLE; + cmd.idx = 0; + ace_issue_cmd(regs, &cmd); + } } @@ -1488,24 +1576,29 @@ __initfunc(void ace_copy(struct ace_regs *regs, void *src, u32 dest, int size)) { - int tsize; - u32 tdest; + unsigned long tdest; + u32 *wsrc; + short tsize, i; if (size <= 0) return; - while(size > 0){ + while (size > 0){ tsize = min(((~dest & (ACE_WINDOW_SIZE - 1)) + 1), min(size, ACE_WINDOW_SIZE)); - tdest = dest & (ACE_WINDOW_SIZE - 1); - regs->WinBase = dest & ~(ACE_WINDOW_SIZE - 1); + tdest = (unsigned long)®s->Window + + (dest & (ACE_WINDOW_SIZE - 1)); + writel(dest & ~(ACE_WINDOW_SIZE - 1), ®s->WinBase); #ifdef __BIG_ENDIAN #error "data must be swapped here" #else -#if 0 - printk("copying %04x from %08x to %06x (Window addr %08x), winbase %02x\n", tsize, (unsigned)src, dest, (unsigned) ((void *)regs->Window + tdest), regs->WinBase); -#endif - memcpy((void *)((void *)regs->Window + tdest), src, tsize); +/* + * XXX - special memcpy needed here!!! + */ + wsrc = src; + for (i = 0; i < (tsize / 4); i++){ + writel(wsrc[i], tdest + i*4); + } #endif dest += tsize; src += tsize; @@ -1518,19 +1611,22 @@ __initfunc(void ace_clear(struct ace_regs *regs, u32 dest, int size)) { - int tsize = 0; - u32 tdest; + unsigned long tdest; + short tsize = 0, i; if (size <= 0) return; - while(size > 0){ + while (size > 0){ tsize = min(((~dest & (ACE_WINDOW_SIZE - 1)) + 1), min(size, ACE_WINDOW_SIZE)); - tdest = dest & (ACE_WINDOW_SIZE - 1); - regs->WinBase = dest & ~(ACE_WINDOW_SIZE - 1); + tdest = (unsigned long)®s->Window + + (dest & (ACE_WINDOW_SIZE - 1)); + writel(dest & ~(ACE_WINDOW_SIZE - 1), ®s->WinBase); - memset((void *)((void *)regs->Window + tdest), 0, tsize); + for (i = 0; i < (tsize / 4); i++){ + writel(0, tdest + i*4); + } dest += tsize; size -= tsize; @@ -1554,13 +1650,17 @@ ap = (struct ace_private *)dev->priv; regs = ap->regs; - if (!(regs->CpuCtrl & CPU_HALTED)){ + if (!(readl(®s->CpuCtrl) & CPU_HALTED)){ printk(KERN_ERR "%s: trying to download firmware while the " "CPU is running!\n", dev->name); return -EFAULT; } - ace_clear(regs, 0x2000, 0x100000-0x2000); + /* + * Do not try to clear more than 512KB or we end up seeing + * funny things on NICs with only 512KB SRAM + */ + ace_clear(regs, 0x2000, 0x80000-0x2000); if (ap->version == 1){ ace_copy(regs, tigonFwText, tigonFwTextAddr, tigonFwTextLen); ace_copy(regs, tigonFwData, tigonFwDataAddr, tigonFwDataLen); @@ -1595,36 +1695,56 @@ */ static void eeprom_start(struct ace_regs *regs) { + u32 local = readl(®s->LocalCtrl); + udelay(1); - regs->LocalCtrl |= (EEPROM_DATA_OUT | EEPROM_WRITE_ENABLE); + local |= EEPROM_DATA_OUT | EEPROM_WRITE_ENABLE; + writel(local, ®s->LocalCtrl); + mb(); udelay(1); - regs->LocalCtrl |= EEPROM_CLK_OUT; + local |= EEPROM_CLK_OUT; + writel(local, ®s->LocalCtrl); + mb(); udelay(1); - regs->LocalCtrl &= ~EEPROM_DATA_OUT; + local &= ~EEPROM_DATA_OUT; + writel(local, ®s->LocalCtrl); + mb(); udelay(1); - regs->LocalCtrl &= ~EEPROM_CLK_OUT; + local &= ~EEPROM_CLK_OUT; + writel(local, ®s->LocalCtrl); + mb(); } static void eeprom_prep(struct ace_regs *regs, u8 magic) { short i; + u32 local; udelay(2); - regs->LocalCtrl &= ~EEPROM_DATA_OUT; - regs->LocalCtrl |= EEPROM_WRITE_ENABLE; + local = readl(®s->LocalCtrl); + local &= ~EEPROM_DATA_OUT; + local |= EEPROM_WRITE_ENABLE; + writel(local, ®s->LocalCtrl); + mb(); for (i = 0; i < 8; i++, magic <<= 1) { udelay(2); if (magic & 0x80) - regs->LocalCtrl |= EEPROM_DATA_OUT; + local |= EEPROM_DATA_OUT; else - regs->LocalCtrl &= ~EEPROM_DATA_OUT; + local &= ~EEPROM_DATA_OUT; + writel(local, ®s->LocalCtrl); + mb(); udelay(1); - regs->LocalCtrl |= EEPROM_CLK_OUT; + local |= EEPROM_CLK_OUT; + writel(local, ®s->LocalCtrl); + mb(); udelay(1); - regs->LocalCtrl &= ~(EEPROM_CLK_OUT | EEPROM_DATA_OUT); + local &= ~(EEPROM_CLK_OUT | EEPROM_DATA_OUT); + writel(local, ®s->LocalCtrl); + mb(); } } @@ -1632,15 +1752,23 @@ static int eeprom_check_ack(struct ace_regs *regs) { int state; - - regs->LocalCtrl &= ~EEPROM_WRITE_ENABLE; + u32 local; + + local = readl(®s->LocalCtrl); + local &= ~EEPROM_WRITE_ENABLE; + writel(local, ®s->LocalCtrl); + mb(); udelay(2); - regs->LocalCtrl |= EEPROM_CLK_OUT; + local |= EEPROM_CLK_OUT; + writel(local, ®s->LocalCtrl); + mb(); udelay(1); /* sample data in middle of high clk */ - state = (regs->LocalCtrl & EEPROM_DATA_IN) != 0; + state = (readl(®s->LocalCtrl) & EEPROM_DATA_IN) != 0; udelay(1); - regs->LocalCtrl &= ~EEPROM_CLK_OUT; + mb(); + writel(readl(®s->LocalCtrl) & ~EEPROM_CLK_OUT, ®s->LocalCtrl); + mb(); return state; } @@ -1648,15 +1776,28 @@ static void eeprom_stop(struct ace_regs *regs) { - regs->LocalCtrl |= EEPROM_WRITE_ENABLE; + u32 local; + + local = readl(®s->LocalCtrl); + local |= EEPROM_WRITE_ENABLE; + writel(local, ®s->LocalCtrl); + mb(); udelay(1); - regs->LocalCtrl &= ~EEPROM_DATA_OUT; + local &= ~EEPROM_DATA_OUT; + writel(local, ®s->LocalCtrl); + mb(); udelay(1); - regs->LocalCtrl |= EEPROM_CLK_OUT; + local |= EEPROM_CLK_OUT; + writel(local, ®s->LocalCtrl); + mb(); udelay(1); - regs->LocalCtrl |= EEPROM_DATA_OUT; + local |= EEPROM_DATA_OUT; + writel(local, ®s->LocalCtrl); + mb(); udelay(2); - regs->LocalCtrl &= ~EEPROM_CLK_OUT; + local &= ~EEPROM_CLK_OUT; + writel(local, ®s->LocalCtrl); + mb(); } @@ -1665,7 +1806,8 @@ */ static u8 read_eeprom_byte(struct ace_regs *regs, unsigned long offset) { - u32 i; + u32 local; + short i; u8 result = 0; if (!regs){ @@ -1695,24 +1837,37 @@ return 0; for (i = 0; i < 8; i++) { - regs->LocalCtrl &= ~EEPROM_WRITE_ENABLE; + local = readl(®s->LocalCtrl); + local &= ~EEPROM_WRITE_ENABLE; + writel(local, ®s->LocalCtrl); udelay(2); - regs->LocalCtrl |= EEPROM_CLK_OUT; + mb(); + local |= EEPROM_CLK_OUT; + writel(local, ®s->LocalCtrl); udelay(1); + mb(); /* sample data mid high clk */ result = (result << 1) | - ((regs->LocalCtrl & EEPROM_DATA_IN) != 0); + ((readl(®s->LocalCtrl) & EEPROM_DATA_IN) != 0); udelay(1); - regs->LocalCtrl &= ~EEPROM_CLK_OUT; - if (i == 7) - regs->LocalCtrl |= EEPROM_WRITE_ENABLE; + mb(); + local = readl(®s->LocalCtrl); + local &= ~EEPROM_CLK_OUT; + writel(local, ®s->LocalCtrl); + mb(); + if (i == 7){ + local |= EEPROM_WRITE_ENABLE; + writel(local, ®s->LocalCtrl); + mb(); + } } - regs->LocalCtrl |= EEPROM_DATA_OUT; + local |= EEPROM_DATA_OUT; + writel(local, ®s->LocalCtrl); udelay(1); - regs->LocalCtrl |= EEPROM_CLK_OUT; + writel(readl(®s->LocalCtrl) | EEPROM_CLK_OUT, ®s->LocalCtrl); udelay(2); - regs->LocalCtrl &= ~EEPROM_CLK_OUT; + writel(readl(®s->LocalCtrl) & ~EEPROM_CLK_OUT, ®s->LocalCtrl); eeprom_stop(regs); return result; @@ -1721,6 +1876,6 @@ /* * Local variables: - * compile-command: "gcc -D__KERNEL__ -D__SMP__ -I/data/home/jes/linux/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2 -DCPU=686 -DMODULE -DMODVERSIONS -include /data/home/jes/linux/include/linux/modversions.h -c -o acenic.o acenic.c" + * compile-command: "gcc -D__KERNEL__ -D__SMP__ -DMODULE -I/data/home/jes/linux/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -DMODVERSIONS -include /data/home/jes/linux/include/linux/modversions.h -c -o acenic.o acenic.c" * End: */ diff -ur --new-file old/linux/drivers/net/acenic.h new/linux/drivers/net/acenic.h --- old/linux/drivers/net/acenic.h Thu Jan 7 21:25:09 1999 +++ new/linux/drivers/net/acenic.h Mon Mar 22 17:08:12 1999 @@ -1,13 +1,84 @@ #ifndef _ACENIC_H_ #define _ACENIC_H_ -#if ((BITS_PER_LONG != 32) && (BITS_PER_LONG != 64)) -#error "BITS_PER_LONG not defined or not valid" +/* + * Addressing: + * + * The Tigon uses 64-bit host addresses, regardless of their actual + * length, and it expects a big-endian format. For 32 bit systems the + * upper 32 bits of the address are simply ignored (zero), however for + * little endian 64 bit systems (Alpha) this looks strange with the + * two parts of the address word being swapped. + * + * The addresses are split in two 32 bit words for all architectures + * as some of them are in PCI shared memory and it is necessary to use + * readl/writel to access them. + * + * The addressing code is derived from Pete Beckman's work, but + * modified to deal properly with readl/writel usage. + */ + +typedef struct { + u32 addrhi; + u32 addrlo; +} aceaddr; + + +static inline void set_aceaddr(aceaddr *aa, volatile void *addr) +{ + unsigned long baddr = virt_to_bus((void *)addr); +#if (BITS_PER_LONG == 64) + aa->addrlo = baddr & 0xffffffff; + aa->addrhi = baddr >> 32; +#else + /* Don't bother setting zero every time */ + aa->addrlo = baddr; #endif + mb(); +} -struct ace_regs { +static inline void set_aceaddr_bus(aceaddr *aa, volatile void *addr) +{ + unsigned long baddr = (unsigned long)addr; +#if (BITS_PER_LONG == 64) + aa->addrlo = baddr & 0xffffffff; + aa->addrhi = baddr >> 32; +#else + /* Don't bother setting zero every time */ + aa->addrlo = baddr; +#endif + mb(); +} + + +static inline void *get_aceaddr(aceaddr *aa) +{ + unsigned long addr; + mb(); +#if (BITS_PER_LONG == 64) + addr = (u64)aa->addrhi << 32 | aa->addrlo; +#else + addr = aa->addrlo; +#endif + return bus_to_virt(addr); +} + + +static inline void *get_aceaddr_bus(aceaddr *aa) +{ + unsigned long addr; + mb(); +#if (BITS_PER_LONG == 64) + addr = (u64)aa->addrhi << 32 | aa->addrlo; +#else + addr = aa->addrlo; +#endif + return (void *)addr; +} + +struct ace_regs { u32 pad0[16]; /* PCI control registers */ u32 HostCtrl; /* 0x40 */ @@ -109,7 +180,7 @@ u32 ModeStat; u32 DmaReadCfg; u32 DmaWriteCfg; /* 0x620 */ - u32 pad15; + u32 TxBufRat; u32 EvtCsm; u32 CmdCsm; u32 TuneRxCoalTicks;/* 0x630 */ @@ -220,6 +291,7 @@ #define ACE_BYTE_SWAP_DATA 0x10 #define ACE_WARN 0x08 #define ACE_WORD_SWAP 0x04 +#define ACE_NO_JUMBO_FRAG 0x200 #define ACE_FATAL 0x40000000 @@ -227,7 +299,7 @@ * DMA config */ -#define DMA_THRESH_8W 0x80; +#define DMA_THRESH_8W 0x80 /* @@ -366,19 +438,19 @@ #define DESC_MORE 0x08 /* - * RX control block flags + * Control block flags */ -#define RX_TCP_UDP_SUM 0x01 -#define RX_IP_SUM 0x02 -#define RX_SPLIT_HDRS 0x04 -#define RX_NO_PSEUDO_HDR_SUM 0x08 +#define FLG_RX_TCP_UDP_SUM 0x01 +#define FLG_RX_IP_SUM 0x02 +#define FLG_RX_SPLIT_HDRS 0x04 +#define FLG_RX_NO_PSDO_HDR_SUM 0x08 +#define FLG_RNG_DISABLED 0x200 /* * Descriptor flags */ - -#define JUMBO_FLAG 0x10 +#define DFLG_RX_JUMBO 0x10 /* * TX ring @@ -389,12 +461,13 @@ #define TX_RING_BASE 0x3800 struct tx_desc{ -#if (BITS_PER_LONG == 64) - u64 addr; -#else - u32 zero; - u32 addr; -#endif + aceaddr addr; + u32 flagsize; +#if 0 +/* + * This is in PCI shared mem and must be accessed with readl/writel + * real layout is: + */ #if __LITTLE_ENDIAN u16 flags; u16 size; @@ -402,6 +475,7 @@ u16 size; u16 flags; #endif +#endif u32 nic_addr; }; @@ -412,19 +486,18 @@ #define RX_JUMBO_RING_ENTRIES 256 #define RX_JUMBO_RING_SIZE (RX_JUMBO_RING_ENTRIES *sizeof(struct rx_desc)) -#define RX_RETURN_RING_ENTRIES (2 * RX_STD_RING_ENTRIES) -#define RX_RETURN_RING_SIZE (RX_RETURN_RING_ENTRIES * \ +#define RX_MINI_RING_ENTRIES 1024 +#define RX_MINI_RING_SIZE (RX_MINI_RING_ENTRIES *sizeof(struct rx_desc)) + +#define RX_RETURN_RING_ENTRIES 2048 +#define RX_RETURN_RING_SIZE (RX_MAX_RETURN_RING_ENTRIES * \ sizeof(struct rx_desc)) -#define RX_RING_THRESH 32 +#define RX_RING_THRESH 64 +#define RX_RING_JUMBO_THRESH 48 struct rx_desc{ -#if (BITS_PER_LONG == 64) - u64 addr; -#else - u32 zero; - u32 addr; -#endif + aceaddr addr; #ifdef __LITTLE_ENDIAN u16 size; u16 idx; @@ -462,12 +535,7 @@ * This struct is shared with the NIC firmware. */ struct ring_ctrl { -#if (BITS_PER_LONG == 64) - u64 rngptr; -#else - u32 zero; - u32 rngptr; -#endif + aceaddr rngptr; #ifdef __LITTLE_ENDIAN u16 flags; u16 max_len; @@ -522,22 +590,12 @@ struct ring_ctrl tx_ctrl; struct ring_ctrl rx_std_ctrl; struct ring_ctrl rx_jumbo_ctrl; + struct ring_ctrl rx_mini_ctrl; struct ring_ctrl rx_return_ctrl; -#if (BITS_PER_LONG == 64) - u64 evt_prd_ptr; - u64 rx_ret_prd_ptr; - u64 tx_csm_ptr; - u64 stats2_ptr; -#else - u32 evt_prd_ptr_hi; - u32 evt_prd_ptr; - u32 rx_ret_prd_ptr_hi; - u32 rx_ret_prd_ptr; - u32 tx_csm_ptr_hi; - u32 tx_csm_ptr; - u32 stats2_ptr_hi; - u32 stats2_ptr; -#endif + aceaddr evt_prd_ptr; + aceaddr rx_ret_prd_ptr; + aceaddr tx_csm_ptr; + aceaddr stats2_ptr; }; /* @@ -555,6 +613,9 @@ struct tx_desc *tx_ring; struct rx_desc rx_std_ring[RX_STD_RING_ENTRIES]; struct rx_desc rx_jumbo_ring[RX_JUMBO_RING_ENTRIES]; +#if 0 + struct rx_desc rx_mini_ring[RX_MINI_RING_ENTRIES]; +#endif struct rx_desc rx_return_ring[RX_RETURN_RING_ENTRIES]; struct event evt_ring[EVT_RING_ENTRIES]; struct ace_info *info; @@ -576,7 +637,7 @@ struct device *next __attribute__ ((aligned (L1_CACHE_BYTES))); unsigned char *trace_buf; - int fw_running, fw_up, jumbo, promisc; + int fw_running, fw_up, jumbo, promisc, mcast_all; int version; int flags; u16 vendor; @@ -598,7 +659,7 @@ static int ace_load_jumbo_rx_ring(struct device *dev); static int ace_flush_jumbo_rx_ring(struct device *dev); static void ace_interrupt(int irq, void *dev_id, struct pt_regs *regs); - +static int ace_load_firmware(struct device *dev); static int ace_open(struct device *dev); static int ace_start_xmit(struct sk_buff *skb, struct device *dev); static int ace_close(struct device *dev); diff -ur --new-file old/linux/drivers/net/acenic_firmware.h new/linux/drivers/net/acenic_firmware.h --- old/linux/drivers/net/acenic_firmware.h Thu Jan 7 21:25:09 1999 +++ new/linux/drivers/net/acenic_firmware.h Mon Mar 22 17:08:12 1999 @@ -1,5554 +1,8532 @@ /* Generated by genfw.c */ int tigonFwReleaseMajor = 0xc; -int tigonFwReleaseMinor = 0x1; -int tigonFwReleaseFix = 0x6; -u32 tigonFwStartAddr = 0x4000; -u32 tigonFwTextAddr = 0x4000; -int tigonFwTextLen = 0x10500; -u32 tigonFwDataAddr = 0x14f50; -int tigonFwDataLen = 0x140; -u32 tigonFwRodataAddr = 0x14500; -int tigonFwRodataLen = 0xa30; -u32 tigonFwBssAddr = 0x150c0; +int tigonFwReleaseMinor = 0x3; +int tigonFwReleaseFix = 0x5; +u32 tigonFwStartAddr = 0x00004000; +u32 tigonFwTextAddr = 0x00004000; +int tigonFwTextLen = 0x10910; +u32 tigonFwRodataAddr = 0x00014910; +int tigonFwRodataLen = 0xaa0; +u32 tigonFwDataAddr = 0x000153d0; +int tigonFwDataLen = 0x150; +u32 tigonFwSbssAddr = 0x00015520; +int tigonFwSbssLen = 0x2c; +u32 tigonFwBssAddr = 0x00015550; int tigonFwBssLen = 0x2080; -u32 tigonFwSbssAddr = 0x15090; -int tigonFwSbssLen = 0x28; u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = { -0x10000003, 0x0, 0xd, 0xd, 0x3c1d0001, 0x8fbd4f84, -0x3a0f021, 0x3c100000, 0x26104000, 0xc00100c, 0x0, 0xd, -0x27bdffd8, 0x3c1cc000, 0x3c1b0013, 0x377bd800, 0xd021, 0x3c170013, -0x36f75430, 0x2e02021, 0x340583d0, 0xafbf0024, 0xc002488, 0xafb00020, -0xc0023e8, 0x0, 0x3c040001, 0x24844560, 0x24050001, 0x2e03021, -0x3821, 0x3c100001, 0x26107140, 0xafb00010, 0xc002403, 0xafbb0014, -0x3c02000f, 0x3442ffff, 0x2021024, 0x362102b, 0x10400009, 0x24050003, -0x3c040001, 0x2484456c, 0x2003021, 0x3603821, 0x3c020010, 0xafa20010, -0xc002403, 0xafa00014, 0x2021, 0x3405c000, 0x3c010001, 0x370821, -0xa02083a0, 0x3c010001, 0x370821, 0xa02083a2, 0x3c010001, 0x370821, -0xa02083a3, 0x3c010001, 0x370821, 0xac2083a4, 0xa2e004c8, 0x418c0, -0x24840001, 0x771021, 0xac40726c, 0x771021, 0xac407270, 0x2e31021, -0xa445726c, 0x2c820020, 0x1440fff7, 0x418c0, 0x2021, 0x3405c000, -0x418c0, 0x24840001, 0x771021, 0xac40736c, 0x771021, 0xac407370, -0x2e31021, 0xa445736c, 0x2c820080, 0x5440fff7, 0x418c0, 0xaf800054, -0xaf80011c, 0x8f820044, 0x34420040, 0xaf820044, 0x8f820044, 0x34420020, -0xaf820044, 0x8f420218, 0x30420002, 0x10400009, 0x0, 0x8f420220, -0x3c030002, 0x34630004, 0x431025, 0xaee204b4, 0x8f42021c, 0x8001074, -0x34420004, 0x8f420220, 0x3c030002, 0x34630006, 0x431025, 0xaee204b4, -0x8f42021c, 0x34420006, 0xaee204bc, 0x8f420218, 0x30420010, 0x1040000a, -0x0, 0x8f42021c, 0x34420004, 0xaee204b8, 0x8f420220, 0x3c03000a, -0x34630004, 0x431025, 0x800108a, 0xaee204b0, 0x8f420220, 0x3c03000a, -0x34630006, 0x431025, 0xaee204b0, 0x8f42021c, 0x34420006, 0xaee204b8, -0x8f420218, 0x30420200, 0x10400003, 0x24020001, 0x8001091, 0xa2e27238, -0xa2e07238, 0x24020001, 0xaf8200a0, 0xaf8200b0, 0x8f830054, 0x8f820054, -0x8001099, 0x24630064, 0x8f820054, 0x621023, 0x2c420065, 0x1440fffc, -0x0, 0xaf800044, 0x8f420208, 0x8f43020c, 0xaee20010, 0xaee30014, -0x8ee40010, 0x8ee50014, 0x26e20030, 0xaee20028, 0x24020480, 0xaee20018, -0xaf840090, 0xaf850094, 0x8ee20028, 0xaf8200b4, 0x96e2001a, 0xaf82009c, -0x8f8200b0, 0x8ee304bc, 0x431025, 0xaf8200b0, 0x8f8200b0, 0x30420004, -0x1440fffd, 0x0, 0x8ee20450, 0x8ee30454, 0xaee304ec, 0x8ee204ec, -0x2442e000, 0x2c422001, 0x1440000d, 0x26e40030, 0x8ee20450, 0x8ee30454, -0x3c040001, 0x24844578, 0x3c050001, 0xafa00010, 0xafa00014, 0x8ee704ec, -0x34a5f000, 0xc002403, 0x603021, 0x26e40030, 0xc002488, 0x24050400, -0x27440080, 0xc002488, 0x24050080, 0x26e4776c, 0xc002488, 0x24050400, -0x8f42025c, 0x26e40094, 0xaee20060, 0x8f420260, 0x27450200, 0x24060008, -0xaee20068, 0x24020006, 0xc00249a, 0xaee20064, 0x3c023b9a, 0x3442ca00, -0x2021, 0x24030002, 0xaee30074, 0xaee30070, 0xaee2006c, 0x240203e8, -0xaee20104, 0x24020001, 0xaee30100, 0xaee2010c, 0x3c030001, 0x641821, -0x90634f50, 0x2e41021, 0x24840001, 0xa043009c, 0x2c82000f, 0x1440fff8, -0x0, 0x8f820040, 0x2e41821, 0x24840001, 0x21702, 0x24420030, -0xa062009c, 0x2e41021, 0xa040009c, 0x96e2046a, 0x30420003, 0x14400009, -0x0, 0x96e2047a, 0x30420003, 0x50400131, 0x3c030800, 0x96e2046a, -0x30420003, 0x1040002a, 0x3c020700, 0x96e2047a, 0x30420003, 0x10400026, -0x3c020700, 0x96e3047a, 0x96e2046a, 0x14620022, 0x3c020700, 0x8ee204b0, -0x24030001, 0xa2e34e10, 0x34420e00, 0xaee204b0, 0x8f420218, 0x30420100, -0x10400005, 0x0, 0x3c020001, 0x2442e128, 0x800111d, 0x21100, -0x3c020001, 0x2442d31c, 0x21100, 0x21182, 0x3c030800, 0x431025, -0x3c010001, 0xac221138, 0x3c020001, 0x2442f640, 0x21100, 0x21182, -0x3c030800, 0x431025, 0x3c010001, 0xac221178, 0x8ee20000, 0x34424000, -0x8001238, 0xaee20000, 0x34423000, 0xafa20018, 0x8ee205f8, 0x8f430228, -0x24420001, 0x304900ff, 0x512300e2, 0xafa00010, 0x8ee205f8, 0x210c0, -0x571021, 0x8fa30018, 0x8fa4001c, 0xac4305fc, 0xac440600, 0x8f870120, -0x27623800, 0x24e80020, 0x102102b, 0x50400001, 0x27683000, 0x8f820128, -0x11020004, 0x0, 0x8f820124, 0x15020007, 0x1021, 0x8ee201a0, -0x3021, 0x24420001, 0xaee201a0, 0x80011a0, 0x8ee201a0, 0x8ee405f8, -0x420c0, 0x801821, 0x8ee40430, 0x8ee50434, 0xa32821, 0xa3302b, -0x822021, 0x862021, 0xace40000, 0xace50004, 0x8ee305f8, 0x24020008, -0xa4e2000e, 0x2402000d, 0xace20018, 0xace9001c, 0x318c0, 0x246305fc, -0x2e31021, 0xace20008, 0x8ee204b4, 0xace20010, 0xaf880120, 0x92e24e10, -0x14400037, 0x24060001, 0x8ee24e20, 0x210c0, 0x24425028, 0x2e22021, -0x8c830000, 0x24020007, 0x1462001f, 0x0, 0x8ee34e20, 0x8ee24e24, -0x1062001b, 0x24030040, 0x8c820004, 0x24420001, 0xac820004, 0x8ee24e24, -0x8ee54e20, 0x24420001, 0x10430007, 0x0, 0x8ee24e24, 0x24420001, -0x10a20005, 0x0, 0x800118a, 0x0, 0x14a00005, 0x0, -0x8f820128, 0x24420020, 0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011, -0x50400013, 0xac800000, 0x80011a0, 0x0, 0x8ee24e20, 0x24030040, -0x24420001, 0x50430003, 0x1021, 0x8ee24e20, 0x24420001, 0xaee24e20, -0x8ee24e20, 0x210c0, 0x24425028, 0x2e22021, 0x24020007, 0xac820000, -0x24020001, 0xac820004, 0x54c0000c, 0xaee905f8, 0x3c040001, 0x24844584, -0xafa00010, 0xafa00014, 0x8ee605f8, 0x8f470228, 0x3c050009, 0xc002403, -0x34a5f000, 0x8001223, 0x0, 0x8f830120, 0x27623800, 0x24660020, -0xc2102b, 0x50400001, 0x27663000, 0x8f820128, 0x10c20004, 0x0, -0x8f820124, 0x14c20007, 0x0, 0x8ee201a0, 0x3021, 0x24420001, -0xaee201a0, 0x8001207, 0x8ee201a0, 0x8ee205f8, 0xac62001c, 0x8ee40490, -0x8ee50494, 0x2462001c, 0xac620008, 0x24020008, 0xa462000e, 0x24020011, -0xac620018, 0xac640000, 0xac650004, 0x8ee204b4, 0xac620010, 0xaf860120, -0x92e24e10, 0x14400037, 0x24060001, 0x8ee24e20, 0x210c0, 0x24425028, -0x2e22021, 0x8c830000, 0x24020012, 0x1462001f, 0x0, 0x8ee34e20, -0x8ee24e24, 0x1062001b, 0x24030040, 0x8c820004, 0x24420001, 0xac820004, -0x8ee24e24, 0x8ee54e20, 0x24420001, 0x10430007, 0x0, 0x8ee24e24, -0x24420001, 0x10a20005, 0x0, 0x80011f1, 0x0, 0x14a00005, -0x0, 0x8f820128, 0x24420020, 0xaf820128, 0x8f820128, 0x8c820004, -0x2c420011, 0x50400013, 0xac800000, 0x8001207, 0x0, 0x8ee24e20, -0x24030040, 0x24420001, 0x50430003, 0x1021, 0x8ee24e20, 0x24420001, -0xaee24e20, 0x8ee24e20, 0x210c0, 0x24425028, 0x2e22021, 0x24020012, -0xac820000, 0x24020001, 0xac820004, 0x14c0001b, 0x0, 0x3c040001, -0x2484458c, 0xafa00010, 0xafa00014, 0x8ee605f8, 0x8f470228, 0x3c050009, -0xc002403, 0x34a5f001, 0x8ee201ac, 0x24420001, 0xaee201ac, 0x8001223, -0x8ee201ac, 0x3c040001, 0x24844598, 0xafa00014, 0x8ee605f8, 0x8f470228, -0x3c050009, 0xc002403, 0x34a5f005, 0x8ee201a8, 0x24420001, 0xaee201a8, -0x8ee201a8, 0x8ee2015c, 0x3c040001, 0x248445a4, 0x3405f001, 0x24420001, -0xaee2015c, 0x8ee2015c, 0x3021, 0x3821, 0xafa00010, 0xc002403, -0xafa00014, 0x8001238, 0x0, 0x3c020001, 0x2442f568, 0x21100, -0x21182, 0x431025, 0x3c010001, 0xac221178, 0x96e2045a, 0x30420003, -0x10400025, 0x3c050fff, 0x8ee204b8, 0x34a5ffff, 0x34420a00, 0xaee204b8, -0x8ee304b8, 0x3c040001, 0x248445b0, 0x24020001, 0xa2e204dc, 0xa2e204dd, -0x3c020002, 0x621825, 0x3c020001, 0x2442a390, 0x451024, 0x21082, -0xaee304b8, 0x3c030800, 0x431025, 0x3c010001, 0xac221120, 0x3c020001, -0x2442adb4, 0x451024, 0x21082, 0x431025, 0x3c010001, 0xac221180, -0x96e6045a, 0x3821, 0x24050011, 0xafa00010, 0xc002403, 0xafa00014, -0x8001268, 0x0, 0x3c020001, 0x2442a9d4, 0x21100, 0x21182, -0x3c030800, 0x431025, 0x3c010001, 0xac221180, 0x96e2046a, 0x30420010, -0x14400009, 0x0, 0x96e2047a, 0x30420010, 0x10400112, 0x0, -0x96e2046a, 0x30420010, 0x10400005, 0x3c020700, 0x96e2047a, 0x30420010, -0x14400102, 0x3c020700, 0x34423000, 0xafa20018, 0x8ee205f8, 0x8f430228, -0x24420001, 0x304900ff, 0x512300e2, 0xafa00010, 0x8ee205f8, 0x210c0, -0x571021, 0x8fa30018, 0x8fa4001c, 0xac4305fc, 0xac440600, 0x8f870120, -0x27623800, 0x24e80020, 0x102102b, 0x50400001, 0x27683000, 0x8f820128, -0x11020004, 0x0, 0x8f820124, 0x15020007, 0x1021, 0x8ee201a0, -0x3021, 0x24420001, 0xaee201a0, 0x80012ea, 0x8ee201a0, 0x8ee405f8, -0x420c0, 0x801821, 0x8ee40430, 0x8ee50434, 0xa32821, 0xa3302b, -0x822021, 0x862021, 0xace40000, 0xace50004, 0x8ee305f8, 0x24020008, -0xa4e2000e, 0x2402000d, 0xace20018, 0xace9001c, 0x318c0, 0x246305fc, -0x2e31021, 0xace20008, 0x8ee204b4, 0xace20010, 0xaf880120, 0x92e24e10, -0x14400037, 0x24060001, 0x8ee24e20, 0x210c0, 0x24425028, 0x2e22021, -0x8c830000, 0x24020007, 0x1462001f, 0x0, 0x8ee34e20, 0x8ee24e24, -0x1062001b, 0x24030040, 0x8c820004, 0x24420001, 0xac820004, 0x8ee24e24, -0x8ee54e20, 0x24420001, 0x10430007, 0x0, 0x8ee24e24, 0x24420001, -0x10a20005, 0x0, 0x80012d4, 0x0, 0x14a00005, 0x0, -0x8f820128, 0x24420020, 0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011, -0x50400013, 0xac800000, 0x80012ea, 0x0, 0x8ee24e20, 0x24030040, -0x24420001, 0x50430003, 0x1021, 0x8ee24e20, 0x24420001, 0xaee24e20, -0x8ee24e20, 0x210c0, 0x24425028, 0x2e22021, 0x24020007, 0xac820000, -0x24020001, 0xac820004, 0x54c0000c, 0xaee905f8, 0x3c040001, 0x24844584, -0xafa00010, 0xafa00014, 0x8ee605f8, 0x8f470228, 0x3c050009, 0xc002403, -0x34a5f000, 0x800136d, 0x0, 0x8f830120, 0x27623800, 0x24660020, -0xc2102b, 0x50400001, 0x27663000, 0x8f820128, 0x10c20004, 0x0, -0x8f820124, 0x14c20007, 0x0, 0x8ee201a0, 0x3021, 0x24420001, -0xaee201a0, 0x8001351, 0x8ee201a0, 0x8ee205f8, 0xac62001c, 0x8ee40490, -0x8ee50494, 0x2462001c, 0xac620008, 0x24020008, 0xa462000e, 0x24020011, -0xac620018, 0xac640000, 0xac650004, 0x8ee204b4, 0xac620010, 0xaf860120, -0x92e24e10, 0x14400037, 0x24060001, 0x8ee24e20, 0x210c0, 0x24425028, -0x2e22021, 0x8c830000, 0x24020012, 0x1462001f, 0x0, 0x8ee34e20, -0x8ee24e24, 0x1062001b, 0x24030040, 0x8c820004, 0x24420001, 0xac820004, -0x8ee24e24, 0x8ee54e20, 0x24420001, 0x10430007, 0x0, 0x8ee24e24, -0x24420001, 0x10a20005, 0x0, 0x800133b, 0x0, 0x14a00005, -0x0, 0x8f820128, 0x24420020, 0xaf820128, 0x8f820128, 0x8c820004, -0x2c420011, 0x50400013, 0xac800000, 0x8001351, 0x0, 0x8ee24e20, -0x24030040, 0x24420001, 0x50430003, 0x1021, 0x8ee24e20, 0x24420001, -0xaee24e20, 0x8ee24e20, 0x210c0, 0x24425028, 0x2e22021, 0x24020012, -0xac820000, 0x24020001, 0xac820004, 0x14c0001b, 0x0, 0x3c040001, -0x2484458c, 0xafa00010, 0xafa00014, 0x8ee605f8, 0x8f470228, 0x3c050009, -0xc002403, 0x34a5f001, 0x8ee201ac, 0x24420001, 0xaee201ac, 0x800136d, -0x8ee201ac, 0x3c040001, 0x24844598, 0xafa00014, 0x8ee605f8, 0x8f470228, -0x3c050009, 0xc002403, 0x34a5f005, 0x8ee201a8, 0x24420001, 0xaee201a8, -0x8ee201a8, 0x8ee2015c, 0x3c040001, 0x248445a4, 0x3405f002, 0x24420001, -0xaee2015c, 0x8ee2015c, 0x3021, 0x3821, 0xafa00010, 0xc002403, -0xafa00014, 0x96e6047a, 0x96e7046a, 0x3c040001, 0x248445bc, 0x24050012, -0xafa00010, 0xc002403, 0xafa00014, 0xc0044c0, 0x0, 0xc002314, -0x0, 0x3c060001, 0x34c63800, 0xaee005f8, 0xaf400228, 0xaf40022c, -0x96e30458, 0x8ee40000, 0x3c0512d8, 0x34a5c358, 0x27623800, 0xaee27248, -0x27623800, 0xaee27250, 0x27623800, 0xaee27254, 0x3661021, 0xaee27260, -0x2402ffff, 0xaee004c4, 0xaee004d0, 0xaee004d4, 0xaee004e0, 0xa2e004e4, -0xaee00dfc, 0xaee00e08, 0xaee00e00, 0xaee00e04, 0xaee00e0c, 0xaee0723c, -0xaee05234, 0xaee05230, 0xaee0522c, 0xaee07240, 0xaee07244, 0xaee0724c, -0xaee07258, 0xaee004c0, 0x2463ffff, 0x852025, 0xaee304e8, 0xaee40000, -0xaf800060, 0xaf820064, 0x3c020100, 0xafa20018, 0x8ee205f8, 0x8f430228, -0x24420001, 0x304900ff, 0x512300e2, 0xafa00010, 0x8ee205f8, 0x210c0, -0x571021, 0x8fa30018, 0x8fa4001c, 0xac4305fc, 0xac440600, 0x8f870120, -0x27623800, 0x24e80020, 0x102102b, 0x50400001, 0x27683000, 0x8f820128, -0x11020004, 0x0, 0x8f820124, 0x15020007, 0x1021, 0x8ee201a0, -0x3021, 0x24420001, 0xaee201a0, 0x8001422, 0x8ee201a0, 0x8ee405f8, -0x420c0, 0x801821, 0x8ee40430, 0x8ee50434, 0xa32821, 0xa3302b, -0x822021, 0x862021, 0xace40000, 0xace50004, 0x8ee305f8, 0x24020008, -0xa4e2000e, 0x2402000d, 0xace20018, 0xace9001c, 0x318c0, 0x246305fc, -0x2e31021, 0xace20008, 0x8ee204b4, 0xace20010, 0xaf880120, 0x92e24e10, -0x14400037, 0x24060001, 0x8ee24e20, 0x210c0, 0x24425028, 0x2e22021, -0x8c830000, 0x24020007, 0x1462001f, 0x0, 0x8ee34e20, 0x8ee24e24, -0x1062001b, 0x24030040, 0x8c820004, 0x24420001, 0xac820004, 0x8ee24e24, -0x8ee54e20, 0x24420001, 0x10430007, 0x0, 0x8ee24e24, 0x24420001, -0x10a20005, 0x0, 0x800140c, 0x0, 0x14a00005, 0x0, -0x8f820128, 0x24420020, 0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011, -0x50400013, 0xac800000, 0x8001422, 0x0, 0x8ee24e20, 0x24030040, -0x24420001, 0x50430003, 0x1021, 0x8ee24e20, 0x24420001, 0xaee24e20, -0x8ee24e20, 0x210c0, 0x24425028, 0x2e22021, 0x24020007, 0xac820000, -0x24020001, 0xac820004, 0x54c0000c, 0xaee905f8, 0x3c040001, 0x24844584, -0xafa00010, 0xafa00014, 0x8ee605f8, 0x8f470228, 0x3c050009, 0xc002403, -0x34a5f000, 0x80014a5, 0x0, 0x8f830120, 0x27623800, 0x24660020, -0xc2102b, 0x50400001, 0x27663000, 0x8f820128, 0x10c20004, 0x0, -0x8f820124, 0x14c20007, 0x0, 0x8ee201a0, 0x3021, 0x24420001, -0xaee201a0, 0x8001489, 0x8ee201a0, 0x8ee205f8, 0xac62001c, 0x8ee40490, -0x8ee50494, 0x2462001c, 0xac620008, 0x24020008, 0xa462000e, 0x24020011, -0xac620018, 0xac640000, 0xac650004, 0x8ee204b4, 0xac620010, 0xaf860120, -0x92e24e10, 0x14400037, 0x24060001, 0x8ee24e20, 0x210c0, 0x24425028, -0x2e22021, 0x8c830000, 0x24020012, 0x1462001f, 0x0, 0x8ee34e20, -0x8ee24e24, 0x1062001b, 0x24030040, 0x8c820004, 0x24420001, 0xac820004, -0x8ee24e24, 0x8ee54e20, 0x24420001, 0x10430007, 0x0, 0x8ee24e24, -0x24420001, 0x10a20005, 0x0, 0x8001473, 0x0, 0x14a00005, -0x0, 0x8f820128, 0x24420020, 0xaf820128, 0x8f820128, 0x8c820004, -0x2c420011, 0x50400013, 0xac800000, 0x8001489, 0x0, 0x8ee24e20, -0x24030040, 0x24420001, 0x50430003, 0x1021, 0x8ee24e20, 0x24420001, -0xaee24e20, 0x8ee24e20, 0x210c0, 0x24425028, 0x2e22021, 0x24020012, -0xac820000, 0x24020001, 0xac820004, 0x14c0001b, 0x0, 0x3c040001, -0x2484458c, 0xafa00010, 0xafa00014, 0x8ee605f8, 0x8f470228, 0x3c050009, -0xc002403, 0x34a5f001, 0x8ee201ac, 0x24420001, 0xaee201ac, 0x80014a5, -0x8ee201ac, 0x3c040001, 0x24844598, 0xafa00014, 0x8ee605f8, 0x8f470228, -0x3c050009, 0xc002403, 0x34a5f005, 0x8ee201a8, 0x24420001, 0xaee201a8, -0x8ee201a8, 0x8ee20150, 0x24420001, 0xaee20150, 0xc0014dc, 0x8ee20150, -0x8f8200a0, 0x30420004, 0x1440fffd, 0x0, 0x8f820040, 0x30420001, -0x14400008, 0x0, 0x8f430104, 0x24020001, 0x10620004, 0x0, -0x8f420264, 0x10400006, 0x0, 0x8ee20178, 0x24420001, 0xaee20178, -0x80014c5, 0x8ee20178, 0x8f820044, 0x34420004, 0xaf820044, 0x8ee20174, -0x24420001, 0xaee20174, 0x8ee20174, 0x8f8200d8, 0x8f8300d4, 0x431023, -0xaee2725c, 0x8ee2725c, 0x1c400003, 0x3c030001, 0x431021, 0xaee2725c, -0xc004054, 0x0, 0xc004400, 0xaf800228, 0x8fbf0024, 0x8fb00020, -0x3e00008, 0x27bd0028, 0x3e00008, 0x0, 0x3e00008, 0x0, -0x0, 0x0, 0x2402002c, 0xaf820050, 0xaee07264, 0x8f420238, -0xaee27268, 0x8f820054, 0x24420067, 0xaf820058, 0xaee07b78, 0xaee07b7c, -0xaee07b74, 0x3c010001, 0x370821, 0xac2083ac, 0x3c010001, 0x370821, -0x3e00008, 0xa02083a9, 0x27bdffd8, 0xafbf0024, 0xafb00020, 0x8f820054, -0x3c030001, 0x8c63500c, 0x24420067, 0x1060000d, 0xaf820058, 0x3c020001, -0x571021, 0x904283a8, 0x10400005, 0x3c030200, 0x3c010001, 0x370821, -0x8001503, 0xa02083a8, 0x8ee20000, 0x431025, 0xaee20000, 0x8f420218, -0x30420100, 0x104000c6, 0x0, 0x8f8200b0, 0x30420004, 0x104000c2, -0x0, 0x3c030001, 0x771821, 0x8c6383c0, 0x8f820104, 0x146200b4, -0x0, 0x3c030001, 0x771821, 0x8c6383c4, 0x8f8200b4, 0x146200ae, -0x0, 0x8f8200b0, 0x3c030080, 0x431024, 0x1040000d, 0x0, -0x8f82011c, 0x34420002, 0xaf82011c, 0x8f8200b0, 0x2403fffb, 0x431024, -0xaf8200b0, 0x8f82011c, 0x2403fffd, 0x431024, 0x80015cc, 0xaf82011c, -0x3c030001, 0x771821, 0x8c6383c0, 0x8f820104, 0x14620082, 0x0, -0x3c030001, 0x771821, 0x8c6383c4, 0x8f8200b4, 0x1462007c, 0x0, -0x3c070001, 0xf73821, 0x8ce783c0, 0x8f8200b0, 0x3c040001, 0x24844630, -0xafa00014, 0xafa20010, 0x8f8600b0, 0x3c050005, 0xc002403, 0x34a50900, -0x8f82011c, 0x34420002, 0xaf82011c, 0x8f830104, 0x8f8200b0, 0x34420001, -0xaf8200b0, 0xaf830104, 0x8f830120, 0x27623800, 0x24660020, 0xc2102b, -0x50400001, 0x27663000, 0x8f820128, 0x10c20004, 0x0, 0x8f820124, -0x14c20006, 0x0, 0x8ee201a0, 0x24420001, 0xaee201a0, 0x80015a0, -0x8ee201a0, 0x8f440208, 0x8f45020c, 0x26e20030, 0xac620008, 0x24020400, -0xa462000e, 0x2402000f, 0xac620018, 0xac60001c, 0xac640000, 0xac650004, -0x8ee204b4, 0xac620010, 0xaf860120, 0x92e24e10, 0x14400037, 0x0, -0x8ee24e20, 0x210c0, 0x24425028, 0x2e22021, 0x8c830000, 0x24020007, -0x1462001f, 0x0, 0x8ee34e20, 0x8ee24e24, 0x1062001b, 0x24030040, -0x8c820004, 0x24420001, 0xac820004, 0x8ee24e24, 0x8ee54e20, 0x24420001, -0x10430007, 0x0, 0x8ee24e24, 0x24420001, 0x10a20005, 0x0, -0x800158a, 0x0, 0x14a00005, 0x0, 0x8f820128, 0x24420020, -0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011, 0x50400013, 0xac800000, -0x80015a0, 0x0, 0x8ee24e20, 0x24030040, 0x24420001, 0x50430003, -0x1021, 0x8ee24e20, 0x24420001, 0xaee24e20, 0x8ee24e20, 0x210c0, -0x24425028, 0x2e22021, 0x24020007, 0xac820000, 0x24020001, 0xac820004, -0x8f82011c, 0x2403fffd, 0x431024, 0xaf82011c, 0x8ee201d4, 0x3c070001, -0xf73821, 0x8ce783c0, 0x24420001, 0xaee201d4, 0x8ee201d4, 0x3c040001, -0x2484463c, 0x80015bd, 0xafa00010, 0x8f820104, 0x3c010001, 0x370821, -0xac2283c0, 0x8f8200b4, 0x3c070001, 0xf73821, 0x8ce783c0, 0x3c040001, -0x24844644, 0x3c010001, 0x370821, 0xac2283c4, 0xafa00010, 0xafa00014, -0x8f8600b0, 0x3c050005, 0xc002403, 0x34a50900, 0x80015cc, 0x0, -0x8f820104, 0x3c010001, 0x370821, 0xac2283c0, 0x8f8200b4, 0x3c010001, -0x370821, 0xac2283c4, 0x8ee27264, 0x92e304e4, 0x24420067, 0x14600006, -0xaee27264, 0x8ee27264, 0x8f430234, 0x43102b, 0x1440007b, 0x0, -0x8ee304d4, 0x8ee204e8, 0x14620004, 0x0, 0x92e204e4, 0x50400074, -0xa2e004e4, 0x8f830120, 0x27623800, 0x24660020, 0xc2102b, 0x50400001, -0x27663000, 0x8f820128, 0x10c20004, 0x0, 0x8f820124, 0x14c20007, -0x0, 0x8ee201a0, 0x8021, 0x24420001, 0xaee201a0, 0x8001637, -0x8ee201a0, 0x8ee204d4, 0xac62001c, 0x8ee404a0, 0x8ee504a4, 0x2462001c, -0xac620008, 0x24020008, 0xa462000e, 0x24020011, 0xac620018, 0xac640000, -0xac650004, 0x8ee204b4, 0xac620010, 0xaf860120, 0x92e24e10, 0x14400037, -0x24100001, 0x8ee24e20, 0x210c0, 0x24425028, 0x2e22021, 0x8c830000, -0x24020012, 0x1462001f, 0x0, 0x8ee34e20, 0x8ee24e24, 0x1062001b, -0x24030040, 0x8c820004, 0x24420001, 0xac820004, 0x8ee24e24, 0x8ee54e20, -0x24420001, 0x10430007, 0x0, 0x8ee24e24, 0x24420001, 0x10a20005, -0x0, 0x8001621, 0x0, 0x14a00005, 0x0, 0x8f820128, -0x24420020, 0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011, 0x50400013, -0xac800000, 0x8001637, 0x0, 0x8ee24e20, 0x24030040, 0x24420001, -0x50430003, 0x1021, 0x8ee24e20, 0x24420001, 0xaee24e20, 0x8ee24e20, -0x210c0, 0x24425028, 0x2e22021, 0x24020012, 0xac820000, 0x24020001, -0xac820004, 0x5600000b, 0x24100001, 0x8ee204d4, 0x3c040001, 0x2484464c, -0xafa00014, 0xafa20010, 0x8ee605f8, 0x8f470228, 0x3c050009, 0xc002403, -0x34a5f006, 0x16000003, 0x24020001, 0x8001650, 0xa2e204e4, 0x8ee2016c, -0x24420001, 0xaee2016c, 0x8ee2016c, 0x8ee204d4, 0xa2e004e4, 0xaee004e0, -0xaee07264, 0xaee204e8, 0x8ee20e0c, 0x1040006d, 0x0, 0x8f830120, -0x27623800, 0x24660020, 0xc2102b, 0x50400001, 0x27663000, 0x8f820128, -0x10c20004, 0x0, 0x8f820124, 0x14c20007, 0x0, 0x8ee201a0, -0x8021, 0x24420001, 0xaee201a0, 0x80016ad, 0x8ee201a0, 0x8ee2723c, -0xac62001c, 0x8ee40498, 0x8ee5049c, 0x2462001c, 0xac620008, 0x24020008, -0xa462000e, 0x24020011, 0xac620018, 0xac640000, 0xac650004, 0x8ee204b4, -0xac620010, 0xaf860120, 0x92e24e10, 0x14400037, 0x24100001, 0x8ee24e20, -0x210c0, 0x24425028, 0x2e22021, 0x8c830000, 0x24020012, 0x1462001f, -0x0, 0x8ee34e20, 0x8ee24e24, 0x1062001b, 0x24030040, 0x8c820004, -0x24420001, 0xac820004, 0x8ee24e24, 0x8ee54e20, 0x24420001, 0x10430007, -0x0, 0x8ee24e24, 0x24420001, 0x10a20005, 0x0, 0x8001697, -0x0, 0x14a00005, 0x0, 0x8f820128, 0x24420020, 0xaf820128, -0x8f820128, 0x8c820004, 0x2c420011, 0x50400013, 0xac800000, 0x80016ad, -0x0, 0x8ee24e20, 0x24030040, 0x24420001, 0x50430003, 0x1021, -0x8ee24e20, 0x24420001, 0xaee24e20, 0x8ee24e20, 0x210c0, 0x24425028, -0x2e22021, 0x24020012, 0xac820000, 0x24020001, 0xac820004, 0x5600000b, -0x24100001, 0x8ee2723c, 0x3c040001, 0x24844658, 0xafa00014, 0xafa20010, -0x8ee6723c, 0x8f470280, 0x3c050009, 0xc002403, 0x34a5f008, 0x56000001, -0xaee00e0c, 0x8ee20170, 0x24420001, 0xaee20170, 0x8ee20170, 0x8ee24e14, -0x10400019, 0x0, 0xaee04e14, 0x8f820040, 0x30420001, 0x14400008, -0x0, 0x8f430104, 0x24020001, 0x10620004, 0x0, 0x8f420264, -0x10400006, 0x0, 0x8ee20178, 0x24420001, 0xaee20178, 0x80016da, -0x8ee20178, 0x8f820044, 0x34420004, 0xaf820044, 0x8ee20174, 0x24420001, -0xaee20174, 0x8ee20174, 0x8ee27268, 0x2442ff99, 0xaee27268, 0x8ee27268, -0x1c4002a8, 0x0, 0x8f420238, 0x104002a5, 0x0, 0x8f420080, -0xaee2004c, 0x8f4200c0, 0xaee20048, 0x8f420084, 0xaee20038, 0x8f420084, -0xaee20234, 0x8f420088, 0xaee20238, 0x8f42008c, 0xaee2023c, 0x8f420090, -0xaee20240, 0x8f420094, 0xaee20244, 0x8f420098, 0xaee20248, 0x8f42009c, -0xaee2024c, 0x8f4200a0, 0xaee20250, 0x8f4200a4, 0xaee20254, 0x8f4200a8, -0xaee20258, 0x8f4200ac, 0xaee2025c, 0x8f4200b0, 0xaee20260, 0x8f4200b4, -0xaee20264, 0x8f4200b8, 0xaee20268, 0x8f4200bc, 0x24040001, 0xaee2026c, -0xaee0003c, 0x41080, 0x571021, 0x8ee3003c, 0x8c420234, 0x24840001, -0x621821, 0x2c82000f, 0xaee3003c, 0x1440fff8, 0x41080, 0x8f4200cc, -0xaee20050, 0x8f4200d0, 0xaee20054, 0x8f830120, 0x27623800, 0x24660020, -0xc2102b, 0x50400001, 0x27663000, 0x8f820128, 0x10c20004, 0x0, -0x8f820124, 0x14c20007, 0x0, 0x8ee201a0, 0x8021, 0x24420001, -0xaee201a0, 0x8001770, 0x8ee201a0, 0x8f440208, 0x8f45020c, 0x26e20030, -0xac620008, 0x24020400, 0xa462000e, 0x2402000f, 0xac620018, 0xac60001c, -0xac640000, 0xac650004, 0x8ee204b4, 0xac620010, 0xaf860120, 0x92e24e10, -0x14400037, 0x24100001, 0x8ee24e20, 0x210c0, 0x24425028, 0x2e22021, -0x8c830000, 0x24020007, 0x1462001f, 0x0, 0x8ee34e20, 0x8ee24e24, -0x1062001b, 0x24030040, 0x8c820004, 0x24420001, 0xac820004, 0x8ee24e24, -0x8ee54e20, 0x24420001, 0x10430007, 0x0, 0x8ee24e24, 0x24420001, -0x10a20005, 0x0, 0x800175a, 0x0, 0x14a00005, 0x0, -0x8f820128, 0x24420020, 0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011, -0x50400013, 0xac800000, 0x8001770, 0x0, 0x8ee24e20, 0x24030040, -0x24420001, 0x50430003, 0x1021, 0x8ee24e20, 0x24420001, 0xaee24e20, -0x8ee24e20, 0x210c0, 0x24425028, 0x2e22021, 0x24020007, 0xac820000, -0x24020001, 0xac820004, 0x12000212, 0x3c020400, 0xafa20018, 0x3c020001, -0x571021, 0x904283a0, 0x1040010b, 0x0, 0x8ee205f8, 0x8f430228, -0x24420001, 0x304a00ff, 0x514300fd, 0xafa00010, 0x8ee205f8, 0x210c0, -0x571021, 0x8fa30018, 0x8fa4001c, 0xac4305fc, 0xac440600, 0x8f830054, -0x8f820054, 0x24690032, 0x1221023, 0x2c420033, 0x1040006a, 0x5821, -0x24180008, 0x240f000d, 0x240d0007, 0x240c0040, 0x240e0001, 0x8f870120, -0x27623800, 0x24e80020, 0x102102b, 0x50400001, 0x27683000, 0x8f820128, -0x11020004, 0x0, 0x8f820124, 0x15020007, 0x1021, 0x8ee201a0, -0x8021, 0x24420001, 0xaee201a0, 0x80017ee, 0x8ee201a0, 0x8ee405f8, -0x420c0, 0x801821, 0x8ee40430, 0x8ee50434, 0xa32821, 0xa3302b, -0x822021, 0x862021, 0xace40000, 0xace50004, 0x8ee205f8, 0xa4f8000e, -0xacef0018, 0xacea001c, 0x210c0, 0x244205fc, 0x2e21021, 0xace20008, -0x8ee204b4, 0xace20010, 0xaf880120, 0x92e24e10, 0x14400033, 0x24100001, -0x8ee24e20, 0x210c0, 0x24425028, 0x2e22021, 0x8c820000, 0x144d001f, -0x0, 0x8ee34e20, 0x8ee24e24, 0x1062001b, 0x0, 0x8c820004, -0x24420001, 0xac820004, 0x8ee24e24, 0x8ee34e20, 0x24420001, 0x104c0007, -0x0, 0x8ee24e24, 0x24420001, 0x10620005, 0x0, 0x80017db, -0x0, 0x14600005, 0x0, 0x8f820128, 0x24420020, 0xaf820128, -0x8f820128, 0x8c820004, 0x2c420011, 0x50400010, 0xac800000, 0x80017ee, -0x0, 0x8ee24e20, 0x24420001, 0x504c0003, 0x1021, 0x8ee24e20, -0x24420001, 0xaee24e20, 0x8ee24e20, 0x210c0, 0x24425028, 0x2e22021, -0xac8d0000, 0xac8e0004, 0x56000006, 0x240b0001, 0x8f820054, 0x1221023, -0x2c420033, 0x1440ff9d, 0x0, 0x316300ff, 0x24020001, 0x14620077, -0x3c050009, 0xaeea05f8, 0x8f830054, 0x8f820054, 0x24690032, 0x1221023, -0x2c420033, 0x10400061, 0x5821, 0x240d0008, 0x240c0011, 0x24080012, -0x24070040, 0x240a0001, 0x8f830120, 0x27623800, 0x24660020, 0xc2102b, -0x50400001, 0x27663000, 0x8f820128, 0x10c20004, 0x0, 0x8f820124, -0x14c20007, 0x0, 0x8ee201a0, 0x8021, 0x24420001, 0xaee201a0, -0x800185a, 0x8ee201a0, 0x8ee205f8, 0xac62001c, 0x8ee40490, 0x8ee50494, -0x2462001c, 0xac620008, 0xa46d000e, 0xac6c0018, 0xac640000, 0xac650004, -0x8ee204b4, 0xac620010, 0xaf860120, 0x92e24e10, 0x14400033, 0x24100001, -0x8ee24e20, 0x210c0, 0x24425028, 0x2e22021, 0x8c820000, 0x1448001f, -0x0, 0x8ee34e20, 0x8ee24e24, 0x1062001b, 0x0, 0x8c820004, -0x24420001, 0xac820004, 0x8ee24e24, 0x8ee34e20, 0x24420001, 0x10470007, -0x0, 0x8ee24e24, 0x24420001, 0x10620005, 0x0, 0x8001847, -0x0, 0x14600005, 0x0, 0x8f820128, 0x24420020, 0xaf820128, -0x8f820128, 0x8c820004, 0x2c420011, 0x50400010, 0xac800000, 0x800185a, -0x0, 0x8ee24e20, 0x24420001, 0x50470003, 0x1021, 0x8ee24e20, -0x24420001, 0xaee24e20, 0x8ee24e20, 0x210c0, 0x24425028, 0x2e22021, -0xac880000, 0xac8a0004, 0x56000006, 0x240b0001, 0x8f820054, 0x1221023, -0x2c420033, 0x1440ffa6, 0x0, 0x316300ff, 0x24020001, 0x14620003, -0x3c050009, 0x8001977, 0x24100001, 0x3c040001, 0x24844664, 0xafa00010, -0xafa00014, 0x8f860120, 0x8f870124, 0x8001876, 0x34a5f011, 0x3c040001, -0x24844670, 0xafa00010, 0xafa00014, 0x8f860120, 0x8f870124, 0x34a5f010, -0xc002403, 0x8021, 0x8001977, 0x0, 0x3c040001, 0x2484467c, -0xafa00014, 0x8ee605f8, 0x8f470228, 0x3c050009, 0x8001970, 0x34a5f00f, -0x8ee205f8, 0x8f430228, 0x24420001, 0x304900ff, 0x512300e2, 0xafa00010, -0x8ee205f8, 0x210c0, 0x571021, 0x8fa30018, 0x8fa4001c, 0xac4305fc, -0xac440600, 0x8f870120, 0x27623800, 0x24e80020, 0x102102b, 0x50400001, -0x27683000, 0x8f820128, 0x11020004, 0x0, 0x8f820124, 0x15020007, -0x1021, 0x8ee201a0, 0x8021, 0x24420001, 0xaee201a0, 0x80018f2, -0x8ee201a0, 0x8ee405f8, 0x420c0, 0x801821, 0x8ee40430, 0x8ee50434, -0xa32821, 0xa3302b, 0x822021, 0x862021, 0xace40000, 0xace50004, -0x8ee305f8, 0x24020008, 0xa4e2000e, 0x2402000d, 0xace20018, 0xace9001c, -0x318c0, 0x246305fc, 0x2e31021, 0xace20008, 0x8ee204b4, 0xace20010, -0xaf880120, 0x92e24e10, 0x14400037, 0x24100001, 0x8ee24e20, 0x210c0, -0x24425028, 0x2e22021, 0x8c830000, 0x24020007, 0x1462001f, 0x0, -0x8ee34e20, 0x8ee24e24, 0x1062001b, 0x24030040, 0x8c820004, 0x24420001, -0xac820004, 0x8ee24e24, 0x8ee54e20, 0x24420001, 0x10430007, 0x0, -0x8ee24e24, 0x24420001, 0x10a20005, 0x0, 0x80018dc, 0x0, -0x14a00005, 0x0, 0x8f820128, 0x24420020, 0xaf820128, 0x8f820128, -0x8c820004, 0x2c420011, 0x50400013, 0xac800000, 0x80018f2, 0x0, -0x8ee24e20, 0x24030040, 0x24420001, 0x50430003, 0x1021, 0x8ee24e20, -0x24420001, 0xaee24e20, 0x8ee24e20, 0x210c0, 0x24425028, 0x2e22021, -0x24020007, 0xac820000, 0x24020001, 0xac820004, 0x5600000c, 0xaee905f8, -0x3c040001, 0x24844688, 0xafa00010, 0xafa00014, 0x8ee605f8, 0x8f470228, -0x3c050009, 0xc002403, 0x34a5f000, 0x8001977, 0x0, 0x8f830120, -0x27623800, 0x24660020, 0xc2102b, 0x50400001, 0x27663000, 0x8f820128, -0x10c20004, 0x0, 0x8f820124, 0x14c20007, 0x0, 0x8ee201a0, -0x8021, 0x24420001, 0xaee201a0, 0x8001959, 0x8ee201a0, 0x8ee205f8, -0xac62001c, 0x8ee40490, 0x8ee50494, 0x2462001c, 0xac620008, 0x24020008, -0xa462000e, 0x24020011, 0xac620018, 0xac640000, 0xac650004, 0x8ee204b4, -0xac620010, 0xaf860120, 0x92e24e10, 0x14400037, 0x24100001, 0x8ee24e20, -0x210c0, 0x24425028, 0x2e22021, 0x8c830000, 0x24020012, 0x1462001f, -0x0, 0x8ee34e20, 0x8ee24e24, 0x1062001b, 0x24030040, 0x8c820004, -0x24420001, 0xac820004, 0x8ee24e24, 0x8ee54e20, 0x24420001, 0x10430007, -0x0, 0x8ee24e24, 0x24420001, 0x10a20005, 0x0, 0x8001943, -0x0, 0x14a00005, 0x0, 0x8f820128, 0x24420020, 0xaf820128, -0x8f820128, 0x8c820004, 0x2c420011, 0x50400013, 0xac800000, 0x8001959, -0x0, 0x8ee24e20, 0x24030040, 0x24420001, 0x50430003, 0x1021, -0x8ee24e20, 0x24420001, 0xaee24e20, 0x8ee24e20, 0x210c0, 0x24425028, -0x2e22021, 0x24020012, 0xac820000, 0x24020001, 0xac820004, 0x5600001d, -0x24100001, 0x3c040001, 0x24844690, 0xafa00010, 0xafa00014, 0x8ee605f8, -0x8f470228, 0x3c050009, 0xc002403, 0x34a5f001, 0x8ee201ac, 0x24420001, -0xaee201ac, 0x8001977, 0x8ee201ac, 0x3c040001, 0x2484469c, 0xafa00014, -0x8ee605f8, 0x8f470228, 0x3c050009, 0x34a5f005, 0xc002403, 0x0, -0x8ee201a8, 0x8021, 0x24420001, 0xaee201a8, 0x8ee201a8, 0x1200000c, -0x24020001, 0x3c010001, 0x370821, 0xa02083a0, 0x8f420238, 0x8ee30154, -0x24630001, 0xaee30154, 0x8ee30154, 0x8001987, 0xaee27268, 0x24020001, -0x3c010001, 0x370821, 0xa02283a0, 0x3c020001, 0x8c42500c, 0x10400187, -0x0, 0x8ee27b74, 0x24430001, 0x284200c9, 0x144001a4, 0xaee37b74, -0x8ee204c4, 0x30420002, 0x14400119, 0xaee07b74, 0x8ee204c4, 0x3c030600, -0x34631000, 0x34420002, 0xaee204c4, 0xafa30018, 0x8ee205f8, 0x8f430228, -0x24420001, 0x304a00ff, 0x514300fd, 0xafa00010, 0x8ee205f8, 0x210c0, -0x571021, 0x8fa30018, 0x8fa4001c, 0xac4305fc, 0xac440600, 0x8f830054, -0x8f820054, 0x24690032, 0x1221023, 0x2c420033, 0x1040006a, 0x5821, -0x24180008, 0x240f000d, 0x240d0007, 0x240c0040, 0x240e0001, 0x8f870120, -0x27623800, 0x24e80020, 0x102102b, 0x50400001, 0x27683000, 0x8f820128, -0x11020004, 0x0, 0x8f820124, 0x15020007, 0x1021, 0x8ee201a0, -0x8021, 0x24420001, 0xaee201a0, 0x8001a10, 0x8ee201a0, 0x8ee405f8, -0x420c0, 0x801821, 0x8ee40430, 0x8ee50434, 0xa32821, 0xa3302b, -0x822021, 0x862021, 0xace40000, 0xace50004, 0x8ee205f8, 0xa4f8000e, -0xacef0018, 0xacea001c, 0x210c0, 0x244205fc, 0x2e21021, 0xace20008, -0x8ee204b4, 0xace20010, 0xaf880120, 0x92e24e10, 0x14400033, 0x24100001, -0x8ee24e20, 0x210c0, 0x24425028, 0x2e22021, 0x8c820000, 0x144d001f, -0x0, 0x8ee34e20, 0x8ee24e24, 0x1062001b, 0x0, 0x8c820004, -0x24420001, 0xac820004, 0x8ee24e24, 0x8ee34e20, 0x24420001, 0x104c0007, -0x0, 0x8ee24e24, 0x24420001, 0x10620005, 0x0, 0x80019fd, -0x0, 0x14600005, 0x0, 0x8f820128, 0x24420020, 0xaf820128, -0x8f820128, 0x8c820004, 0x2c420011, 0x50400010, 0xac800000, 0x8001a10, -0x0, 0x8ee24e20, 0x24420001, 0x504c0003, 0x1021, 0x8ee24e20, -0x24420001, 0xaee24e20, 0x8ee24e20, 0x210c0, 0x24425028, 0x2e22021, -0xac8d0000, 0xac8e0004, 0x56000006, 0x240b0001, 0x8f820054, 0x1221023, -0x2c420033, 0x1440ff9d, 0x0, 0x316300ff, 0x24020001, 0x54620078, -0xafa00010, 0xaeea05f8, 0x8f830054, 0x8f820054, 0x24690032, 0x1221023, -0x2c420033, 0x10400061, 0x5821, 0x240d0008, 0x240c0011, 0x24080012, -0x24070040, 0x240a0001, 0x8f830120, 0x27623800, 0x24660020, 0xc2102b, -0x50400001, 0x27663000, 0x8f820128, 0x10c20004, 0x0, 0x8f820124, -0x14c20007, 0x0, 0x8ee201a0, 0x8021, 0x24420001, 0xaee201a0, -0x8001a7c, 0x8ee201a0, 0x8ee205f8, 0xac62001c, 0x8ee40490, 0x8ee50494, -0x2462001c, 0xac620008, 0xa46d000e, 0xac6c0018, 0xac640000, 0xac650004, -0x8ee204b4, 0xac620010, 0xaf860120, 0x92e24e10, 0x14400033, 0x24100001, -0x8ee24e20, 0x210c0, 0x24425028, 0x2e22021, 0x8c820000, 0x1448001f, -0x0, 0x8ee34e20, 0x8ee24e24, 0x1062001b, 0x0, 0x8c820004, -0x24420001, 0xac820004, 0x8ee24e24, 0x8ee34e20, 0x24420001, 0x10470007, -0x0, 0x8ee24e24, 0x24420001, 0x10620005, 0x0, 0x8001a69, -0x0, 0x14600005, 0x0, 0x8f820128, 0x24420020, 0xaf820128, -0x8f820128, 0x8c820004, 0x2c420011, 0x50400010, 0xac800000, 0x8001a7c, -0x0, 0x8ee24e20, 0x24420001, 0x50470003, 0x1021, 0x8ee24e20, -0x24420001, 0xaee24e20, 0x8ee24e20, 0x210c0, 0x24425028, 0x2e22021, -0xac880000, 0xac8a0004, 0x56000006, 0x240b0001, 0x8f820054, 0x1221023, -0x2c420033, 0x1440ffa6, 0x0, 0x316300ff, 0x24020001, 0x10620022, -0x0, 0x3c040001, 0x24844664, 0xafa00010, 0xafa00014, 0x8f860120, -0x8f870124, 0x3c050009, 0xc002403, 0x34a5f011, 0x8001aa8, 0x0, -0x3c040001, 0x24844670, 0xafa00014, 0x8f860120, 0x8f870124, 0x3c050009, -0xc002403, 0x34a5f010, 0x8001aa8, 0x0, 0x3c040001, 0x2484467c, -0xafa00014, 0x8ee605f8, 0x8f470228, 0x3c050009, 0xc002403, 0x34a5f00f, -0x8ee201a8, 0x24420001, 0xaee201a8, 0x8ee201a8, 0x8ee20158, 0x24420001, -0xaee20158, 0x8ee20158, 0x8ee204c4, 0x30420001, 0x10400055, 0x0, -0x8f420218, 0x30420080, 0x10400029, 0x0, 0x8f820044, 0x34420040, -0xaf820044, 0x8ee27b6c, 0x402821, 0x8ee200c0, 0x8ee300c4, 0x24060000, -0x2407ffff, 0x2021, 0x461024, 0x1444000d, 0x671824, 0x1465000b, -0x0, 0x8ee27b70, 0x402821, 0x8ee200e0, 0x8ee300e4, 0x2021, -0x461024, 0x14440003, 0x671824, 0x1065000b, 0x0, 0x8ee200c0, -0x8ee300c4, 0x8ee400e0, 0x8ee500e4, 0xaee37b6c, 0xaee57b70, 0x8f820044, -0x38420020, 0x8001b33, 0xaf820044, 0x8f820044, 0x2403ffdf, 0x431024, -0x8001b33, 0xaf820044, 0x8f820044, 0x2403ffdf, 0x431024, 0xaf820044, -0x8ee27b6c, 0x402821, 0x8ee200c0, 0x8ee300c4, 0x24060000, 0x2407ffff, -0x2021, 0x461024, 0x1444000d, 0x671824, 0x1465000b, 0x0, -0x8ee27b70, 0x402821, 0x8ee200e0, 0x8ee300e4, 0x2021, 0x461024, -0x14440003, 0x671824, 0x1065000b, 0x0, 0x8ee200c0, 0x8ee300c4, -0x8ee400e0, 0x8ee500e4, 0xaee37b6c, 0xaee57b70, 0x8f820044, 0x38420040, -0x8001b33, 0xaf820044, 0x8f820044, 0x34420040, 0x8001b33, 0xaf820044, -0x8f820044, 0x34420040, 0xaf820044, 0x8ee27b7c, 0x24430001, 0x28420015, -0x14400028, 0xaee37b7c, 0x8f820044, 0x38420020, 0xaf820044, 0x8001b33, -0xaee07b7c, 0x8ee204c4, 0x30420001, 0x10400011, 0x0, 0x8f420218, -0x30420080, 0x10400009, 0x0, 0x8f820044, 0x34420020, 0xaf820044, -0x8f820044, 0x2403ffbf, 0x431024, 0x8001b31, 0xaf820044, 0x8f820044, -0x34420060, 0x8001b31, 0xaf820044, 0x8f820044, 0x34420040, 0xaf820044, -0x8ee27b78, 0x24430001, 0x28421389, 0x14400005, 0xaee37b78, 0x8f820044, -0x38420020, 0xaf820044, 0xaee07b78, 0xc00457c, 0x0, 0x8fbf0024, -0x8fb00020, 0x3e00008, 0x27bd0028, 0x0, 0x27bdffb8, 0xafbf0044, -0xafb60040, 0xafb5003c, 0xafb40038, 0xafb30034, 0xafb20030, 0xafb1002c, -0xafb00028, 0x8f960064, 0x32c20004, 0x1040000c, 0x24020004, 0xaf820064, -0x8f420114, 0xaee204d0, 0x8f820060, 0x34420008, 0xaf820060, 0x8ee20168, -0x24420001, 0xaee20168, 0x80022ee, 0x8ee20168, 0x32c20001, 0x10400004, -0x24020001, 0xaf820064, 0x80022ee, 0x0, 0x32c20002, 0x1440000c, -0x3c050003, 0x3c040001, 0x24844714, 0x34a50001, 0x2c03021, 0x3821, -0xafa00010, 0xc002403, 0xafa00014, 0x2402fff8, 0x80022ee, 0xaf820064, -0x8f43022c, 0x8f42010c, 0x5062000c, 0xafa00010, 0x8f42022c, 0x21080, -0x5a1021, 0x8c420300, 0xafa20020, 0x8f42022c, 0x24070001, 0x24420001, -0x3042003f, 0x8001b7c, 0xaf42022c, 0x3c040001, 0x24844720, 0xafa00014, -0x8f46022c, 0x8f47010c, 0x3c050003, 0xc002403, 0x34a5f01f, 0x3821, -0x14e00003, 0x0, 0x80022e7, 0xaf960064, 0x93a20020, 0x2443ffff, -0x2c620011, 0x10400656, 0x31080, 0x3c010001, 0x220821, 0x8c2247d8, -0x400008, 0x0, 0x8fa20020, 0x30420fff, 0xaee20dfc, 0x8f820060, -0x34420200, 0xaf820060, 0x8ee20118, 0x24420001, 0xaee20118, 0x80022e2, -0x8ee20118, 0x8fa20020, 0x24030001, 0x3c010001, 0x370821, 0xa02383a1, -0x30420fff, 0xaee25228, 0x8f820060, 0x34420100, 0xaf820060, 0x8ee20144, -0x24420001, 0xaee20144, 0x80022e2, 0x8ee20144, 0x8fa20020, 0x21200, -0x22502, 0x24020001, 0x10820005, 0x24020002, 0x10820009, 0x2402fffe, -0x8001bc5, 0xafa00010, 0x8ee204c4, 0xaee40070, 0xaee40074, 0x34420001, -0x8001bb9, 0xaee204c4, 0x8ee304c4, 0xaee40070, 0xaee40074, 0x621824, -0xaee304c4, 0x8f840054, 0x41442, 0x41c82, 0x431021, 0x41cc2, -0x431023, 0x41d02, 0x431021, 0x41d42, 0x431023, 0x8001bcc, -0xaee20078, 0x3c040001, 0x2484472c, 0xafa00014, 0x8fa60020, 0x3c050003, -0xc002403, 0x34a50004, 0x8ee20110, 0x24420001, 0xaee20110, 0x80022e2, -0x8ee20110, 0x27440212, 0xc0022f8, 0x24050006, 0x3049001f, 0x920c0, -0x2e41021, 0x9442726c, 0x30424000, 0x1040000a, 0x971021, 0x97430212, -0xa443726e, 0x8f430214, 0x971021, 0xac437270, 0x2e41821, 0x34028000, -0x8001c75, 0xa462726c, 0x9443726e, 0x97420212, 0x14620006, 0x2e41021, -0x971021, 0x8c437270, 0x8f420214, 0x1062009f, 0x2e41021, 0x9442726c, -0x30428000, 0x1040002a, 0x2406ffff, 0x2021, 0x410c0, 0x2e21021, -0x9442736c, 0x30424000, 0x54400005, 0x803021, 0x24840001, 0x2c820080, -0x1440fff8, 0x410c0, 0x4c10010, 0x618c0, 0x610c0, 0x571821, -0x8c63736c, 0x571021, 0xafa30010, 0x8c427370, 0x3c040001, 0x24844738, -0xafa20014, 0x8f470214, 0x3c050003, 0xc002403, 0x34a50013, 0x8001c8c, -0x3c020800, 0x97440212, 0x771021, 0xa444736e, 0x8f440214, 0x771021, -0x2e31821, 0xac447370, 0x34028000, 0xa462736c, 0x910c0, 0x2e21021, -0x8001c75, 0xa446726c, 0x2e41021, 0x9445726c, 0x8001c2a, 0x510c0, -0x9443736e, 0x97420212, 0x14620006, 0x510c0, 0x971021, 0x8c437370, -0x8f420214, 0x10620065, 0x510c0, 0x2e21021, 0x9445736c, 0x510c0, -0x2e21021, 0x9442736c, 0x30428000, 0x1040fff0, 0x971021, 0x520c0, -0x971021, 0x9443736e, 0x97420212, 0x14620006, 0x2406ffff, 0x971021, -0x8c437370, 0x8f420214, 0x10620053, 0x3c020800, 0x2021, 0x410c0, -0x2e21021, 0x9442736c, 0x30424000, 0x54400005, 0x803021, 0x24840001, -0x2c820080, 0x1440fff8, 0x410c0, 0x4c10023, 0x618c0, 0x910c0, -0x571821, 0x8c63726c, 0x571021, 0xafa30010, 0x8c427270, 0x3c040001, -0x24844744, 0xafa20014, 0x8f470214, 0x3c050003, 0xc002403, 0x34a5f017, -0x8001c8c, 0x3c020800, 0x8f430210, 0xb71021, 0xac43776c, 0x8f430214, -0xb71021, 0xac437770, 0x3c020001, 0x571021, 0x8c4283a4, 0x24420001, -0x3c010001, 0x370821, 0xac2283a4, 0x3c030001, 0x771821, 0x8c6383a4, -0x2e51021, 0x8001c7e, 0xa443776c, 0x97440212, 0x771021, 0xa444736e, -0x8f440214, 0x771021, 0x2e31821, 0xac447370, 0x34028000, 0xa462736c, -0x510c0, 0x2e21021, 0xa446736c, 0x2021, 0x428c0, 0x2e51021, -0x9442776c, 0x1040ffdc, 0x24840001, 0x2c820080, 0x5440fffa, 0x428c0, -0x92e204c8, 0x10400006, 0x24020001, 0x8ee304cc, 0x1221004, 0x621825, -0x8001c8b, 0xaee304cc, 0x8f830228, 0x24020001, 0x1221004, 0x621825, -0xaf830228, 0x3c020800, 0x34421000, 0xafa20018, 0x8ee205f8, 0x8f430228, -0x24420001, 0x304a00ff, 0x514300fd, 0xafa00010, 0x8ee205f8, 0x210c0, -0x571021, 0x8fa30018, 0x8fa4001c, 0xac4305fc, 0xac440600, 0x8f830054, -0x8f820054, 0x24690032, 0x1221023, 0x2c420033, 0x1040006a, 0x5821, -0x24100008, 0x240f000d, 0x240d0007, 0x240c0040, 0x240e0001, 0x8f870120, -0x27623800, 0x24e80020, 0x102102b, 0x50400001, 0x27683000, 0x8f820128, -0x11020004, 0x0, 0x8f820124, 0x15020007, 0x1021, 0x8ee201a0, -0x3821, 0x24420001, 0xaee201a0, 0x8001d04, 0x8ee201a0, 0x8ee405f8, -0x420c0, 0x801821, 0x8ee40430, 0x8ee50434, 0xa32821, 0xa3302b, -0x822021, 0x862021, 0xace40000, 0xace50004, 0x8ee205f8, 0xa4f0000e, -0xacef0018, 0xacea001c, 0x210c0, 0x244205fc, 0x2e21021, 0xace20008, -0x8ee204b4, 0xace20010, 0xaf880120, 0x92e24e10, 0x14400033, 0x24070001, -0x8ee24e20, 0x210c0, 0x24425028, 0x2e22021, 0x8c820000, 0x144d001f, -0x0, 0x8ee34e20, 0x8ee24e24, 0x1062001b, 0x0, 0x8c820004, -0x24420001, 0xac820004, 0x8ee24e24, 0x8ee34e20, 0x24420001, 0x104c0007, -0x0, 0x8ee24e24, 0x24420001, 0x10620005, 0x0, 0x8001cf1, -0x0, 0x14600005, 0x0, 0x8f820128, 0x24420020, 0xaf820128, -0x8f820128, 0x8c820004, 0x2c420011, 0x50400010, 0xac800000, 0x8001d04, -0x0, 0x8ee24e20, 0x24420001, 0x504c0003, 0x1021, 0x8ee24e20, -0x24420001, 0xaee24e20, 0x8ee24e20, 0x210c0, 0x24425028, 0x2e22021, -0xac8d0000, 0xac8e0004, 0x54e00006, 0x240b0001, 0x8f820054, 0x1221023, -0x2c420033, 0x1440ff9d, 0x0, 0x316300ff, 0x24020001, 0x54620078, -0xafa00010, 0xaeea05f8, 0x8f830054, 0x8f820054, 0x24690032, 0x1221023, -0x2c420033, 0x10400061, 0x5821, 0x240e0008, 0x240d0011, 0x240a0012, -0x24080040, 0x240c0001, 0x8f830120, 0x27623800, 0x24660020, 0xc2102b, -0x50400001, 0x27663000, 0x8f820128, 0x10c20004, 0x0, 0x8f820124, -0x14c20007, 0x0, 0x8ee201a0, 0x3821, 0x24420001, 0xaee201a0, -0x8001d70, 0x8ee201a0, 0x8ee205f8, 0xac62001c, 0x8ee40490, 0x8ee50494, -0x2462001c, 0xac620008, 0xa46e000e, 0xac6d0018, 0xac640000, 0xac650004, -0x8ee204b4, 0xac620010, 0xaf860120, 0x92e24e10, 0x14400033, 0x24070001, -0x8ee24e20, 0x210c0, 0x24425028, 0x2e22021, 0x8c820000, 0x144a001f, -0x0, 0x8ee34e20, 0x8ee24e24, 0x1062001b, 0x0, 0x8c820004, -0x24420001, 0xac820004, 0x8ee24e24, 0x8ee34e20, 0x24420001, 0x10480007, -0x0, 0x8ee24e24, 0x24420001, 0x10620005, 0x0, 0x8001d5d, -0x0, 0x14600005, 0x0, 0x8f820128, 0x24420020, 0xaf820128, -0x8f820128, 0x8c820004, 0x2c420011, 0x50400010, 0xac800000, 0x8001d70, -0x0, 0x8ee24e20, 0x24420001, 0x50480003, 0x1021, 0x8ee24e20, -0x24420001, 0xaee24e20, 0x8ee24e20, 0x210c0, 0x24425028, 0x2e22021, -0xac8a0000, 0xac8c0004, 0x54e00006, 0x240b0001, 0x8f820054, 0x1221023, -0x2c420033, 0x1440ffa6, 0x0, 0x316300ff, 0x24020001, 0x10620022, -0x0, 0x3c040001, 0x24844750, 0xafa00010, 0xafa00014, 0x8f860120, -0x8f870124, 0x3c050009, 0xc002403, 0x34a5f011, 0x8001d9c, 0x0, -0x3c040001, 0x2484475c, 0xafa00014, 0x8f860120, 0x8f870124, 0x3c050009, -0xc002403, 0x34a5f010, 0x8001d9c, 0x0, 0x3c040001, 0x24844768, -0xafa00014, 0x8ee605f8, 0x8f470228, 0x3c050009, 0xc002403, 0x34a5f00f, -0x8ee201a8, 0x24420001, 0xaee201a8, 0x8ee201a8, 0x8ee20124, 0x24420001, -0xaee20124, 0x8001f93, 0x8ee20124, 0x27440212, 0xc0022f8, 0x24050006, -0x3049001f, 0x928c0, 0x2e51021, 0x9442726c, 0x30428000, 0x1040002f, -0x2e51021, 0x9442726c, 0x30424000, 0x1440001c, 0xb71021, 0x9443726e, -0x97420212, 0x14620018, 0xb71021, 0x8c437270, 0x8f420214, 0x54620016, -0xafa20010, 0x92e204c8, 0x10400007, 0x24020001, 0x8ee304cc, 0x1221004, -0x21027, 0x621824, 0x8001dc5, 0xaee304cc, 0x8f830228, 0x1221004, -0x21027, 0x621824, 0xaf830228, 0x910c0, 0x2e21821, 0x3402c000, -0x8001e4a, 0xa462726c, 0x8f420214, 0xafa20010, 0x910c0, 0x571021, -0x8c42726c, 0x3c040001, 0x24844774, 0x3c050003, 0xafa20014, 0x8f470210, -0x34a5f01c, 0xc002403, 0x1203021, 0x8001e7f, 0x3c020800, 0xb71021, -0x9443726e, 0x97420212, 0x14620019, 0x918c0, 0xb71021, 0x8c437270, -0x8f420214, 0x14620014, 0x918c0, 0x2e51021, 0x9447726c, 0x720c0, -0x971021, 0x9443736e, 0xb71021, 0xa443726e, 0x971021, 0x8c437370, -0xb71021, 0xac437270, 0x2e41021, 0x9443736c, 0x2e51021, 0xa443726c, -0x2e41821, 0x3402c000, 0x8001e4a, 0xa462736c, 0x2e31021, 0x9447726c, -0x3021, 0x720c0, 0x2e41021, 0x9442736c, 0x4021, 0x30428000, -0x14400025, 0xe02821, 0x605021, 0x340bc000, 0x971021, 0x9443736e, -0x97420212, 0x54620015, 0xe02821, 0x971021, 0x8c437370, 0x8f420214, -0x54620010, 0xe02821, 0x11000006, 0x2e41021, 0x9443736c, 0x510c0, -0x2e21021, 0x8001e16, 0xa443736c, 0x9443736c, 0x2ea1021, 0xa443726c, -0x710c0, 0x2e21021, 0xa44b736c, 0x8001e24, 0x24060001, 0x510c0, -0x2e21021, 0x9447736c, 0x720c0, 0x2e41021, 0x9442736c, 0x30428000, -0x1040ffdf, 0x25080001, 0x30c200ff, 0x14400025, 0x2021, 0x720c0, -0x971021, 0x9443736e, 0x97420212, 0x1462000f, 0x910c0, 0x971021, -0x8c437370, 0x8f420214, 0x1462000a, 0x910c0, 0x2e41821, 0x3402c000, -0x15000015, 0xa462736c, 0x910c0, 0x2e21821, 0x34028000, 0x8001e4a, -0xa462726c, 0x571021, 0x8c42726c, 0x3c040001, 0x24844780, 0x3c050003, -0xafa20010, 0x710c0, 0x571021, 0x8c42736c, 0x34a5001e, 0x1203021, -0xc002403, 0xafa20014, 0x8001e7f, 0x3c020800, 0x2021, 0x428c0, -0xb71021, 0x9443776e, 0x97420212, 0x5462002b, 0x24840001, 0xb71021, -0x8c437770, 0x8f420214, 0x54620026, 0x24840001, 0x3c020001, 0x571021, -0x8c4283a4, 0x2442ffff, 0x3c010001, 0x370821, 0xac2283a4, 0x3c020001, -0x571021, 0x8c4283a4, 0x809021, 0x242102b, 0x1040000e, 0x24b1776c, -0x24b07774, 0x2f02021, 0x2f12821, 0xc002490, 0x24060008, 0x26310008, -0x3c020001, 0x571021, 0x8c4283a4, 0x26520001, 0x242102b, 0x1440fff5, -0x26100008, 0x3c040001, 0x972021, 0x8c8483a4, 0x24050008, 0x420c0, -0x2484776c, 0xc002488, 0x2e42021, 0x8001e7f, 0x3c020800, 0x2c820080, -0x1440ffcf, 0x428c0, 0x3c020800, 0x34422000, 0xafa20018, 0x8ee205f8, -0x8f430228, 0x24420001, 0x304a00ff, 0x514300fd, 0xafa00010, 0x8ee205f8, -0x210c0, 0x571021, 0x8fa30018, 0x8fa4001c, 0xac4305fc, 0xac440600, -0x8f830054, 0x8f820054, 0x24690032, 0x1221023, 0x2c420033, 0x1040006a, -0x5821, 0x24100008, 0x240f000d, 0x240d0007, 0x240c0040, 0x240e0001, -0x8f870120, 0x27623800, 0x24e80020, 0x102102b, 0x50400001, 0x27683000, -0x8f820128, 0x11020004, 0x0, 0x8f820124, 0x15020007, 0x1021, -0x8ee201a0, 0x3821, 0x24420001, 0xaee201a0, 0x8001ef7, 0x8ee201a0, -0x8ee405f8, 0x420c0, 0x801821, 0x8ee40430, 0x8ee50434, 0xa32821, -0xa3302b, 0x822021, 0x862021, 0xace40000, 0xace50004, 0x8ee205f8, -0xa4f0000e, 0xacef0018, 0xacea001c, 0x210c0, 0x244205fc, 0x2e21021, -0xace20008, 0x8ee204b4, 0xace20010, 0xaf880120, 0x92e24e10, 0x14400033, -0x24070001, 0x8ee24e20, 0x210c0, 0x24425028, 0x2e22021, 0x8c820000, -0x144d001f, 0x0, 0x8ee34e20, 0x8ee24e24, 0x1062001b, 0x0, -0x8c820004, 0x24420001, 0xac820004, 0x8ee24e24, 0x8ee34e20, 0x24420001, -0x104c0007, 0x0, 0x8ee24e24, 0x24420001, 0x10620005, 0x0, -0x8001ee4, 0x0, 0x14600005, 0x0, 0x8f820128, 0x24420020, -0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011, 0x50400010, 0xac800000, -0x8001ef7, 0x0, 0x8ee24e20, 0x24420001, 0x504c0003, 0x1021, -0x8ee24e20, 0x24420001, 0xaee24e20, 0x8ee24e20, 0x210c0, 0x24425028, -0x2e22021, 0xac8d0000, 0xac8e0004, 0x54e00006, 0x240b0001, 0x8f820054, -0x1221023, 0x2c420033, 0x1440ff9d, 0x0, 0x316300ff, 0x24020001, -0x54620078, 0xafa00010, 0xaeea05f8, 0x8f830054, 0x8f820054, 0x24690032, -0x1221023, 0x2c420033, 0x10400061, 0x5821, 0x240e0008, 0x240d0011, -0x240a0012, 0x24080040, 0x240c0001, 0x8f830120, 0x27623800, 0x24660020, -0xc2102b, 0x50400001, 0x27663000, 0x8f820128, 0x10c20004, 0x0, -0x8f820124, 0x14c20007, 0x0, 0x8ee201a0, 0x3821, 0x24420001, -0xaee201a0, 0x8001f63, 0x8ee201a0, 0x8ee205f8, 0xac62001c, 0x8ee40490, -0x8ee50494, 0x2462001c, 0xac620008, 0xa46e000e, 0xac6d0018, 0xac640000, -0xac650004, 0x8ee204b4, 0xac620010, 0xaf860120, 0x92e24e10, 0x14400033, -0x24070001, 0x8ee24e20, 0x210c0, 0x24425028, 0x2e22021, 0x8c820000, -0x144a001f, 0x0, 0x8ee34e20, 0x8ee24e24, 0x1062001b, 0x0, -0x8c820004, 0x24420001, 0xac820004, 0x8ee24e24, 0x8ee34e20, 0x24420001, -0x10480007, 0x0, 0x8ee24e24, 0x24420001, 0x10620005, 0x0, -0x8001f50, 0x0, 0x14600005, 0x0, 0x8f820128, 0x24420020, -0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011, 0x50400010, 0xac800000, -0x8001f63, 0x0, 0x8ee24e20, 0x24420001, 0x50480003, 0x1021, -0x8ee24e20, 0x24420001, 0xaee24e20, 0x8ee24e20, 0x210c0, 0x24425028, -0x2e22021, 0xac8a0000, 0xac8c0004, 0x54e00006, 0x240b0001, 0x8f820054, -0x1221023, 0x2c420033, 0x1440ffa6, 0x0, 0x316300ff, 0x24020001, -0x10620022, 0x0, 0x3c040001, 0x24844750, 0xafa00010, 0xafa00014, -0x8f860120, 0x8f870124, 0x3c050009, 0xc002403, 0x34a5f011, 0x8001f8f, -0x0, 0x3c040001, 0x2484475c, 0xafa00014, 0x8f860120, 0x8f870124, -0x3c050009, 0xc002403, 0x34a5f010, 0x8001f8f, 0x0, 0x3c040001, -0x24844768, 0xafa00014, 0x8ee605f8, 0x8f470228, 0x3c050009, 0xc002403, -0x34a5f00f, 0x8ee201a8, 0x24420001, 0xaee201a8, 0x8ee201a8, 0x8ee20128, -0x24420001, 0xaee20128, 0x8ee20128, 0x8ee20160, 0x24420001, 0xaee20160, -0x80022e2, 0x8ee20160, 0x8fa20020, 0x21200, 0x21d02, 0x24020001, -0x10620005, 0x24020002, 0x1062000d, 0x0, 0x8001fb3, 0xafa00010, -0x92e204c8, 0x14400006, 0x24020001, 0x8f820228, 0xaee204cc, 0x2402ffff, -0xaf820228, 0x24020001, 0x8001fba, 0xa2e204c8, 0x92e204c8, 0x5040000c, -0xa2e004c8, 0x8ee204cc, 0xaf820228, 0x8001fba, 0xa2e004c8, 0x3c040001, -0x24844788, 0xafa00014, 0x8fa60020, 0x3c050003, 0xc002403, 0x34a5f009, -0x8ee2013c, 0x24420001, 0xaee2013c, 0x80022e2, 0x8ee2013c, 0x8fa20020, -0x21200, 0x22502, 0x24020001, 0x10820005, 0x24020002, 0x1082000f, -0x0, 0x8001fdf, 0xafa00010, 0x8f820220, 0x3c0308ff, 0x3463ffff, -0x431024, 0x34420008, 0xaf820220, 0x24020001, 0x3c010001, 0x370821, -0xa02283a2, 0x8001fe6, 0xaee40108, 0x8f820220, 0x3c0308ff, 0x3463fff7, -0x431024, 0xaf820220, 0x3c010001, 0x370821, 0xa02083a2, 0x8001fe6, -0xaee40108, 0x3c040001, 0x24844794, 0xafa00014, 0x8fa60020, 0x3c050003, -0xc002403, 0x34a5f00a, 0x8ee2012c, 0x24420001, 0xaee2012c, 0x80022e2, -0x8ee2012c, 0x8fa20020, 0x21200, 0x21d02, 0x24020001, 0x10620005, -0x24020002, 0x1062000e, 0x0, 0x800200d, 0xafa00010, 0x8f820220, -0x3c0308ff, 0x3463ffff, 0x431024, 0x34420008, 0xaf820220, 0x24020001, -0x3c010001, 0x370821, 0x8002014, 0xa02283a3, 0x3c020001, 0x571021, -0x904283a2, 0x3c010001, 0x370821, 0x1440000e, 0xa02083a3, 0x8f820220, -0x3c0308ff, 0x3463fff7, 0x431024, 0x8002014, 0xaf820220, 0x3c040001, -0x248447a0, 0xafa00014, 0x8fa60020, 0x3c050003, 0xc002403, 0x34a5f00b, -0x8ee20114, 0x24420001, 0xaee20114, 0x80022e2, 0x8ee20114, 0x27840208, -0x27450200, 0xc00249a, 0x24060008, 0x26e40094, 0x27450200, 0xc00249a, -0x24060008, 0x8ee20134, 0x24420001, 0xaee20134, 0x80022e2, 0x8ee20134, -0x8f460248, 0x24040001, 0xc004eac, 0x24050004, 0x8ee20130, 0x24420001, -0xaee20130, 0x80022e2, 0x8ee20130, 0x8ef301c4, 0x8ef401c8, 0x8ef501cc, -0x8ee20140, 0x26e40030, 0x24420001, 0xaee20140, 0x8ef00140, 0x8ef10074, -0x8ef20070, 0xc002488, 0x24050400, 0xaef301c4, 0xaef401c8, 0xaef501cc, -0xaef00140, 0xaef10074, 0xaef20070, 0x8f42025c, 0x26e40094, 0xaee20060, -0x8f420260, 0x27450200, 0x24060008, 0xaee20068, 0x24020006, 0xc00249a, -0xaee20064, 0x3c023b9a, 0x3442ca00, 0xaee2006c, 0x240203e8, 0x24040002, -0x24030001, 0xaee20104, 0xaee40100, 0xaee3010c, 0x8f820220, 0x30420008, -0x10400004, 0x0, 0xaee30108, 0x800205d, 0x2021, 0xaee40108, -0x2021, 0x3c030001, 0x641821, 0x90634f60, 0x2e41021, 0x24840001, -0xa043009c, 0x2c82000f, 0x1440fff8, 0x0, 0x8f820040, 0x2e41821, -0x24840001, 0x21702, 0x24420030, 0xa062009c, 0x2e41021, 0x80022e2, -0xa040009c, 0x240a0400, 0x24090040, 0x24080001, 0x8f830100, 0x27623000, -0x24660020, 0xc2102b, 0x50400001, 0x27662800, 0x8f820108, 0x10c20004, -0x0, 0x8f820104, 0x14c20007, 0x26e20030, 0x8ee201a4, 0x3821, -0x24420001, 0xaee201a4, 0x800209f, 0x8ee201a4, 0x8ee404a8, 0x8ee504ac, -0xac620008, 0xa46a000e, 0xac600018, 0xac60001c, 0xac640000, 0xac650004, -0x8ee204bc, 0xac620010, 0xaf860100, 0x92e204dc, 0x1440000e, 0x24070001, -0x8ee24e18, 0x24420001, 0x50490003, 0x1021, 0x8ee24e18, 0x24420001, -0xaee24e18, 0x8ee24e18, 0x210c0, 0x24424e28, 0x2e21021, 0xac400000, -0xac480004, 0x10e0ffd2, 0x0, 0x8ee20148, 0x24420001, 0xaee20148, -0x80022e2, 0x8ee20148, 0x3c020900, 0xaee05228, 0xaee0522c, 0xaee05230, -0xaee05234, 0xaee001c8, 0x3c010001, 0x370821, 0xa02083a1, 0xafa20018, -0x8ee205f8, 0x8f430228, 0x24420001, 0x304a00ff, 0x514300fd, 0xafa00010, -0x8ee205f8, 0x210c0, 0x571021, 0x8fa30018, 0x8fa4001c, 0xac4305fc, -0xac440600, 0x8f830054, 0x8f820054, 0x24690032, 0x1221023, 0x2c420033, -0x1040006a, 0x5821, 0x24100008, 0x240f000d, 0x240d0007, 0x240c0040, -0x240e0001, 0x8f870120, 0x27623800, 0x24e80020, 0x102102b, 0x50400001, -0x27683000, 0x8f820128, 0x11020004, 0x0, 0x8f820124, 0x15020007, -0x1021, 0x8ee201a0, 0x3821, 0x24420001, 0xaee201a0, 0x8002126, -0x8ee201a0, 0x8ee405f8, 0x420c0, 0x801821, 0x8ee40430, 0x8ee50434, -0xa32821, 0xa3302b, 0x822021, 0x862021, 0xace40000, 0xace50004, -0x8ee205f8, 0xa4f0000e, 0xacef0018, 0xacea001c, 0x210c0, 0x244205fc, -0x2e21021, 0xace20008, 0x8ee204b4, 0xace20010, 0xaf880120, 0x92e24e10, -0x14400033, 0x24070001, 0x8ee24e20, 0x210c0, 0x24425028, 0x2e22021, -0x8c820000, 0x144d001f, 0x0, 0x8ee34e20, 0x8ee24e24, 0x1062001b, -0x0, 0x8c820004, 0x24420001, 0xac820004, 0x8ee24e24, 0x8ee34e20, -0x24420001, 0x104c0007, 0x0, 0x8ee24e24, 0x24420001, 0x10620005, -0x0, 0x8002113, 0x0, 0x14600005, 0x0, 0x8f820128, -0x24420020, 0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011, 0x50400010, -0xac800000, 0x8002126, 0x0, 0x8ee24e20, 0x24420001, 0x504c0003, -0x1021, 0x8ee24e20, 0x24420001, 0xaee24e20, 0x8ee24e20, 0x210c0, -0x24425028, 0x2e22021, 0xac8d0000, 0xac8e0004, 0x54e00006, 0x240b0001, -0x8f820054, 0x1221023, 0x2c420033, 0x1440ff9d, 0x0, 0x316300ff, -0x24020001, 0x54620078, 0xafa00010, 0xaeea05f8, 0x8f830054, 0x8f820054, -0x24690032, 0x1221023, 0x2c420033, 0x10400061, 0x5821, 0x240e0008, -0x240d0011, 0x240a0012, 0x24080040, 0x240c0001, 0x8f830120, 0x27623800, -0x24660020, 0xc2102b, 0x50400001, 0x27663000, 0x8f820128, 0x10c20004, -0x0, 0x8f820124, 0x14c20007, 0x0, 0x8ee201a0, 0x3821, -0x24420001, 0xaee201a0, 0x8002192, 0x8ee201a0, 0x8ee205f8, 0xac62001c, -0x8ee40490, 0x8ee50494, 0x2462001c, 0xac620008, 0xa46e000e, 0xac6d0018, -0xac640000, 0xac650004, 0x8ee204b4, 0xac620010, 0xaf860120, 0x92e24e10, -0x14400033, 0x24070001, 0x8ee24e20, 0x210c0, 0x24425028, 0x2e22021, -0x8c820000, 0x144a001f, 0x0, 0x8ee34e20, 0x8ee24e24, 0x1062001b, -0x0, 0x8c820004, 0x24420001, 0xac820004, 0x8ee24e24, 0x8ee34e20, -0x24420001, 0x10480007, 0x0, 0x8ee24e24, 0x24420001, 0x10620005, -0x0, 0x800217f, 0x0, 0x14600005, 0x0, 0x8f820128, -0x24420020, 0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011, 0x50400010, -0xac800000, 0x8002192, 0x0, 0x8ee24e20, 0x24420001, 0x50480003, -0x1021, 0x8ee24e20, 0x24420001, 0xaee24e20, 0x8ee24e20, 0x210c0, -0x24425028, 0x2e22021, 0xac8a0000, 0xac8c0004, 0x54e00006, 0x240b0001, -0x8f820054, 0x1221023, 0x2c420033, 0x1440ffa6, 0x0, 0x316300ff, -0x24020001, 0x10620022, 0x0, 0x3c040001, 0x24844750, 0xafa00010, -0xafa00014, 0x8f860120, 0x8f870124, 0x3c050009, 0xc002403, 0x34a5f011, -0x80021be, 0x0, 0x3c040001, 0x2484475c, 0xafa00014, 0x8f860120, -0x8f870124, 0x3c050009, 0xc002403, 0x34a5f010, 0x80021be, 0x0, -0x3c040001, 0x24844768, 0xafa00014, 0x8ee605f8, 0x8f470228, 0x3c050009, -0xc002403, 0x34a5f00f, 0x8ee201a8, 0x24420001, 0xaee201a8, 0x8ee201a8, -0x8ee20120, 0x24420001, 0xaee20120, 0x8ee20120, 0x8ee20164, 0x24420001, -0xaee20164, 0x80022e2, 0x8ee20164, 0x8f42025c, 0x26e40094, 0xaee20060, -0x8f420260, 0x27450200, 0x24060008, 0xc00249a, 0xaee20068, 0x8f820220, -0x30420008, 0x14400002, 0x24020001, 0x24020002, 0xaee20108, 0x8ee2011c, -0x24420001, 0xaee2011c, 0x80022e2, 0x8ee2011c, 0x3c040001, 0x248447ac, -0xafa00010, 0xafa00014, 0x8fa60020, 0x3c050003, 0xc002403, 0x34a5f00f, -0x93a20020, 0x3c030700, 0x34631000, 0x431025, 0xafa20018, 0x8ee205f8, -0x8f430228, 0x24420001, 0x304900ff, 0x512300e2, 0xafa00010, 0x8ee205f8, -0x210c0, 0x571021, 0x8fa30018, 0x8fa4001c, 0xac4305fc, 0xac440600, -0x8f870120, 0x27623800, 0x24e80020, 0x102102b, 0x50400001, 0x27683000, -0x8f820128, 0x11020004, 0x0, 0x8f820124, 0x15020007, 0x1021, -0x8ee201a0, 0x3821, 0x24420001, 0xaee201a0, 0x8002257, 0x8ee201a0, -0x8ee405f8, 0x420c0, 0x801821, 0x8ee40430, 0x8ee50434, 0xa32821, -0xa3302b, 0x822021, 0x862021, 0xace40000, 0xace50004, 0x8ee305f8, -0x24020008, 0xa4e2000e, 0x2402000d, 0xace20018, 0xace9001c, 0x318c0, -0x246305fc, 0x2e31021, 0xace20008, 0x8ee204b4, 0xace20010, 0xaf880120, -0x92e24e10, 0x14400037, 0x24070001, 0x8ee24e20, 0x210c0, 0x24425028, -0x2e22021, 0x8c830000, 0x24020007, 0x1462001f, 0x0, 0x8ee34e20, -0x8ee24e24, 0x1062001b, 0x24030040, 0x8c820004, 0x24420001, 0xac820004, -0x8ee24e24, 0x8ee54e20, 0x24420001, 0x10430007, 0x0, 0x8ee24e24, -0x24420001, 0x10a20005, 0x0, 0x8002241, 0x0, 0x14a00005, -0x0, 0x8f820128, 0x24420020, 0xaf820128, 0x8f820128, 0x8c820004, -0x2c420011, 0x50400013, 0xac800000, 0x8002257, 0x0, 0x8ee24e20, -0x24030040, 0x24420001, 0x50430003, 0x1021, 0x8ee24e20, 0x24420001, -0xaee24e20, 0x8ee24e20, 0x210c0, 0x24425028, 0x2e22021, 0x24020007, -0xac820000, 0x24020001, 0xac820004, 0x54e0000c, 0xaee905f8, 0x3c040001, -0x248447b4, 0xafa00010, 0xafa00014, 0x8ee605f8, 0x8f470228, 0x3c050009, -0xc002403, 0x34a5f000, 0x80022da, 0x0, 0x8f830120, 0x27623800, -0x24660020, 0xc2102b, 0x50400001, 0x27663000, 0x8f820128, 0x10c20004, -0x0, 0x8f820124, 0x14c20007, 0x0, 0x8ee201a0, 0x3821, -0x24420001, 0xaee201a0, 0x80022be, 0x8ee201a0, 0x8ee205f8, 0xac62001c, -0x8ee40490, 0x8ee50494, 0x2462001c, 0xac620008, 0x24020008, 0xa462000e, -0x24020011, 0xac620018, 0xac640000, 0xac650004, 0x8ee204b4, 0xac620010, -0xaf860120, 0x92e24e10, 0x14400037, 0x24070001, 0x8ee24e20, 0x210c0, -0x24425028, 0x2e22021, 0x8c830000, 0x24020012, 0x1462001f, 0x0, -0x8ee34e20, 0x8ee24e24, 0x1062001b, 0x24030040, 0x8c820004, 0x24420001, -0xac820004, 0x8ee24e24, 0x8ee54e20, 0x24420001, 0x10430007, 0x0, -0x8ee24e24, 0x24420001, 0x10a20005, 0x0, 0x80022a8, 0x0, -0x14a00005, 0x0, 0x8f820128, 0x24420020, 0xaf820128, 0x8f820128, -0x8c820004, 0x2c420011, 0x50400013, 0xac800000, 0x80022be, 0x0, -0x8ee24e20, 0x24030040, 0x24420001, 0x50430003, 0x1021, 0x8ee24e20, -0x24420001, 0xaee24e20, 0x8ee24e20, 0x210c0, 0x24425028, 0x2e22021, -0x24020012, 0xac820000, 0x24020001, 0xac820004, 0x14e0001b, 0x0, -0x3c040001, 0x248447bc, 0xafa00010, 0xafa00014, 0x8ee605f8, 0x8f470228, -0x3c050009, 0xc002403, 0x34a5f001, 0x8ee201ac, 0x24420001, 0xaee201ac, -0x80022da, 0x8ee201ac, 0x3c040001, 0x248447c8, 0xafa00014, 0x8ee605f8, -0x8f470228, 0x3c050009, 0xc002403, 0x34a5f005, 0x8ee201a8, 0x24420001, -0xaee201a8, 0x8ee201a8, 0x8ee2014c, 0x24420001, 0xaee2014c, 0x8ee2014c, -0x8ee2015c, 0x24420001, 0xaee2015c, 0x8ee2015c, 0x8f43022c, 0x8f42010c, -0x14620009, 0x24020002, 0xaf820064, 0x8f820064, 0x14400005, 0x0, -0x8f43022c, 0x8f42010c, 0x1462f877, 0x0, 0x8fbf0044, 0x8fb60040, -0x8fb5003c, 0x8fb40038, 0x8fb30034, 0x8fb20030, 0x8fb1002c, 0x8fb00028, -0x3e00008, 0x27bd0048, 0x27bdfff8, 0x2408ffff, 0x10a00014, 0x4821, -0x3c0aedb8, 0x354a8320, 0x90870000, 0x24840001, 0x3021, 0x1071026, -0x30420001, 0x10400002, 0x81842, 0x6a1826, 0x604021, 0x24c60001, -0x2cc20008, 0x1440fff7, 0x73842, 0x25290001, 0x125102b, 0x1440fff0, -0x0, 0x1001021, 0x3e00008, 0x27bd0008, 0x0, 0x0, -0x27bdffe8, 0x27642800, 0xafbf0010, 0xc002488, 0x24051000, 0x24020021, -0xaf800100, 0xaf800104, 0xaf800108, 0xaf800110, 0xaf800114, 0xaf800118, -0xaf800120, 0xaf800124, 0xaf800128, 0xaf800130, 0xaf800134, 0xaf800138, -0xaee04e18, 0xaee04e1c, 0xaee04e20, 0xaee04e24, 0xaf82011c, 0x8f420218, -0x30420040, 0x10400004, 0x0, 0x8f82011c, 0x34420004, 0xaf82011c, -0x8fbf0010, 0x3e00008, 0x27bd0018, 0x27bdffe0, 0xafbf0018, 0x8f820104, -0xafa20010, 0x8f820100, 0x3c050002, 0xafa20014, 0x8f8600b0, 0x8f87011c, -0x3c040001, 0x2484487c, 0xc002403, 0x34a5f000, 0x8f8300b0, 0x3c027f00, -0x621824, 0x3c020400, 0x1062002b, 0x43102b, 0x14400008, 0x3c022000, -0x3c020100, 0x10620026, 0x3c020200, 0x10620013, 0x0, 0x8002372, -0x0, 0x1062000a, 0x43102b, 0x1040001e, 0x3c024000, 0x1462001c, -0x0, 0x8ee2018c, 0x24420001, 0xaee2018c, 0x8002372, 0x8ee2018c, -0x8ee20188, 0x24420001, 0xaee20188, 0x8002372, 0x8ee20188, 0x8f82011c, -0x34420002, 0xaf82011c, 0x8f830104, 0x8f8200b0, 0x34420001, 0xaf8200b0, -0xaf830104, 0x8f82011c, 0x2403fffd, 0x431024, 0xaf82011c, 0x8ee2019c, -0x24420001, 0xaee2019c, 0x8002375, 0x8ee2019c, 0x8f8200b0, 0x34420001, -0xaf8200b0, 0x8fbf0018, 0x3e00008, 0x27bd0020, 0x27bdffe0, 0xafbf001c, -0xafb00018, 0x8f820120, 0xafa20010, 0x8f820124, 0x3c050001, 0xafa20014, -0x8f8600a0, 0x8f87011c, 0x3c040001, 0x24844888, 0xc002403, 0x34a5f000, -0x8f8300a0, 0x3c027f00, 0x621824, 0x3c020400, 0x10620055, 0x8021, -0x43102b, 0x14400008, 0x3c042000, 0x3c020100, 0x1062004f, 0x3c020200, -0x1062003c, 0x0, 0x80023e0, 0x0, 0x10640005, 0x83102b, -0x10400047, 0x3c024000, 0x14620045, 0x0, 0x8f8200a0, 0x441024, -0x10400006, 0x0, 0x8ee20190, 0x24420001, 0xaee20190, 0x80023a9, -0x8ee20190, 0x8ee20194, 0x24420001, 0xaee20194, 0x8ee20194, 0x8f82011c, -0x34420002, 0xaf82011c, 0x8f82011c, 0x30420200, 0x1040001b, 0x0, -0x8f8300a0, 0x8f840124, 0x8f8200ac, 0x14400007, 0x24020001, 0x3c020001, -0x3442f000, 0x621024, 0x50400001, 0x24100001, 0x24020001, 0x1200000d, -0xaf8200a0, 0x8f820124, 0x2442ffe0, 0xaf820124, 0x8f820124, 0x8f820124, -0x27633000, 0x43102b, 0x10400005, 0x276237e0, 0xaf820124, 0x80023ca, -0x0, 0xaf840124, 0x8f82011c, 0x2403fffd, 0x431024, 0x80023e3, -0xaf82011c, 0x8f82011c, 0x34420002, 0xaf82011c, 0x8f830124, 0x8f8200a0, -0x34420001, 0xaf8200a0, 0xaf830124, 0x8f82011c, 0x2403fffd, 0x431024, -0xaf82011c, 0x8ee20198, 0x24420001, 0xaee20198, 0x80023e3, 0x8ee20198, -0x8f8200a0, 0x34420001, 0xaf8200a0, 0x8fbf001c, 0x8fb00018, 0x3e00008, -0x27bd0020, 0x0, 0x3c020001, 0x8c424f88, 0x27bdffe8, 0xafbf0014, -0x14400012, 0xafb00010, 0x3c100001, 0x261050c0, 0x2002021, 0xc002488, -0x24052000, 0x26021fe0, 0x3c010001, 0xac225094, 0x3c010001, 0xac225090, -0xaf420250, 0x24022000, 0xaf500254, 0xaf420258, 0x24020001, 0x3c010001, -0xac224f88, 0x8fbf0014, 0x8fb00010, 0x3e00008, 0x27bd0018, 0x3c030001, -0x8c635094, 0x8c820000, 0x8fa80010, 0x8fa90014, 0xac620000, 0x3c020001, -0x8c425094, 0x8c830004, 0xac430004, 0xac450008, 0x8f840054, 0x2443ffe0, -0xac460010, 0xac470014, 0xac480018, 0xac49001c, 0x3c010001, 0xac235094, -0xac44000c, 0x3c020001, 0x244250c0, 0x62182b, 0x10600005, 0x0, -0x3c020001, 0x8c425090, 0x3c010001, 0xac225094, 0x3c030001, 0x8c635094, -0x3c020001, 0x8c424f70, 0xac620000, 0x3c030001, 0x8c635094, 0x3c020001, -0x8c424f70, 0xac620004, 0x3e00008, 0xaf430250, 0x3c030001, 0x8c635094, -0x3c020001, 0x8c424f70, 0x27bdffd0, 0xafb40020, 0x8fb40040, 0xafb00010, -0x808021, 0xafb50024, 0x8fb50044, 0x8fa40048, 0xafb10014, 0xa08821, -0xafbf0028, 0xafb3001c, 0xafb20018, 0xac620000, 0x3c050001, 0x8ca55094, -0x3c020001, 0x8c424f70, 0xc09021, 0xe09821, 0x10800006, 0xaca20004, -0x24a50008, 0xc002490, 0x24060018, 0x800244e, 0x0, 0x24a40008, -0xc002488, 0x24050018, 0x3c020001, 0x8c425094, 0x3c050001, 0x24a550c0, -0x2442ffe0, 0x3c010001, 0xac225094, 0x45102b, 0x10400005, 0x0, -0x3c020001, 0x8c425090, 0x3c010001, 0xac225094, 0x3c030001, 0x8c635094, -0x8e020000, 0xac620000, 0x3c030001, 0x8c635094, 0x8e020004, 0xac620004, -0xac710008, 0x8f840054, 0x2462ffe0, 0x3c010001, 0xac225094, 0x45102b, -0xac720010, 0xac730014, 0xac740018, 0xac75001c, 0x10400005, 0xac64000c, -0x3c020001, 0x8c425090, 0x3c010001, 0xac225094, 0x3c030001, 0x8c635094, -0x3c020001, 0x8c424f70, 0xac620000, 0x3c030001, 0x8c635094, 0x3c020001, -0x8c424f70, 0xac620004, 0xaf430250, 0x8fbf0028, 0x8fb50024, 0x8fb40020, -0x8fb3001c, 0x8fb20018, 0x8fb10014, 0x8fb00010, 0x3e00008, 0x27bd0030, -0x10a00005, 0x0, 0xac800000, 0x24a5fffc, 0x14a0fffd, 0x24840004, -0x3e00008, 0x0, 0x10c00007, 0x0, 0x8c820000, 0x24840004, -0x24c6fffc, 0xaca20000, 0x14c0fffb, 0x24a50004, 0x3e00008, 0x0, -0x10c00007, 0x0, 0x8ca20000, 0x24a50004, 0x24c6fffc, 0xac820000, -0x14c0fffb, 0x24840004, 0x3e00008, 0x0, 0x3e00008, 0x0, -0x27bdffd8, 0xafbf0020, 0x8ee304d4, 0x8ee204d0, 0x10620436, 0x0, -0x8ee204d4, 0x8ee304ec, 0x21100, 0x626021, 0x95870008, 0x8d8a0000, -0x8d8b0004, 0x958d000a, 0x8ee2724c, 0x8ee3725c, 0x30e4ffff, 0x441021, -0x62182b, 0x10600015, 0x31a20004, 0x8f8200d8, 0x8ee37248, 0x431023, -0xaee2725c, 0x8ee2725c, 0x1c400003, 0x3c030001, 0x431021, 0xaee2725c, -0x8ee2724c, 0x8ee3725c, 0x441021, 0x62182b, 0x10600006, 0x31a20004, -0x8ee201b4, 0x24420001, 0xaee201b4, 0x80028e1, 0x8ee201b4, 0x10400240, -0x31a20200, 0x1040014d, 0x4821, 0x96e2045a, 0x30420010, 0x10400149, -0x0, 0x8f840100, 0x27623000, 0x24850020, 0xa2102b, 0x50400001, -0x27652800, 0x8f820108, 0x10a20004, 0x0, 0x8f820104, 0x14a20006, -0x2402000c, 0x8ee201a4, 0x24420001, 0xaee201a4, 0x800252c, 0x8ee201a4, -0xac8a0000, 0xac8b0004, 0x8ee37254, 0x24060005, 0xa482000e, 0xac860018, -0xac830008, 0x8ee204d4, 0xac82001c, 0x8ee204b8, 0xac820010, 0xaf850100, -0x92e204dc, 0x14400036, 0x24090001, 0x8ee24e18, 0x210c0, 0x24424e28, -0x2e22021, 0x8c820000, 0x1446001f, 0x0, 0x8ee34e18, 0x8ee24e1c, -0x1062001b, 0x24030040, 0x8c820004, 0x24420001, 0xac820004, 0x8ee24e1c, -0x8ee54e18, 0x24420001, 0x10430007, 0x0, 0x8ee24e1c, 0x24420001, -0x10a20005, 0x0, 0x8002516, 0x0, 0x14a00005, 0x0, -0x8f820108, 0x24420020, 0xaf820108, 0x8f820108, 0x8c820004, 0x2c420011, -0x50400013, 0xac800000, 0x800252c, 0x0, 0x8ee24e18, 0x24030040, -0x24420001, 0x50430003, 0x1021, 0x8ee24e18, 0x24420001, 0xaee24e18, -0x8ee24e18, 0x210c0, 0x24424e28, 0x2e22021, 0x24020005, 0xac820000, -0x24020001, 0xac820004, 0x1520000a, 0x3c040001, 0xafab0010, 0x8ee27254, -0x3c040001, 0x24844af0, 0x3c050004, 0xafa20014, 0x8ee604d4, 0x80028be, -0x34a5f114, 0x8ee27254, 0x34843800, 0x3641821, 0x24420010, 0x43102b, -0x14400073, 0x0, 0x8ee27254, 0x24480010, 0x3641021, 0x102102b, -0x14400002, 0x3c02ffff, 0x1024021, 0x8f850100, 0x27623000, 0x24a60020, -0xc2102b, 0x50400001, 0x27662800, 0x8f820108, 0x10c20004, 0x0, -0x8f820104, 0x14c20007, 0x2563000c, 0x8ee201a4, 0x4821, 0x24420001, -0xaee201a4, 0x80025a0, 0x8ee201a4, 0x2c64000c, 0x1441021, 0xaca20000, -0xaca30004, 0x24e2fff4, 0xa4a2000e, 0x24020006, 0xaca80008, 0xaca20018, -0x8ee204d4, 0xaca2001c, 0x8ee204b8, 0x3c030002, 0x431025, 0xaca20010, -0xaf860100, 0x92e204dc, 0x14400037, 0x24090001, 0x8ee24e18, 0x210c0, -0x24424e28, 0x2e22021, 0x8c830000, 0x24020005, 0x1462001f, 0x0, -0x8ee34e18, 0x8ee24e1c, 0x1062001b, 0x24030040, 0x8c820004, 0x24420001, -0xac820004, 0x8ee24e1c, 0x8ee54e18, 0x24420001, 0x10430007, 0x0, -0x8ee24e1c, 0x24420001, 0x10a20005, 0x0, 0x800258a, 0x0, -0x14a00005, 0x0, 0x8f820108, 0x24420020, 0xaf820108, 0x8f820108, -0x8c820004, 0x2c420011, 0x50400013, 0xac800000, 0x80025a0, 0x0, -0x8ee24e18, 0x24030040, 0x24420001, 0x50430003, 0x1021, 0x8ee24e18, -0x24420001, 0xaee24e18, 0x8ee24e18, 0x210c0, 0x24424e28, 0x2e22021, -0x24020005, 0xac820000, 0x24020001, 0xac820004, 0x1520000a, 0x2508fffc, -0xafab0010, 0x8ee27254, 0x3c040001, 0x24844af0, 0x3c050004, 0xafa20014, -0x8ee604d4, 0x80028be, 0x34a5f125, 0x34028100, 0xa5020000, 0x9582000e, -0x800261d, 0xa5020002, 0x8f850100, 0x27623000, 0x24a60020, 0xc2102b, -0x50400001, 0x27662800, 0x8f820108, 0x10c20004, 0x0, 0x8f820104, -0x14c20007, 0x2563000c, 0x8ee201a4, 0x4821, 0x24420001, 0xaee201a4, -0x800260d, 0x8ee201a4, 0x2c64000c, 0x1441021, 0xaca20000, 0xaca30004, -0x8ee37254, 0x24e2fff4, 0xa4a2000e, 0x24020006, 0xaca20018, 0x24630010, -0xaca30008, 0x8ee204d4, 0xaca2001c, 0x8ee204b8, 0x3c030002, 0x431025, -0xaca20010, 0xaf860100, 0x92e204dc, 0x14400037, 0x24090001, 0x8ee24e18, -0x210c0, 0x24424e28, 0x2e22021, 0x8c830000, 0x24020005, 0x1462001f, -0x0, 0x8ee34e18, 0x8ee24e1c, 0x1062001b, 0x24030040, 0x8c820004, -0x24420001, 0xac820004, 0x8ee24e1c, 0x8ee54e18, 0x24420001, 0x10430007, -0x0, 0x8ee24e1c, 0x24420001, 0x10a20005, 0x0, 0x80025f7, -0x0, 0x14a00005, 0x0, 0x8f820108, 0x24420020, 0xaf820108, -0x8f820108, 0x8c820004, 0x2c420011, 0x50400013, 0xac800000, 0x800260d, -0x0, 0x8ee24e18, 0x24030040, 0x24420001, 0x50430003, 0x1021, -0x8ee24e18, 0x24420001, 0xaee24e18, 0x8ee24e18, 0x210c0, 0x24424e28, -0x2e22021, 0x24020005, 0xac820000, 0x24020001, 0xac820004, 0x1520000a, -0x34028100, 0xafab0010, 0x8ee27254, 0x3c040001, 0x24844af0, 0x3c050004, -0xafa20014, 0x8ee604d4, 0x80028be, 0x34a5f015, 0x8ee37254, 0xa462000c, -0x8ee37254, 0x9582000e, 0xa462000e, 0x8002681, 0x24e70004, 0x8f840100, -0x27623000, 0x24850020, 0xa2102b, 0x50400001, 0x27652800, 0x8f820108, -0x10a20004, 0x0, 0x8f820104, 0x14a20007, 0x24020006, 0x8ee201a4, -0x4821, 0x24420001, 0xaee201a4, 0x8002677, 0x8ee201a4, 0xac8a0000, -0xac8b0004, 0x8ee37254, 0xa487000e, 0xac820018, 0xac830008, 0x8ee204d4, -0xac82001c, 0x8ee204b8, 0x3c030002, 0x431025, 0xac820010, 0xaf850100, -0x92e204dc, 0x14400037, 0x24090001, 0x8ee24e18, 0x210c0, 0x24424e28, -0x2e22021, 0x8c830000, 0x24020005, 0x1462001f, 0x0, 0x8ee34e18, -0x8ee24e1c, 0x1062001b, 0x24030040, 0x8c820004, 0x24420001, 0xac820004, -0x8ee24e1c, 0x8ee54e18, 0x24420001, 0x10430007, 0x0, 0x8ee24e1c, -0x24420001, 0x10a20005, 0x0, 0x8002661, 0x0, 0x14a00005, -0x0, 0x8f820108, 0x24420020, 0xaf820108, 0x8f820108, 0x8c820004, -0x2c420011, 0x50400013, 0xac800000, 0x8002677, 0x0, 0x8ee24e18, -0x24030040, 0x24420001, 0x50430003, 0x1021, 0x8ee24e18, 0x24420001, -0xaee24e18, 0x8ee24e18, 0x210c0, 0x24424e28, 0x2e22021, 0x24020005, -0xac820000, 0x24020001, 0xac820004, 0x15200009, 0x3c050004, 0xafab0010, -0x8ee27254, 0x3c040001, 0x24844af0, 0xafa20014, 0x8ee604d4, 0x80028be, -0x34a5f004, 0x8ee2724c, 0x30e7ffff, 0x471021, 0xaee2724c, 0x8ee204d4, -0x8ee304ec, 0x8ee47248, 0x21100, 0x431021, 0xac44000c, 0x8ee27248, -0xafa20018, 0x8ee3724c, 0xafa3001c, 0x8ee2724c, 0x2c42003c, 0x10400004, -0x24620001, 0x2403fffe, 0x431024, 0xafa2001c, 0x8ee27254, 0x3c060001, -0x34c63800, 0x8ee3724c, 0x2405fff8, 0x471021, 0x24420007, 0x451024, -0x24630007, 0xaee27248, 0x8ee2725c, 0x8ee47248, 0x651824, 0x431023, -0xaee2725c, 0x3661021, 0x82202b, 0x14800004, 0x3c03ffff, 0x8ee27248, -0x431021, 0xaee27248, 0x8ee27248, 0xaee27254, 0x8f8200f0, 0x24470008, -0x27621800, 0xe2102b, 0x50400001, 0x27671000, 0x8f8200f4, 0x14e20007, -0x0, 0x8ee201b0, 0x4821, 0x24420001, 0xaee201b0, 0x80026c4, -0x8ee201b0, 0x8f8200f0, 0x24090001, 0x8fa30018, 0x8fa4001c, 0xac430000, -0xac440004, 0xaf8700f0, 0x15200012, 0xd1142, 0x8f8200f0, 0xafa20010, -0x8f8200f4, 0x3c040001, 0x24844afc, 0xafa20014, 0x8fa60018, 0x8fa7001c, -0x3c050004, 0xc002403, 0x34a5f005, 0x8ee20088, 0x24420001, 0xaee20088, -0x8ee20088, 0x80028d3, 0xaee0724c, 0x30430003, 0x24020002, 0x10620016, -0x28620003, 0x10400005, 0x24020001, 0x10620008, 0x0, 0x8002703, -0x0, 0x24020003, 0x10620017, 0x0, 0x8002703, 0x0, -0x8ee200e8, 0x8ee300ec, 0x24630001, 0x2c640001, 0x441021, 0xaee200e8, -0xaee300ec, 0x8ee200e8, 0x8002703, 0x8ee300ec, 0x8ee200f0, 0x8ee300f4, -0x24630001, 0x2c640001, 0x441021, 0xaee200f0, 0xaee300f4, 0x8ee200f0, -0x8002703, 0x8ee300f4, 0x8ee200f8, 0x8ee300fc, 0x24630001, 0x2c640001, -0x441021, 0xaee200f8, 0xaee300fc, 0x8ee200f8, 0x8ee300fc, 0x8ee2724c, -0x8ee400e0, 0x8ee500e4, 0x401821, 0x1021, 0xa32821, 0xa3302b, -0x822021, 0x862021, 0xaee400e0, 0xaee500e4, 0x80028d3, 0xaee0724c, -0x30e2ffff, 0x104001c1, 0x31a20200, 0x1040014d, 0x4821, 0x96e2045a, -0x30420010, 0x10400149, 0x0, 0x8f840100, 0x27623000, 0x24850020, -0xa2102b, 0x50400001, 0x27652800, 0x8f820108, 0x10a20004, 0x0, -0x8f820104, 0x14a20006, 0x2402000c, 0x8ee201a4, 0x24420001, 0xaee201a4, -0x800276e, 0x8ee201a4, 0xac8a0000, 0xac8b0004, 0x8ee37254, 0x24060005, -0xa482000e, 0xac860018, 0xac830008, 0x8ee204d4, 0xac82001c, 0x8ee204b8, -0xac820010, 0xaf850100, 0x92e204dc, 0x14400036, 0x24090001, 0x8ee24e18, -0x210c0, 0x24424e28, 0x2e22021, 0x8c820000, 0x1446001f, 0x0, -0x8ee34e18, 0x8ee24e1c, 0x1062001b, 0x24030040, 0x8c820004, 0x24420001, -0xac820004, 0x8ee24e1c, 0x8ee54e18, 0x24420001, 0x10430007, 0x0, -0x8ee24e1c, 0x24420001, 0x10a20005, 0x0, 0x8002758, 0x0, -0x14a00005, 0x0, 0x8f820108, 0x24420020, 0xaf820108, 0x8f820108, -0x8c820004, 0x2c420011, 0x50400013, 0xac800000, 0x800276e, 0x0, -0x8ee24e18, 0x24030040, 0x24420001, 0x50430003, 0x1021, 0x8ee24e18, -0x24420001, 0xaee24e18, 0x8ee24e18, 0x210c0, 0x24424e28, 0x2e22021, -0x24020005, 0xac820000, 0x24020001, 0xac820004, 0x1520000a, 0x3c040001, -0xafab0010, 0x8ee27254, 0x3c040001, 0x24844af0, 0x3c050004, 0xafa20014, -0x8ee604d4, 0x80028be, 0x34a5f014, 0x8ee27254, 0x34843800, 0x3641821, -0x24420010, 0x43102b, 0x14400073, 0x0, 0x8ee27254, 0x24480010, -0x3641021, 0x102102b, 0x14400002, 0x3c02ffff, 0x1024021, 0x8f850100, -0x27623000, 0x24a60020, 0xc2102b, 0x50400001, 0x27662800, 0x8f820108, -0x10c20004, 0x0, 0x8f820104, 0x14c20007, 0x2563000c, 0x8ee201a4, -0x4821, 0x24420001, 0xaee201a4, 0x80027e2, 0x8ee201a4, 0x2c64000c, -0x1441021, 0xaca20000, 0xaca30004, 0x24e2fff4, 0xa4a2000e, 0x24020006, -0xaca80008, 0xaca20018, 0x8ee204d4, 0xaca2001c, 0x8ee204b8, 0x3c030002, -0x431025, 0xaca20010, 0xaf860100, 0x92e204dc, 0x14400037, 0x24090001, -0x8ee24e18, 0x210c0, 0x24424e28, 0x2e22021, 0x8c830000, 0x24020005, -0x1462001f, 0x0, 0x8ee34e18, 0x8ee24e1c, 0x1062001b, 0x24030040, -0x8c820004, 0x24420001, 0xac820004, 0x8ee24e1c, 0x8ee54e18, 0x24420001, -0x10430007, 0x0, 0x8ee24e1c, 0x24420001, 0x10a20005, 0x0, -0x80027cc, 0x0, 0x14a00005, 0x0, 0x8f820108, 0x24420020, -0xaf820108, 0x8f820108, 0x8c820004, 0x2c420011, 0x50400013, 0xac800000, -0x80027e2, 0x0, 0x8ee24e18, 0x24030040, 0x24420001, 0x50430003, -0x1021, 0x8ee24e18, 0x24420001, 0xaee24e18, 0x8ee24e18, 0x210c0, -0x24424e28, 0x2e22021, 0x24020005, 0xac820000, 0x24020001, 0xac820004, -0x1520000a, 0x2508fffc, 0xafab0010, 0x8ee27254, 0x3c040001, 0x24844af0, -0x3c050004, 0xafa20014, 0x8ee604d4, 0x80028be, 0x34a5f015, 0x34028100, -0xa5020000, 0x9582000e, 0x800285f, 0xa5020002, 0x8f850100, 0x27623000, -0x24a60020, 0xc2102b, 0x50400001, 0x27662800, 0x8f820108, 0x10c20004, -0x0, 0x8f820104, 0x14c20007, 0x2563000c, 0x8ee201a4, 0x4821, -0x24420001, 0xaee201a4, 0x800284f, 0x8ee201a4, 0x2c64000c, 0x1441021, -0xaca20000, 0xaca30004, 0x8ee37254, 0x24e2fff4, 0xa4a2000e, 0x24020006, -0xaca20018, 0x24630010, 0xaca30008, 0x8ee204d4, 0xaca2001c, 0x8ee204b8, -0x3c030002, 0x431025, 0xaca20010, 0xaf860100, 0x92e204dc, 0x14400037, -0x24090001, 0x8ee24e18, 0x210c0, 0x24424e28, 0x2e22021, 0x8c830000, -0x24020005, 0x1462001f, 0x0, 0x8ee34e18, 0x8ee24e1c, 0x1062001b, -0x24030040, 0x8c820004, 0x24420001, 0xac820004, 0x8ee24e1c, 0x8ee54e18, -0x24420001, 0x10430007, 0x0, 0x8ee24e1c, 0x24420001, 0x10a20005, -0x0, 0x8002839, 0x0, 0x14a00005, 0x0, 0x8f820108, -0x24420020, 0xaf820108, 0x8f820108, 0x8c820004, 0x2c420011, 0x50400013, -0xac800000, 0x800284f, 0x0, 0x8ee24e18, 0x24030040, 0x24420001, -0x50430003, 0x1021, 0x8ee24e18, 0x24420001, 0xaee24e18, 0x8ee24e18, -0x210c0, 0x24424e28, 0x2e22021, 0x24020005, 0xac820000, 0x24020001, -0xac820004, 0x1520000a, 0x34028100, 0xafab0010, 0x8ee27254, 0x3c040001, -0x24844af0, 0x3c050004, 0xafa20014, 0x8ee604d4, 0x80028be, 0x34a5f016, -0x8ee37254, 0xa462000c, 0x8ee37254, 0x9582000e, 0xa462000e, 0x80028c2, -0x24e70004, 0x8f830100, 0x27623000, 0x24640020, 0x82102b, 0x50400001, -0x27642800, 0x8f820108, 0x10820004, 0x0, 0x8f820104, 0x14820007, -0x24050005, 0x8ee201a4, 0x4821, 0x24420001, 0xaee201a4, 0x80028b6, -0x8ee201a4, 0xac6a0000, 0xac6b0004, 0x8ee27254, 0xa467000e, 0xac650018, -0xac620008, 0x8ee204d4, 0xac62001c, 0x8ee204b8, 0xac620010, 0xaf840100, -0x92e204dc, 0x14400036, 0x24090001, 0x8ee24e18, 0x210c0, 0x24424e28, -0x2e22021, 0x8c820000, 0x1445001f, 0x0, 0x8ee34e18, 0x8ee24e1c, -0x1062001b, 0x24030040, 0x8c820004, 0x24420001, 0xac820004, 0x8ee24e1c, -0x8ee54e18, 0x24420001, 0x10430007, 0x0, 0x8ee24e1c, 0x24420001, -0x10a20005, 0x0, 0x80028a0, 0x0, 0x14a00005, 0x0, -0x8f820108, 0x24420020, 0xaf820108, 0x8f820108, 0x8c820004, 0x2c420011, -0x50400013, 0xac800000, 0x80028b6, 0x0, 0x8ee24e18, 0x24030040, -0x24420001, 0x50430003, 0x1021, 0x8ee24e18, 0x24420001, 0xaee24e18, -0x8ee24e18, 0x210c0, 0x24424e28, 0x2e22021, 0x24020005, 0xac820000, -0x24020001, 0xac820004, 0x1520000b, 0x3c050004, 0x3c040001, 0x24844b08, -0xafab0010, 0xafa00014, 0x8ee604d4, 0x34a5f017, 0xc002403, 0x30e7ffff, -0x80028e1, 0x0, 0x8ee27254, 0x3c050001, 0x30e4ffff, 0x441021, -0xaee27254, 0x8ee2724c, 0x8ee37254, 0x34a53800, 0x441021, 0xaee2724c, -0x3651021, 0x62182b, 0x14600004, 0x3c03ffff, 0x8ee27254, 0x431021, -0xaee27254, 0x8ee304d4, 0x96e20458, 0x24630001, 0x2442ffff, 0x621824, -0xaee304d4, 0x8ee304d4, 0x8ee204d0, 0x14620005, 0x0, 0x8f820060, -0x2403fff7, 0x431024, 0xaf820060, 0x8fbf0020, 0x3e00008, 0x27bd0028, -0x27bdffe0, 0xafbf0018, 0x8ee304d8, 0x8ee204d0, 0x10620189, 0x0, -0x8ee204d8, 0x8ee304ec, 0x21100, 0x621821, 0x94670008, 0x92e204dd, -0x8c680000, 0x8c690004, 0x10400023, 0x946a000a, 0x8ee204b8, 0x34460400, -0x31420200, 0x1040001f, 0x0, 0x96e2045a, 0x30420010, 0x1040001b, -0x3c028000, 0x3c010001, 0x370821, 0xac2283c8, 0x8ee27254, 0x9464000e, -0x3c050001, 0x34a53800, 0x24420004, 0xaee27254, 0x8ee37254, 0x42400, -0x3651021, 0x3c010001, 0x370821, 0xac2483cc, 0x62182b, 0x14600005, -0x24e70004, 0x8ee27254, 0x3c03ffff, 0x431021, 0xaee27254, 0x8ee27254, -0x8002917, 0xaee27248, 0x8ee604b8, 0x8ee2725c, 0x30e4ffff, 0x44102a, -0x10400015, 0x0, 0x8f8200d8, 0x8ee37248, 0x431023, 0xaee2725c, -0x8ee2725c, 0x1c400007, 0x44102a, 0x8ee2725c, 0x3c030001, 0x431021, -0xaee2725c, 0x8ee2725c, 0x44102a, 0x10400006, 0x0, 0x8ee201b4, -0x24420001, 0xaee201b4, 0x8002a72, 0x8ee201b4, 0x3c020001, 0x571021, -0x8c4283c8, 0x54400001, 0x24e7fffc, 0x31420004, 0x104000b9, 0x30e2ffff, -0x3c020001, 0x571021, 0x8c4283c8, 0x1040002f, 0x5021, 0x8f840100, -0x27623000, 0x24850020, 0xa2102b, 0x50400001, 0x27652800, 0x8f820108, -0x10a20032, 0x0, 0x8f820104, 0x10a2002f, 0x24020015, 0xac880000, -0xac890004, 0x8ee37254, 0xa487000e, 0xac820018, 0xac830008, 0x8ee204d8, -0x3c030001, 0x771821, 0x8c6383cc, 0xac860010, 0x431025, 0xac82001c, -0xaf850100, 0x92e204dc, 0x14400066, 0x240a0001, 0x8ee24e18, 0x24030040, -0x24420001, 0x50430003, 0x1021, 0x8ee24e18, 0x24420001, 0xaee24e18, -0x8ee24e18, 0x210c0, 0x24424e28, 0x2e21821, 0x24020015, 0xac620000, -0x24020001, 0x80029bf, 0xac620004, 0x8f840100, 0x27623000, 0x24850020, -0xa2102b, 0x50400001, 0x27652800, 0x8f820108, 0x10a20004, 0x0, -0x8f820104, 0x14a20006, 0x24020006, 0x8ee201a4, 0x24420001, 0xaee201a4, -0x80029bf, 0x8ee201a4, 0xac880000, 0xac890004, 0x8ee37254, 0xa487000e, -0xac820018, 0xac830008, 0x8ee204d8, 0xac860010, 0xac82001c, 0xaf850100, -0x92e204dc, 0x14400037, 0x240a0001, 0x8ee24e18, 0x210c0, 0x24424e28, -0x2e22021, 0x8c830000, 0x24020005, 0x1462001f, 0x0, 0x8ee34e18, -0x8ee24e1c, 0x1062001b, 0x24030040, 0x8c820004, 0x24420001, 0xac820004, -0x8ee24e1c, 0x8ee54e18, 0x24420001, 0x10430007, 0x0, 0x8ee24e1c, -0x24420001, 0x10a20005, 0x0, 0x80029a9, 0x0, 0x14a00005, -0x0, 0x8f820108, 0x24420020, 0xaf820108, 0x8f820108, 0x8c820004, -0x2c420011, 0x50400013, 0xac800000, 0x80029bf, 0x0, 0x8ee24e18, -0x24030040, 0x24420001, 0x50430003, 0x1021, 0x8ee24e18, 0x24420001, -0xaee24e18, 0x8ee24e18, 0x210c0, 0x24424e28, 0x2e22021, 0x24020005, -0xac820000, 0x24020001, 0xac820004, 0x1540000a, 0x24020001, 0xafa90010, -0x8ee27254, 0x3c040001, 0x24844af0, 0x3c050004, 0xafa20014, 0x8ee604d4, -0x8002a4f, 0x34a5f204, 0xa2e204dd, 0x8ee204d8, 0x8ee304ec, 0x8ee47248, -0x3c060001, 0x34c63800, 0x3c010001, 0x370821, 0xac2083c8, 0x3c010001, -0x370821, 0xac2083cc, 0x21100, 0x431021, 0xac44000c, 0x8ee27254, -0x2405fff8, 0x30e3ffff, 0x431021, 0x24420007, 0x451024, 0x24630007, -0xaee27248, 0x8ee2725c, 0x8ee47248, 0x651824, 0x431023, 0xaee2725c, -0x3661021, 0x82202b, 0x14800004, 0x3c03ffff, 0x8ee27248, 0x431021, -0xaee27248, 0x8ee27248, 0x8002a64, 0xaee27254, 0x10400073, 0x0, -0x8f830100, 0x27623000, 0x24640020, 0x82102b, 0x14400002, 0x5021, -0x27642800, 0x8f820108, 0x10820004, 0x0, 0x8f820104, 0x14820006, -0x24050005, 0x8ee201a4, 0x24420001, 0xaee201a4, 0x8002a46, 0x8ee201a4, -0xac680000, 0xac690004, 0x8ee27254, 0xa467000e, 0xac650018, 0xac620008, -0x8ee204d8, 0xac660010, 0xac62001c, 0xaf840100, 0x92e204dc, 0x14400036, -0x240a0001, 0x8ee24e18, 0x210c0, 0x24424e28, 0x2e22021, 0x8c820000, -0x1445001f, 0x0, 0x8ee34e18, 0x8ee24e1c, 0x1062001b, 0x24030040, -0x8c820004, 0x24420001, 0xac820004, 0x8ee24e1c, 0x8ee54e18, 0x24420001, -0x10430007, 0x0, 0x8ee24e1c, 0x24420001, 0x10a20005, 0x0, -0x8002a30, 0x0, 0x14a00005, 0x0, 0x8f820108, 0x24420020, -0xaf820108, 0x8f820108, 0x8c820004, 0x2c420011, 0x50400013, 0xac800000, -0x8002a46, 0x0, 0x8ee24e18, 0x24030040, 0x24420001, 0x50430003, -0x1021, 0x8ee24e18, 0x24420001, 0xaee24e18, 0x8ee24e18, 0x210c0, -0x24424e28, 0x2e22021, 0x24020005, 0xac820000, 0x24020001, 0xac820004, -0x1540000c, 0x30e5ffff, 0x3c040001, 0x24844b08, 0x3c050004, 0xafa90010, -0xafa00014, 0x8ee604d4, 0x34a5f237, 0xc002403, 0x30e7ffff, 0x8002a72, -0x0, 0x8ee27254, 0x451021, 0xaee27254, 0x8ee2725c, 0x8ee37254, -0x3c040001, 0x34843800, 0xa2e004dd, 0x451023, 0xaee2725c, 0x3641021, -0x62182b, 0x14600004, 0x3c03ffff, 0x8ee27254, 0x431021, 0xaee27254, -0x8ee304d8, 0x96e20458, 0x24630001, 0x2442ffff, 0x621824, 0xaee304d8, -0x8ee304d8, 0x8ee204d0, 0x14620005, 0x0, 0x8f820060, 0x2403fff7, -0x431024, 0xaf820060, 0x8fbf0018, 0x3e00008, 0x27bd0020, 0x27bdffe0, -0xafbf001c, 0xafb00018, 0x8f820100, 0x8ee34e1c, 0x8f820104, 0x8f850108, -0x24020040, 0x24630001, 0x50620003, 0x1021, 0x8ee24e1c, 0x24420001, -0xaee24e1c, 0x8ee24e1c, 0x8ee34e1c, 0x210c0, 0x24424e28, 0x2e22021, -0x8ee24e18, 0x8c870004, 0x14620007, 0xa03021, 0x8f820108, 0x24420020, -0xaf820108, 0x8f820108, 0x8002aa2, 0xac800000, 0x8ee24e1c, 0x24030040, -0x24420001, 0x50430003, 0x1021, 0x8ee24e1c, 0x24420001, 0x210c0, -0x24424e28, 0x2e22021, 0x8c820004, 0x8f830108, 0x21140, 0x621821, -0xaf830108, 0xac800000, 0x8cc30018, 0x2c620002, 0x144000ba, 0x2c620004, -0x5440008d, 0x24030040, 0x2c620007, 0x104000b5, 0x2c620005, 0x144000b3, -0x0, 0x8ee204e0, 0x471021, 0xaee204e0, 0x8ee204e0, 0x8f43023c, -0x43102b, 0x144000b5, 0x0, 0x8ee304d4, 0x8ee204e8, 0x506200b1, -0xa2e004e4, 0x8f830120, 0x27623800, 0x24660020, 0xc2102b, 0x50400001, -0x27663000, 0x8f820128, 0x10c20004, 0x0, 0x8f820124, 0x14c20007, -0x0, 0x8ee201a0, 0x8021, 0x24420001, 0xaee201a0, 0x8002b13, -0x8ee201a0, 0x8ee204d4, 0xac62001c, 0x8ee404a0, 0x8ee504a4, 0x2462001c, -0xac620008, 0x24020008, 0xa462000e, 0x24020011, 0xac620018, 0xac640000, -0xac650004, 0x8ee204b4, 0xac620010, 0xaf860120, 0x92e24e10, 0x14400037, -0x24100001, 0x8ee24e20, 0x210c0, 0x24425028, 0x2e22021, 0x8c830000, -0x24020012, 0x1462001f, 0x0, 0x8ee34e20, 0x8ee24e24, 0x1062001b, -0x24030040, 0x8c820004, 0x24420001, 0xac820004, 0x8ee24e24, 0x8ee54e20, -0x24420001, 0x10430007, 0x0, 0x8ee24e24, 0x24420001, 0x10a20005, -0x0, 0x8002afd, 0x0, 0x14a00005, 0x0, 0x8f820128, -0x24420020, 0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011, 0x50400013, -0xac800000, 0x8002b13, 0x0, 0x8ee24e20, 0x24030040, 0x24420001, -0x50430003, 0x1021, 0x8ee24e20, 0x24420001, 0xaee24e20, 0x8ee24e20, -0x210c0, 0x24425028, 0x2e22021, 0x24020012, 0xac820000, 0x24020001, -0xac820004, 0x5600000b, 0x24100001, 0x8ee204d4, 0x3c040001, 0x24844b14, -0xafa00014, 0xafa20010, 0x8ee605f8, 0x8f470228, 0x3c050009, 0xc002403, -0x34a5f006, 0x16000003, 0x24020001, 0x8002b69, 0xa2e204e4, 0x8ee2016c, -0x24420001, 0xaee2016c, 0x8ee2016c, 0x8ee204d4, 0xa2e004e4, 0xaee004e0, -0xaee204e8, 0x8f42023c, 0x5040003c, 0xaee07264, 0x8ee20180, 0x24420001, -0xaee20180, 0x8ee20180, 0x8002b69, 0xaee07264, 0x8ee204f4, 0x24420001, -0x50430003, 0x1021, 0x8ee204f4, 0x24420001, 0xaee204f4, 0x8ee204f4, -0x8cc30018, 0x21080, 0x571021, 0x8c4404f8, 0x24020003, 0x1462000f, -0x0, 0x3c020001, 0x571021, 0x904283a1, 0x10400014, 0x0, -0x8ee201c8, 0x8ee35230, 0x441021, 0xaee201c8, 0x8ee201cc, 0x641821, -0x306300ff, 0x8002b59, 0xaee35230, 0x8ee201c4, 0x8ee30e00, 0x441021, -0xaee201c4, 0x8ee201cc, 0x641821, 0x306301ff, 0xaee30e00, 0x441021, -0xaee201cc, 0x8ee20000, 0x34420040, 0x8002b69, 0xaee20000, 0x94c7000e, -0x8cc2001c, 0x3c040001, 0x24844b20, 0xafa60014, 0xafa20010, 0x8cc60018, -0x3c050008, 0xc002403, 0x34a50910, 0x8fbf001c, 0x8fb00018, 0x3e00008, -0x27bd0020, 0x27bdff98, 0xafbf0060, 0xafbe005c, 0xafb60058, 0xafb50054, -0xafb40050, 0xafb3004c, 0xafb20048, 0xafb10044, 0xafb00040, 0x8f830108, -0x8f820104, 0xafa00024, 0x106203df, 0xafa0002c, 0x3c1e0001, 0x37de3800, -0x3c0bffff, 0x8f930108, 0x8e620018, 0x8f830104, 0x2443fffe, 0x2c620014, -0x104003c7, 0x31080, 0x3c010001, 0x220821, 0x8c224b30, 0x400008, -0x0, 0x9663000e, 0x8ee2724c, 0x8ee404e0, 0x431021, 0xaee2724c, -0x8e63001c, 0x96e20458, 0x24840001, 0xaee404e0, 0x24630001, 0x2442ffff, -0x621824, 0xaee304d4, 0x8f42023c, 0x82202b, 0x148003b1, 0x0, -0x8f830120, 0x27623800, 0x24660020, 0xc2102b, 0x50400001, 0x27663000, -0x8f820128, 0x10c20004, 0x0, 0x8f820124, 0x14c20007, 0x0, -0x8ee201a0, 0x8021, 0x24420001, 0xaee201a0, 0x8002bf6, 0x8ee201a0, -0x8ee204d4, 0xac62001c, 0x8ee404a0, 0x8ee504a4, 0x2462001c, 0xac620008, -0x24020008, 0xa462000e, 0x24020011, 0xac620018, 0xac640000, 0xac650004, -0x8ee204b4, 0xac620010, 0xaf860120, 0x92e24e10, 0x14400037, 0x24100001, -0x8ee24e20, 0x210c0, 0x24425028, 0x2e22021, 0x8c830000, 0x24020012, -0x1462001f, 0x0, 0x8ee34e20, 0x8ee24e24, 0x1062001b, 0x240c0040, -0x8c820004, 0x24420001, 0xac820004, 0x8ee24e24, 0x8ee34e20, 0x24420001, -0x104c0007, 0x0, 0x8ee24e24, 0x24420001, 0x10620005, 0x0, -0x8002be0, 0x0, 0x14600005, 0x0, 0x8f820128, 0x24420020, -0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011, 0x50400013, 0xac800000, -0x8002bf6, 0x0, 0x8ee24e20, 0x240c0040, 0x24420001, 0x504c0003, -0x1021, 0x8ee24e20, 0x24420001, 0xaee24e20, 0x8ee24e20, 0x210c0, -0x24425028, 0x2e22021, 0x24020012, 0x240c0001, 0xac820000, 0xac8c0004, -0x5600000d, 0x24100001, 0x8ee204d4, 0x3c040001, 0x24844b14, 0xafa00014, -0xafa20010, 0x8ee605f8, 0x8f470228, 0x3c050009, 0x34a5f006, 0xc002403, -0xafab0038, 0x8fab0038, 0x1200030a, 0x240c0001, 0x8002f11, 0x0, -0x966c001c, 0xafac002c, 0x9662001e, 0x3c0c8000, 0xafac0024, 0xae62001c, -0x8e75001c, 0x8ee204ec, 0x8ee404ec, 0x151900, 0x621021, 0x8c52000c, -0x92e27b88, 0x641821, 0x9476000a, 0x14400003, 0x32c20002, 0xaef27b94, -0xaef57b8c, 0x1040004b, 0x8021, 0x96e2045a, 0x30420002, 0x10400047, -0x0, 0x8e63001c, 0x8ee204ec, 0x32100, 0x821021, 0x8c42000c, -0x37e1821, 0x24420022, 0x43102b, 0x1440000a, 0x24050014, 0x8ee204ec, -0x821021, 0x8c44000c, 0xafab0038, 0xc002f65, 0x2484000e, 0x8fab0038, -0x8002c4a, 0x3050ffff, 0x8ee204ec, 0x821021, 0x8c42000c, 0x9450000e, -0x94430010, 0x94440012, 0x94450014, 0x2038021, 0x2048021, 0x2058021, -0x94430016, 0x94440018, 0x9445001a, 0x2038021, 0x2048021, 0x2058021, -0x9443001c, 0x9444001e, 0x94420020, 0x2038021, 0x2048021, 0x2028021, -0x101c02, 0x3202ffff, 0x628021, 0x8e63001c, 0x8ee204ec, 0x102402, -0x32900, 0xa21021, 0x8c43000c, 0x3202ffff, 0x828021, 0x37e1021, -0x24630018, 0x62182b, 0x14600009, 0x0, 0x8ee204ec, 0xa21021, -0x8c43000c, 0x101027, 0x3c01ffff, 0x230821, 0x8002c67, 0xa4220018, -0x8ee204ec, 0xa21021, 0x8c43000c, 0x101027, 0xa4620018, 0x96e2045a, -0x8821, 0x30420008, 0x14400063, 0xa021, 0x8e63001c, 0x8ee204ec, -0x33100, 0xc21021, 0x8c42000c, 0x37e1821, 0x24420022, 0x43102b, -0x14400035, 0x0, 0x8ee204ec, 0xc21021, 0x8c42000c, 0x24470010, -0x37e1021, 0xe2102b, 0x50400001, 0xeb3821, 0x8ee204ec, 0x94f10000, -0xc21021, 0x8c42000c, 0x24470016, 0x37e1021, 0xe2102b, 0x14400002, -0x2634ffec, 0xeb3821, 0x8ee204ec, 0x90e30001, 0xc21021, 0x8c42000c, -0x2447001a, 0x37e1021, 0xe2102b, 0x14400002, 0x2838821, 0xeb3821, -0x94e20000, 0x24e70002, 0x2228821, 0x37e1021, 0xe2102b, 0x50400001, -0xeb3821, 0x94e20000, 0x24e70002, 0x2228821, 0x37e1021, 0xe2102b, -0x50400001, 0xeb3821, 0x94e20000, 0x24e70002, 0x2228821, 0x37e1021, -0xe2102b, 0x50400001, 0xeb3821, 0x94e20000, 0x8002cc8, 0x2228821, -0x8ee204ec, 0xc21021, 0x8c43000c, 0x8ee204ec, 0x94710010, 0x8ee304ec, -0xc21021, 0x8c44000c, 0xc31821, 0x8c62000c, 0x2634ffec, 0x90840017, -0x8ee304ec, 0x9442001a, 0x2848821, 0xc31821, 0x8c65000c, 0x8ee304ec, -0x2228821, 0x8ee204ec, 0xc31821, 0xc21021, 0x8c44000c, 0x8c62000c, -0x94a3001c, 0x9484001e, 0x94420020, 0x2238821, 0x2248821, 0x2228821, -0x111c02, 0x3222ffff, 0x628821, 0x111c02, 0x3222ffff, 0x628821, -0x32c20001, 0x104000b2, 0x0, 0x96e2045a, 0x30420001, 0x104000ae, -0x32c20080, 0x10400008, 0x0, 0x92e27b88, 0x14400005, 0x0, -0x240c0001, 0xa2ec7b88, 0xaef57b8c, 0xaef27b94, 0x8ee304ec, 0x151100, -0x431021, 0x8c47000c, 0x37e1821, 0x24e2000e, 0x43102b, 0x14400008, -0xe02021, 0x2405000e, 0xc002f65, 0xafab0038, 0x3042ffff, 0x8fab0038, -0x8002d01, 0x2028021, 0x94e60000, 0x24e70002, 0x94e50000, 0x24e70002, -0x94e30000, 0x24e70002, 0x94e20000, 0x24e70002, 0x94e40000, 0x24e70002, -0x2068021, 0x2058021, 0x2038021, 0x2028021, 0x94e20000, 0x94e30002, -0x2048021, 0x2028021, 0x2038021, 0x101c02, 0x3202ffff, 0x628021, -0x101c02, 0x3202ffff, 0x8ee47b8c, 0x628021, 0x14950004, 0x3205ffff, -0x96620016, 0x8002d0f, 0x512021, 0x96620016, 0x542021, 0x41402, -0x3083ffff, 0x432021, 0x852023, 0x41402, 0x822021, 0x3084ffff, -0x50800001, 0x3404ffff, 0x8ee27b94, 0x24430017, 0x37e1021, 0x62102b, -0x50400001, 0x6b1821, 0x90630000, 0x24020011, 0x14620031, 0x24020006, -0x8ee27b94, 0x37e1821, 0x24420028, 0x43102b, 0x14400018, 0x0, -0x8ee27b8c, 0x12a2000a, 0x32c20100, 0x8ee27b94, 0x3c01ffff, 0x220821, -0x94220028, 0x822021, 0x41c02, 0x3082ffff, 0x622021, 0x32c20100, -0x14400004, 0x41027, 0x92e27b88, 0x14400002, 0x41027, 0x3044ffff, -0x8ee27b94, 0x3c01ffff, 0x220821, 0x8002d82, 0xa4240028, 0x8ee27b8c, -0x12a20008, 0x32c20100, 0x8ee27b94, 0x94420028, 0x822021, 0x41c02, -0x3082ffff, 0x622021, 0x32c20100, 0x14400004, 0x41027, 0x92e27b88, -0x14400002, 0x41027, 0x3044ffff, 0x8ee27b94, 0x8002d82, 0xa4440028, -0x1462002f, 0x37e1821, 0x8ee27b94, 0x24420032, 0x43102b, 0x14400018, -0x0, 0x8ee27b8c, 0x12a2000a, 0x32c20100, 0x8ee27b94, 0x3c01ffff, -0x220821, 0x94220032, 0x822021, 0x41c02, 0x3082ffff, 0x622021, -0x32c20100, 0x14400004, 0x41027, 0x92e27b88, 0x14400002, 0x41027, -0x3044ffff, 0x8ee27b94, 0x3c01ffff, 0x220821, 0x8002d82, 0xa4240032, -0x8ee27b8c, 0x12a20008, 0x32c20100, 0x8ee27b94, 0x94420032, 0x822021, -0x41c02, 0x3082ffff, 0x622021, 0x32c20100, 0x14400004, 0x41027, -0x92e27b88, 0x14400002, 0x41027, 0x3044ffff, 0x8ee27b94, 0xa4440032, -0x8fac0024, 0x1180002c, 0x37e1821, 0x8e420000, 0xae42fffc, 0x2642000a, -0x43102b, 0x1440001b, 0x34038100, 0x26430004, 0x37e1021, 0x62102b, -0x14400003, 0x602021, 0x6b1821, 0x602021, 0x8c620000, 0x24630004, -0xae420000, 0x37e1021, 0x62102b, 0x50400001, 0x6b1821, 0x8c620000, -0xac820000, 0x34028100, 0xa4620000, 0x24630002, 0x37e1021, 0x62102b, -0x50400001, 0x6b1821, 0x97ac002e, 0x8002dac, 0xa46c0000, 0x8e420004, -0x8e440008, 0xa6430008, 0x97ac002e, 0xa64c000a, 0xae420000, 0xae440004, -0x9662000e, 0x2652fffc, 0x24420004, 0xa662000e, 0x9662000e, 0x8ee3724c, -0x621821, 0xaee3724c, 0xafb20018, 0x8ee3724c, 0xafa3001c, 0x8ee2724c, -0x2c42003c, 0x10400004, 0x24620001, 0x2403fffe, 0x431024, 0xafa2001c, -0x32c20080, 0x1040000c, 0x32c20100, 0x8ee27b98, 0x24430001, 0x210c0, -0x571021, 0xaee37b98, 0x8fa30018, 0x8fa4001c, 0xac437b9c, 0xac447ba0, -0x8002e98, 0xaee0724c, 0x10400072, 0x0, 0x8ee27b98, 0x24430001, -0x210c0, 0x571021, 0xaee37b98, 0x8fa30018, 0x8fa4001c, 0xac437b9c, -0xac447ba0, 0x8ee27b98, 0x10400063, 0x4821, 0x5021, 0x8f8200f0, -0x24480008, 0x27621800, 0x102102b, 0x50400001, 0x27681000, 0x8f8200f4, -0x15020007, 0x0, 0x8ee201b0, 0x8021, 0x24420001, 0xaee201b0, -0x8002df2, 0x8ee201b0, 0x8f8300f0, 0x24100001, 0x1571021, 0x8c447b9c, -0x8c457ba0, 0xac640000, 0xac650004, 0xaf8800f0, 0x16000006, 0x2ea1021, -0x8ee20088, 0x24420001, 0xaee20088, 0x8002e37, 0x8ee20088, 0x8c427ba0, -0x8ee400e0, 0x8ee500e4, 0x8ee67b8c, 0x401821, 0x1021, 0xa32821, -0xa3382b, 0x822021, 0x872021, 0x8ee204ec, 0xc93021, 0x63100, -0xaee400e0, 0xaee500e4, 0xc23021, 0x94c2000a, 0x240c0002, 0x21142, -0x30430003, 0x106c0016, 0x28620003, 0x10400005, 0x240c0001, 0x106c0008, -0x0, 0x8002e37, 0x0, 0x240c0003, 0x106c0017, 0x0, -0x8002e37, 0x0, 0x8ee200e8, 0x8ee300ec, 0x24630001, 0x2c640001, -0x441021, 0xaee200e8, 0xaee300ec, 0x8ee200e8, 0x8002e37, 0x8ee300ec, -0x8ee200f0, 0x8ee300f4, 0x24630001, 0x2c640001, 0x441021, 0xaee200f0, -0xaee300f4, 0x8ee200f0, 0x8002e37, 0x8ee300f4, 0x8ee200f8, 0x8ee300fc, -0x24630001, 0x2c640001, 0x441021, 0xaee200f8, 0xaee300fc, 0x8ee200f8, -0x8ee300fc, 0x8ee27b98, 0x25290001, 0x122102b, 0x1440ffa0, 0x254a0008, -0xa2e07b88, 0x8002e97, 0xaee07b98, 0x8f8200f0, 0x24470008, 0x27621800, -0xe2102b, 0x50400001, 0x27671000, 0x8f8200f4, 0x14e20007, 0x0, -0x8ee201b0, 0x8021, 0x24420001, 0xaee201b0, 0x8002e55, 0x8ee201b0, -0x8f8200f0, 0x24100001, 0x8fa30018, 0x8fa4001c, 0xac430000, 0xac440004, -0xaf8700f0, 0x16000007, 0x0, 0x8ee20088, 0x24420001, 0xaee20088, -0x8ee20088, 0x8002e98, 0xaee0724c, 0x8ee2724c, 0x8ee400e0, 0x8ee500e4, -0x240c0002, 0x401821, 0x1021, 0xa32821, 0xa3302b, 0x822021, -0x862021, 0x161142, 0x30430003, 0xaee400e0, 0xaee500e4, 0x106c0017, -0x2c620003, 0x10400005, 0x240c0001, 0x106c0008, 0x0, 0x8002e98, -0xaee0724c, 0x240c0003, 0x106c0019, 0x0, 0x8002e98, 0xaee0724c, -0x8ee200e8, 0x8ee300ec, 0x24630001, 0x2c640001, 0x441021, 0xaee200e8, -0xaee300ec, 0x8ee200e8, 0x8ee300ec, 0x8002e98, 0xaee0724c, 0x8ee200f0, -0x8ee300f4, 0x24630001, 0x2c640001, 0x441021, 0xaee200f0, 0xaee300f4, -0x8ee200f0, 0x8ee300f4, 0x8002e98, 0xaee0724c, 0x8ee200f8, 0x8ee300fc, -0x24630001, 0x2c640001, 0x441021, 0xaee200f8, 0xaee300fc, 0x8ee200f8, -0x8ee300fc, 0xaee0724c, 0x8e62001c, 0x96e30458, 0x8ee404e0, 0x24420001, -0x2463ffff, 0x431024, 0x24840001, 0xaee204d4, 0xaee404e0, 0x8f42023c, -0x82202b, 0x148000a8, 0x0, 0x8f830120, 0x27623800, 0x24660020, -0xc2102b, 0x50400001, 0x27663000, 0x8f820128, 0x10c20004, 0x0, -0x8f820124, 0x14c20007, 0x0, 0x8ee201a0, 0x8021, 0x24420001, -0xaee201a0, 0x8002eff, 0x8ee201a0, 0x8ee204d4, 0xac62001c, 0x8ee404a0, -0x8ee504a4, 0x2462001c, 0xac620008, 0x24020008, 0xa462000e, 0x24020011, -0xac620018, 0xac640000, 0xac650004, 0x8ee204b4, 0xac620010, 0xaf860120, -0x92e24e10, 0x14400037, 0x24100001, 0x8ee24e20, 0x210c0, 0x24425028, -0x2e22021, 0x8c830000, 0x24020012, 0x1462001f, 0x0, 0x8ee34e20, -0x8ee24e24, 0x1062001b, 0x240c0040, 0x8c820004, 0x24420001, 0xac820004, -0x8ee24e24, 0x8ee34e20, 0x24420001, 0x104c0007, 0x0, 0x8ee24e24, -0x24420001, 0x10620005, 0x0, 0x8002ee9, 0x0, 0x14600005, -0x0, 0x8f820128, 0x24420020, 0xaf820128, 0x8f820128, 0x8c820004, -0x2c420011, 0x50400013, 0xac800000, 0x8002eff, 0x0, 0x8ee24e20, -0x240c0040, 0x24420001, 0x504c0003, 0x1021, 0x8ee24e20, 0x24420001, -0xaee24e20, 0x8ee24e20, 0x210c0, 0x24425028, 0x2e22021, 0x24020012, -0x240c0001, 0xac820000, 0xac8c0004, 0x5600000d, 0x24100001, 0x8ee204d4, -0x3c040001, 0x24844b14, 0xafa00014, 0xafa20010, 0x8ee605f8, 0x8f470228, -0x3c050009, 0x34a5f006, 0xc002403, 0xafab0038, 0x8fab0038, 0x16000003, -0x240c0001, 0x8002f4c, 0xa2ec04e4, 0x8ee2016c, 0x24420001, 0xaee2016c, -0x8ee2016c, 0x8ee204d4, 0xa2e004e4, 0xaee004e0, 0xaee07264, 0xaee204e8, -0x8f42023c, 0x10400030, 0x0, 0x8ee20180, 0x24420001, 0xaee20180, -0x8002f4c, 0x8ee20180, 0x8ee204f4, 0x240c0040, 0x24420001, 0x504c0003, -0x1021, 0x8ee204f4, 0x24420001, 0xaee204f4, 0x8ee204f4, 0x8e630018, -0x240c0003, 0x21080, 0x571021, 0x146c000f, 0x8c4404f8, 0x3c020001, -0x571021, 0x904283a1, 0x10400014, 0x0, 0x8ee201c8, 0x8ee35230, -0x441021, 0xaee201c8, 0x8ee201cc, 0x641821, 0x306300ff, 0x8002f47, -0xaee35230, 0x8ee201c4, 0x8ee30e00, 0x441021, 0xaee201c4, 0x8ee201cc, -0x641821, 0x306301ff, 0xaee30e00, 0x441021, 0xaee201cc, 0x8ee20000, -0x34420040, 0xaee20000, 0x8f820108, 0x24420020, 0xaf820108, 0x8f820108, -0x8f820108, 0x27633000, 0x43102b, 0x14400002, 0x27622800, 0xaf820108, -0x8f830108, 0x8f820104, 0x1462fc26, 0x0, 0x8fbf0060, 0x8fbe005c, -0x8fb60058, 0x8fb50054, 0x8fb40050, 0x8fb3004c, 0x8fb20048, 0x8fb10044, -0x8fb00040, 0x3e00008, 0x27bd0068, 0x52843, 0x10a0000d, 0x3021, -0x3c030001, 0x34633800, 0x3c07ffff, 0x3631021, 0x82102b, 0x50400001, -0x872021, 0x94820000, 0x24840002, 0x24a5ffff, 0x14a0fff8, 0xc23021, -0x61c02, 0x30c2ffff, 0x623021, 0x61c02, 0x30c2ffff, 0x623021, -0x3e00008, 0x30c2ffff, 0x27bdff88, 0x240f0001, 0xafbf0070, 0xafbe006c, -0xafb60068, 0xafb50064, 0xafb40060, 0xafb3005c, 0xafb20058, 0xafb10054, -0xafb00050, 0xa3a00027, 0xafaf002c, 0x8ee204c4, 0x8021, 0x30420001, -0x1440002a, 0xa3a00037, 0x8f8700e0, 0x8f8800c4, 0x8f8200e8, 0xe22023, -0x2c821000, 0x50400001, 0x24841000, 0x420c2, 0x801821, 0x8ee400c8, -0x8ee500cc, 0x1021, 0xa32821, 0xa3302b, 0x822021, 0x862021, -0xaee400c8, 0xaee500cc, 0x8f8300c8, 0x3c02000a, 0x3442efff, 0x1032023, -0x44102b, 0x10400003, 0x3c02000a, 0x3442f000, 0x822021, 0x801821, -0x8ee400c0, 0x8ee500c4, 0x1021, 0xa32821, 0xa3302b, 0x822021, -0x862021, 0xaee400c0, 0xaee500c4, 0xaf8800c8, 0xaf8700e4, 0x80034bc, -0xaf8700e8, 0x3c020001, 0x571021, 0x904283b0, 0x1040000b, 0x0, -0x3c140001, 0x297a021, 0x8e9483b4, 0x3c130001, 0x2779821, 0x8e7383b8, -0x3c120001, 0x2579021, 0x8003183, 0x8e5283bc, 0x8f8300e0, 0x8f8200e4, -0x10430007, 0x8821, 0x8f8200e4, 0x24110001, 0x8c430000, 0x8c440004, -0xafa30018, 0xafa4001c, 0x1620000e, 0x3c02ffff, 0x8f8200c4, 0xafa20010, -0x8f8200c8, 0x3c040001, 0x24844be0, 0xafa20014, 0x8f8600e0, 0x8f8700e4, -0x3c050006, 0xc002403, 0x34a5f000, 0x80034bc, 0x0, 0x8fa3001c, -0x8fb20018, 0x3074ffff, 0x2694fffc, 0x621024, 0x10400058, 0x2409821, -0x3c020080, 0x621024, 0x1040000a, 0x3c040040, 0x8ee2007c, 0x24420001, -0xaee2007c, 0x8ee2007c, 0x8ee201ec, 0x24420001, 0xaee201ec, 0x80034b6, -0x8ee201ec, 0x3c060004, 0x3c0b0001, 0x3c0a0002, 0x3c050010, 0x3c090008, -0x8ee20080, 0x3c080020, 0x34078000, 0x24420001, 0xaee20080, 0x8ee20080, -0x8fa2001c, 0x441824, 0x10660021, 0xc3102b, 0x14400007, 0x0, -0x106b0011, 0x0, 0x106a0015, 0x0, 0x8003039, 0x42042, -0x10650023, 0xa3102b, 0x14400005, 0x0, 0x10690019, 0x0, -0x8003039, 0x42042, 0x10680021, 0x0, 0x8003039, 0x42042, -0x8ee20034, 0x24420001, 0xaee20034, 0x8ee20034, 0x8003039, 0x42042, -0x8ee201dc, 0x24420001, 0xaee201dc, 0x8ee201dc, 0x8003039, 0x42042, -0x8ee201e0, 0x24420001, 0xaee201e0, 0x8ee201e0, 0x8003039, 0x42042, -0x8ee201e4, 0x24420001, 0xaee201e4, 0x8ee201e4, 0x8003039, 0x42042, -0x8ee20030, 0x24420001, 0xaee20030, 0x8ee20030, 0x8003039, 0x42042, -0x8ee201e8, 0x24420001, 0xaee201e8, 0x8ee201e8, 0x42042, 0x1087047c, -0x0, 0x8002ffe, 0x0, 0x3c020001, 0x571021, 0x904283a2, -0x14400084, 0x24020001, 0x3c030001, 0x771821, 0x906383a3, 0x1462007f, -0x3c020100, 0x8e430000, 0x621024, 0x1040006f, 0x2402ffff, 0x14620005, -0x24100001, 0x96430004, 0x3402ffff, 0x10620075, 0x0, 0x92e204c8, -0x14400072, 0x0, 0x3c020001, 0x571021, 0x8c4283a4, 0x28420005, -0x10400020, 0x3821, 0x3c020001, 0x571021, 0x8c4283a4, 0x18400016, -0x2821, 0x96660000, 0x520c0, 0x971021, 0x9442776e, 0x14460009, -0x971021, 0x94437770, 0x96620002, 0x14620005, 0x971021, 0x94437772, -0x96620004, 0x50620008, 0x24070001, 0x3c020001, 0x571021, 0x8c4283a4, -0x24a50001, 0xa2102a, 0x5440ffee, 0x520c0, 0x30e200ff, 0x10400440, -0x0, 0x80030c5, 0x0, 0x2402021, 0xc0022f8, 0x24050006, -0x3044001f, 0x428c0, 0x2e51021, 0x9442726c, 0x30424000, 0x14400434, -0xb71021, 0x9443726e, 0x96620000, 0x1462000b, 0x418c0, 0xb71021, -0x94437270, 0x96620002, 0x14620006, 0x418c0, 0xb71021, 0x94437272, -0x96620004, 0x10620035, 0x418c0, 0x2e31021, 0x9442726c, 0x30428000, -0x14400421, 0x2e31021, 0x944b726c, 0x96670000, 0xb28c0, 0xb71021, -0x9442736e, 0x80030a7, 0x3021, 0x420c0, 0x2e41021, 0x9443736c, -0x2e41021, 0x944b736c, 0x30638000, 0x14600010, 0xb28c0, 0xb71021, -0x9442736e, 0x1447fff5, 0x1602021, 0xb71021, 0x94437370, 0x96620002, -0x5462fff1, 0x420c0, 0xb71021, 0x94437372, 0x96620004, 0x5462ffec, -0x420c0, 0x24060001, 0x30c200ff, 0x10400400, 0x0, 0x80030c5, -0x0, 0x97430202, 0x96420000, 0x146203fa, 0x0, 0x97430204, -0x96420002, 0x146203f6, 0x0, 0x97430206, 0x96420004, 0x146203f2, -0x0, 0x92420000, 0x3a030001, 0x30420001, 0x431024, 0x10400074, -0x2402ffff, 0x8e630000, 0x14620004, 0x3402ffff, 0x96630004, 0x1062006f, -0x240f0002, 0x3c020001, 0x571021, 0x904283a2, 0x1440006a, 0x240f0003, -0x92e204c8, 0x54400068, 0xafaf002c, 0x3c020001, 0x571021, 0x8c4283a4, -0x28420005, 0x10400020, 0x3821, 0x3c020001, 0x571021, 0x8c4283a4, -0x18400016, 0x2821, 0x96660000, 0x520c0, 0x971021, 0x9442776e, -0x14460009, 0x971021, 0x94437770, 0x96620002, 0x14620005, 0x971021, -0x94437772, 0x96620004, 0x50620008, 0x24070001, 0x3c020001, 0x571021, -0x8c4283a4, 0x24a50001, 0xa2102a, 0x5440ffee, 0x520c0, 0x30e200ff, -0x14400044, 0x240f0003, 0x80034b6, 0x0, 0x2402021, 0xc0022f8, -0x24050006, 0x3044001f, 0x428c0, 0x2e51021, 0x9442726c, 0x30424000, -0x144003af, 0xb71021, 0x9443726e, 0x96620000, 0x1462000b, 0x418c0, -0xb71021, 0x94437270, 0x96620002, 0x14620006, 0x418c0, 0xb71021, -0x94437272, 0x96620004, 0x10620027, 0x418c0, 0x2e31021, 0x9442726c, -0x30428000, 0x1440039c, 0x2e31021, 0x944b726c, 0x96670000, 0xb28c0, -0xb71021, 0x9442736e, 0x800312c, 0x3021, 0x420c0, 0x2e41021, -0x9443736c, 0x2e41021, 0x944b736c, 0x30638000, 0x14600010, 0xb28c0, -0xb71021, 0x9442736e, 0x1447fff5, 0x1602021, 0xb71021, 0x94437370, -0x96620002, 0x5462fff1, 0x420c0, 0xb71021, 0x94437372, 0x96620004, -0x5462ffec, 0x420c0, 0x24060001, 0x30c200ff, 0x1040037b, 0x0, -0x800313f, 0x240f0003, 0x240f0001, 0xafaf002c, 0x8f420260, 0x54102b, -0x1040003a, 0x0, 0x8f8300e4, 0x8f8200e0, 0x10620003, 0x24630008, -0xaf8300e4, 0xaf8300e8, 0x8ee400c0, 0x8ee500c4, 0x2801821, 0x1021, -0xa32821, 0xa3302b, 0x822021, 0x862021, 0xaee400c0, 0xaee500c4, -0x8ee20058, 0x24420001, 0xaee20058, 0x8ee20058, 0x8ee2007c, 0x24420001, -0xaee2007c, 0x8ee2007c, 0x8f8200e0, 0xafa20010, 0x8f8200e4, 0x3c040001, -0x24844be8, 0xafa20014, 0x8fa60018, 0x8fa7001c, 0x3c050006, 0xc002403, -0x34a5f003, 0x80034bc, 0x0, 0x8ee25230, 0xafa20010, 0x8ee25234, -0x3c040001, 0x24844bf4, 0xafa20014, 0x8ee60e00, 0x8ee70e08, 0x3c050006, -0xc002403, 0x34a5f002, 0x8ee201bc, 0x24420001, 0xaee201bc, 0x8ee20000, -0x8ee301bc, 0x2403ffbf, 0x431024, 0x8003460, 0xaee20000, 0x96e20468, -0x54102b, 0x10400003, 0x0, 0x240f0001, 0xa3af0027, 0x12800301, -0x24160007, 0x24150040, 0x241e0001, 0x240e0012, 0x8ee2723c, 0x8f430280, -0x24420001, 0x304203ff, 0x106202d3, 0x0, 0x93a20027, 0x10400014, -0x0, 0x8ee35230, 0x8ee25234, 0x10620009, 0x26ed5234, 0x8ee65234, -0x8ee35234, 0x21140, 0x24425238, 0x2e28021, 0x24630001, 0x80031af, -0x306b00ff, 0x92e27238, 0x1440ffca, 0x0, 0x8ee201d0, 0x24420001, -0xaee201d0, 0x8ee201d0, 0x8ee30e00, 0x8ee20e08, 0x1062ffc2, 0x26ed0e08, -0x8ee60e08, 0x8ee30e08, 0x21140, 0x24420e10, 0x2e28021, 0x24630001, -0x306b01ff, 0x96e2046a, 0x30420010, 0x10400019, 0x0, 0x9642000c, -0x340f8100, 0x144f0015, 0x0, 0x3c020001, 0x571021, 0x904283b0, -0x14400010, 0x0, 0x9642000e, 0xa6020016, 0x8e420008, 0x8e430004, -0x8e440000, 0x2694fffc, 0xae42000c, 0xae430008, 0xae440004, 0x9602000e, -0x26730004, 0x240f0001, 0xa3af0037, 0x34420200, 0xa602000e, 0x8e020000, -0x8e030004, 0x3c040001, 0x34843800, 0x306a0007, 0x26a9823, 0x3641021, -0x262102b, 0x10400005, 0x28aa021, 0x2641023, 0x3621823, 0x3c020020, -0x439823, 0x26820007, 0x2404fff8, 0x9603000a, 0x446024, 0x6a1821, -0x6c102b, 0x10400002, 0x1803821, 0x603821, 0xae130018, 0x8f880120, -0x24e20007, 0x443824, 0x27623800, 0x25090020, 0x122102b, 0x50400001, -0x27693000, 0x8f820128, 0x11220004, 0x0, 0x8f820124, 0x15220007, -0x1401821, 0x8ee201a0, 0x8821, 0x24420001, 0xaee201a0, 0x800323c, -0x8ee201a0, 0x8e040000, 0x8e050004, 0x1021, 0xad130008, 0xa507000e, -0xad160018, 0xad06001c, 0xa3302b, 0xa32823, 0x822023, 0x862023, -0xad040000, 0xad050004, 0x8ee204b0, 0xad020010, 0xaf890120, 0x92e24e10, -0x14400033, 0x24110001, 0x8ee24e20, 0x210c0, 0x24425028, 0x2e22021, -0x8c820000, 0x1456001f, 0x0, 0x8ee34e20, 0x8ee24e24, 0x1062001b, -0x0, 0x8c820004, 0x24420001, 0xac820004, 0x8ee24e24, 0x8ee34e20, -0x24420001, 0x10550007, 0x0, 0x8ee24e24, 0x24420001, 0x10620005, -0x0, 0x8003229, 0x0, 0x14600005, 0x0, 0x8f820128, -0x24420020, 0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011, 0x50400010, -0xac800000, 0x800323c, 0x0, 0x8ee24e20, 0x24420001, 0x50550003, -0x1021, 0x8ee24e20, 0x24420001, 0xaee24e20, 0x8ee24e20, 0x210c0, -0x24425028, 0x2e22021, 0xac960000, 0xac9e0004, 0x16200018, 0x3c050006, -0x8e020018, 0x3c040001, 0x24844c00, 0xafa20010, 0x8e020000, 0x8e030004, -0x34a5f009, 0x2003021, 0xc002403, 0xafa30014, 0x93a20037, 0x10400216, -0x340f8100, 0x8e420004, 0x8e430008, 0x8e44000c, 0xa64f000c, 0xae420000, -0xae430004, 0xae440008, 0x96020016, 0x8003460, 0xa642000e, 0x14ec0168, -0x28a1823, 0x960c000a, 0x9603000e, 0x28a1023, 0xa602000a, 0x34620004, -0xa602000e, 0x8f880120, 0x27623800, 0x25090020, 0x122102b, 0x14400002, -0x306affff, 0x27693000, 0x8f820128, 0x11220004, 0x0, 0x8f820124, -0x15220007, 0x24040020, 0x8ee201a0, 0x8821, 0x24420001, 0xaee201a0, -0x80032ba, 0x8ee201a0, 0x8ee5723c, 0x8ee60480, 0x8ee70484, 0xa504000e, -0x24040004, 0xad100008, 0xad040018, 0x52940, 0xa01821, 0x1021, -0xe33821, 0xe3202b, 0xc23021, 0xc43021, 0xad060000, 0xad070004, -0x8ee2723c, 0xad02001c, 0x8ee204b4, 0xad020010, 0xaf890120, 0x92e24e10, -0x14400033, 0x24110001, 0x8ee24e20, 0x210c0, 0x24425028, 0x2e22021, -0x8c820000, 0x1456001f, 0x0, 0x8ee34e20, 0x8ee24e24, 0x1062001b, -0x0, 0x8c820004, 0x24420001, 0xac820004, 0x8ee24e24, 0x8ee34e20, -0x24420001, 0x10550007, 0x0, 0x8ee24e24, 0x24420001, 0x10620005, -0x0, 0x80032a7, 0x0, 0x14600005, 0x0, 0x8f820128, -0x24420020, 0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011, 0x50400010, -0xac800000, 0x80032ba, 0x0, 0x8ee24e20, 0x24420001, 0x50550003, -0x1021, 0x8ee24e20, 0x24420001, 0xaee24e20, 0x8ee24e20, 0x210c0, -0x24425028, 0x2e22021, 0xac960000, 0xac9e0004, 0x1620000d, 0x0, -0xa60c000a, 0xa60a000e, 0x8f820100, 0xafa20010, 0x8f820104, 0x3c040001, -0x24844c0c, 0x3c050006, 0xafa20014, 0x8ee6723c, 0x800342b, 0x34a5f00b, -0x3c010001, 0x370821, 0xa02083b0, 0xadab0000, 0x8ee201cc, 0x8ee3723c, -0x2442ffff, 0xaee201cc, 0x8ee201cc, 0x24630001, 0x306303ff, 0x26e25234, -0x15a20006, 0xaee3723c, 0x8ee201c8, 0x2442ffff, 0xaee201c8, 0x80032df, -0x8ee201c8, 0x8ee201c4, 0x2442ffff, 0xaee201c4, 0x8ee201c4, 0x8f420240, -0x10400073, 0x0, 0x8ee20e0c, 0x24420001, 0xaee20e0c, 0x8f430240, -0x43102b, 0x14400176, 0xa021, 0x8f830120, 0x27623800, 0x24660020, -0xc2102b, 0x50400001, 0x27663000, 0x8f820128, 0x10c20004, 0x0, -0x8f820124, 0x14c20007, 0x0, 0x8ee201a0, 0x8821, 0x24420001, -0xaee201a0, 0x800333f, 0x8ee201a0, 0x8ee2723c, 0xac62001c, 0x8ee40498, -0x8ee5049c, 0x2462001c, 0xac620008, 0x24020008, 0xa462000e, 0x24020011, -0xac620018, 0xac640000, 0xac650004, 0x8ee204b4, 0xac620010, 0xaf860120, -0x92e24e10, 0x14400033, 0x24110001, 0x8ee24e20, 0x210c0, 0x24425028, -0x2e22021, 0x8c820000, 0x144e001f, 0x0, 0x8ee34e20, 0x8ee24e24, -0x1062001b, 0x0, 0x8c820004, 0x24420001, 0xac820004, 0x8ee24e24, -0x8ee34e20, 0x24420001, 0x10550007, 0x0, 0x8ee24e24, 0x24420001, -0x10620005, 0x0, 0x800332c, 0x0, 0x14600005, 0x0, -0x8f820128, 0x24420020, 0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011, -0x50400010, 0xac800000, 0x800333f, 0x0, 0x8ee24e20, 0x24420001, -0x50550003, 0x1021, 0x8ee24e20, 0x24420001, 0xaee24e20, 0x8ee24e20, -0x210c0, 0x24425028, 0x2e22021, 0xac8e0000, 0xac9e0004, 0x5620000d, -0x24110001, 0x8ee2723c, 0x3c040001, 0x24844c18, 0xafa00014, 0xafa20010, -0x8ee6723c, 0x8f470280, 0x3c050009, 0x34a5f008, 0xc002403, 0xafae0048, -0x8fae0048, 0x56200001, 0xaee00e0c, 0x8ee20184, 0x24420001, 0xaee20184, -0x80033b8, 0x8ee20184, 0x8f830120, 0x27623800, 0x24660020, 0xc2102b, -0x50400001, 0x27663000, 0x8f820128, 0x10c20004, 0x0, 0x8f820124, -0x14c20007, 0x0, 0x8ee201a0, 0x8821, 0x24420001, 0xaee201a0, -0x80033aa, 0x8ee201a0, 0x8ee2723c, 0xac62001c, 0x8ee40498, 0x8ee5049c, -0x2462001c, 0xac620008, 0x24020008, 0xa462000e, 0x24020011, 0xac620018, -0xac640000, 0xac650004, 0x8ee204b4, 0xac620010, 0xaf860120, 0x92e24e10, -0x14400033, 0x24110001, 0x8ee24e20, 0x210c0, 0x24425028, 0x2e22021, -0x8c820000, 0x144e001f, 0x0, 0x8ee34e20, 0x8ee24e24, 0x1062001b, -0x0, 0x8c820004, 0x24420001, 0xac820004, 0x8ee24e24, 0x8ee34e20, -0x24420001, 0x10550007, 0x0, 0x8ee24e24, 0x24420001, 0x10620005, -0x0, 0x8003397, 0x0, 0x14600005, 0x0, 0x8f820128, -0x24420020, 0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011, 0x50400010, -0xac800000, 0x80033aa, 0x0, 0x8ee24e20, 0x24420001, 0x50550003, -0x1021, 0x8ee24e20, 0x24420001, 0xaee24e20, 0x8ee24e20, 0x210c0, -0x24425028, 0x2e22021, 0xac8e0000, 0xac9e0004, 0x1620000d, 0x0, -0x8ee2723c, 0x3c040001, 0x24844c18, 0xafa00014, 0xafa20010, 0x8ee6723c, -0x8f470280, 0x3c050009, 0x34a5f008, 0xc002403, 0xafae0048, 0x8fae0048, -0x8ee20170, 0x24420001, 0xaee20170, 0x8ee20170, 0x800345e, 0xa021, -0x960c000a, 0x183102b, 0x54400001, 0x1801821, 0xa603000a, 0x8f880120, -0x27623800, 0x25090020, 0x122102b, 0x50400001, 0x27693000, 0x8f820128, -0x11220004, 0x0, 0x8f820124, 0x15220007, 0x24040020, 0x8ee201a0, -0x8821, 0x24420001, 0xaee201a0, 0x800341f, 0x8ee201a0, 0x8ee5723c, -0x8ee60480, 0x8ee70484, 0xa504000e, 0x24040004, 0xad100008, 0xad040018, -0x52940, 0xa01821, 0x1021, 0xe33821, 0xe3202b, 0xc23021, -0xc43021, 0xad060000, 0xad070004, 0x8ee2723c, 0xad02001c, 0x8ee204b4, -0xad020010, 0xaf890120, 0x92e24e10, 0x14400033, 0x24110001, 0x8ee24e20, -0x210c0, 0x24425028, 0x2e22021, 0x8c820000, 0x1456001f, 0x0, -0x8ee34e20, 0x8ee24e24, 0x1062001b, 0x0, 0x8c820004, 0x24420001, -0xac820004, 0x8ee24e24, 0x8ee34e20, 0x24420001, 0x10550007, 0x0, -0x8ee24e24, 0x24420001, 0x10620005, 0x0, 0x800340c, 0x0, -0x14600005, 0x0, 0x8f820128, 0x24420020, 0xaf820128, 0x8f820128, -0x8c820004, 0x2c420011, 0x50400010, 0xac800000, 0x800341f, 0x0, -0x8ee24e20, 0x24420001, 0x50550003, 0x1021, 0x8ee24e20, 0x24420001, -0xaee24e20, 0x8ee24e20, 0x210c0, 0x24425028, 0x2e22021, 0xac960000, -0xac9e0004, 0x1620001d, 0x0, 0xa60c000a, 0x8f820100, 0xafa20010, -0x8f820104, 0x3c040001, 0x24844c0c, 0x3c050006, 0xafa20014, 0x8ee6723c, -0x34a5f00d, 0xc002403, 0x2003821, 0x93a20037, 0x10400031, 0x340f8100, -0x8e420004, 0x8e430008, 0x8e44000c, 0xa64f000c, 0xae420000, 0xae430004, -0xae440008, 0x96020016, 0xa642000e, 0x9602000e, 0x3042fdff, 0x8003460, -0xa602000e, 0x8ee201cc, 0x2442ffff, 0xaee201cc, 0x8ee201cc, 0x8ee201c4, -0x3c04001f, 0x3c010001, 0x370821, 0xa03e83b0, 0x2442ffff, 0xaee201c4, -0x9603000a, 0x3484ffff, 0x8ee201c4, 0x6a1821, 0x2639821, 0x93202b, -0x10800003, 0x3c02fff5, 0x34421000, 0x2629821, 0xadab0000, 0x8ee2723c, -0x24420001, 0x304203ff, 0xaee2723c, 0x8f420240, 0x10400004, 0x283a023, -0x8ee20e0c, 0x24420001, 0xaee20e0c, 0xa3a00027, 0x1680fd29, 0x0, -0x12800024, 0x0, 0x3c010001, 0x370821, 0xac3483b4, 0x3c010001, -0x370821, 0xac3383b8, 0x3c010001, 0x370821, 0xac3283bc, 0x93a20037, -0x10400008, 0x0, 0x3c020001, 0x571021, 0x8c4283bc, 0x24420004, -0x3c010001, 0x370821, 0xac2283bc, 0x8ee2723c, 0x8f430280, 0x24420001, -0x304203ff, 0x14620006, 0x0, 0x8ee201c0, 0x24420001, 0xaee201c0, -0x80034bc, 0x8ee201c0, 0x8ee201b8, 0x24420001, 0xaee201b8, 0x80034bc, -0x8ee201b8, 0x97a4001e, 0x2484fffc, 0x801821, 0x8ee400c0, 0x8ee500c4, -0x1021, 0xa32821, 0xa3302b, 0x822021, 0x862021, 0xaee400c0, -0xaee500c4, 0x8faf002c, 0x24020002, 0x11e2000f, 0x29e20003, 0x14400017, -0x24020003, 0x15e20015, 0x0, 0x8ee200d0, 0x8ee300d4, 0x24630001, -0x2c640001, 0x441021, 0xaee200d0, 0xaee300d4, 0x8ee200d0, 0x80034b6, -0x8ee300d4, 0x8ee200d8, 0x8ee300dc, 0x24630001, 0x2c640001, 0x441021, -0xaee200d8, 0xaee300dc, 0x8ee200d8, 0x80034b6, 0x8ee300dc, 0x8ee200c8, -0x8ee300cc, 0x24630001, 0x2c640001, 0x441021, 0xaee200c8, 0xaee300cc, -0x8ee200c8, 0x8ee300cc, 0x8f8300e4, 0x8f8200e0, 0x10620003, 0x24630008, -0xaf8300e4, 0xaf8300e8, 0x8fbf0070, 0x8fbe006c, 0x8fb60068, 0x8fb50064, -0x8fb40060, 0x8fb3005c, 0x8fb20058, 0x8fb10054, 0x8fb00050, 0x3e00008, -0x27bd0078, 0x27bdffb0, 0xafb50044, 0xa821, 0xafb00030, 0x8021, -0xafbf004c, 0xafb60048, 0xafb40040, 0xafb3003c, 0xafb20038, 0xafb10034, -0x8ee204c4, 0x24140001, 0x30420001, 0x1440002a, 0xb021, 0x8f8700e0, -0x8f8800c4, 0x8f8200e8, 0xe22023, 0x2c821000, 0x50400001, 0x24841000, -0x420c2, 0x801821, 0x8ee400c8, 0x8ee500cc, 0x1021, 0xa32821, -0xa3302b, 0x822021, 0x862021, 0xaee400c8, 0xaee500cc, 0x8f8300c8, -0x3c02000a, 0x3442efff, 0x1032023, 0x44102b, 0x10400003, 0x3c02000a, -0x3442f000, 0x822021, 0x801821, 0x8ee400c0, 0x8ee500c4, 0x1021, -0xa32821, 0xa3302b, 0x822021, 0x862021, 0xaee400c0, 0xaee500c4, -0xaf8800c8, 0xaf8700e4, 0x8003840, 0xaf8700e8, 0x3c020001, 0x571021, -0x904283b0, 0x1040000b, 0x0, 0x3c130001, 0x2779821, 0x8e7383b4, -0x3c110001, 0x2378821, 0x8e3183b8, 0x3c120001, 0x2579021, 0x80036d8, -0x8e5283bc, 0x8f8300e0, 0x8f8200e4, 0x10430007, 0x4821, 0x8f8200e4, -0x24090001, 0x8c430000, 0x8c440004, 0xafa30018, 0xafa4001c, 0x1520000e, -0x3c02ffff, 0x8f8200c4, 0xafa20010, 0x8f8200c8, 0x3c040001, 0x24844be0, -0xafa20014, 0x8f8600e0, 0x8f8700e4, 0x3c050006, 0xc002403, 0x34a5f000, -0x8003840, 0x0, 0x8fa3001c, 0x8fb20018, 0x3073ffff, 0x2673fffc, -0x621024, 0x10400058, 0x2408821, 0x3c020080, 0x621024, 0x1040000a, -0x3c040040, 0x8ee2007c, 0x24420001, 0xaee2007c, 0x8ee2007c, 0x8ee201ec, -0x24420001, 0xaee201ec, 0x800383a, 0x8ee201ec, 0x3c060004, 0x3c0b0001, -0x3c0a0002, 0x3c050010, 0x3c090008, 0x8ee20080, 0x3c080020, 0x34078000, -0x24420001, 0xaee20080, 0x8ee20080, 0x8fa2001c, 0x441824, 0x10660021, -0xc3102b, 0x14400007, 0x0, 0x106b0011, 0x0, 0x106a0015, -0x0, 0x8003582, 0x42042, 0x10650023, 0xa3102b, 0x14400005, -0x0, 0x10690019, 0x0, 0x8003582, 0x42042, 0x10680021, -0x0, 0x8003582, 0x42042, 0x8ee20034, 0x24420001, 0xaee20034, -0x8ee20034, 0x8003582, 0x42042, 0x8ee201dc, 0x24420001, 0xaee201dc, -0x8ee201dc, 0x8003582, 0x42042, 0x8ee201e0, 0x24420001, 0xaee201e0, -0x8ee201e0, 0x8003582, 0x42042, 0x8ee201e4, 0x24420001, 0xaee201e4, -0x8ee201e4, 0x8003582, 0x42042, 0x8ee20030, 0x24420001, 0xaee20030, -0x8ee20030, 0x8003582, 0x42042, 0x8ee201e8, 0x24420001, 0xaee201e8, -0x8ee201e8, 0x42042, 0x108702b7, 0x0, 0x8003547, 0x0, -0x3c020001, 0x571021, 0x904283a2, 0x14400084, 0x24020001, 0x3c030001, -0x771821, 0x906383a3, 0x1462007f, 0x3c020100, 0x8e430000, 0x621024, -0x1040006f, 0x2402ffff, 0x14620005, 0x24100001, 0x96430004, 0x3402ffff, -0x10620075, 0x0, 0x92e204c8, 0x14400072, 0x0, 0x3c020001, -0x571021, 0x8c4283a4, 0x28420005, 0x10400020, 0x3821, 0x3c020001, -0x571021, 0x8c4283a4, 0x18400016, 0x2821, 0x96260000, 0x520c0, -0x971021, 0x9442776e, 0x14460009, 0x971021, 0x94437770, 0x96220002, -0x14620005, 0x971021, 0x94437772, 0x96220004, 0x50620008, 0x24070001, -0x3c020001, 0x571021, 0x8c4283a4, 0x24a50001, 0xa2102a, 0x5440ffee, -0x520c0, 0x30e200ff, 0x1040027b, 0x0, 0x800360e, 0x0, -0x2402021, 0xc0022f8, 0x24050006, 0x3044001f, 0x428c0, 0x2e51021, -0x9442726c, 0x30424000, 0x1440026f, 0xb71021, 0x9443726e, 0x96220000, -0x1462000b, 0x418c0, 0xb71021, 0x94437270, 0x96220002, 0x14620006, -0x418c0, 0xb71021, 0x94437272, 0x96220004, 0x10620035, 0x418c0, -0x2e31021, 0x9442726c, 0x30428000, 0x1440025c, 0x2e31021, 0x9448726c, -0x96270000, 0x828c0, 0xb71021, 0x9442736e, 0x80035f0, 0x3021, -0x420c0, 0x2e41021, 0x9443736c, 0x2e41021, 0x9448736c, 0x30638000, -0x14600010, 0x828c0, 0xb71021, 0x9442736e, 0x1447fff5, 0x1002021, -0xb71021, 0x94437370, 0x96220002, 0x5462fff1, 0x420c0, 0xb71021, -0x94437372, 0x96220004, 0x5462ffec, 0x420c0, 0x24060001, 0x30c200ff, -0x1040023b, 0x0, 0x800360e, 0x0, 0x97430202, 0x96420000, -0x14620235, 0x0, 0x97430204, 0x96420002, 0x14620231, 0x0, -0x97430206, 0x96420004, 0x1462022d, 0x0, 0x92420000, 0x3a030001, -0x30420001, 0x431024, 0x10400074, 0x2402ffff, 0x8e230000, 0x14620004, -0x3402ffff, 0x96230004, 0x1062006f, 0x24140002, 0x3c020001, 0x571021, -0x904283a2, 0x1440006a, 0x24140003, 0x92e204c8, 0x14400067, 0x0, -0x3c020001, 0x571021, 0x8c4283a4, 0x28420005, 0x10400020, 0x3821, -0x3c020001, 0x571021, 0x8c4283a4, 0x18400016, 0x2821, 0x96260000, -0x520c0, 0x971021, 0x9442776e, 0x14460009, 0x971021, 0x94437770, -0x96220002, 0x14620005, 0x971021, 0x94437772, 0x96220004, 0x50620008, -0x24070001, 0x3c020001, 0x571021, 0x8c4283a4, 0x24a50001, 0xa2102a, -0x5440ffee, 0x520c0, 0x30e200ff, 0x14400044, 0x24140003, 0x800383a, -0x0, 0x2402021, 0xc0022f8, 0x24050006, 0x3044001f, 0x428c0, -0x2e51021, 0x9442726c, 0x30424000, 0x144001ea, 0xb71021, 0x9443726e, -0x96220000, 0x1462000b, 0x418c0, 0xb71021, 0x94437270, 0x96220002, -0x14620006, 0x418c0, 0xb71021, 0x94437272, 0x96220004, 0x10620027, -0x418c0, 0x2e31021, 0x9442726c, 0x30428000, 0x144001d7, 0x2e31021, -0x9448726c, 0x96270000, 0x828c0, 0xb71021, 0x9442736e, 0x8003675, -0x3021, 0x420c0, 0x2e41021, 0x9443736c, 0x2e41021, 0x9448736c, -0x30638000, 0x14600010, 0x828c0, 0xb71021, 0x9442736e, 0x1447fff5, -0x1002021, 0xb71021, 0x94437370, 0x96220002, 0x5462fff1, 0x420c0, -0xb71021, 0x94437372, 0x96220004, 0x5462ffec, 0x420c0, 0x24060001, -0x30c200ff, 0x104001b6, 0x0, 0x8003688, 0x24140003, 0x24140001, -0x8f420260, 0x53102b, 0x10400049, 0x0, 0x8f8300e4, 0x8f8200e0, -0x10620003, 0x24630008, 0xaf8300e4, 0xaf8300e8, 0x8ee400c0, 0x8ee500c4, -0x2601821, 0x1021, 0xa32821, 0xa3302b, 0x822021, 0x862021, -0xaee400c0, 0xaee500c4, 0x8ee20058, 0x24420001, 0xaee20058, 0x8ee20058, -0x8ee2007c, 0x24420001, 0xaee2007c, 0x8ee2007c, 0x8f8200e0, 0xafa20010, -0x8f8200e4, 0x3c040001, 0x24844be8, 0xafa20014, 0x8fa60018, 0x8fa7001c, -0x3c050006, 0xc002403, 0x34a5f003, 0x8003840, 0x0, 0x8ee25230, -0xafa20010, 0x8ee25234, 0x3c040001, 0x24844bf4, 0xafa20014, 0x8ee60e00, -0x8ee70e08, 0xc002403, 0x34a5f002, 0x8ee201bc, 0x24420001, 0xaee201bc, -0x8ee20000, 0x8ee301bc, 0x2403ffbf, 0x431024, 0x80037e8, 0xaee20000, -0x8ee25230, 0xafa20010, 0x8ee25234, 0x3c040001, 0x24844bf4, 0xafa20014, -0x8ee60e00, 0x8ee70e08, 0x3c050006, 0xc002403, 0x34a5f002, 0x8ee201bc, -0x24420001, 0xaee201bc, 0x80037e8, 0x8ee201bc, 0x96e20468, 0x53102b, -0x54400001, 0x3c158000, 0x12600131, 0x3c0c001f, 0x358cffff, 0x8ee2723c, -0x8f430280, 0x24420001, 0x304203ff, 0x10620108, 0x0, 0x12a00014, -0x0, 0x8ee35230, 0x8ee25234, 0x10620009, 0x26ee5234, 0x8eeb5234, -0x8ee35234, 0x21140, 0x24425238, 0x2e28021, 0x24630001, 0x8003702, -0x306800ff, 0x92e27238, 0x1440ffc0, 0x3c050006, 0x8ee201d0, 0x24420001, -0xaee201d0, 0x8ee201d0, 0x8ee30e00, 0x8ee20e08, 0x1062ffcb, 0x26ee0e08, -0x8eeb0e08, 0xa821, 0x8ee30e08, 0x21140, 0x24420e10, 0x2e28021, -0x24630001, 0x306801ff, 0x96e2046a, 0x30420010, 0x10400017, 0x34028100, -0x9643000c, 0x14620014, 0x0, 0x3c020001, 0x571021, 0x904283b0, -0x1440000f, 0x0, 0x9642000e, 0xa6020016, 0x8e420008, 0x8e430004, -0x8e440000, 0x2673fffc, 0xae42000c, 0xae430008, 0xae440004, 0x9602000e, -0x26310004, 0x24160001, 0x34420200, 0xa602000e, 0x9603000a, 0x2605021, -0x73102b, 0x10400002, 0x2606821, 0x605021, 0x2d42003d, 0x1040002a, -0x3821, 0x9623000c, 0x24020800, 0x54620027, 0xae110018, 0x3c020001, -0x571021, 0x904283b0, 0x54400022, 0xae110018, 0x26220017, 0x182102b, -0x10400013, 0x0, 0x3c02fff5, 0x511021, 0x90421017, 0x38430006, -0x2c630001, 0x38420011, 0x2c420001, 0x621825, 0x10600013, 0x26220010, -0x182102b, 0x1040000e, 0x0, 0x3c07fff5, 0xf13821, 0x94e71010, -0x800374e, 0x24e7000e, 0x92220017, 0x38430006, 0x2c630001, 0x38420011, -0x2c420001, 0x621825, 0x50600004, 0xae110018, 0x96270010, 0x24e7000e, -0xae110018, 0x3c020001, 0x571021, 0x904283b0, 0x2102b, 0x14e00002, -0x24ec0, 0x1403821, 0x8f830120, 0x27623800, 0x24660020, 0xc2102b, -0x50400001, 0x27663000, 0x8f820128, 0x10c20004, 0x0, 0x8f820124, -0x14c20007, 0x2402000b, 0x8ee201a0, 0x4821, 0x24420001, 0xaee201a0, -0x80037af, 0x8ee201a0, 0x8e040000, 0x8e050004, 0xac620018, 0x1751025, -0x491025, 0xac710008, 0xa467000e, 0xac62001c, 0xac640000, 0xac650004, -0x8ee204b0, 0xac620010, 0xaf860120, 0x92e24e10, 0x14400038, 0x24090001, -0x8ee24e20, 0x210c0, 0x24425028, 0x2e22021, 0x8c830000, 0x24020007, -0x14620020, 0x0, 0x8ee34e20, 0x8ee24e24, 0x1062001c, 0x0, -0x8c820004, 0x24420001, 0xac820004, 0x8ee34e24, 0x8ee54e20, 0x24020040, -0x24630001, 0x10620007, 0x0, 0x8ee24e24, 0x24420001, 0x10a20005, -0x0, 0x8003799, 0x0, 0x14a00005, 0x0, 0x8f820128, -0x24420020, 0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011, 0x50400013, -0xac800000, 0x80037af, 0x0, 0x8ee24e20, 0x24030040, 0x24420001, -0x50430003, 0x1021, 0x8ee24e20, 0x24420001, 0xaee24e20, 0x8ee24e20, -0x210c0, 0x24425028, 0x2e22021, 0x24020007, 0xac820000, 0x24020001, -0xac820004, 0x15200018, 0x3c050006, 0x8e020018, 0x3c040001, 0x24844c00, -0xafa20010, 0x8e020000, 0x8e030004, 0x34a5f009, 0x2003021, 0xc002403, -0xafa30014, 0x32c200ff, 0x1040002b, 0x34028100, 0x8e430004, 0x8e440008, -0x8e45000c, 0xa642000c, 0xae430000, 0xae440004, 0xae450008, 0x96020016, -0x80037e8, 0xa642000e, 0x154d000a, 0x0, 0x9602000e, 0xa613000a, -0x34420004, 0xa602000e, 0x3c010001, 0x370821, 0xa02083b0, 0x80037e6, -0x9821, 0x9604000a, 0x93102b, 0x10400002, 0x2601821, 0x801821, -0x24020001, 0xa603000a, 0x3c010001, 0x370821, 0xa02283b0, 0x9604000a, -0x2248821, 0x191102b, 0x10400003, 0x3c02fff5, 0x34421000, 0x2228821, -0x2649823, 0xa821, 0x1660fef4, 0xadc80000, 0x12600021, 0x32c200ff, -0x3c010001, 0x370821, 0xac3383b4, 0x3c010001, 0x370821, 0xac3183b8, -0x3c010001, 0x370821, 0x10400008, 0xac3283bc, 0x3c020001, 0x571021, -0x8c4283bc, 0x24420004, 0x3c010001, 0x370821, 0xac2283bc, 0x8ee2723c, -0x8f430280, 0x24420001, 0x14620006, 0x0, 0x8ee201c0, 0x24420001, -0xaee201c0, 0x8003840, 0x8ee201c0, 0x8ee201b8, 0x24420001, 0xaee201b8, -0x8003840, 0x8ee201b8, 0x97a4001e, 0x2484fffc, 0x801821, 0x8ee400c0, -0x8ee500c4, 0x1021, 0xa32821, 0xa3302b, 0x822021, 0x862021, -0x24020002, 0xaee400c0, 0xaee500c4, 0x1282000f, 0x2a820003, 0x14400017, -0x24020003, 0x16820015, 0x0, 0x8ee200d0, 0x8ee300d4, 0x24630001, -0x2c640001, 0x441021, 0xaee200d0, 0xaee300d4, 0x8ee200d0, 0x800383a, -0x8ee300d4, 0x8ee200d8, 0x8ee300dc, 0x24630001, 0x2c640001, 0x441021, -0xaee200d8, 0xaee300dc, 0x8ee200d8, 0x800383a, 0x8ee300dc, 0x8ee200c8, -0x8ee300cc, 0x24630001, 0x2c640001, 0x441021, 0xaee200c8, 0xaee300cc, -0x8ee200c8, 0x8ee300cc, 0x8f8300e4, 0x8f8200e0, 0x10620003, 0x24630008, -0xaf8300e4, 0xaf8300e8, 0x8fbf004c, 0x8fb60048, 0x8fb50044, 0x8fb40040, -0x8fb3003c, 0x8fb20038, 0x8fb10034, 0x8fb00030, 0x3e00008, 0x27bd0050, -0x27bdff90, 0xafb60060, 0xb021, 0xafbf0068, 0xafbe0064, 0xafb5005c, -0xafb40058, 0xafb30054, 0xafb20050, 0xafb1004c, 0xafb00048, 0x8ee204c4, -0x8821, 0x24150001, 0x30420001, 0x1440002a, 0xa3a0002f, 0x8f8700e0, -0x8f8800c4, 0x8f8200e8, 0xe22023, 0x2c821000, 0x50400001, 0x24841000, -0x420c2, 0x801821, 0x8ee400c8, 0x8ee500cc, 0x1021, 0xa32821, -0xa3302b, 0x822021, 0x862021, 0xaee400c8, 0xaee500cc, 0x8f8300c8, -0x3c02000a, 0x3442efff, 0x1032023, 0x44102b, 0x10400003, 0x3c02000a, -0x3442f000, 0x822021, 0x801821, 0x8ee400c0, 0x8ee500c4, 0x1021, -0xa32821, 0xa3302b, 0x822021, 0x862021, 0xaee400c0, 0xaee500c4, -0xaf8800c8, 0xaf8700e4, 0x8003c4b, 0xaf8700e8, 0x3c020001, 0x571021, -0x904283b0, 0x1040000b, 0x0, 0x3c130001, 0x2779821, 0x8e7383b4, -0x3c100001, 0x2178021, 0x8e1083b8, 0x3c120001, 0x2579021, 0x8003a49, -0x8e5283bc, 0x8f8300e0, 0x8f8200e4, 0x10430007, 0x3821, 0x8f8200e4, -0x24070001, 0x8c430000, 0x8c440004, 0xafa30018, 0xafa4001c, 0x14e0000e, -0x3c02ffff, 0x8f8200c4, 0xafa20010, 0x8f8200c8, 0x3c040001, 0x24844c24, -0xafa20014, 0x8f8600e0, 0x8f8700e4, 0x3c050006, 0xc002403, 0x34a5f200, -0x8003c4b, 0x0, 0x8fa3001c, 0x8fb20018, 0x3073ffff, 0x2673fffc, -0x621024, 0x10400058, 0x2408021, 0x3c020080, 0x621024, 0x1040000a, -0x3c040040, 0x8ee2007c, 0x24420001, 0xaee2007c, 0x8ee2007c, 0x8ee201ec, -0x24420001, 0xaee201ec, 0x8003c45, 0x8ee201ec, 0x3c060004, 0x3c0b0001, -0x3c0a0002, 0x3c050010, 0x3c090008, 0x8ee20080, 0x3c080020, 0x34078000, -0x24420001, 0xaee20080, 0x8ee20080, 0x8fa2001c, 0x441824, 0x10660021, -0xc3102b, 0x14400007, 0x0, 0x106b0011, 0x0, 0x106a0015, -0x0, 0x8003906, 0x42042, 0x10650023, 0xa3102b, 0x14400005, -0x0, 0x10690019, 0x0, 0x8003906, 0x42042, 0x10680021, -0x0, 0x8003906, 0x42042, 0x8ee20034, 0x24420001, 0xaee20034, -0x8ee20034, 0x8003906, 0x42042, 0x8ee201dc, 0x24420001, 0xaee201dc, -0x8ee201dc, 0x8003906, 0x42042, 0x8ee201e0, 0x24420001, 0xaee201e0, -0x8ee201e0, 0x8003906, 0x42042, 0x8ee201e4, 0x24420001, 0xaee201e4, -0x8ee201e4, 0x8003906, 0x42042, 0x8ee20030, 0x24420001, 0xaee20030, -0x8ee20030, 0x8003906, 0x42042, 0x8ee201e8, 0x24420001, 0xaee201e8, -0x8ee201e8, 0x42042, 0x1087033e, 0x0, 0x80038cb, 0x0, -0x3c020001, 0x571021, 0x904283a2, 0x14400084, 0x24020001, 0x3c030001, -0x771821, 0x906383a3, 0x1462007f, 0x3c020100, 0x8e430000, 0x621024, -0x1040006f, 0x2402ffff, 0x14620005, 0x24110001, 0x96430004, 0x3402ffff, -0x10620075, 0x0, 0x92e204c8, 0x14400072, 0x0, 0x3c020001, -0x571021, 0x8c4283a4, 0x28420005, 0x10400020, 0x3821, 0x3c020001, -0x571021, 0x8c4283a4, 0x18400016, 0x2821, 0x96060000, 0x520c0, -0x971021, 0x9442776e, 0x14460009, 0x971021, 0x94437770, 0x96020002, -0x14620005, 0x971021, 0x94437772, 0x96020004, 0x50620008, 0x24070001, -0x3c020001, 0x571021, 0x8c4283a4, 0x24a50001, 0xa2102a, 0x5440ffee, -0x520c0, 0x30e200ff, 0x10400302, 0x0, 0x8003992, 0x0, -0x2402021, 0xc0022f8, 0x24050006, 0x3044001f, 0x428c0, 0x2e51021, -0x9442726c, 0x30424000, 0x144002f6, 0xb71021, 0x9443726e, 0x96020000, -0x1462000b, 0x418c0, 0xb71021, 0x94437270, 0x96020002, 0x14620006, -0x418c0, 0xb71021, 0x94437272, 0x96020004, 0x10620035, 0x418c0, -0x2e31021, 0x9442726c, 0x30428000, 0x144002e3, 0x2e31021, 0x944d726c, -0x96070000, 0xd28c0, 0xb71021, 0x9442736e, 0x8003974, 0x3021, -0x420c0, 0x2e41021, 0x9443736c, 0x2e41021, 0x944d736c, 0x30638000, -0x14600010, 0xd28c0, 0xb71021, 0x9442736e, 0x1447fff5, 0x1a02021, -0xb71021, 0x94437370, 0x96020002, 0x5462fff1, 0x420c0, 0xb71021, -0x94437372, 0x96020004, 0x5462ffec, 0x420c0, 0x24060001, 0x30c200ff, -0x104002c2, 0x0, 0x8003992, 0x0, 0x97430202, 0x96420000, -0x146202bc, 0x0, 0x97430204, 0x96420002, 0x146202b8, 0x0, -0x97430206, 0x96420004, 0x146202b4, 0x0, 0x92420000, 0x3a230001, -0x30420001, 0x431024, 0x10400074, 0x2402ffff, 0x8e030000, 0x14620004, -0x3402ffff, 0x96030004, 0x1062006f, 0x24150002, 0x3c020001, 0x571021, -0x904283a2, 0x1440006a, 0x24150003, 0x92e204c8, 0x14400067, 0x0, -0x3c020001, 0x571021, 0x8c4283a4, 0x28420005, 0x10400020, 0x3821, -0x3c020001, 0x571021, 0x8c4283a4, 0x18400016, 0x2821, 0x96060000, -0x520c0, 0x971021, 0x9442776e, 0x14460009, 0x971021, 0x94437770, -0x96020002, 0x14620005, 0x971021, 0x94437772, 0x96020004, 0x50620008, -0x24070001, 0x3c020001, 0x571021, 0x8c4283a4, 0x24a50001, 0xa2102a, -0x5440ffee, 0x520c0, 0x30e200ff, 0x14400044, 0x24150003, 0x8003c45, -0x0, 0x2402021, 0xc0022f8, 0x24050006, 0x3044001f, 0x428c0, -0x2e51021, 0x9442726c, 0x30424000, 0x14400271, 0xb71021, 0x9443726e, -0x96020000, 0x1462000b, 0x418c0, 0xb71021, 0x94437270, 0x96020002, -0x14620006, 0x418c0, 0xb71021, 0x94437272, 0x96020004, 0x10620027, -0x418c0, 0x2e31021, 0x9442726c, 0x30428000, 0x1440025e, 0x2e31021, -0x944d726c, 0x96070000, 0xd28c0, 0xb71021, 0x9442736e, 0x80039f9, -0x3021, 0x420c0, 0x2e41021, 0x9443736c, 0x2e41021, 0x944d736c, -0x30638000, 0x14600010, 0xd28c0, 0xb71021, 0x9442736e, 0x1447fff5, -0x1a02021, 0xb71021, 0x94437370, 0x96020002, 0x5462fff1, 0x420c0, -0xb71021, 0x94437372, 0x96020004, 0x5462ffec, 0x420c0, 0x24060001, -0x30c200ff, 0x1040023d, 0x0, 0x8003a0c, 0x24150003, 0x24150001, -0x8f420260, 0x53102b, 0x10400036, 0x0, 0x8f8300e4, 0x8f8200e0, -0x10620003, 0x24630008, 0xaf8300e4, 0xaf8300e8, 0x8ee400c0, 0x8ee500c4, -0x2601821, 0x1021, 0xa32821, 0xa3302b, 0x822021, 0x862021, -0xaee400c0, 0xaee500c4, 0x8ee20058, 0x24420001, 0xaee20058, 0x8ee20058, -0x8ee2007c, 0x24420001, 0xaee2007c, 0x8ee2007c, 0x8f8200e0, 0xafa20010, -0x8f8200e4, 0x3c040001, 0x24844c30, 0xafa20014, 0x8fa60018, 0x8fa7001c, -0x3c050006, 0xc002403, 0x34a5f203, 0x8003c4b, 0x0, 0x8ee25230, -0xafa20010, 0x8ee25234, 0x3c040001, 0x24844c3c, 0xafa20014, 0x8ee60e00, -0x8ee70e08, 0x3c050006, 0xc002403, 0x34a5f202, 0x8ee201bc, 0x24420001, -0xaee201bc, 0x8003bf2, 0x8ee201bc, 0x96e20468, 0x53102b, 0x54400001, -0x3c168000, 0x126001cb, 0x3c0e001f, 0x35ceffff, 0x3c0ffff5, 0x35ef1000, -0x241e0040, 0x8ee2723c, 0x8f430280, 0x24420001, 0x304203ff, 0x1062019e, -0x0, 0x12c00012, 0x0, 0x8ee35230, 0x8ee25234, 0x1062000a, -0x26f85234, 0x8ef45234, 0xafb80024, 0x8ee35234, 0x21140, 0x24425238, -0x2e28821, 0x24630001, 0x8003a75, 0x306d00ff, 0x8ee201d0, 0x24420001, -0xaee201d0, 0x8ee201d0, 0x8ee30e00, 0x8ee20e08, 0x1062ffca, 0x26f80e08, -0x8ef40e08, 0xb021, 0xafb80024, 0x8ee30e08, 0x21140, 0x24420e10, -0x2e28821, 0x24630001, 0x306d01ff, 0x96e2046a, 0x30420010, 0x10400018, -0x34028100, 0x9643000c, 0x14620015, 0x0, 0x3c020001, 0x571021, -0x904283b0, 0x14400010, 0x0, 0x9642000e, 0xa6220016, 0x8e420008, -0x8e430004, 0x8e440000, 0x2673fffc, 0xae42000c, 0xae430008, 0xae440004, -0x9622000e, 0x26100004, 0x24180001, 0xa3b8002f, 0x34420200, 0xa622000e, -0x8e220000, 0x8e230004, 0x3c040001, 0x34843800, 0x2003021, 0x306a0007, -0x20a8023, 0x3641021, 0x202102b, 0x10400005, 0x26a9821, 0x2041023, -0x3621823, 0x3c020020, 0x438023, 0x26620007, 0x9623000a, 0x2418fff8, -0x58c824, 0x6a1821, 0x79102b, 0x10400002, 0x3206021, 0x606021, -0x1801821, 0x24620007, 0x2418fff8, 0x586024, 0x26c102b, 0x14400004, -0x1932823, 0x1832823, 0x8003ab3, 0xc31021, 0xd31021, 0x4a2023, -0x1c4102b, 0x54400001, 0x8f2021, 0x25420040, 0x4c102b, 0x14400035, -0x5821, 0x94c3000c, 0x24020800, 0x54620032, 0xae260018, 0x3c020001, -0x571021, 0x904283b0, 0x5440002d, 0xae260018, 0x24c20017, 0x1c2102b, -0x10400013, 0x0, 0x3c02fff5, 0x461021, 0x90421017, 0x38430006, -0x2c630001, 0x38420011, 0x2c420001, 0x621825, 0x10600014, 0x24c20010, -0x1c2102b, 0x1040000e, 0x0, 0x3c0bfff5, 0x1665821, 0x956b1010, -0x8003ae4, 0x2562000e, 0x90c20017, 0x38430006, 0x2c630001, 0x38420011, -0x2c420001, 0x621825, 0x10600005, 0x1601821, 0x94cb0010, 0x2562000e, -0x4a5821, 0x1601821, 0x24620007, 0x2418fff8, 0x585824, 0xc31021, -0x4a2023, 0x1c4102b, 0x10400002, 0x1632823, 0x8f2021, 0xae260018, -0x3c020001, 0x571021, 0x904283b0, 0x2102b, 0x216c0, 0x15600002, -0xafa20044, 0x1805821, 0x30820001, 0x10400007, 0x4021, 0x90880000, -0x24840001, 0x1c4102b, 0x10400002, 0x24a5ffff, 0x8f2021, 0x50a00012, -0x81c02, 0x2ca20002, 0x54400009, 0x24a5ffff, 0x94820000, 0x24840002, -0x1024021, 0x1c4102b, 0x10400006, 0x24a5fffe, 0x8003b11, 0x8f2021, -0x90820000, 0x21200, 0x1024021, 0x14a0fff2, 0x2ca20002, 0x81c02, -0x3102ffff, 0x624021, 0x3108ffff, 0x1402821, 0x11400011, 0x2002021, -0x2ca20002, 0x54400009, 0x24a5ffff, 0x94820000, 0x24840002, 0x1024021, -0x1c4102b, 0x10400006, 0x24a5fffe, 0x8003b28, 0x8f2021, 0x90820000, -0x21200, 0x1024021, 0x14a0fff2, 0x2ca20002, 0x81c02, 0x3102ffff, -0x624021, 0x81c02, 0x3102ffff, 0x8f890120, 0x624021, 0x27623800, -0x25230020, 0x62102b, 0x14400002, 0x3108ffff, 0x27633000, 0x8f820128, -0x10620004, 0x0, 0x8f820124, 0x14620007, 0x1402821, 0x8ee201a0, -0x3821, 0x24420001, 0xaee201a0, 0x8003bb9, 0x8ee201a0, 0x8e260000, -0x8e270004, 0x81400, 0x3448000b, 0xad300008, 0xa52b000e, 0xad280018, -0x8fb80044, 0x2021, 0x2961025, 0x581025, 0xad22001c, 0xe5102b, -0xe53823, 0xc43023, 0xc23023, 0xad260000, 0xad270004, 0x8ee204b0, -0xad220010, 0xaf830120, 0x92e24e10, 0x1440005f, 0x24070001, 0x2502ffee, -0x2c420002, 0x14400003, 0x24020011, 0x15020024, 0x0, 0x8ee24e20, -0x210c0, 0x24425028, 0x2e22021, 0x8c830000, 0x24020012, 0x1462000f, -0x0, 0x8ee34e20, 0x8ee24e24, 0x1062000b, 0x0, 0x8c820004, -0x24420001, 0xac820004, 0x8ee24e24, 0x8ee34e20, 0x24420001, 0x105e002a, -0x0, 0x8003b98, 0x0, 0x8ee24e20, 0x24420001, 0x505e0003, -0x1021, 0x8ee24e20, 0x24420001, 0xaee24e20, 0x8ee24e20, 0x210c0, -0x24425028, 0x2e22021, 0x8003bb6, 0x24020012, 0x8ee24e20, 0x210c0, -0x24425028, 0x2e22021, 0x8c830000, 0x24020007, 0x1462001f, 0x0, -0x8ee34e20, 0x8ee24e24, 0x1062001b, 0x0, 0x8c820004, 0x24420001, -0xac820004, 0x8ee24e24, 0x8ee34e20, 0x24420001, 0x105e0007, 0x0, -0x8ee24e24, 0x24420001, 0x10620005, 0x0, 0x8003ba4, 0x0, -0x14600005, 0x0, 0x8f820128, 0x24420020, 0xaf820128, 0x8f820128, -0x8c820004, 0x2c420011, 0x50400012, 0xac800000, 0x8003bb9, 0x0, -0x8ee24e20, 0x24420001, 0x505e0003, 0x1021, 0x8ee24e20, 0x24420001, -0xaee24e20, 0x8ee24e20, 0x210c0, 0x24425028, 0x2e22021, 0x24020007, -0xac820000, 0x24020001, 0xac820004, 0x14e00019, 0x3c050006, 0x3c040001, -0x24844c00, 0x8e220018, 0x34a5f209, 0xafa20010, 0x8e220000, 0x8e230004, -0x2203021, 0x1603821, 0xc002403, 0xafa30014, 0x93a2002f, 0x1040002a, -0x34028100, 0x8e430004, 0x8e440008, 0x8e45000c, 0xa642000c, 0xae430000, -0xae440004, 0xae450008, 0x96220016, 0x8003bf2, 0xa642000e, 0x1599000a, -0x26a1823, 0x9622000e, 0xa623000a, 0x34420004, 0xa622000e, 0x3c010001, -0x370821, 0xa02083b0, 0x8003bef, 0x9821, 0x9624000a, 0x83102b, -0x54400001, 0x801821, 0x24020001, 0xa623000a, 0x3c010001, 0x370821, -0xa02283b0, 0x9622000a, 0x4a1821, 0x2038021, 0x1d0102b, 0x54400001, -0x20f8021, 0x2639823, 0xb021, 0x8fb80024, 0x1660fe5e, 0xaf0d0000, -0x12600022, 0x0, 0x3c010001, 0x370821, 0xac3383b4, 0x3c010001, -0x370821, 0xac3083b8, 0x3c010001, 0x370821, 0xac3283bc, 0x93a2002f, -0x10400008, 0x0, 0x3c020001, 0x571021, 0x8c4283bc, 0x24420004, -0x3c010001, 0x370821, 0xac2283bc, 0x8f430280, 0x8ee2723c, 0x14620006, -0x0, 0x8ee201c0, 0x24420001, 0xaee201c0, 0x8003c4b, 0x8ee201c0, -0x8ee201b8, 0x24420001, 0xaee201b8, 0x8003c4b, 0x8ee201b8, 0x97a4001e, -0x2484fffc, 0x801821, 0x8ee400c0, 0x8ee500c4, 0x1021, 0xa32821, -0xa3302b, 0x822021, 0x862021, 0x24020002, 0xaee400c0, 0xaee500c4, -0x12a2000f, 0x2aa20003, 0x14400017, 0x24020003, 0x16a20015, 0x0, -0x8ee200d0, 0x8ee300d4, 0x24630001, 0x2c640001, 0x441021, 0xaee200d0, -0xaee300d4, 0x8ee200d0, 0x8003c45, 0x8ee300d4, 0x8ee200d8, 0x8ee300dc, -0x24630001, 0x2c640001, 0x441021, 0xaee200d8, 0xaee300dc, 0x8ee200d8, -0x8003c45, 0x8ee300dc, 0x8ee200c8, 0x8ee300cc, 0x24630001, 0x2c640001, -0x441021, 0xaee200c8, 0xaee300cc, 0x8ee200c8, 0x8ee300cc, 0x8f8300e4, -0x8f8200e0, 0x10620003, 0x24630008, 0xaf8300e4, 0xaf8300e8, 0x8fbf0068, -0x8fbe0064, 0x8fb60060, 0x8fb5005c, 0x8fb40058, 0x8fb30054, 0x8fb20050, -0x8fb1004c, 0x8fb00048, 0x3e00008, 0x27bd0070, 0x27bdffe0, 0xafbf0018, -0x8ee30e04, 0x8ee20dfc, 0x10620074, 0x0, 0x8ee30dfc, 0x8ee20e04, -0x622023, 0x4820001, 0x24840200, 0x8ee30e08, 0x8ee20e04, 0x43102b, -0x14400004, 0x24020200, 0x8ee30e04, 0x8003c6d, 0x431823, 0x8ee20e08, -0x8ee30e04, 0x431023, 0x2443ffff, 0x804821, 0x69102a, 0x54400001, -0x604821, 0x8f870100, 0x27623000, 0x24e80020, 0x102102b, 0x50400001, -0x27682800, 0x8f820108, 0x11020004, 0x0, 0x8f820104, 0x15020007, -0x1021, 0x8ee201a4, 0x2021, 0x24420001, 0xaee201a4, 0x8003caf, -0x8ee201a4, 0x8ee40e04, 0x42140, 0x801821, 0x8ee40460, 0x8ee50464, -0xa32821, 0xa3302b, 0x822021, 0x862021, 0xace40000, 0xace50004, -0x8ee30e04, 0x91140, 0xa4e2000e, 0x24020002, 0xace20018, 0x31940, -0x24630e10, 0x2e31021, 0xace20008, 0x8ee20e04, 0xace2001c, 0x8ee204bc, -0xace20010, 0xaf880100, 0x92e204dc, 0x14400011, 0x24040001, 0x8ee24e18, -0x24030040, 0x24420001, 0x50430003, 0x1021, 0x8ee24e18, 0x24420001, -0xaee24e18, 0x8ee24e18, 0x210c0, 0x24424e28, 0x2e21821, 0x24020002, -0xac620000, 0x24020001, 0xac620004, 0x1480000e, 0x24030040, 0x8ee20e04, -0xafa20010, 0x8ee20e08, 0x3c050007, 0xafa20014, 0x8ee60dfc, 0x8ee70e00, -0x3c040001, 0x24844c44, 0xc002403, 0x34a5f001, 0x8003ccd, 0x0, -0x8ee204f0, 0x24420001, 0x50430003, 0x1021, 0x8ee204f0, 0x24420001, -0xaee204f0, 0x8ee204f0, 0x21080, 0x571021, 0xac4904f8, 0x8ee20e04, -0x491021, 0x304201ff, 0xaee20e04, 0x8ee30e04, 0x8ee20dfc, 0x14620005, -0x0, 0x8f820060, 0x2403fdff, 0x431024, 0xaf820060, 0x8fbf0018, -0x3e00008, 0x27bd0020, 0x27bdffe0, 0xafbf0018, 0x8ee3522c, 0x8ee25228, -0x10620074, 0x0, 0x8ee35228, 0x8ee2522c, 0x622023, 0x4820001, -0x24840100, 0x8ee35234, 0x8ee2522c, 0x43102b, 0x14400004, 0x24020100, -0x8ee3522c, 0x8003cef, 0x431823, 0x8ee25234, 0x8ee3522c, 0x431023, -0x2443ffff, 0x804821, 0x69102a, 0x54400001, 0x604821, 0x8f870100, -0x27623000, 0x24e80020, 0x102102b, 0x50400001, 0x27682800, 0x8f820108, -0x11020004, 0x0, 0x8f820104, 0x15020007, 0x1021, 0x8ee201a4, -0x2021, 0x24420001, 0xaee201a4, 0x8003d31, 0x8ee201a4, 0x8ee4522c, -0x42140, 0x801821, 0x8ee40470, 0x8ee50474, 0xa32821, 0xa3302b, -0x822021, 0x862021, 0xace40000, 0xace50004, 0x8ee3522c, 0x91140, -0xa4e2000e, 0x24020003, 0xace20018, 0x31940, 0x24635238, 0x2e31021, -0xace20008, 0x8ee2522c, 0xace2001c, 0x8ee204bc, 0xace20010, 0xaf880100, -0x92e204dc, 0x14400011, 0x24040001, 0x8ee24e18, 0x24030040, 0x24420001, -0x50430003, 0x1021, 0x8ee24e18, 0x24420001, 0xaee24e18, 0x8ee24e18, -0x210c0, 0x24424e28, 0x2e21821, 0x24020003, 0xac620000, 0x24020001, -0xac620004, 0x1480000e, 0x24030040, 0x8ee2522c, 0xafa20010, 0x8ee25234, -0x3c050007, 0xafa20014, 0x8ee65228, 0x8ee75230, 0x3c040001, 0x24844c50, -0xc002403, 0x34a5f010, 0x8003d4f, 0x0, 0x8ee204f0, 0x24420001, -0x50430003, 0x1021, 0x8ee204f0, 0x24420001, 0xaee204f0, 0x8ee204f0, -0x21080, 0x571021, 0xac4904f8, 0x8ee2522c, 0x491021, 0x304200ff, -0xaee2522c, 0x8ee3522c, 0x8ee25228, 0x14620005, 0x0, 0x8f820060, -0x2403feff, 0x431024, 0xaf820060, 0x8fbf0018, 0x3e00008, 0x27bd0020, -0x8f820120, 0x8ee34e24, 0x8f820124, 0x8f860128, 0x24020040, 0x24630001, -0x50620003, 0x1021, 0x8ee24e24, 0x24420001, 0xaee24e24, 0x8ee24e24, -0x8ee44e24, 0x8ee34e20, 0x210c0, 0x24425028, 0x14830007, 0x2e22821, -0x8f820128, 0x24420020, 0xaf820128, 0x8f820128, 0x8003d82, 0xaca00000, -0x8ee24e24, 0x24030040, 0x24420001, 0x50430003, 0x1021, 0x8ee24e24, -0x24420001, 0x210c0, 0x24425028, 0x2e22821, 0x8ca20004, 0x8f830128, -0x21140, 0x621821, 0xaf830128, 0xaca00000, 0x8cc20018, 0x2443fffe, -0x2c620012, 0x10400008, 0x31080, 0x3c010001, 0x220821, 0x8c224c60, -0x400008, 0x0, 0x24020001, 0xaee24e14, 0x3e00008, 0x0, -0x27bdffc8, 0xafbf0030, 0xafb5002c, 0xafb40028, 0xafb30024, 0xafb20020, -0xafb1001c, 0xafb00018, 0x8f830128, 0x8f820124, 0x106202b0, 0x9821, -0x3c11001f, 0x3631ffff, 0x3c12fff5, 0x36521000, 0x24150012, 0x24140040, -0x8f8c0128, 0x8f820128, 0x24420020, 0xaf820128, 0x9182001b, 0x8f830128, -0x2443fffe, 0x2c620012, 0x1040029c, 0x31080, 0x3c010001, 0x220821, -0x8c224cb8, 0x400008, 0x0, 0x8f420218, 0x30420100, 0x10400007, -0x0, 0x95830016, 0x95820018, 0x621823, 0x31402, 0x431021, -0xa5820016, 0x8d82001c, 0x3c038000, 0x3044ffff, 0x436824, 0x3c030800, -0x431824, 0x11a00004, 0xad84001c, 0x41140, 0x8003dc8, 0x24425238, -0x41140, 0x24420e10, 0x2e25821, 0x9562000e, 0x3042fffc, 0x10600004, -0xa562000e, 0x95840016, 0x8003eb0, 0x0, 0x8d690018, 0x4021, -0x952a0000, 0x25290002, 0x95270000, 0x25290002, 0x95260000, 0x25290002, -0x95250000, 0x25290002, 0x95240000, 0x25290002, 0x95230000, 0x25290002, -0x95220000, 0x25290002, 0x1475021, 0x1465021, 0x1455021, 0x1445021, -0x1435021, 0x1425021, 0xa1c02, 0x3142ffff, 0x625021, 0xa1c02, -0x3142ffff, 0x625021, 0x96e2046a, 0x314effff, 0x30420002, 0x10400044, -0x5021, 0x25220014, 0x222102b, 0x10400014, 0x1201821, 0x2405000a, -0x2021, 0x223102b, 0x54400001, 0x721821, 0x94620000, 0x24630002, -0x24a5ffff, 0x14a0fff9, 0x822021, 0x41c02, 0x3082ffff, 0x622021, -0x41402, 0x3083ffff, 0x431021, 0x3042ffff, 0x8003e23, 0x1425021, -0x952a0000, 0x25290002, 0x95280000, 0x25290002, 0x95270000, 0x25290002, -0x95260000, 0x25290002, 0x95250000, 0x25290002, 0x95230000, 0x25290002, -0x95220000, 0x25290002, 0x95240000, 0x25290002, 0x1485021, 0x1475021, -0x1465021, 0x1455021, 0x1435021, 0x1425021, 0x95220000, 0x95230002, -0x1445021, 0x1425021, 0x1435021, 0xa1c02, 0x3142ffff, 0x625021, -0xa1c02, 0x3142ffff, 0x625021, 0x3148ffff, 0x51000001, 0x3408ffff, -0x8d620018, 0x9443000c, 0x24020800, 0x54620005, 0xa5680010, 0x9562000e, -0x34420002, 0xa562000e, 0xa5680010, 0x96e2046a, 0x2821, 0x30420008, -0x14400056, 0x3021, 0x8d630018, 0x24620024, 0x222102b, 0x10400034, -0x24690010, 0x229102b, 0x54400001, 0x1324821, 0x95250000, 0x24690014, -0x229102b, 0x10400002, 0x24a5ffec, 0x1324821, 0x95220000, 0x30420fff, -0x14400003, 0x25290002, 0x8003e50, 0x24130001, 0x9821, 0xa03021, -0x229102b, 0x54400001, 0x1324821, 0x91220001, 0x25290002, 0xa22821, -0x229102b, 0x54400001, 0x1324821, 0x25290002, 0x229102b, 0x54400001, -0x1324821, 0x95220000, 0x25290002, 0xa22821, 0x229102b, 0x54400001, -0x1324821, 0x95220000, 0x25290002, 0xa22821, 0x229102b, 0x54400001, -0x1324821, 0x95220000, 0x25290002, 0xa22821, 0x229102b, 0x54400001, -0x1324821, 0x95220000, 0x8003e89, 0xa22821, 0x94650010, 0x94620014, -0x24690016, 0x30420fff, 0x14400003, 0x24a5ffec, 0x8003e7c, 0x24130001, -0x9821, 0xa03021, 0x91230001, 0x25290004, 0x95220000, 0x25290002, -0x95240000, 0x25290002, 0xa32821, 0xa22821, 0x95220000, 0x95230002, -0xa42821, 0xa22821, 0xa32821, 0x51c02, 0x30a2ffff, 0x622821, -0x51c02, 0x30a2ffff, 0x622821, 0x96e2046a, 0x30420001, 0x1040001e, -0x2021, 0x95820016, 0x4e2023, 0x41402, 0x822021, 0x326200ff, -0x50400002, 0x862021, 0x852021, 0x41402, 0x822021, 0x3084ffff, -0x50800001, 0x3404ffff, 0x8d620018, 0x24430017, 0x223102b, 0x54400001, -0x721821, 0x90620000, 0x38430011, 0x2c630001, 0x38420006, 0x2c420001, -0x621825, 0x10600004, 0x0, 0x9562000e, 0x34420001, 0xa562000e, -0x9562000e, 0x240a0002, 0x30420004, 0x10400002, 0xa5640012, 0x240a0004, -0x8f880120, 0x27623800, 0x25090020, 0x122102b, 0x50400001, 0x27693000, -0x8f820128, 0x11220004, 0x0, 0x8f820124, 0x15220007, 0x24040020, -0x8ee201a0, 0x8021, 0x24420001, 0xaee201a0, 0x8003f3f, 0x8ee201a0, -0x8ee5723c, 0x8ee60480, 0x8ee70484, 0xad0b0008, 0xa504000e, 0xad0a0018, -0x52940, 0xa01821, 0x1021, 0xe33821, 0xe3202b, 0xc23021, -0xc43021, 0xad060000, 0xad070004, 0x8ee2723c, 0x4d1025, 0xad02001c, -0x8ee204b4, 0xad020010, 0xaf890120, 0x92e24e10, 0x14400060, 0x24100001, -0x2543ffee, 0x2c630002, 0x39420011, 0x2c420001, 0x621825, 0x10600024, -0x0, 0x8ee24e20, 0x210c0, 0x24425028, 0x2e22021, 0x8c820000, -0x1455000f, 0x0, 0x8ee34e20, 0x8ee24e24, 0x1062000b, 0x0, -0x8c820004, 0x24420001, 0xac820004, 0x8ee24e24, 0x8ee34e20, 0x24420001, -0x1054002b, 0x0, 0x8003f1e, 0x0, 0x8ee24e20, 0x24420001, -0x50540003, 0x1021, 0x8ee24e20, 0x24420001, 0xaee24e20, 0x8ee24e20, -0x210c0, 0x24425028, 0x2e22021, 0x24020001, 0x8003f3e, 0xac950000, -0x8ee24e20, 0x210c0, 0x24425028, 0x2e22021, 0x8c830000, 0x24020007, -0x1462001f, 0x0, 0x8ee34e20, 0x8ee24e24, 0x1062001b, 0x0, -0x8c820004, 0x24420001, 0xac820004, 0x8ee24e24, 0x8ee34e20, 0x24420001, -0x10540007, 0x0, 0x8ee24e24, 0x24420001, 0x10620005, 0x0, -0x8003f2a, 0x0, 0x14600005, 0x0, 0x8f820128, 0x24420020, -0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011, 0x50400012, 0xac800000, -0x8003f3f, 0x0, 0x8ee24e20, 0x24420001, 0x50540003, 0x1021, -0x8ee24e20, 0x24420001, 0xaee24e20, 0x8ee24e20, 0x210c0, 0x24425028, -0x2e22021, 0x24020007, 0xac820000, 0x24020001, 0xac820004, 0x1600000d, -0x0, 0x8f820120, 0x3c040001, 0x24844ca8, 0xafa00014, 0xafa20010, -0x8d86001c, 0x8f870124, 0x3c050008, 0xc002403, 0x34a50001, 0x8004047, -0x0, 0x8ee2723c, 0x24420001, 0x304203ff, 0x11a00006, 0xaee2723c, -0x8ee201c8, 0x2442ffff, 0xaee201c8, 0x8003f5b, 0x8ee201c8, 0x8ee201c4, -0x2442ffff, 0xaee201c4, 0x8ee201c4, 0x8ee201cc, 0x2442ffff, 0xaee201cc, -0x8004047, 0x8ee201cc, 0x8f420240, 0x104000e5, 0x0, 0x8ee20e0c, -0x24420001, 0x8004047, 0xaee20e0c, 0x9582001e, 0xad82001c, 0x8f420240, -0x10400072, 0x0, 0x8ee20e0c, 0x24420001, 0xaee20e0c, 0x8f430240, -0x43102b, 0x144000d5, 0x0, 0x8f830120, 0x27623800, 0x24660020, -0xc2102b, 0x50400001, 0x27663000, 0x8f820128, 0x10c20004, 0x0, -0x8f820124, 0x14c20007, 0x0, 0x8ee201a0, 0x8021, 0x24420001, -0xaee201a0, 0x8003fca, 0x8ee201a0, 0x8ee2723c, 0xac62001c, 0x8ee40498, -0x8ee5049c, 0x2462001c, 0xac620008, 0x24020008, 0xa462000e, 0x24020011, -0xac620018, 0xac640000, 0xac650004, 0x8ee204b4, 0xac620010, 0xaf860120, -0x92e24e10, 0x14400034, 0x24100001, 0x8ee24e20, 0x210c0, 0x24425028, -0x2e22021, 0x8c820000, 0x1455001f, 0x0, 0x8ee34e20, 0x8ee24e24, -0x1062001b, 0x0, 0x8c820004, 0x24420001, 0xac820004, 0x8ee24e24, -0x8ee34e20, 0x24420001, 0x10540007, 0x0, 0x8ee24e24, 0x24420001, -0x10620005, 0x0, 0x8003fb6, 0x0, 0x14600005, 0x0, -0x8f820128, 0x24420020, 0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011, -0x50400011, 0xac800000, 0x8003fca, 0x0, 0x8ee24e20, 0x24420001, -0x50540003, 0x1021, 0x8ee24e20, 0x24420001, 0xaee24e20, 0x8ee24e20, -0x210c0, 0x24425028, 0x2e22021, 0x24020001, 0xac950000, 0xac820004, -0x5600000b, 0x24100001, 0x8ee2723c, 0x3c040001, 0x24844c18, 0xafa00014, -0xafa20010, 0x8ee6723c, 0x8f470280, 0x3c050009, 0xc002403, 0x34a5f008, -0x56000001, 0xaee00e0c, 0x8ee20184, 0x24420001, 0xaee20184, 0x8004040, -0x8ee20184, 0x8f830120, 0x27623800, 0x24660020, 0xc2102b, 0x50400001, -0x27663000, 0x8f820128, 0x10c20004, 0x0, 0x8f820124, 0x14c20007, -0x0, 0x8ee201a0, 0x8021, 0x24420001, 0xaee201a0, 0x8004034, -0x8ee201a0, 0x8ee2723c, 0xac62001c, 0x8ee40498, 0x8ee5049c, 0x2462001c, -0xac620008, 0x24020008, 0xa462000e, 0x24020011, 0xac620018, 0xac640000, -0xac650004, 0x8ee204b4, 0xac620010, 0xaf860120, 0x92e24e10, 0x14400034, -0x24100001, 0x8ee24e20, 0x210c0, 0x24425028, 0x2e22021, 0x8c820000, -0x1455001f, 0x0, 0x8ee34e20, 0x8ee24e24, 0x1062001b, 0x0, -0x8c820004, 0x24420001, 0xac820004, 0x8ee24e24, 0x8ee34e20, 0x24420001, -0x10540007, 0x0, 0x8ee24e24, 0x24420001, 0x10620005, 0x0, -0x8004020, 0x0, 0x14600005, 0x0, 0x8f820128, 0x24420020, -0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011, 0x50400011, 0xac800000, -0x8004034, 0x0, 0x8ee24e20, 0x24420001, 0x50540003, 0x1021, -0x8ee24e20, 0x24420001, 0xaee24e20, 0x8ee24e20, 0x210c0, 0x24425028, -0x2e22021, 0x24020001, 0xac950000, 0xac820004, 0x1600000b, 0x0, -0x8ee2723c, 0x3c040001, 0x24844c18, 0xafa00014, 0xafa20010, 0x8ee6723c, -0x8f470280, 0x3c050009, 0xc002403, 0x34a5f008, 0x8ee20170, 0x24420001, -0xaee20170, 0x8004047, 0x8ee20170, 0x24020001, 0xaee24e14, 0x8f830128, -0x8f820124, 0x1462fd58, 0x0, 0x8fbf0030, 0x8fb5002c, 0x8fb40028, -0x8fb30024, 0x8fb20020, 0x8fb1001c, 0x8fb00018, 0x3e00008, 0x27bd0038, -0x27bdffe8, 0x27840208, 0x27450200, 0x24060008, 0xafbf0014, 0xc00249a, -0xafb00010, 0x24040001, 0x24100001, 0x2402241f, 0xaf900210, 0xaf900200, -0xaf800204, 0xaf820214, 0x8f460248, 0x24030004, 0x3c020040, 0x3c010001, -0xac234ff8, 0x3c010001, 0xac234ffc, 0x3c010001, 0xac20509c, 0x3c010001, -0xac224ff4, 0x3c010001, 0xac234ffc, 0xc004eac, 0x24050004, 0xc004734, -0x0, 0x8ee20000, 0x3c03feff, 0x3463fffd, 0x431024, 0xaee20000, -0x3c023c00, 0xaf82021c, 0x3c010001, 0x370821, 0xac30839c, 0x8fbf0014, -0x8fb00010, 0x3e00008, 0x27bd0018, 0x27bdffe0, 0x3c050008, 0x34a50400, -0xafbf0018, 0xafa00010, 0xafa00014, 0x8f860200, 0x3c040001, 0x24844d60, -0xc002403, 0x3821, 0x8ee20270, 0x24420001, 0xaee20270, 0x8ee20270, -0x8f830200, 0x3c023f00, 0x621824, 0x8fbf0018, 0x3c020400, 0x3e00008, -0x27bd0020, 0x27bdffd8, 0xafbf0020, 0xafb1001c, 0xafb00018, 0x8f900220, -0x8ee20204, 0x3821, 0x24420001, 0xaee20204, 0x8ee20204, 0x3c020300, -0x2021024, 0x10400027, 0x3c110400, 0xc00428b, 0x0, 0x3c020100, -0x2021024, 0x10400007, 0x0, 0x8ee20208, 0x24420001, 0xaee20208, -0x8ee20208, 0x80040b6, 0x3c03fdff, 0x8ee2020c, 0x24420001, 0xaee2020c, -0x8ee2020c, 0x3c03fdff, 0x3463ffff, 0x3c0808ff, 0x3508ffff, 0x8ee20000, -0x3c040001, 0x24844d6c, 0x3c050008, 0x2003021, 0x431024, 0xaee20000, -0x8f820220, 0x3821, 0x3c030300, 0x481024, 0x431025, 0xaf820220, -0xafa00010, 0xc002403, 0xafa00014, 0x8004286, 0x0, 0x2111024, -0x1040001f, 0x3c024000, 0x8f830224, 0x24021402, 0x1462000b, 0x3c03fdff, -0x3c040001, 0x24844d78, 0x3c050008, 0xafa00010, 0xafa00014, 0x8f860224, -0x34a5ffff, 0xc002403, 0x3821, 0x3c03fdff, 0x8ee20000, 0x3463ffff, -0x2002021, 0x431024, 0xc004c08, 0xaee20000, 0x8ee20210, 0x24420001, -0xaee20210, 0x8ee20210, 0x8f820220, 0x3c0308ff, 0x3463ffff, 0x431024, -0x8004285, 0x511025, 0x2021024, 0x10400142, 0x0, 0x8ee2021c, -0x24420001, 0xaee2021c, 0x8ee2021c, 0x8f820220, 0x3c0308ff, 0x3463ffff, -0x431024, 0x34420004, 0xaf820220, 0x8f830054, 0x8f820054, 0x80040fe, -0x24630002, 0x8f820054, 0x621023, 0x2c420003, 0x1440fffc, 0x0, -0x8f8600e0, 0x8f8400e4, 0x30c20007, 0x10400012, 0x0, 0x8f8300e4, -0x2402fff8, 0xc21024, 0x1043000d, 0x0, 0x8f820054, 0x8f8300e0, -0x14c30009, 0x24440050, 0x8f820054, 0x821023, 0x2c420051, 0x10400004, -0x0, 0x8f8200e0, 0x10c2fff9, 0x0, 0x8f820220, 0x3c0308ff, -0x3463fffd, 0x431024, 0xaf820220, 0x8f8600e0, 0x30c20007, 0x10400003, -0x2402fff8, 0xc23024, 0xaf8600e0, 0x8f8300c4, 0x3c02001f, 0x3442ffff, -0x24680008, 0x48102b, 0x10400003, 0x3c02fff5, 0x34421000, 0x1024021, -0x8f8b00c8, 0x8f850120, 0x8f840124, 0x8004135, 0x6021, 0x27623800, -0x82102b, 0x50400001, 0x27643000, 0x10a40010, 0x318200ff, 0x8c820018, -0x38430007, 0x2c630001, 0x3842000b, 0x2c420001, 0x621825, 0x5060fff3, -0x24840020, 0x8ee20230, 0x240c0001, 0x24420001, 0xaee20230, 0x8ee20230, -0x8c8b0008, 0x318200ff, 0x14400065, 0x0, 0x3c020001, 0x571021, -0x904283b0, 0x14400060, 0x0, 0x8f8400e4, 0xc41023, 0x218c3, -0x4620001, 0x24630200, 0x8f8900c4, 0x10600005, 0x24020001, 0x10620009, -0x0, 0x8004177, 0x0, 0x8ee20220, 0x1205821, 0x24420001, -0xaee20220, 0x80041ac, 0x8ee20220, 0x8ee20224, 0x3c05000a, 0x24420001, -0xaee20224, 0x8c8b0000, 0x34a5f000, 0x8ee20224, 0x12b1823, 0xa3102b, -0x54400001, 0x651821, 0x2c62233f, 0x14400040, 0x0, 0x8f8200e8, -0x24420008, 0xaf8200e8, 0x8f8200e8, 0x8f8200e4, 0x1205821, 0x24420008, -0xaf8200e4, 0x80041ac, 0x8f8200e4, 0x8ee20228, 0x3c03000a, 0x24420001, -0xaee20228, 0x8c840000, 0x3463f000, 0x8ee20228, 0x883823, 0x67102b, -0x54400001, 0xe33821, 0x3c020003, 0x34420d40, 0x47102b, 0x10400003, -0x0, 0x80041ac, 0x805821, 0x8f8200e4, 0x24440008, 0xaf8400e4, -0x8f8400e4, 0x10860018, 0x3c05000a, 0x34a5f000, 0x3c0a0003, 0x354a0d40, -0x8ee2007c, 0x24420001, 0xaee2007c, 0x8c830000, 0x8ee2007c, 0x683823, -0xa7102b, 0x54400001, 0xe53821, 0x147102b, 0x54400007, 0x605821, -0x8f8200e4, 0x24440008, 0xaf8400e4, 0x8f8400e4, 0x1486ffef, 0x0, -0x14860005, 0x0, 0x1205821, 0xaf8600e4, 0x80041ac, 0xaf8600e8, -0xaf8400e4, 0xaf8400e8, 0x8f8200c8, 0x3c03000a, 0x3463f000, 0x483823, -0x67102b, 0x54400001, 0xe33821, 0x3c020003, 0x34420d3f, 0x47102b, -0x54400007, 0x6021, 0x1683823, 0x67102b, 0x54400003, 0xe33821, -0x80041bf, 0x3c020003, 0x3c020003, 0x34420d3f, 0x47102b, 0x14400016, -0x318200ff, 0x14400006, 0x0, 0x3c020001, 0x571021, 0x904283b0, -0x1040000f, 0x0, 0x8ee2022c, 0x3c04fdff, 0x8ee30000, 0x3484ffff, -0x24420001, 0xaee2022c, 0x8ee2022c, 0x24020001, 0x641824, 0x3c010001, -0x370821, 0xa02283a8, 0x800421c, 0xaee30000, 0xaf8b00c8, 0x8f8300c8, -0x8f8200c4, 0x3c04000a, 0x3484f000, 0x623823, 0x87102b, 0x54400001, -0xe43821, 0x3c020003, 0x34420d40, 0x47102b, 0x2ce30001, 0x431025, -0x10400008, 0x0, 0x8f820220, 0x3c0308ff, 0x3463ffff, 0x431024, -0x3c034000, 0x431025, 0xaf820220, 0x8f8600e0, 0x8f8400e4, 0x10c4002a, -0x0, 0x8ee2007c, 0x24420001, 0xaee2007c, 0x8ee2007c, 0x24c2fff8, -0xaf8200e0, 0x3c020001, 0x8c427140, 0x3c030008, 0x8f8600e0, 0x431024, -0x1040001d, 0x0, 0x10c4001b, 0x240dfff8, 0x3c0a000a, 0x354af000, -0x3c0c0080, 0x24850008, 0x27622800, 0x50a20001, 0x27651800, 0x8c880004, -0x8c820000, 0x8ca90000, 0x3103ffff, 0x431021, 0x4d1024, 0x24430010, -0x6b102b, 0x54400001, 0x6a1821, 0x12b102b, 0x54400001, 0x12a4821, -0x10690002, 0x10c1025, 0xac820004, 0xa02021, 0x14c4ffeb, 0x24850008, -0x8f820220, 0x3c0308ff, 0x3463ffff, 0x431024, 0x34420002, 0xaf820220, -0x8f830054, 0x8f820054, 0x8004227, 0x24630001, 0x8f820054, 0x621023, -0x2c420002, 0x1440fffc, 0x0, 0x8f820220, 0x3c0308ff, 0x3463fffb, -0x431024, 0xaf820220, 0x6010055, 0x0, 0x8ee20218, 0x24420001, -0xaee20218, 0x8ee20218, 0x8f820220, 0x3c0308ff, 0x3463ffff, 0x431024, -0x34420004, 0xaf820220, 0x8f830054, 0x8f820054, 0x8004241, 0x24630002, -0x8f820054, 0x621023, 0x2c420003, 0x1440fffc, 0x0, 0x8f8600e0, -0x30c20007, 0x10400012, 0x0, 0x8f8300e4, 0x2402fff8, 0xc21024, -0x1043000d, 0x0, 0x8f820054, 0x8f8300e0, 0x14c30009, 0x24440032, -0x8f820054, 0x821023, 0x2c420033, 0x10400004, 0x0, 0x8f8200e0, -0x10c2fff9, 0x0, 0x8f820220, 0x3c0308ff, 0x3463fffd, 0x431024, -0xaf820220, 0x8f8600e0, 0x30c20007, 0x10400003, 0x2402fff8, 0xc23024, -0xaf8600e0, 0x240301f5, 0x8f8200e8, 0x673823, 0x718c0, 0x431021, -0xaf8200e8, 0x8f8200e8, 0xaf8200e4, 0x8ee2007c, 0x3c0408ff, 0x3484ffff, -0x471021, 0xaee2007c, 0x8f820220, 0x3c038000, 0x34630002, 0x441024, -0x431025, 0xaf820220, 0x8f830054, 0x8f820054, 0x800427d, 0x24630001, -0x8f820054, 0x621023, 0x2c420002, 0x1440fffc, 0x0, 0x8f820220, -0x3c0308ff, 0x3463fffb, 0x431024, 0xaf820220, 0x8fbf0020, 0x8fb1001c, -0x8fb00018, 0x3e00008, 0x27bd0028, 0x3c020001, 0x8c42500c, 0x27bdffd8, -0x10400012, 0xafbf0020, 0x3c040001, 0x24844d84, 0x3c050008, 0x24020001, -0x3c010001, 0x370821, 0xac22839c, 0xafa00010, 0xafa00014, 0x8f860220, -0x34a50498, 0x3c010001, 0xac20500c, 0x3c010001, 0xac225000, 0xc002403, -0x3821, 0x8f420268, 0x3c037fff, 0x3463ffff, 0x431024, 0xaf420268, -0x8ee204c0, 0x8ee404c4, 0x2403fffe, 0x431024, 0x30840002, 0x1080011e, -0xaee204c0, 0x8ee204c4, 0x2403fffd, 0x431024, 0xaee204c4, 0x8f820044, -0x3c030600, 0x34632000, 0x34420020, 0xaf820044, 0xafa30018, 0x8ee205f8, -0x8f430228, 0x24420001, 0x304a00ff, 0x514300fe, 0xafa00010, 0x8ee205f8, -0x210c0, 0x571021, 0x8fa30018, 0x8fa4001c, 0xac4305fc, 0xac440600, -0x8f830054, 0x8f820054, 0x24690032, 0x1221023, 0x2c420033, 0x1040006a, -0x5821, 0x24180008, 0x240f000d, 0x240d0007, 0x240c0040, 0x240e0001, -0x8f870120, 0x27623800, 0x24e80020, 0x102102b, 0x50400001, 0x27683000, -0x8f820128, 0x11020004, 0x0, 0x8f820124, 0x15020007, 0x1021, -0x8ee201a0, 0x2821, 0x24420001, 0xaee201a0, 0x800432d, 0x8ee201a0, -0x8ee405f8, 0x420c0, 0x801821, 0x8ee40430, 0x8ee50434, 0xa32821, -0xa3302b, 0x822021, 0x862021, 0xace40000, 0xace50004, 0x8ee205f8, -0xa4f8000e, 0xacef0018, 0xacea001c, 0x210c0, 0x244205fc, 0x2e21021, -0xace20008, 0x8ee204b4, 0xace20010, 0xaf880120, 0x92e24e10, 0x14400033, -0x24050001, 0x8ee24e20, 0x210c0, 0x24425028, 0x2e22021, 0x8c820000, -0x144d001f, 0x0, 0x8ee34e20, 0x8ee24e24, 0x1062001b, 0x0, -0x8c820004, 0x24420001, 0xac820004, 0x8ee24e24, 0x8ee34e20, 0x24420001, -0x104c0007, 0x0, 0x8ee24e24, 0x24420001, 0x10620005, 0x0, -0x800431a, 0x0, 0x14600005, 0x0, 0x8f820128, 0x24420020, -0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011, 0x50400010, 0xac800000, -0x800432d, 0x0, 0x8ee24e20, 0x24420001, 0x504c0003, 0x1021, -0x8ee24e20, 0x24420001, 0xaee24e20, 0x8ee24e20, 0x210c0, 0x24425028, -0x2e22021, 0xac8d0000, 0xac8e0004, 0x54a00006, 0x240b0001, 0x8f820054, -0x1221023, 0x2c420033, 0x1440ff9d, 0x0, 0x316300ff, 0x24020001, -0x54620079, 0xafa00010, 0xaeea05f8, 0x8f830054, 0x8f820054, 0x24690032, -0x1221023, 0x2c420033, 0x10400061, 0x5821, 0x240d0008, 0x240c0011, -0x24080012, 0x24070040, 0x240a0001, 0x8f830120, 0x27623800, 0x24660020, -0xc2102b, 0x50400001, 0x27663000, 0x8f820128, 0x10c20004, 0x0, -0x8f820124, 0x14c20007, 0x0, 0x8ee201a0, 0x2821, 0x24420001, -0xaee201a0, 0x8004399, 0x8ee201a0, 0x8ee205f8, 0xac62001c, 0x8ee40490, -0x8ee50494, 0x2462001c, 0xac620008, 0xa46d000e, 0xac6c0018, 0xac640000, -0xac650004, 0x8ee204b4, 0xac620010, 0xaf860120, 0x92e24e10, 0x14400033, -0x24050001, 0x8ee24e20, 0x210c0, 0x24425028, 0x2e22021, 0x8c820000, -0x1448001f, 0x0, 0x8ee34e20, 0x8ee24e24, 0x1062001b, 0x0, -0x8c820004, 0x24420001, 0xac820004, 0x8ee24e24, 0x8ee34e20, 0x24420001, -0x10470007, 0x0, 0x8ee24e24, 0x24420001, 0x10620005, 0x0, -0x8004386, 0x0, 0x14600005, 0x0, 0x8f820128, 0x24420020, -0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011, 0x50400010, 0xac800000, -0x8004399, 0x0, 0x8ee24e20, 0x24420001, 0x50470003, 0x1021, -0x8ee24e20, 0x24420001, 0xaee24e20, 0x8ee24e20, 0x210c0, 0x24425028, -0x2e22021, 0xac880000, 0xac8a0004, 0x54a00006, 0x240b0001, 0x8f820054, -0x1221023, 0x2c420033, 0x1440ffa6, 0x0, 0x316300ff, 0x24020001, -0x54620003, 0xafa00010, 0x80043c6, 0x0, 0x3c040001, 0x24844d90, -0xafa00014, 0x8f860120, 0x8f870124, 0x3c050009, 0xc002403, 0x34a5f011, -0x80043c6, 0x0, 0x3c040001, 0x24844d9c, 0xafa00014, 0x8f860120, -0x8f870124, 0x3c050009, 0xc002403, 0x34a5f010, 0x80043c6, 0x0, -0x3c040001, 0x24844da8, 0xafa00014, 0x8ee605f8, 0x8f470228, 0x3c050009, -0xc002403, 0x34a5f00f, 0x8ee201a8, 0x24420001, 0xaee201a8, 0x8ee201a8, -0x8ee20158, 0x24420001, 0xaee20158, 0x8ee20158, 0x8fbf0020, 0x3e00008, -0x27bd0028, 0x3c020001, 0x8c42500c, 0x27bdffe0, 0x1440000d, 0xafbf0018, -0x3c040001, 0x24844db4, 0x3c050008, 0xafa00010, 0xafa00014, 0x8f860220, -0x34a50499, 0x24020001, 0x3c010001, 0xac22500c, 0xc002403, 0x3821, -0x8ee204c0, 0x3c030001, 0x771821, 0x946383a2, 0x34420001, 0x10600007, -0xaee204c0, 0x8f820220, 0x3c0308ff, 0x3463ffff, 0x431024, 0x34420008, -0xaf820220, 0x24040001, 0xc004fb3, 0x24050004, 0xaf420268, 0x8fbf0018, -0x3e00008, 0x27bd0020, 0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, 0x3c120001, 0x26521100, -0x3c140001, 0x8e944f80, 0x3c100001, 0x26101020, 0x3c15c000, 0x36b50060, -0x8e8a0000, 0x8eb30000, 0x26a400b, 0x248000a, 0x200f821, 0x0, -0xd, 0x0, 0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x80014d6, 0x0, 0x80014d8, 0x3c0a0001, -0x80014d8, 0x3c0a0002, 0x80014d8, 0x0, 0x80024a6, 0x0, -0x80014d8, 0x3c0a0003, 0x80014d8, 0x3c0a0004, 0x8002f7c, 0x0, -0x80014d8, 0x3c0a0005, 0x8003cd8, 0x0, 0x8003c56, 0x0, -0x80014d8, 0x3c0a0006, 0x80014d8, 0x3c0a0007, 0x80014d8, 0x0, -0x80014d8, 0x0, 0x80014d8, 0x0, 0x8002a75, 0x0, -0x80014d8, 0x3c0a000b, 0x80014d8, 0x3c0a000c, 0x80014d8, 0x3c0a000d, -0x8002378, 0x0, 0x8002335, 0x0, 0x80014d8, 0x3c0a000e, -0x8001b38, 0x0, 0x80024a4, 0x0, 0x80014d8, 0x3c0a000f, -0x8004097, 0x0, 0x8004081, 0x0, 0x80014d8, 0x3c0a0010, -0x80014ee, 0x0, 0x80014d8, 0x3c0a0011, 0x80014d8, 0x3c0a0012, -0x80014d8, 0x3c0a0013, 0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, 0x3c030001, 0x34633800, -0x24050080, 0x2404001f, 0x2406ffff, 0x24020001, 0xaf80021c, 0xaf820200, -0xaf820220, 0x3631021, 0xaf8200c0, 0x3631021, 0xaf8200c4, 0x3631021, -0xaf8200c8, 0x27623800, 0xaf8200d0, 0x27623800, 0xaf8200d4, 0x27623800, -0xaf8200d8, 0x27621800, 0xaf8200e0, 0x27621800, 0xaf8200e4, 0x27621800, -0xaf8200e8, 0x27621000, 0xaf8200f0, 0x27621000, 0xaf8200f4, 0x27621000, -0xaf8200f8, 0xaca00000, 0x2484ffff, 0x1486fffd, 0x24a50004, 0x8f830040, -0x3c02f000, 0x621824, 0x3c025000, 0x1062000c, 0x43102b, 0x14400006, -0x3c026000, 0x3c024000, 0x10620008, 0x24020800, 0x80044f9, 0x0, -0x10620004, 0x24020800, 0x80044f9, 0x0, 0x24020700, 0x3c010001, -0xac225010, 0x3e00008, 0x0, 0x27bdffd0, 0xafbf0028, 0x3c010001, -0xc004be5, 0xac204ff8, 0x24040001, 0x2821, 0x27a60020, 0x34028000, -0xc004802, 0xa7a20020, 0x8f830054, 0x8f820054, 0x800450b, 0x24630064, -0x8f820054, 0x621023, 0x2c420065, 0x1440fffc, 0x24040001, 0x24050001, -0xc0047c0, 0x27a60020, 0x8f830054, 0x8f820054, 0x8004517, 0x24630064, -0x8f820054, 0x621023, 0x2c420065, 0x1440fffc, 0x24040001, 0x24050001, -0xc0047c0, 0x27a60020, 0x8f830054, 0x8f820054, 0x8004523, 0x24630064, -0x8f820054, 0x621023, 0x2c420065, 0x1440fffc, 0x24040001, 0x24050002, -0xc0047c0, 0x27a60018, 0x8f830054, 0x8f820054, 0x800452f, 0x24630064, -0x8f820054, 0x621023, 0x2c420065, 0x1440fffc, 0x24040001, 0x24050003, -0xc0047c0, 0x27a6001a, 0x97a20020, 0x10400022, 0x24030001, 0x3c020001, -0x8c424ff8, 0x97a30018, 0x34420001, 0x3c010001, 0xac224ff8, 0x24020015, -0x14620008, 0x3402f423, 0x97a3001a, 0x14620005, 0x24020003, 0x3c010001, -0xac2250ac, 0x8004562, 0x3c08fff0, 0x97a30018, 0x24027810, 0x1462000a, -0x24020002, 0x97a3001a, 0x24020001, 0x14620006, 0x24020002, 0x24020004, -0x3c010001, 0xac2250ac, 0x8004562, 0x3c08fff0, 0x3c010001, 0xac2250ac, -0x8004562, 0x3c08fff0, 0x3c020001, 0x8c424ff8, 0x3c010001, 0xac2350ac, -0x34420004, 0x3c010001, 0xac224ff8, 0x3c08fff0, 0x3508bdc0, 0x8f830054, -0x97a60018, 0x3c070001, 0x8ce750ac, 0x3c040001, 0x24844e20, 0x24020001, -0x3c010001, 0xac225000, 0xafa60010, 0x3c060001, 0x8cc64ff8, 0x97a2001a, -0x3c05000d, 0x34a50100, 0x3c010001, 0xac204ffc, 0x681821, 0x3c010001, -0xac2350a4, 0xc002403, 0xafa20014, 0x8fbf0028, 0x3e00008, 0x27bd0030, -0x27bdffe8, 0x24070004, 0x3c040001, 0x8c844ffc, 0x3021, 0x24020001, -0x1482000a, 0xafbf0010, 0x3c020001, 0x8c42714c, 0x3c050004, 0x30428000, -0x1040000c, 0x34a593e0, 0x3c05000f, 0x8004595, 0x34a54240, 0x3c020001, -0x8c42714c, 0x3c05000f, 0x30428000, 0x10400003, 0x34a54240, 0x3c05001e, -0x34a58480, 0x3c020001, 0x8c4250a4, 0x8f830054, 0x451021, 0x431023, -0x45102b, 0x1440002e, 0x0, 0x3c020001, 0x8c425004, 0x1440002a, -0x2cc20001, 0x7182b, 0x431024, 0x1040001d, 0x0, 0x3c090001, -0x8d294ff8, 0x240b0001, 0x3c054000, 0x3c080001, 0x2508714c, 0x250afffc, -0x42042, 0x14800002, 0x24e7ffff, 0x24040008, 0x891024, 0x5040000b, -0x2cc20001, 0x148b0004, 0x0, 0x8d020000, 0x80045ba, 0x451024, -0x8d420000, 0x451024, 0x54400001, 0x24060001, 0x2cc20001, 0x7182b, -0x431024, 0x5440ffed, 0x42042, 0x3c010001, 0x10c00024, 0xac244ffc, -0x8f830054, 0x24020001, 0x3c010001, 0xac225000, 0x3c010001, 0xac2350a4, -0x3c020001, 0x8c425000, 0x10400006, 0x24020001, 0x3c010001, 0xac205000, -0x3c010001, 0x370821, 0xac22839c, 0x3c030001, 0x771821, 0x8c63839c, -0x24020008, 0x10620005, 0x24020001, 0xc0045ea, 0x0, 0x80045e7, -0x0, 0x3c030001, 0x8c634ffc, 0x10620007, 0x2402000e, 0x3c030001, -0x8c6370c0, 0x10620003, 0x0, 0xc004c08, 0x8f840220, 0x8fbf0010, -0x3e00008, 0x27bd0018, 0x27bdffe0, 0x3c02fdff, 0xafbf0018, 0x8ee30000, -0x3c050001, 0x8ca54ffc, 0x3c040001, 0x8c845014, 0x3442ffff, 0x621824, -0x14a40008, 0xaee30000, 0x3c030001, 0x771821, 0x8c63839c, 0x3c020001, -0x8c425018, 0x10620008, 0x0, 0x3c020001, 0x571021, 0x8c42839c, -0x3c010001, 0xac255014, 0x3c010001, 0xac225018, 0x3c030001, 0x8c634ffc, -0x24020002, 0x10620126, 0x2c620003, 0x10400005, 0x24020001, 0x10620008, -0x0, 0x800472e, 0x0, 0x24020004, 0x1062007c, 0x24020001, -0x800472f, 0x0, 0x3c020001, 0x571021, 0x8c42839c, 0x2443ffff, -0x2c620008, 0x10400117, 0x31080, 0x3c010001, 0x220821, 0x8c224e38, -0x400008, 0x0, 0xc004734, 0x0, 0x3c020001, 0x8c425008, -0x3c010001, 0xac204f90, 0x104000c5, 0x24020002, 0x3c010001, 0x370821, -0xac22839c, 0x3c010001, 0x8004731, 0xac205008, 0xc004843, 0x0, -0x3c030001, 0x8c635020, 0x24020011, 0x146200fd, 0x24020003, 0x80046b1, -0x0, 0x3c050001, 0x8ca54ffc, 0x3c060001, 0x8cc6714c, 0xc004eac, -0x24040001, 0x24020005, 0x3c010001, 0xac205008, 0x3c010001, 0x370821, -0x8004731, 0xac22839c, 0x3c040001, 0x24844e2c, 0x3c05000f, 0x34a50100, -0x3021, 0x3821, 0xafa00010, 0xc002403, 0xafa00014, 0x8004731, -0x0, 0x8f820220, 0x3c03f700, 0x431025, 0x80046d8, 0xaf820220, -0x8f820220, 0x3c030004, 0x431024, 0x14400095, 0x24020007, 0x8f830054, -0x3c020001, 0x8c4250a0, 0x2463d8f0, 0x431023, 0x2c422710, 0x144000d1, -0x24020001, 0x800472f, 0x0, 0x3c050001, 0x8ca54ffc, 0xc004fb3, -0x24040001, 0xc005078, 0x24040001, 0x3c030001, 0x8c637144, 0x46100c3, -0x24020001, 0x3c020008, 0x621024, 0x10400006, 0x0, 0x8f820214, -0x3c03ffff, 0x431024, 0x800467a, 0x3442251f, 0x8f820214, 0x3c03ffff, -0x431024, 0x3442241f, 0xaf820214, 0x8ee20000, 0x3c030200, 0x431025, -0xaee20000, 0x8f820220, 0x2403fffb, 0x431024, 0xaf820220, 0x8f820220, -0x34420002, 0xaf820220, 0x24020008, 0x3c010001, 0x370821, 0xc0043cd, -0xac22839c, 0x8004731, 0x0, 0x3c020001, 0x571021, 0x8c42839c, -0x2443ffff, 0x2c620008, 0x1040009e, 0x31080, 0x3c010001, 0x220821, -0x8c224e58, 0x400008, 0x0, 0xc00428b, 0x0, 0x3c010001, -0xac205000, 0xaf800204, 0x3c010001, 0xc004734, 0xac207110, 0x8f820044, -0x34428080, 0xaf820044, 0x8f830054, 0x3c010001, 0xac204f90, 0x80046da, -0x24020002, 0x8f830054, 0x3c020001, 0x8c4250a0, 0x2463d8f0, 0x431023, -0x2c422710, 0x14400081, 0x24020003, 0x3c010001, 0x370821, 0x8004731, -0xac22839c, 0x3c020001, 0x8c427148, 0x30424000, 0x10400005, 0x0, -0x8f820044, 0x3c03ffff, 0x80046c0, 0x34637fff, 0x8f820044, 0x2403ff7f, -0x431024, 0xaf820044, 0x8f830054, 0x80046da, 0x24020004, 0x8f830054, -0x3c020001, 0x8c4250a0, 0x2463d8f0, 0x431023, 0x2c422710, 0x14400065, -0x24020005, 0x3c010001, 0x370821, 0x8004731, 0xac22839c, 0x8f820220, -0x3c03f700, 0x431025, 0xaf820220, 0xaf800204, 0x3c010001, 0xac207110, -0x8f830054, 0x24020006, 0x3c010001, 0x370821, 0xac22839c, 0x3c010001, -0x8004731, 0xac2350a0, 0x3c05fffe, 0x34a57960, 0x3c040001, 0x8f820054, -0x3c030001, 0x8c6350a0, 0x3484869f, 0x451021, 0x621823, 0x83202b, -0x10800046, 0x0, 0x24020007, 0x3c010001, 0x370821, 0x8004731, -0xac22839c, 0x8f820220, 0x3c04f700, 0x441025, 0xaf820220, 0x8f820220, -0x3c030300, 0x431024, 0x14400005, 0x1821, 0x8f820220, 0x24030001, -0x441025, 0xaf820220, 0x10600030, 0x24020001, 0x8f820214, 0x3c03ffff, -0x3c040001, 0x8c845098, 0x431024, 0x3442251f, 0xaf820214, 0x24020008, -0x3c010001, 0x370821, 0xac22839c, 0x10800007, 0x24020001, 0x3c010001, -0xac2270c0, 0xc004c08, 0x8f840220, 0x8004731, 0x0, 0x8f820220, -0x3c030008, 0x431024, 0x1440001a, 0x2402000e, 0x3c010001, 0xac2270c0, -0x8ee20000, 0x24040001, 0x3c030200, 0x431025, 0xc005078, 0xaee20000, -0x8f820220, 0x2403fffb, 0x431024, 0xaf820220, 0x8f820220, 0x34420002, -0xc0043cd, 0xaf820220, 0x3c050001, 0x8ca54ffc, 0xc004fb3, 0x24040001, -0x8004731, 0x0, 0x24020001, 0x3c010001, 0xac225000, 0x8fbf0018, -0x3e00008, 0x27bd0020, 0x8f820200, 0x8f820220, 0x8f820220, 0x34420004, -0xaf820220, 0x8f820200, 0x3c060001, 0x8cc64ffc, 0x34420004, 0xaf820200, -0x24020002, 0x10c20048, 0x2cc20003, 0x10400005, 0x24020001, 0x10c20008, -0x0, 0x8004788, 0x0, 0x24020004, 0x10c20013, 0x24020001, -0x8004788, 0x0, 0x3c030001, 0x8c634fe8, 0x3c020001, 0x8c424ff4, -0x3c040001, 0x8c845010, 0x3c050001, 0x8ca54fec, 0xaf860200, 0xaf860220, -0x34630022, 0x441025, 0x451025, 0x34420002, 0x8004787, 0xaf830200, -0xaf820200, 0xaf820220, 0x8f820044, 0x3c030001, 0x8c635098, 0x34428080, -0xaf820044, 0x10600005, 0x3c033f00, 0x3c020001, 0x8c424fe0, 0x800477b, -0x346300e0, 0x8f8400f0, 0x276217f8, 0x14820002, 0x24850008, 0x27651000, -0x8f8200f4, 0x10a20007, 0x3c038000, 0x34630040, 0x3c020001, 0x24424fa0, -0xac820000, 0xac830004, 0xaf8500f0, 0x3c020001, 0x8c424fe0, 0x3c033f00, -0x346300e2, 0x431025, 0xaf820200, 0x3c030001, 0x8c634fe4, 0x3c04f700, -0x3c020001, 0x8c424ff4, 0x3c050001, 0x8ca55010, 0x641825, 0x431025, -0x451025, 0xaf820220, 0x3e00008, 0x0, 0x8f820220, 0x3c030001, -0x8c634ffc, 0x34420004, 0xaf820220, 0x24020001, 0x1062000f, 0x0, -0x8f830054, 0x8f820054, 0x24630002, 0x621023, 0x2c420003, 0x10400011, -0x0, 0x8f820054, 0x621023, 0x2c420003, 0x1040000c, 0x0, -0x8004799, 0x0, 0x8f830054, 0x8f820054, 0x80047a5, 0x24630007, -0x8f820054, 0x621023, 0x2c420008, 0x1440fffc, 0x0, 0x8f8400e0, -0x30820007, 0x1040000d, 0x0, 0x8f820054, 0x8f8300e0, 0x14830009, -0x24450032, 0x8f820054, 0xa21023, 0x2c420033, 0x10400004, 0x0, -0x8f8200e0, 0x1082fff9, 0x0, 0x8f820220, 0x2403fffd, 0x431024, -0xaf820220, 0x3e00008, 0x0, 0x0, 0x27bdffd8, 0xafb20018, -0x809021, 0xafb3001c, 0xa09821, 0xafb10014, 0xc08821, 0xafb00010, -0x8021, 0xafbf0020, 0xa6200000, 0xc004bbf, 0x24040001, 0x26100001, -0x2e020020, 0x1440fffb, 0x0, 0xc004bbf, 0x2021, 0xc004bbf, -0x24040001, 0xc004bbf, 0x24040001, 0xc004bbf, 0x2021, 0x24100010, -0x2501024, 0x10400002, 0x2021, 0x24040001, 0xc004bbf, 0x108042, -0x1600fffa, 0x2501024, 0x24100010, 0x2701024, 0x10400002, 0x2021, -0x24040001, 0xc004bbf, 0x108042, 0x1600fffa, 0x2701024, 0xc004be5, -0x34108000, 0xc004be5, 0x0, 0xc004b9f, 0x0, 0x50400005, -0x108042, 0x96220000, 0x501025, 0xa6220000, 0x108042, 0x1600fff7, -0x0, 0xc004be5, 0x0, 0x8fbf0020, 0x8fb3001c, 0x8fb20018, -0x8fb10014, 0x8fb00010, 0x3e00008, 0x27bd0028, 0x27bdffd8, 0xafb10014, -0x808821, 0xafb20018, 0xa09021, 0xafb3001c, 0xc09821, 0xafb00010, -0x8021, 0xafbf0020, 0xc004bbf, 0x24040001, 0x26100001, 0x2e020020, -0x1440fffb, 0x0, 0xc004bbf, 0x2021, 0xc004bbf, 0x24040001, -0xc004bbf, 0x2021, 0xc004bbf, 0x24040001, 0x24100010, 0x2301024, -0x10400002, 0x2021, 0x24040001, 0xc004bbf, 0x108042, 0x1600fffa, -0x2301024, 0x24100010, 0x2501024, 0x10400002, 0x2021, 0x24040001, -0xc004bbf, 0x108042, 0x1600fffa, 0x2501024, 0xc004bbf, 0x24040001, -0xc004bbf, 0x2021, 0x34108000, 0x96620000, 0x501024, 0x10400002, -0x2021, 0x24040001, 0xc004bbf, 0x108042, 0x1600fff8, 0x0, -0xc004be5, 0x0, 0x8fbf0020, 0x8fb3001c, 0x8fb20018, 0x8fb10014, -0x8fb00010, 0x3e00008, 0x27bd0028, 0x3c030001, 0x8c635020, 0x3c020001, -0x8c425064, 0x27bdffd8, 0xafbf0020, 0xafb1001c, 0x10620003, 0xafb00018, -0x3c010001, 0xac235064, 0x2463ffff, 0x2c620013, 0x10400349, 0x31080, -0x3c010001, 0x220821, 0x8c224e80, 0x400008, 0x0, 0xc004be5, -0x8021, 0x34028000, 0xa7a20010, 0x27b10010, 0xc004bbf, 0x24040001, -0x26100001, 0x2e020020, 0x1440fffb, 0x0, 0xc004bbf, 0x2021, -0xc004bbf, 0x24040001, 0xc004bbf, 0x2021, 0xc004bbf, 0x24040001, -0x24100010, 0x32020001, 0x10400002, 0x2021, 0x24040001, 0xc004bbf, -0x108042, 0x1600fffa, 0x32020001, 0x24100010, 0xc004bbf, 0x2021, -0x108042, 0x1600fffc, 0x0, 0xc004bbf, 0x24040001, 0xc004bbf, -0x2021, 0x34108000, 0x96220000, 0x501024, 0x10400002, 0x2021, -0x24040001, 0xc004bbf, 0x108042, 0x1600fff8, 0x0, 0xc004be5, -0x0, 0x8004b98, 0x24020002, 0x27b10010, 0xa7a00010, 0x8021, -0xc004bbf, 0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, 0x0, -0xc004bbf, 0x2021, 0xc004bbf, 0x24040001, 0xc004bbf, 0x24040001, -0xc004bbf, 0x2021, 0x24100010, 0x32020001, 0x10400002, 0x2021, -0x24040001, 0xc004bbf, 0x108042, 0x1600fffa, 0x32020001, 0x24100010, -0xc004bbf, 0x2021, 0x108042, 0x1600fffc, 0x0, 0xc004be5, -0x34108000, 0xc004be5, 0x0, 0xc004b9f, 0x0, 0x50400005, -0x108042, 0x96220000, 0x501025, 0xa6220000, 0x108042, 0x1600fff7, -0x0, 0xc004be5, 0x0, 0x97a20010, 0x30428000, 0x144002dc, -0x24020003, 0x8004b98, 0x0, 0x24021200, 0xa7a20010, 0x27b10010, -0x8021, 0xc004bbf, 0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, -0x0, 0xc004bbf, 0x2021, 0xc004bbf, 0x24040001, 0xc004bbf, -0x2021, 0xc004bbf, 0x24040001, 0x24100010, 0x32020001, 0x10400002, -0x2021, 0x24040001, 0xc004bbf, 0x108042, 0x1600fffa, 0x32020001, -0x24100010, 0xc004bbf, 0x2021, 0x108042, 0x1600fffc, 0x0, -0xc004bbf, 0x24040001, 0xc004bbf, 0x2021, 0x34108000, 0x96220000, -0x501024, 0x10400002, 0x2021, 0x24040001, 0xc004bbf, 0x108042, -0x1600fff8, 0x0, 0xc004be5, 0x0, 0x8f830054, 0x8004b8a, -0x24020004, 0x8f830054, 0x3c020001, 0x8c4250a8, 0x2463ff9c, 0x431023, -0x2c420064, 0x1440029e, 0x24020002, 0x3c030001, 0x8c6350ac, 0x10620297, -0x2c620003, 0x14400296, 0x24020011, 0x24020003, 0x10620005, 0x24020004, -0x10620291, 0x2402000f, 0x8004b98, 0x24020011, 0x8004b98, 0x24020005, -0x24020014, 0xa7a20010, 0x27b10010, 0x8021, 0xc004bbf, 0x24040001, -0x26100001, 0x2e020020, 0x1440fffb, 0x0, 0xc004bbf, 0x2021, -0xc004bbf, 0x24040001, 0xc004bbf, 0x2021, 0xc004bbf, 0x24040001, -0x24100010, 0x32020001, 0x10400002, 0x2021, 0x24040001, 0xc004bbf, -0x108042, 0x1600fffa, 0x32020001, 0x24100010, 0x32020012, 0x10400002, -0x2021, 0x24040001, 0xc004bbf, 0x108042, 0x1600fffa, 0x32020012, -0xc004bbf, 0x24040001, 0xc004bbf, 0x2021, 0x34108000, 0x96220000, -0x501024, 0x10400002, 0x2021, 0x24040001, 0xc004bbf, 0x108042, -0x1600fff8, 0x0, 0xc004be5, 0x0, 0x8f830054, 0x8004b8a, -0x24020006, 0x8f830054, 0x3c020001, 0x8c4250a8, 0x2463ff9c, 0x431023, -0x2c420064, 0x14400250, 0x24020007, 0x8004b98, 0x0, 0x24020006, -0xa7a20010, 0x27b10010, 0x8021, 0xc004bbf, 0x24040001, 0x26100001, -0x2e020020, 0x1440fffb, 0x0, 0xc004bbf, 0x2021, 0xc004bbf, -0x24040001, 0xc004bbf, 0x2021, 0xc004bbf, 0x24040001, 0x24100010, -0x32020001, 0x10400002, 0x2021, 0x24040001, 0xc004bbf, 0x108042, -0x1600fffa, 0x32020001, 0x24100010, 0x32020013, 0x10400002, 0x2021, -0x24040001, 0xc004bbf, 0x108042, 0x1600fffa, 0x32020013, 0xc004bbf, -0x24040001, 0xc004bbf, 0x2021, 0x34108000, 0x96220000, 0x501024, -0x10400002, 0x2021, 0x24040001, 0xc004bbf, 0x108042, 0x1600fff8, -0x0, 0xc004be5, 0x0, 0x8f830054, 0x8004b8a, 0x24020008, -0x8f830054, 0x3c020001, 0x8c4250a8, 0x2463ff9c, 0x431023, 0x2c420064, -0x1440020f, 0x24020009, 0x8004b98, 0x0, 0x27b10010, 0xa7a00010, -0x8021, 0xc004bbf, 0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, -0x0, 0xc004bbf, 0x2021, 0xc004bbf, 0x24040001, 0xc004bbf, -0x24040001, 0xc004bbf, 0x2021, 0x24100010, 0x32020001, 0x10400002, -0x2021, 0x24040001, 0xc004bbf, 0x108042, 0x1600fffa, 0x32020001, -0x24100010, 0x32020018, 0x10400002, 0x2021, 0x24040001, 0xc004bbf, -0x108042, 0x1600fffa, 0x32020018, 0xc004be5, 0x34108000, 0xc004be5, -0x0, 0xc004b9f, 0x0, 0x50400005, 0x108042, 0x96220000, -0x501025, 0xa6220000, 0x108042, 0x1600fff7, 0x0, 0xc004be5, -0x8021, 0x97a20010, 0x27b10010, 0x34420001, 0xa7a20010, 0xc004bbf, -0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, 0x0, 0xc004bbf, -0x2021, 0xc004bbf, 0x24040001, 0xc004bbf, 0x2021, 0xc004bbf, -0x24040001, 0x24100010, 0x32020001, 0x10400002, 0x2021, 0x24040001, -0xc004bbf, 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 0x32020018, -0x10400002, 0x2021, 0x24040001, 0xc004bbf, 0x108042, 0x1600fffa, -0x32020018, 0xc004bbf, 0x24040001, 0xc004bbf, 0x2021, 0x34108000, -0x96220000, 0x501024, 0x10400002, 0x2021, 0x24040001, 0xc004bbf, -0x108042, 0x1600fff8, 0x0, 0xc004be5, 0x0, 0x8f830054, -0x8004b8a, 0x2402000a, 0x8f830054, 0x3c020001, 0x8c4250a8, 0x2463ff9c, -0x431023, 0x2c420064, 0x1440019b, 0x2402000b, 0x8004b98, 0x0, -0x27b10010, 0xa7a00010, 0x8021, 0xc004bbf, 0x24040001, 0x26100001, -0x2e020020, 0x1440fffb, 0x0, 0xc004bbf, 0x2021, 0xc004bbf, -0x24040001, 0xc004bbf, 0x24040001, 0xc004bbf, 0x2021, 0x24100010, -0x32020001, 0x10400002, 0x2021, 0x24040001, 0xc004bbf, 0x108042, -0x1600fffa, 0x32020001, 0x24100010, 0x32020017, 0x10400002, 0x2021, -0x24040001, 0xc004bbf, 0x108042, 0x1600fffa, 0x32020017, 0xc004be5, -0x34108000, 0xc004be5, 0x0, 0xc004b9f, 0x0, 0x50400005, -0x108042, 0x96220000, 0x501025, 0xa6220000, 0x108042, 0x1600fff7, -0x0, 0xc004be5, 0x8021, 0x97a20010, 0x27b10010, 0x34420700, -0xa7a20010, 0xc004bbf, 0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, -0x0, 0xc004bbf, 0x2021, 0xc004bbf, 0x24040001, 0xc004bbf, -0x2021, 0xc004bbf, 0x24040001, 0x24100010, 0x32020001, 0x10400002, -0x2021, 0x24040001, 0xc004bbf, 0x108042, 0x1600fffa, 0x32020001, -0x24100010, 0x32020017, 0x10400002, 0x2021, 0x24040001, 0xc004bbf, -0x108042, 0x1600fffa, 0x32020017, 0xc004bbf, 0x24040001, 0xc004bbf, -0x2021, 0x34108000, 0x96220000, 0x501024, 0x10400002, 0x2021, -0x24040001, 0xc004bbf, 0x108042, 0x1600fff8, 0x0, 0xc004be5, -0x0, 0x8f830054, 0x8004b8a, 0x2402000c, 0x8f830054, 0x3c020001, -0x8c4250a8, 0x2463ff9c, 0x431023, 0x2c420064, 0x14400127, 0x24020012, -0x8004b98, 0x0, 0x27b10010, 0xa7a00010, 0x8021, 0xc004bbf, -0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, 0x0, 0xc004bbf, -0x2021, 0xc004bbf, 0x24040001, 0xc004bbf, 0x24040001, 0xc004bbf, -0x2021, 0x24100010, 0x32020001, 0x10400002, 0x2021, 0x24040001, -0xc004bbf, 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 0x32020014, -0x10400002, 0x2021, 0x24040001, 0xc004bbf, 0x108042, 0x1600fffa, -0x32020014, 0xc004be5, 0x34108000, 0xc004be5, 0x0, 0xc004b9f, -0x0, 0x50400005, 0x108042, 0x96220000, 0x501025, 0xa6220000, -0x108042, 0x1600fff7, 0x0, 0xc004be5, 0x8021, 0x97a20010, -0x27b10010, 0x34420010, 0xa7a20010, 0xc004bbf, 0x24040001, 0x26100001, -0x2e020020, 0x1440fffb, 0x0, 0xc004bbf, 0x2021, 0xc004bbf, -0x24040001, 0xc004bbf, 0x2021, 0xc004bbf, 0x24040001, 0x24100010, -0x32020001, 0x10400002, 0x2021, 0x24040001, 0xc004bbf, 0x108042, -0x1600fffa, 0x32020001, 0x24100010, 0x32020014, 0x10400002, 0x2021, -0x24040001, 0xc004bbf, 0x108042, 0x1600fffa, 0x32020014, 0xc004bbf, -0x24040001, 0xc004bbf, 0x2021, 0x34108000, 0x96220000, 0x501024, -0x10400002, 0x2021, 0x24040001, 0xc004bbf, 0x108042, 0x1600fff8, -0x0, 0xc004be5, 0x0, 0x8f830054, 0x8004b8a, 0x24020013, -0x8f830054, 0x3c020001, 0x8c4250a8, 0x2463ff9c, 0x431023, 0x2c420064, -0x144000b3, 0x2402000d, 0x8004b98, 0x0, 0x27b10010, 0xa7a00010, -0x8021, 0xc004bbf, 0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, -0x0, 0xc004bbf, 0x2021, 0xc004bbf, 0x24040001, 0xc004bbf, -0x24040001, 0xc004bbf, 0x2021, 0x24100010, 0x32020001, 0x10400002, -0x2021, 0x24040001, 0xc004bbf, 0x108042, 0x1600fffa, 0x32020001, -0x24100010, 0x32020018, 0x10400002, 0x2021, 0x24040001, 0xc004bbf, -0x108042, 0x1600fffa, 0x32020018, 0xc004be5, 0x34108000, 0xc004be5, -0x0, 0xc004b9f, 0x0, 0x50400005, 0x108042, 0x96220000, -0x501025, 0xa6220000, 0x108042, 0x1600fff7, 0x0, 0xc004be5, -0x8021, 0x97a20010, 0x27b10010, 0x3042fffe, 0xa7a20010, 0xc004bbf, -0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, 0x0, 0xc004bbf, -0x2021, 0xc004bbf, 0x24040001, 0xc004bbf, 0x2021, 0xc004bbf, -0x24040001, 0x24100010, 0x32020001, 0x10400002, 0x2021, 0x24040001, -0xc004bbf, 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 0x32020018, -0x10400002, 0x2021, 0x24040001, 0xc004bbf, 0x108042, 0x1600fffa, -0x32020018, 0xc004bbf, 0x24040001, 0xc004bbf, 0x2021, 0x34108000, -0x96220000, 0x501024, 0x10400002, 0x2021, 0x24040001, 0xc004bbf, -0x108042, 0x1600fff8, 0x0, 0xc004be5, 0x0, 0x8f830054, -0x8004b8a, 0x2402000e, 0x24020840, 0xa7a20010, 0x27b10010, 0x8021, -0xc004bbf, 0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, 0x0, -0xc004bbf, 0x2021, 0xc004bbf, 0x24040001, 0xc004bbf, 0x2021, -0xc004bbf, 0x24040001, 0x24100010, 0x32020001, 0x10400002, 0x2021, -0x24040001, 0xc004bbf, 0x108042, 0x1600fffa, 0x32020001, 0x24100010, -0x32020013, 0x10400002, 0x2021, 0x24040001, 0xc004bbf, 0x108042, -0x1600fffa, 0x32020013, 0xc004bbf, 0x24040001, 0xc004bbf, 0x2021, -0x34108000, 0x96220000, 0x501024, 0x10400002, 0x2021, 0x24040001, -0xc004bbf, 0x108042, 0x1600fff8, 0x0, 0xc004be5, 0x0, -0x8f830054, 0x24020010, 0x3c010001, 0xac225020, 0x3c010001, 0x8004b9a, -0xac2350a8, 0x8f830054, 0x3c020001, 0x8c4250a8, 0x2463ff9c, 0x431023, -0x2c420064, 0x14400004, 0x0, 0x24020011, 0x3c010001, 0xac225020, -0x8fbf0020, 0x8fb1001c, 0x8fb00018, 0x3e00008, 0x27bd0028, 0x8f850044, -0x8f820044, 0x3c030001, 0x431025, 0x3c030008, 0xaf820044, 0x8f840054, -0x8f820054, 0xa32824, 0x8004bab, 0x24840001, 0x8f820054, 0x821023, -0x2c420002, 0x1440fffc, 0x0, 0x8f820044, 0x3c03fffe, 0x3463ffff, -0x431024, 0xaf820044, 0x8f830054, 0x8f820054, 0x8004bb9, 0x24630001, -0x8f820054, 0x621023, 0x2c420002, 0x1440fffc, 0x0, 0x3e00008, -0xa01021, 0x8f830044, 0x3c02fff0, 0x3442ffff, 0x42480, 0x621824, -0x3c020002, 0x822025, 0x641825, 0xaf830044, 0x8f820044, 0x3c030001, -0x431025, 0xaf820044, 0x8f830054, 0x8f820054, 0x8004bd1, 0x24630001, -0x8f820054, 0x621023, 0x2c420002, 0x1440fffc, 0x0, 0x8f820044, -0x3c03fffe, 0x3463ffff, 0x431024, 0xaf820044, 0x8f830054, 0x8f820054, -0x8004bdf, 0x24630001, 0x8f820054, 0x621023, 0x2c420002, 0x1440fffc, -0x0, 0x3e00008, 0x0, 0x8f820044, 0x3c03fff0, 0x3463ffff, -0x431024, 0xaf820044, 0x8f820044, 0x3c030001, 0x431025, 0xaf820044, -0x8f830054, 0x8f820054, 0x8004bf3, 0x24630001, 0x8f820054, 0x621023, -0x2c420002, 0x1440fffc, 0x0, 0x8f820044, 0x3c03fffe, 0x3463ffff, -0x431024, 0xaf820044, 0x8f830054, 0x8f820054, 0x8004c01, 0x24630001, -0x8f820054, 0x621023, 0x2c420002, 0x1440fffc, 0x0, 0x3e00008, -0x0, 0x0, 0x27bdffe8, 0xafbf0010, 0x3c030001, 0x771821, -0x8c63839c, 0x24020008, 0x1462021c, 0x803021, 0x3c020001, 0x8c425098, -0x14400033, 0x0, 0x8f850224, 0x38a30020, 0x2c630001, 0x38a20010, -0x2c420001, 0x621825, 0x1460000d, 0x38a30030, 0x2c630001, 0x38a20400, -0x2c420001, 0x621825, 0x14600007, 0x38a30402, 0x2c630001, 0x38a20404, -0x2c420001, 0x621825, 0x10600005, 0x0, 0xc00428b, 0x0, -0x8004c41, 0x2402000e, 0xc0043cd, 0x0, 0x3c050001, 0x8ca54ffc, -0xc004fb3, 0x24040001, 0x3c030001, 0x8c634ffc, 0x24020004, 0x14620005, -0x2403fffb, 0x3c020001, 0x8c424ff8, 0x8004c3d, 0x2403fff7, 0x3c020001, -0x8c424ff8, 0x431024, 0x3c010001, 0xac224ff8, 0x2402000e, 0x3c010001, -0xc00428b, 0xac2270c0, 0x8004e2b, 0x0, 0x8f820220, 0x3c030400, -0x431024, 0x10400027, 0x2403ffbf, 0x8f850224, 0x3c020001, 0x8c4270cc, -0xa32024, 0x431024, 0x1482000c, 0x0, 0x3c020001, 0x8c4270d0, -0x24420001, 0x3c010001, 0xac2270d0, 0x2c420002, 0x14400008, 0x24020001, -0x3c010001, 0x8004c61, 0xac2270f0, 0x3c010001, 0xac2070d0, 0x3c010001, -0xac2070f0, 0x3c020001, 0x8c4270f0, 0x10400006, 0x30a20040, 0x10400004, -0x24020001, 0x3c010001, 0x8004c6c, 0xac2270f4, 0x3c010001, 0xac2070f4, -0x3c010001, 0xac2570cc, 0x3c010001, 0x8004c7c, 0xac207100, 0x24020001, -0x3c010001, 0xac227100, 0x3c010001, 0xac2070f0, 0x3c010001, 0xac2070d0, -0x3c010001, 0xac2070f4, 0x3c010001, 0xac2070cc, 0x3c030001, 0x8c6370c0, -0x3c020001, 0x8c4270c4, 0x10620003, 0x3c020200, 0x3c010001, 0xac2370c4, -0xc21024, 0x10400007, 0x2463ffff, 0x8f820220, 0x24030001, 0x3c010001, -0xac235000, 0x8004e29, 0x3c03f700, 0x2c62000e, 0x10400198, 0x31080, -0x3c010001, 0x220821, 0x8c224ed0, 0x400008, 0x0, 0x8ee20000, -0x3c03fdff, 0x3463ffff, 0x431024, 0xaee20000, 0x3c010001, 0xac2070f0, -0x3c010001, 0xac2070d0, 0x3c010001, 0xac207100, 0x3c010001, 0xac2070cc, -0x3c010001, 0xac2070f4, 0x3c010001, 0xac2070e8, 0x3c010001, 0xac2070e0, -0xc00478a, 0xaf800224, 0x24020002, 0x3c010001, 0xac2270c0, 0xc00428b, -0x0, 0xaf800204, 0x8f820200, 0x2403fffd, 0x431024, 0xaf820200, -0x3c010001, 0xac207110, 0x8f830054, 0x3c020001, 0x8c4270e8, 0x24040001, -0x3c010001, 0xac2470fc, 0x24420001, 0x3c010001, 0xac2270e8, 0x2c420004, -0x3c010001, 0xac2370e4, 0x14400006, 0x24020003, 0x3c010001, 0xac245000, -0x3c010001, 0x8004e27, 0xac2070e8, 0x3c010001, 0x8004e27, 0xac2270c0, -0x8f830054, 0x3c020001, 0x8c4270e4, 0x2463d8f0, 0x431023, 0x2c422710, -0x14400154, 0x24020004, 0x3c010001, 0x8004e27, 0xac2270c0, 0x3c040001, -0x8c84509c, 0x3c010001, 0xc004e2e, 0xac2070d8, 0x3c020001, 0x8c42710c, -0xaf820204, 0x8f820204, 0x30420030, 0x1440013c, 0x24020002, 0x3c030001, -0x8c63710c, 0x24020005, 0x3c010001, 0xac2270c0, 0x3c010001, 0x8004e27, -0xac237110, 0x3c020001, 0x8c4270f0, 0x10400139, 0x0, 0x3c020001, -0x8c4270cc, 0x10400135, 0x0, 0x3c010001, 0xac2270f8, 0x24020003, -0x3c010001, 0xac2270d0, 0x8004dba, 0x24020006, 0x3c010001, 0xac2070d8, -0x8f820204, 0x34420040, 0xaf820204, 0x3c020001, 0x8c427110, 0x24030007, -0x3c010001, 0xac2370c0, 0x34420040, 0x3c010001, 0xac227110, 0x3c020001, -0x8c4270f0, 0x10400005, 0x0, 0x3c020001, 0x8c4270cc, 0x10400110, -0x24020002, 0x3c050001, 0x24a570d0, 0x8ca20000, 0x2c424e21, 0x1040010a, -0x24020002, 0x3c020001, 0x8c4270f4, 0x1040010f, 0x2404ffbf, 0x3c020001, -0x8c4270cc, 0x3c030001, 0x8c6370f8, 0x441024, 0x641824, 0x14430007, -0x24020001, 0x24020003, 0xaca20000, 0x24020008, 0x3c010001, 0x8004e27, -0xac2270c0, 0x3c010001, 0x8004e27, 0xac2270c0, 0x3c020001, 0x8c4270fc, -0x1040000c, 0x24020001, 0x3c040001, 0xc004e3b, 0x8c8470cc, 0x3c020001, -0x8c427118, 0x14400005, 0x24020001, 0x3c020001, 0x8c427114, 0x10400006, -0x24020001, 0x3c010001, 0xac225000, 0x3c010001, 0x8004e27, 0xac2070e8, -0x8f820204, 0x34420040, 0xaf820204, 0x3c020001, 0x8c427110, 0x3c030001, -0x8c6370e0, 0x34420040, 0x3c010001, 0xac227110, 0x3c020001, 0x8c4270cc, -0x2c630001, 0x318c0, 0x3c010001, 0xac2370e0, 0x30420008, 0x3c010001, -0xac2270dc, 0x8f830054, 0x24020009, 0x3c010001, 0xac2270c0, 0x3c010001, -0x8004e27, 0xac2370e4, 0x8f830054, 0x3c020001, 0x8c4270e4, 0x2463d8f0, -0x431023, 0x2c422710, 0x144000b6, 0x0, 0x3c020001, 0x8c4270f0, -0x10400005, 0x0, 0x3c020001, 0x8c4270cc, 0x104000b7, 0x24020002, -0x3c030001, 0x246370d0, 0x8c620000, 0x2c424e21, 0x104000b1, 0x24020002, -0x3c020001, 0x8c4270fc, 0x1040000e, 0x0, 0x3c020001, 0x8c4270cc, -0x3c010001, 0xac2070fc, 0x30420080, 0x1040002f, 0x2402000c, 0x8f820204, -0x30420080, 0x1440000c, 0x24020003, 0x8004da7, 0x2402000c, 0x3c020001, -0x8c4270cc, 0x30420080, 0x14400005, 0x24020003, 0x8f820204, 0x30420080, -0x1040001f, 0x24020003, 0xac620000, 0x2402000a, 0x3c010001, 0xac2270c0, -0x3c040001, 0x24847108, 0x8c820000, 0x3c030001, 0x8c6370e0, 0x431025, -0xaf820204, 0x8c830000, 0x3c040001, 0x8c8470e0, 0x2402000b, 0x3c010001, -0xac2270c0, 0x641825, 0x3c010001, 0xac237110, 0x3c050001, 0x24a570d0, -0x8ca20000, 0x2c424e21, 0x1040007d, 0x24020002, 0x3c020001, 0x8c427100, -0x10400005, 0x0, 0x2402000c, 0x3c010001, 0x8004e27, 0xac2270c0, -0x3c020001, 0x8c4270f0, 0x1040007a, 0x0, 0x3c040001, 0x8c8470cc, -0x1080006c, 0x30820008, 0x3c030001, 0x8c6370dc, 0x10620072, 0x24020003, -0x3c010001, 0xac2470f8, 0xaca20000, 0x24020006, 0x3c010001, 0x8004e27, -0xac2270c0, 0x8f8400f0, 0x276217f8, 0x14820002, 0x24850008, 0x27651000, -0x8f8200f4, 0x10a20007, 0x3c038000, 0x34630040, 0x3c020001, 0x24424fa0, -0xac820000, 0xac830004, 0xaf8500f0, 0x8f820200, 0x34420002, 0xaf820200, -0x8f830054, 0x2402000d, 0x3c010001, 0xac2270c0, 0x3c010001, 0xac2370e4, -0x8f830054, 0x3c020001, 0x8c4270e4, 0x2463d8f0, 0x431023, 0x2c422710, -0x1440003a, 0x0, 0x3c020001, 0x8c427100, 0x10400029, 0x2402000e, -0x3c030001, 0x8c637114, 0x3c010001, 0x14600015, 0xac2270c0, 0xc0043cd, -0x0, 0x3c050001, 0x8ca54ffc, 0xc004fb3, 0x24040001, 0x3c030001, -0x8c634ffc, 0x24020004, 0x14620005, 0x2403fffb, 0x3c020001, 0x8c424ff8, -0x8004df6, 0x2403fff7, 0x3c020001, 0x8c424ff8, 0x431024, 0x3c010001, -0xac224ff8, 0x8ee20000, 0x3c030200, 0x431025, 0xaee20000, 0x8f820224, -0x3c010001, 0xac22711c, 0x8f820220, 0x2403fffb, 0x431024, 0xaf820220, -0x8f820220, 0x34420002, 0x8004e27, 0xaf820220, 0x3c020001, 0x8c4270f0, -0x10400005, 0x0, 0x3c020001, 0x8c4270cc, 0x1040000f, 0x24020002, -0x3c020001, 0x8c4270d0, 0x2c424e21, 0x1040000a, 0x24020002, 0x3c020001, -0x8c4270f0, 0x1040000f, 0x0, 0x3c020001, 0x8c4270cc, 0x1440000b, -0x0, 0x24020002, 0x3c010001, 0x8004e27, 0xac2270c0, 0x3c020001, -0x8c4270f0, 0x10400003, 0x0, 0xc00428b, 0x0, 0x8f820220, -0x3c03f700, 0x431025, 0xaf820220, 0x8fbf0010, 0x3e00008, 0x27bd0018, -0x3c030001, 0x24637118, 0x8c620000, 0x10400005, 0x34422000, 0x3c010001, -0xac22710c, 0x8004e39, 0xac600000, 0x3c010001, 0xac24710c, 0x3e00008, -0x0, 0x27bdffe0, 0x30820030, 0xafbf0018, 0x3c010001, 0xac227114, -0x14400067, 0x3c02ffff, 0x34421f0e, 0x821024, 0x14400061, 0x24020030, -0x30822000, 0x1040005d, 0x30838000, 0x31a02, 0x30820001, 0x21200, -0x3c040001, 0x8c84509c, 0x621825, 0x331c2, 0x3c030001, 0x2463507c, -0x30828000, 0x21202, 0x30840001, 0x42200, 0x441025, 0x239c2, -0x61080, 0x431021, 0x471021, 0x90430000, 0x24020001, 0x10620025, -0x0, 0x10600007, 0x24020002, 0x10620013, 0x24020003, 0x1062002c, -0x3c05000f, 0x8004e9d, 0x0, 0x8f820200, 0x2403feff, 0x431024, -0xaf820200, 0x8f820220, 0x3c03fffe, 0x3463ffff, 0x431024, 0xaf820220, -0x3c010001, 0xac207154, 0x3c010001, 0x8004ea8, 0xac20715c, 0x8f820200, -0x34420100, 0xaf820200, 0x8f820220, 0x3c03fffe, 0x3463ffff, 0x431024, -0xaf820220, 0x24020100, 0x3c010001, 0xac227154, 0x3c010001, 0x8004ea8, -0xac20715c, 0x8f820200, 0x2403feff, 0x431024, 0xaf820200, 0x8f820220, -0x3c030001, 0x431025, 0xaf820220, 0x3c010001, 0xac207154, 0x3c010001, -0x8004ea8, 0xac23715c, 0x8f820200, 0x34420100, 0xaf820200, 0x8f820220, -0x3c030001, 0x431025, 0xaf820220, 0x24020100, 0x3c010001, 0xac227154, -0x3c010001, 0x8004ea8, 0xac23715c, 0x34a5ffff, 0x3c040001, 0x24844f08, -0xafa30010, 0xc002403, 0xafa00014, 0x8004ea8, 0x0, 0x24020030, -0x3c010001, 0xac227118, 0x8fbf0018, 0x3e00008, 0x27bd0020, 0x0, -0x27bdffc8, 0xafb10024, 0x808821, 0xafb3002c, 0xa09821, 0xafb00020, -0xc08021, 0x3c040001, 0x24844f20, 0x3c050009, 0x3c020001, 0x8c424ffc, -0x34a59001, 0x2203021, 0x2603821, 0xafbf0030, 0xafb20028, 0xa7a0001a, -0xafb00014, 0xc002403, 0xafa20010, 0x24020002, 0x126200e9, 0x2e620003, -0x10400005, 0x24020001, 0x1262000a, 0x3c02fffb, 0x8004fac, 0x0, -0x24020004, 0x1262006d, 0x24020008, 0x1262006c, 0x3c02ffec, 0x8004fac, -0x0, 0x3442ffff, 0x2028024, 0x119140, 0x3c010001, 0x320821, -0xac30712c, 0x3c024000, 0x2021024, 0x10400046, 0x1023c2, 0x30840030, -0x101382, 0x3042000c, 0x3c030001, 0x24635024, 0x431021, 0x823821, -0x3c020020, 0x2021024, 0x10400006, 0x24020100, 0x3c010001, 0x320821, -0xac227130, 0x8004eef, 0x3c020080, 0x3c010001, 0x320821, 0xac207130, -0x3c020080, 0x2021024, 0x10400006, 0x111940, 0x3c020001, 0x3c010001, -0x230821, 0x8004efb, 0xac227138, 0x111140, 0x3c010001, 0x220821, -0xac207138, 0x94e30000, 0x32024000, 0x10400003, 0xa7a30018, 0x34624000, -0xa7a20018, 0x24040001, 0x94e20002, 0x24050004, 0x24e60002, 0x34420001, -0xc004802, 0xa4e20002, 0x24040001, 0x2821, 0xc004802, 0x27a60018, -0x3c020001, 0x8c424ffc, 0x24110001, 0x3c010001, 0xac315008, 0x14530004, -0x32028000, 0xc00428b, 0x0, 0x32028000, 0x10400095, 0x0, -0xc00428b, 0x0, 0x24020002, 0x3c010001, 0xac315000, 0x3c010001, -0x8004fac, 0xac224ffc, 0x24040001, 0x24050004, 0x27b0001a, 0xc004802, -0x2003021, 0x24040001, 0x2821, 0xc004802, 0x2003021, 0x3c020001, -0x521021, 0x8c427124, 0x3c040001, 0x8c844ffc, 0x3c03bfff, 0x3463ffff, -0x3c010001, 0xac335008, 0x431024, 0x3c010001, 0x320821, 0x10930074, -0xac227124, 0x8004fac, 0x0, 0x3c02ffec, 0x3442ffff, 0x2028024, -0x3c020008, 0x2028025, 0x111140, 0x3c010001, 0x220821, 0xac307128, -0x3c022000, 0x2021024, 0x10400005, 0x24020001, 0x3c010001, 0xac225098, -0x8004f4d, 0x3c024000, 0x3c010001, 0xac205098, 0x3c024000, 0x2021024, -0x1440001c, 0x0, 0x3c020001, 0x8c425098, 0x10400007, 0x24022020, -0x3c010001, 0xac22509c, 0x24020001, 0x3c010001, 0x370821, 0xac22839c, -0x3c04bfff, 0x111940, 0x3c020001, 0x431021, 0x8c427120, 0x3c050001, -0x8ca54ffc, 0x3484ffff, 0x441024, 0x3c010001, 0x230821, 0xac227120, -0x24020001, 0x10a20044, 0x0, 0x8004faa, 0x0, 0x3c020001, -0x8c425098, 0x1040001c, 0x24022000, 0x3c010001, 0xac22509c, 0x3c0300a0, -0x2031024, 0x14430005, 0x111140, 0x3402a000, 0x3c010001, 0x8004fa5, -0xac22509c, 0x3c030001, 0x621821, 0x8c637128, 0x3c020020, 0x621024, -0x10400004, 0x24022001, 0x3c010001, 0x8004fa5, 0xac22509c, 0x3c020080, -0x621024, 0x1040001f, 0x3402a001, 0x3c010001, 0x8004fa5, 0xac22509c, -0x3c020020, 0x2021024, 0x10400007, 0x111940, 0x24020100, 0x3c010001, -0x230821, 0xac227134, 0x8004f99, 0x3c020080, 0x111140, 0x3c010001, -0x220821, 0xac207134, 0x3c020080, 0x2021024, 0x10400006, 0x111940, -0x3c020001, 0x3c010001, 0x230821, 0x8004fa5, 0xac22713c, 0x111140, -0x3c010001, 0x220821, 0xac20713c, 0x3c030001, 0x8c634ffc, 0x24020001, -0x10620003, 0x0, 0xc00428b, 0x0, 0x8fbf0030, 0x8fb3002c, -0x8fb20028, 0x8fb10024, 0x8fb00020, 0x3e00008, 0x27bd0038, 0x27bdffd0, -0xafb40028, 0x80a021, 0xafb20020, 0x9021, 0xafb30024, 0x9821, -0xafb1001c, 0x8821, 0x24020002, 0xafbf002c, 0xafb00018, 0xa7a00012, -0x10a20068, 0xa7a00010, 0x2ca20003, 0x10400005, 0x24020001, 0x10a2000a, -0x148140, 0x8005070, 0x2201021, 0x24020004, 0x10a2005e, 0x24020008, -0x10a2005d, 0x142140, 0x8005070, 0x2201021, 0x3c030001, 0x701821, -0x8c63712c, 0x3c024000, 0x621024, 0x14400009, 0x24040001, 0x3c027fff, -0x3442ffff, 0x628824, 0x3c010001, 0x300821, 0xac317124, 0x8005070, -0x2201021, 0x24050001, 0xc0047c0, 0x27a60010, 0x24040001, 0x24050001, -0xc0047c0, 0x27a60010, 0x97a20010, 0x30420004, 0x10400034, 0x3c114000, -0x3c030001, 0x8c6350ac, 0x24020003, 0x10620008, 0x2c620004, 0x14400029, -0x3c028000, 0x24020004, 0x10620014, 0x24040001, 0x8005019, 0x3c028000, -0x24040001, 0x24050011, 0x27b00012, 0xc0047c0, 0x2003021, 0x24040001, -0x24050011, 0xc0047c0, 0x2003021, 0x97a30012, 0x30624000, 0x10400002, -0x3c130010, 0x3c130008, 0x3c120001, 0x8005016, 0x30628000, 0x24050014, -0x27b00012, 0xc0047c0, 0x2003021, 0x24040001, 0x24050014, 0xc0047c0, -0x2003021, 0x97a30012, 0x30621000, 0x10400002, 0x3c130010, 0x3c130008, -0x3c120001, 0x30620800, 0x54400001, 0x3c120002, 0x3c028000, 0x2221025, -0x2531825, 0x8005023, 0x438825, 0x3c110001, 0x2308821, 0x8e31712c, -0x3c027fff, 0x3442ffff, 0x2228824, 0x141140, 0x3c010001, 0x220821, -0xac317124, 0x8005070, 0x2201021, 0x142140, 0x3c030001, 0x641821, -0x8c637128, 0x3c024000, 0x621024, 0x14400008, 0x3c027fff, 0x3442ffff, -0x628824, 0x3c010001, 0x240821, 0xac317120, 0x8005070, 0x2201021, -0x3c020001, 0x8c42500c, 0x1040002d, 0x3c11c00c, 0x3c020001, 0x8c425098, -0x3c03e00c, 0x3c010001, 0x240821, 0x8c247134, 0x2102b, 0x21023, -0x431024, 0x10800004, 0x518825, 0x3c020020, 0x800504d, 0x2228825, -0x3c02ffdf, 0x3442ffff, 0x2228824, 0x141140, 0x3c010001, 0x220821, -0x8c22713c, 0x10400003, 0x3c020080, 0x8005058, 0x2228825, 0x3c02ff7f, -0x3442ffff, 0x2228824, 0x3c020001, 0x8c425070, 0x10400002, 0x3c020800, -0x2228825, 0x3c020001, 0x8c425074, 0x10400002, 0x3c020400, 0x2228825, -0x3c020001, 0x8c425078, 0x10400006, 0x3c020100, 0x800506b, 0x2228825, -0x3c027fff, 0x3442ffff, 0x628824, 0x141140, 0x3c010001, 0x220821, -0xac317120, 0x2201021, 0x8fbf002c, 0x8fb40028, 0x8fb30024, 0x8fb20020, -0x8fb1001c, 0x8fb00018, 0x3e00008, 0x27bd0030, 0x27bdffd8, 0xafb40020, -0x80a021, 0xafbf0024, 0xafb3001c, 0xafb20018, 0xafb10014, 0xafb00010, -0x8f900200, 0x3c030001, 0x8c634ffc, 0x8f930220, 0x24020002, 0x106200b1, -0x2c620003, 0x10400005, 0x24020001, 0x1062000a, 0x141940, 0x8005137, -0x0, 0x24020004, 0x1062005a, 0x24020008, 0x10620059, 0x149140, -0x8005137, 0x0, 0x3c040001, 0x832021, 0x8c84712c, 0x3c110001, -0x2238821, 0x8e317124, 0x3c024000, 0x821024, 0x1040003e, 0x3c020008, -0x2221024, 0x10400020, 0x36100002, 0x3c020001, 0x431021, 0x8c427130, -0x10400005, 0x36100020, 0x36100100, 0x3c020020, 0x80050af, 0x2228825, -0x2402feff, 0x2028024, 0x3c02ffdf, 0x3442ffff, 0x2228824, 0x141140, -0x3c010001, 0x220821, 0x8c227138, 0x10400005, 0x3c020001, 0x2629825, -0x3c020080, 0x80050ce, 0x2228825, 0x3c02fffe, 0x3442ffff, 0x2629824, -0x3c02ff7f, 0x3442ffff, 0x80050ce, 0x2228824, 0x2402fedf, 0x2028024, -0x3c02fffe, 0x3442ffff, 0x2629824, 0x3c02ff5f, 0x3442ffff, 0x2228824, -0x3c010001, 0x230821, 0xac207130, 0x3c010001, 0x230821, 0xac207138, -0xc00478a, 0x0, 0xaf900200, 0xaf930220, 0x8f820220, 0x2403fffb, -0x431024, 0xaf820220, 0x8f820220, 0x34420002, 0xaf820220, 0x80050e5, -0x141140, 0x8f820200, 0x2403fffd, 0x431024, 0xc00478a, 0xaf820200, -0x3c02bfff, 0x3442ffff, 0xc00428b, 0x2228824, 0x141140, 0x3c010001, -0x220821, 0x8005137, 0xac317124, 0x149140, 0x3c040001, 0x922021, -0x8c847128, 0x3c110001, 0x2328821, 0x8e317120, 0x3c024000, 0x821024, -0x14400011, 0x0, 0x3c020001, 0x8c425098, 0x14400006, 0x3c02bfff, -0x8f820200, 0x34420002, 0xc00478a, 0xaf820200, 0x3c02bfff, 0x3442ffff, -0xc00428b, 0x2228824, 0x3c010001, 0x320821, 0x8005137, 0xac317120, -0x3c020001, 0x8c425098, 0x1440002d, 0x141140, 0x3c020020, 0x821024, -0x10400007, 0x36100020, 0x24020100, 0x3c010001, 0x320821, 0xac227134, -0x8005117, 0x36100100, 0x3c010001, 0x320821, 0xac207134, 0x2402feff, -0x2028024, 0x3c020080, 0x821024, 0x10400007, 0x141940, 0x3c020001, -0x3c010001, 0x230821, 0xac22713c, 0x8005128, 0x2629825, 0x141140, -0x3c010001, 0x220821, 0xac20713c, 0x3c02fffe, 0x3442ffff, 0x2629824, -0xc00478a, 0x0, 0xaf900200, 0xaf930220, 0x8f820220, 0x2403fffb, -0x431024, 0xaf820220, 0x8f820220, 0x34420002, 0xaf820220, 0x141140, -0x3c010001, 0x220821, 0xac317120, 0x8fbf0024, 0x8fb40020, 0x8fb3001c, -0x8fb20018, 0x8fb10014, 0x8fb00010, 0x3e00008, 0x27bd0028, 0x0, -0x0 }; -u32 tigonFwData[(MAX_DATA_LEN/4) + 1] __initdata = { -0x416c7465, 0x6f6e2041, 0x63654e49, 0x43205600, 0x416c7465, 0x6f6e2041, -0x63654e49, 0x43205600, 0x42424242, 0x0, 0x0, 0x0, -0x135430, 0x13e7fc, 0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x60cf00, 0x60, 0xcf000000, 0x0, -0x0, 0x0, 0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x3, 0x0, 0x1, 0x0, -0x0, 0x0, 0x0, 0x0, 0x1, 0x0, -0x0, 0x0, 0x0, 0x0, 0x1000000, 0x21000000, -0x12000140, 0x0, 0x0, 0x20000000, 0x120000a0, 0x0, -0x12000060, 0x12000180, 0x120001e0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, 0x30001, 0x1, -0x30201, 0x0, 0x0 }; +0x10000003, +0x0, 0xd, 0xd, 0x3c1d0001, +0x8fbd5404, 0x3a0f021, 0x3c100000, 0x26104000, +0xc00100c, 0x0, 0xd, 0x27bdffd8, +0x3c1cc000, 0x3c1b0013, 0x377bd800, 0xd021, +0x3c170013, 0x36f75418, 0x2e02021, 0x340583e8, +0xafbf0024, 0xc00248c, 0xafb00020, 0xc0023ec, +0x0, 0x3c040001, 0x24844970, 0x24050001, +0x2e03021, 0x3821, 0x3c100001, 0x261075d0, +0xafb00010, 0xc002407, 0xafbb0014, 0x3c02000f, +0x3442ffff, 0x2021024, 0x362102b, 0x10400009, +0x24050003, 0x3c040001, 0x2484497c, 0x2003021, +0x3603821, 0x3c020010, 0xafa20010, 0xc002407, +0xafa00014, 0x2021, 0x3405c000, 0x3c010001, +0x370821, 0xa02083b0, 0x3c010001, 0x370821, +0xa02083b2, 0x3c010001, 0x370821, 0xa02083b3, +0x3c010001, 0x370821, 0xac2083b4, 0xa2e004d8, +0x418c0, 0x24840001, 0x771021, 0xac40727c, +0x771021, 0xac407280, 0x2e31021, 0xa445727c, +0x2c820020, 0x1440fff7, 0x418c0, 0x2021, +0x3405c000, 0x418c0, 0x24840001, 0x771021, +0xac40737c, 0x771021, 0xac407380, 0x2e31021, +0xa445737c, 0x2c820080, 0x5440fff7, 0x418c0, +0xaf800054, 0xaf80011c, 0x8f820044, 0x34420040, +0xaf820044, 0x8f820044, 0x34420020, 0xaf820044, +0x8f420218, 0x30420002, 0x10400009, 0x0, +0x8f420220, 0x3c030002, 0x34630004, 0x431025, +0xaee204c4, 0x8f42021c, 0x8001074, 0x34420004, +0x8f420220, 0x3c030002, 0x34630006, 0x431025, +0xaee204c4, 0x8f42021c, 0x34420006, 0xaee204cc, +0x8f420218, 0x30420010, 0x1040000a, 0x0, +0x8f42021c, 0x34420004, 0xaee204c8, 0x8f420220, +0x3c03000a, 0x34630004, 0x431025, 0x800108a, +0xaee204c0, 0x8f420220, 0x3c03000a, 0x34630006, +0x431025, 0xaee204c0, 0x8f42021c, 0x34420006, +0xaee204c8, 0x8f420218, 0x30420200, 0x10400003, +0x24020001, 0x8001091, 0xa2e27248, 0xa2e07248, +0x24020001, 0xaf8200a0, 0xaf8200b0, 0x8f830054, +0x8f820054, 0x8001099, 0x24630064, 0x8f820054, +0x621023, 0x2c420065, 0x1440fffc, 0x0, +0xaf800044, 0x8f420208, 0x8f43020c, 0xaee20010, +0xaee30014, 0x8ee40010, 0x8ee50014, 0x26e20030, +0xaee20028, 0x24020490, 0xaee20018, 0xaf840090, +0xaf850094, 0x8ee20028, 0xaf8200b4, 0x96e2001a, +0xaf82009c, 0x8f8200b0, 0x8ee304cc, 0x431025, +0xaf8200b0, 0x8f8200b0, 0x30420004, 0x1440fffd, +0x0, 0x8ee20450, 0x8ee30454, 0xaee304fc, +0x8ee204fc, 0x2442e000, 0x2c422001, 0x1440000d, +0x26e40030, 0x8ee20450, 0x8ee30454, 0x3c040001, +0x24844988, 0x3c050001, 0xafa00010, 0xafa00014, +0x8ee704fc, 0x34a5f000, 0xc002407, 0x603021, +0x26e40030, 0xc00248c, 0x24050400, 0x27440080, +0xc00248c, 0x24050080, 0x26e4777c, 0xc00248c, +0x24050400, 0x8f42025c, 0x26e40094, 0xaee20060, +0x8f420260, 0x27450200, 0x24060008, 0xaee20068, +0x24020006, 0xc00249e, 0xaee20064, 0x3c023b9a, +0x3442ca00, 0x2021, 0x24030002, 0xaee30074, +0xaee30070, 0xaee2006c, 0x240203e8, 0xaee20104, +0x24020001, 0xaee30100, 0xaee2010c, 0x3c030001, +0x641821, 0x906353d0, 0x2e41021, 0x24840001, +0xa043009c, 0x2c82000f, 0x1440fff8, 0x0, +0x8f820040, 0x2e41821, 0x24840001, 0x21702, +0x24420030, 0xa062009c, 0x2e41021, 0xa040009c, +0x96e2046a, 0x30420003, 0x14400009, 0x0, +0x96e2047a, 0x30420003, 0x50400131, 0x3c030800, +0x96e2046a, 0x30420003, 0x1040002a, 0x3c020700, +0x96e2047a, 0x30420003, 0x10400026, 0x3c020700, +0x96e3047a, 0x96e2046a, 0x14620022, 0x3c020700, +0x8ee204c0, 0x24030001, 0xa2e34e20, 0x34420e00, +0xaee204c0, 0x8f420218, 0x30420100, 0x10400005, +0x0, 0x3c020001, 0x2442e178, 0x800111d, +0x21100, 0x3c020001, 0x2442d36c, 0x21100, +0x21182, 0x3c030800, 0x431025, 0x3c010001, +0xac221238, 0x3c020001, 0x2442f690, 0x21100, +0x21182, 0x3c030800, 0x431025, 0x3c010001, +0xac221278, 0x8ee20000, 0x34424000, 0x8001238, +0xaee20000, 0x34423000, 0xafa20018, 0x8ee20608, +0x8f430228, 0x24420001, 0x304900ff, 0x512300e2, +0xafa00010, 0x8ee20608, 0x210c0, 0x571021, +0x8fa30018, 0x8fa4001c, 0xac43060c, 0xac440610, +0x8f870120, 0x27623800, 0x24e80020, 0x102102b, +0x50400001, 0x27683000, 0x8f820128, 0x11020004, +0x0, 0x8f820124, 0x15020007, 0x1021, +0x8ee201a4, 0x3021, 0x24420001, 0xaee201a4, +0x80011a0, 0x8ee201a4, 0x8ee40608, 0x420c0, +0x801821, 0x8ee40430, 0x8ee50434, 0xa32821, +0xa3302b, 0x822021, 0x862021, 0xace40000, +0xace50004, 0x8ee30608, 0x24020008, 0xa4e2000e, +0x2402000d, 0xace20018, 0xace9001c, 0x318c0, +0x2463060c, 0x2e31021, 0xace20008, 0x8ee204c4, +0xace20010, 0xaf880120, 0x92e24e20, 0x14400037, +0x24060001, 0x8ee24e30, 0x210c0, 0x24425038, +0x2e22021, 0x8c830000, 0x24020007, 0x1462001f, +0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b, +0x24030040, 0x8c820004, 0x24420001, 0xac820004, +0x8ee24e34, 0x8ee54e30, 0x24420001, 0x10430007, +0x0, 0x8ee24e34, 0x24420001, 0x10a20005, +0x0, 0x800118a, 0x0, 0x14a00005, +0x0, 0x8f820128, 0x24420020, 0xaf820128, +0x8f820128, 0x8c820004, 0x2c420011, 0x50400013, +0xac800000, 0x80011a0, 0x0, 0x8ee24e30, +0x24030040, 0x24420001, 0x50430003, 0x1021, +0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30, +0x210c0, 0x24425038, 0x2e22021, 0x24020007, +0xac820000, 0x24020001, 0xac820004, 0x54c0000c, +0xaee90608, 0x3c040001, 0x24844994, 0xafa00010, +0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009, +0xc002407, 0x34a5f000, 0x8001223, 0x0, +0x8f830120, 0x27623800, 0x24660020, 0xc2102b, +0x50400001, 0x27663000, 0x8f820128, 0x10c20004, +0x0, 0x8f820124, 0x14c20007, 0x0, +0x8ee201a4, 0x3021, 0x24420001, 0xaee201a4, +0x8001207, 0x8ee201a4, 0x8ee20608, 0xac62001c, +0x8ee404a0, 0x8ee504a4, 0x2462001c, 0xac620008, +0x24020008, 0xa462000e, 0x24020011, 0xac620018, +0xac640000, 0xac650004, 0x8ee204c4, 0xac620010, +0xaf860120, 0x92e24e20, 0x14400037, 0x24060001, +0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, +0x8c830000, 0x24020012, 0x1462001f, 0x0, +0x8ee34e30, 0x8ee24e34, 0x1062001b, 0x24030040, +0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34, +0x8ee54e30, 0x24420001, 0x10430007, 0x0, +0x8ee24e34, 0x24420001, 0x10a20005, 0x0, +0x80011f1, 0x0, 0x14a00005, 0x0, +0x8f820128, 0x24420020, 0xaf820128, 0x8f820128, +0x8c820004, 0x2c420011, 0x50400013, 0xac800000, +0x8001207, 0x0, 0x8ee24e30, 0x24030040, +0x24420001, 0x50430003, 0x1021, 0x8ee24e30, +0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, +0x24425038, 0x2e22021, 0x24020012, 0xac820000, +0x24020001, 0xac820004, 0x14c0001b, 0x0, +0x3c040001, 0x2484499c, 0xafa00010, 0xafa00014, +0x8ee60608, 0x8f470228, 0x3c050009, 0xc002407, +0x34a5f001, 0x8ee201b0, 0x24420001, 0xaee201b0, +0x8001223, 0x8ee201b0, 0x3c040001, 0x248449a8, +0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009, +0xc002407, 0x34a5f005, 0x8ee201ac, 0x24420001, +0xaee201ac, 0x8ee201ac, 0x8ee20160, 0x3c040001, +0x248449b4, 0x3405f001, 0x24420001, 0xaee20160, +0x8ee20160, 0x3021, 0x3821, 0xafa00010, +0xc002407, 0xafa00014, 0x8001238, 0x0, +0x3c020001, 0x2442f5b8, 0x21100, 0x21182, +0x431025, 0x3c010001, 0xac221278, 0x96e2045a, +0x30420003, 0x10400025, 0x3c050fff, 0x8ee204c8, +0x34a5ffff, 0x34420a00, 0xaee204c8, 0x8ee304c8, +0x3c040001, 0x248449c0, 0x24020001, 0xa2e204ec, +0xa2e204ed, 0x3c020002, 0x621825, 0x3c020001, +0x2442a3a0, 0x451024, 0x21082, 0xaee304c8, +0x3c030800, 0x431025, 0x3c010001, 0xac221220, +0x3c020001, 0x2442ade4, 0x451024, 0x21082, +0x431025, 0x3c010001, 0xac221280, 0x96e6045a, +0x3821, 0x24050011, 0xafa00010, 0xc002407, +0xafa00014, 0x8001268, 0x0, 0x3c020001, +0x2442a9e4, 0x21100, 0x21182, 0x3c030800, +0x431025, 0x3c010001, 0xac221280, 0x96e2046a, +0x30420010, 0x14400009, 0x0, 0x96e2047a, +0x30420010, 0x10400112, 0x0, 0x96e2046a, +0x30420010, 0x10400005, 0x3c020700, 0x96e2047a, +0x30420010, 0x14400102, 0x3c020700, 0x34423000, +0xafa20018, 0x8ee20608, 0x8f430228, 0x24420001, +0x304900ff, 0x512300e2, 0xafa00010, 0x8ee20608, +0x210c0, 0x571021, 0x8fa30018, 0x8fa4001c, +0xac43060c, 0xac440610, 0x8f870120, 0x27623800, +0x24e80020, 0x102102b, 0x50400001, 0x27683000, +0x8f820128, 0x11020004, 0x0, 0x8f820124, +0x15020007, 0x1021, 0x8ee201a4, 0x3021, +0x24420001, 0xaee201a4, 0x80012ea, 0x8ee201a4, +0x8ee40608, 0x420c0, 0x801821, 0x8ee40430, +0x8ee50434, 0xa32821, 0xa3302b, 0x822021, +0x862021, 0xace40000, 0xace50004, 0x8ee30608, +0x24020008, 0xa4e2000e, 0x2402000d, 0xace20018, +0xace9001c, 0x318c0, 0x2463060c, 0x2e31021, +0xace20008, 0x8ee204c4, 0xace20010, 0xaf880120, +0x92e24e20, 0x14400037, 0x24060001, 0x8ee24e30, +0x210c0, 0x24425038, 0x2e22021, 0x8c830000, +0x24020007, 0x1462001f, 0x0, 0x8ee34e30, +0x8ee24e34, 0x1062001b, 0x24030040, 0x8c820004, +0x24420001, 0xac820004, 0x8ee24e34, 0x8ee54e30, +0x24420001, 0x10430007, 0x0, 0x8ee24e34, +0x24420001, 0x10a20005, 0x0, 0x80012d4, +0x0, 0x14a00005, 0x0, 0x8f820128, +0x24420020, 0xaf820128, 0x8f820128, 0x8c820004, +0x2c420011, 0x50400013, 0xac800000, 0x80012ea, +0x0, 0x8ee24e30, 0x24030040, 0x24420001, +0x50430003, 0x1021, 0x8ee24e30, 0x24420001, +0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, +0x2e22021, 0x24020007, 0xac820000, 0x24020001, +0xac820004, 0x54c0000c, 0xaee90608, 0x3c040001, +0x24844994, 0xafa00010, 0xafa00014, 0x8ee60608, +0x8f470228, 0x3c050009, 0xc002407, 0x34a5f000, +0x800136d, 0x0, 0x8f830120, 0x27623800, +0x24660020, 0xc2102b, 0x50400001, 0x27663000, +0x8f820128, 0x10c20004, 0x0, 0x8f820124, +0x14c20007, 0x0, 0x8ee201a4, 0x3021, +0x24420001, 0xaee201a4, 0x8001351, 0x8ee201a4, +0x8ee20608, 0xac62001c, 0x8ee404a0, 0x8ee504a4, +0x2462001c, 0xac620008, 0x24020008, 0xa462000e, +0x24020011, 0xac620018, 0xac640000, 0xac650004, +0x8ee204c4, 0xac620010, 0xaf860120, 0x92e24e20, +0x14400037, 0x24060001, 0x8ee24e30, 0x210c0, +0x24425038, 0x2e22021, 0x8c830000, 0x24020012, +0x1462001f, 0x0, 0x8ee34e30, 0x8ee24e34, +0x1062001b, 0x24030040, 0x8c820004, 0x24420001, +0xac820004, 0x8ee24e34, 0x8ee54e30, 0x24420001, +0x10430007, 0x0, 0x8ee24e34, 0x24420001, +0x10a20005, 0x0, 0x800133b, 0x0, +0x14a00005, 0x0, 0x8f820128, 0x24420020, +0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011, +0x50400013, 0xac800000, 0x8001351, 0x0, +0x8ee24e30, 0x24030040, 0x24420001, 0x50430003, +0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30, +0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, +0x24020012, 0xac820000, 0x24020001, 0xac820004, +0x14c0001b, 0x0, 0x3c040001, 0x2484499c, +0xafa00010, 0xafa00014, 0x8ee60608, 0x8f470228, +0x3c050009, 0xc002407, 0x34a5f001, 0x8ee201b0, +0x24420001, 0xaee201b0, 0x800136d, 0x8ee201b0, +0x3c040001, 0x248449a8, 0xafa00014, 0x8ee60608, +0x8f470228, 0x3c050009, 0xc002407, 0x34a5f005, +0x8ee201ac, 0x24420001, 0xaee201ac, 0x8ee201ac, +0x8ee20160, 0x3c040001, 0x248449b4, 0x3405f002, +0x24420001, 0xaee20160, 0x8ee20160, 0x3021, +0x3821, 0xafa00010, 0xc002407, 0xafa00014, +0x96e6047a, 0x96e7046a, 0x3c040001, 0x248449cc, +0x24050012, 0xafa00010, 0xc002407, 0xafa00014, +0xc004500, 0x0, 0xc002318, 0x0, +0x3c060001, 0x34c63800, 0xaee00608, 0xaf400228, +0xaf40022c, 0x96e30458, 0x8ee40000, 0x3c0512d8, +0x34a5c358, 0x27623800, 0xaee27258, 0x27623800, +0xaee27260, 0x27623800, 0xaee27264, 0x3661021, +0xaee27270, 0x2402ffff, 0xaee004d4, 0xaee004e0, +0xaee004e4, 0xaee004f0, 0xa2e004f4, 0xaee00e0c, +0xaee00e18, 0xaee00e10, 0xaee00e14, 0xaee00e1c, +0xaee0724c, 0xaee05244, 0xaee05240, 0xaee0523c, +0xaee07250, 0xaee07254, 0xaee0725c, 0xaee07268, +0xaee004d0, 0x2463ffff, 0x852025, 0xaee304f8, +0xaee40000, 0xaf800060, 0xaf820064, 0x3c020100, +0xafa20018, 0x8ee20608, 0x8f430228, 0x24420001, +0x304900ff, 0x512300e2, 0xafa00010, 0x8ee20608, +0x210c0, 0x571021, 0x8fa30018, 0x8fa4001c, +0xac43060c, 0xac440610, 0x8f870120, 0x27623800, +0x24e80020, 0x102102b, 0x50400001, 0x27683000, +0x8f820128, 0x11020004, 0x0, 0x8f820124, +0x15020007, 0x1021, 0x8ee201a4, 0x3021, +0x24420001, 0xaee201a4, 0x8001422, 0x8ee201a4, +0x8ee40608, 0x420c0, 0x801821, 0x8ee40430, +0x8ee50434, 0xa32821, 0xa3302b, 0x822021, +0x862021, 0xace40000, 0xace50004, 0x8ee30608, +0x24020008, 0xa4e2000e, 0x2402000d, 0xace20018, +0xace9001c, 0x318c0, 0x2463060c, 0x2e31021, +0xace20008, 0x8ee204c4, 0xace20010, 0xaf880120, +0x92e24e20, 0x14400037, 0x24060001, 0x8ee24e30, +0x210c0, 0x24425038, 0x2e22021, 0x8c830000, +0x24020007, 0x1462001f, 0x0, 0x8ee34e30, +0x8ee24e34, 0x1062001b, 0x24030040, 0x8c820004, +0x24420001, 0xac820004, 0x8ee24e34, 0x8ee54e30, +0x24420001, 0x10430007, 0x0, 0x8ee24e34, +0x24420001, 0x10a20005, 0x0, 0x800140c, +0x0, 0x14a00005, 0x0, 0x8f820128, +0x24420020, 0xaf820128, 0x8f820128, 0x8c820004, +0x2c420011, 0x50400013, 0xac800000, 0x8001422, +0x0, 0x8ee24e30, 0x24030040, 0x24420001, +0x50430003, 0x1021, 0x8ee24e30, 0x24420001, +0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, +0x2e22021, 0x24020007, 0xac820000, 0x24020001, +0xac820004, 0x54c0000c, 0xaee90608, 0x3c040001, +0x24844994, 0xafa00010, 0xafa00014, 0x8ee60608, +0x8f470228, 0x3c050009, 0xc002407, 0x34a5f000, +0x80014a5, 0x0, 0x8f830120, 0x27623800, +0x24660020, 0xc2102b, 0x50400001, 0x27663000, +0x8f820128, 0x10c20004, 0x0, 0x8f820124, +0x14c20007, 0x0, 0x8ee201a4, 0x3021, +0x24420001, 0xaee201a4, 0x8001489, 0x8ee201a4, +0x8ee20608, 0xac62001c, 0x8ee404a0, 0x8ee504a4, +0x2462001c, 0xac620008, 0x24020008, 0xa462000e, +0x24020011, 0xac620018, 0xac640000, 0xac650004, +0x8ee204c4, 0xac620010, 0xaf860120, 0x92e24e20, +0x14400037, 0x24060001, 0x8ee24e30, 0x210c0, +0x24425038, 0x2e22021, 0x8c830000, 0x24020012, +0x1462001f, 0x0, 0x8ee34e30, 0x8ee24e34, +0x1062001b, 0x24030040, 0x8c820004, 0x24420001, +0xac820004, 0x8ee24e34, 0x8ee54e30, 0x24420001, +0x10430007, 0x0, 0x8ee24e34, 0x24420001, +0x10a20005, 0x0, 0x8001473, 0x0, +0x14a00005, 0x0, 0x8f820128, 0x24420020, +0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011, +0x50400013, 0xac800000, 0x8001489, 0x0, +0x8ee24e30, 0x24030040, 0x24420001, 0x50430003, +0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30, +0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, +0x24020012, 0xac820000, 0x24020001, 0xac820004, +0x14c0001b, 0x0, 0x3c040001, 0x2484499c, +0xafa00010, 0xafa00014, 0x8ee60608, 0x8f470228, +0x3c050009, 0xc002407, 0x34a5f001, 0x8ee201b0, +0x24420001, 0xaee201b0, 0x80014a5, 0x8ee201b0, +0x3c040001, 0x248449a8, 0xafa00014, 0x8ee60608, +0x8f470228, 0x3c050009, 0xc002407, 0x34a5f005, +0x8ee201ac, 0x24420001, 0xaee201ac, 0x8ee201ac, +0x8ee20154, 0x24420001, 0xaee20154, 0xc0014dc, +0x8ee20154, 0x8f8200a0, 0x30420004, 0x1440fffd, +0x0, 0x8f820040, 0x30420001, 0x14400008, +0x0, 0x8f430104, 0x24020001, 0x10620004, +0x0, 0x8f420264, 0x10400006, 0x0, +0x8ee2017c, 0x24420001, 0xaee2017c, 0x80014c5, +0x8ee2017c, 0x8f820044, 0x34420004, 0xaf820044, +0x8ee20178, 0x24420001, 0xaee20178, 0x8ee20178, +0x8f8200d8, 0x8f8300d4, 0x431023, 0xaee2726c, +0x8ee2726c, 0x1c400003, 0x3c030001, 0x431021, +0xaee2726c, 0xc004068, 0x0, 0xc004440, +0xaf800228, 0x8fbf0024, 0x8fb00020, 0x3e00008, +0x27bd0028, 0x3e00008, 0x0, 0x3e00008, +0x0, 0x0, 0x0, 0x2402002c, +0xaf820050, 0xaee07274, 0x8f420238, 0xaee27278, +0x8f820054, 0x24420067, 0xaf820058, 0xaee07b88, +0xaee07b8c, 0xaee07b84, 0x3c010001, 0x370821, +0xac2083bc, 0x3c010001, 0x370821, 0x3e00008, +0xa02083b9, 0x27bdffd8, 0xafbf0024, 0xafb00020, +0x8f820054, 0x3c030001, 0x8c635488, 0x24420067, +0x1060000d, 0xaf820058, 0x3c020001, 0x571021, +0x904283b8, 0x10400005, 0x3c030200, 0x3c010001, +0x370821, 0x8001503, 0xa02083b8, 0x8ee20000, +0x431025, 0xaee20000, 0x8f420218, 0x30420100, +0x104000c6, 0x0, 0x8f8200b0, 0x30420004, +0x104000c2, 0x0, 0x3c030001, 0x771821, +0x8c6383d0, 0x8f820104, 0x146200b4, 0x0, +0x3c030001, 0x771821, 0x8c6383d4, 0x8f8200b4, +0x146200ae, 0x0, 0x8f8200b0, 0x3c030080, +0x431024, 0x1040000d, 0x0, 0x8f82011c, +0x34420002, 0xaf82011c, 0x8f8200b0, 0x2403fffb, +0x431024, 0xaf8200b0, 0x8f82011c, 0x2403fffd, +0x431024, 0x80015cc, 0xaf82011c, 0x3c030001, +0x771821, 0x8c6383d0, 0x8f820104, 0x14620082, +0x0, 0x3c030001, 0x771821, 0x8c6383d4, +0x8f8200b4, 0x1462007c, 0x0, 0x3c070001, +0xf73821, 0x8ce783d0, 0x8f8200b0, 0x3c040001, +0x24844a40, 0xafa00014, 0xafa20010, 0x8f8600b0, +0x3c050005, 0xc002407, 0x34a50900, 0x8f82011c, +0x34420002, 0xaf82011c, 0x8f830104, 0x8f8200b0, +0x34420001, 0xaf8200b0, 0xaf830104, 0x8f830120, +0x27623800, 0x24660020, 0xc2102b, 0x50400001, +0x27663000, 0x8f820128, 0x10c20004, 0x0, +0x8f820124, 0x14c20006, 0x0, 0x8ee201a4, +0x24420001, 0xaee201a4, 0x80015a0, 0x8ee201a4, +0x8f440208, 0x8f45020c, 0x26e20030, 0xac620008, +0x24020400, 0xa462000e, 0x2402000f, 0xac620018, +0xac60001c, 0xac640000, 0xac650004, 0x8ee204c4, +0xac620010, 0xaf860120, 0x92e24e20, 0x14400037, +0x0, 0x8ee24e30, 0x210c0, 0x24425038, +0x2e22021, 0x8c830000, 0x24020007, 0x1462001f, +0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b, +0x24030040, 0x8c820004, 0x24420001, 0xac820004, +0x8ee24e34, 0x8ee54e30, 0x24420001, 0x10430007, +0x0, 0x8ee24e34, 0x24420001, 0x10a20005, +0x0, 0x800158a, 0x0, 0x14a00005, +0x0, 0x8f820128, 0x24420020, 0xaf820128, +0x8f820128, 0x8c820004, 0x2c420011, 0x50400013, +0xac800000, 0x80015a0, 0x0, 0x8ee24e30, +0x24030040, 0x24420001, 0x50430003, 0x1021, +0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30, +0x210c0, 0x24425038, 0x2e22021, 0x24020007, +0xac820000, 0x24020001, 0xac820004, 0x8f82011c, +0x2403fffd, 0x431024, 0xaf82011c, 0x8ee201e4, +0x3c070001, 0xf73821, 0x8ce783d0, 0x24420001, +0xaee201e4, 0x8ee201e4, 0x3c040001, 0x24844a4c, +0x80015bd, 0xafa00010, 0x8f820104, 0x3c010001, +0x370821, 0xac2283d0, 0x8f8200b4, 0x3c070001, +0xf73821, 0x8ce783d0, 0x3c040001, 0x24844a54, +0x3c010001, 0x370821, 0xac2283d4, 0xafa00010, +0xafa00014, 0x8f8600b0, 0x3c050005, 0xc002407, +0x34a50900, 0x80015cc, 0x0, 0x8f820104, +0x3c010001, 0x370821, 0xac2283d0, 0x8f8200b4, +0x3c010001, 0x370821, 0xac2283d4, 0x8ee27274, +0x92e304f4, 0x24420067, 0x14600006, 0xaee27274, +0x8ee27274, 0x8f430234, 0x43102b, 0x1440007b, +0x0, 0x8ee304e4, 0x8ee204f8, 0x14620004, +0x0, 0x92e204f4, 0x50400074, 0xa2e004f4, +0x8f830120, 0x27623800, 0x24660020, 0xc2102b, +0x50400001, 0x27663000, 0x8f820128, 0x10c20004, +0x0, 0x8f820124, 0x14c20007, 0x0, +0x8ee201a4, 0x8021, 0x24420001, 0xaee201a4, +0x8001637, 0x8ee201a4, 0x8ee204e4, 0xac62001c, +0x8ee404b0, 0x8ee504b4, 0x2462001c, 0xac620008, +0x24020008, 0xa462000e, 0x24020011, 0xac620018, +0xac640000, 0xac650004, 0x8ee204c4, 0xac620010, +0xaf860120, 0x92e24e20, 0x14400037, 0x24100001, +0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, +0x8c830000, 0x24020012, 0x1462001f, 0x0, +0x8ee34e30, 0x8ee24e34, 0x1062001b, 0x24030040, +0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34, +0x8ee54e30, 0x24420001, 0x10430007, 0x0, +0x8ee24e34, 0x24420001, 0x10a20005, 0x0, +0x8001621, 0x0, 0x14a00005, 0x0, +0x8f820128, 0x24420020, 0xaf820128, 0x8f820128, +0x8c820004, 0x2c420011, 0x50400013, 0xac800000, +0x8001637, 0x0, 0x8ee24e30, 0x24030040, +0x24420001, 0x50430003, 0x1021, 0x8ee24e30, +0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, +0x24425038, 0x2e22021, 0x24020012, 0xac820000, +0x24020001, 0xac820004, 0x5600000b, 0x24100001, +0x8ee204e4, 0x3c040001, 0x24844a5c, 0xafa00014, +0xafa20010, 0x8ee60608, 0x8f470228, 0x3c050009, +0xc002407, 0x34a5f006, 0x16000003, 0x24020001, +0x8001650, 0xa2e204f4, 0x8ee20170, 0x24420001, +0xaee20170, 0x8ee20170, 0x8ee204e4, 0xa2e004f4, +0xaee004f0, 0xaee07274, 0xaee204f8, 0x8ee20e1c, +0x1040006d, 0x0, 0x8f830120, 0x27623800, +0x24660020, 0xc2102b, 0x50400001, 0x27663000, +0x8f820128, 0x10c20004, 0x0, 0x8f820124, +0x14c20007, 0x0, 0x8ee201a4, 0x8021, +0x24420001, 0xaee201a4, 0x80016ad, 0x8ee201a4, +0x8ee2724c, 0xac62001c, 0x8ee404a8, 0x8ee504ac, +0x2462001c, 0xac620008, 0x24020008, 0xa462000e, +0x24020011, 0xac620018, 0xac640000, 0xac650004, +0x8ee204c4, 0xac620010, 0xaf860120, 0x92e24e20, +0x14400037, 0x24100001, 0x8ee24e30, 0x210c0, +0x24425038, 0x2e22021, 0x8c830000, 0x24020012, +0x1462001f, 0x0, 0x8ee34e30, 0x8ee24e34, +0x1062001b, 0x24030040, 0x8c820004, 0x24420001, +0xac820004, 0x8ee24e34, 0x8ee54e30, 0x24420001, +0x10430007, 0x0, 0x8ee24e34, 0x24420001, +0x10a20005, 0x0, 0x8001697, 0x0, +0x14a00005, 0x0, 0x8f820128, 0x24420020, +0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011, +0x50400013, 0xac800000, 0x80016ad, 0x0, +0x8ee24e30, 0x24030040, 0x24420001, 0x50430003, +0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30, +0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, +0x24020012, 0xac820000, 0x24020001, 0xac820004, +0x5600000b, 0x24100001, 0x8ee2724c, 0x3c040001, +0x24844a68, 0xafa00014, 0xafa20010, 0x8ee6724c, +0x8f470280, 0x3c050009, 0xc002407, 0x34a5f008, +0x56000001, 0xaee00e1c, 0x8ee20174, 0x24420001, +0xaee20174, 0x8ee20174, 0x8ee24e24, 0x10400019, +0x0, 0xaee04e24, 0x8f820040, 0x30420001, +0x14400008, 0x0, 0x8f430104, 0x24020001, +0x10620004, 0x0, 0x8f420264, 0x10400006, +0x0, 0x8ee2017c, 0x24420001, 0xaee2017c, +0x80016da, 0x8ee2017c, 0x8f820044, 0x34420004, +0xaf820044, 0x8ee20178, 0x24420001, 0xaee20178, +0x8ee20178, 0x8ee27278, 0x2442ff99, 0xaee27278, +0x8ee27278, 0x1c4002ad, 0x0, 0x8f420238, +0x104002aa, 0x0, 0x3c020001, 0x571021, +0x904283e0, 0x144002a5, 0x0, 0x8f420080, +0xaee2004c, 0x8f4200c0, 0xaee20048, 0x8f420084, +0xaee20038, 0x8f420084, 0xaee20244, 0x8f420088, +0xaee20248, 0x8f42008c, 0xaee2024c, 0x8f420090, +0xaee20250, 0x8f420094, 0xaee20254, 0x8f420098, +0xaee20258, 0x8f42009c, 0xaee2025c, 0x8f4200a0, +0xaee20260, 0x8f4200a4, 0xaee20264, 0x8f4200a8, +0xaee20268, 0x8f4200ac, 0xaee2026c, 0x8f4200b0, +0xaee20270, 0x8f4200b4, 0xaee20274, 0x8f4200b8, +0xaee20278, 0x8f4200bc, 0x24040001, 0xaee2027c, +0xaee0003c, 0x41080, 0x571021, 0x8ee3003c, +0x8c420244, 0x24840001, 0x621821, 0x2c82000f, +0xaee3003c, 0x1440fff8, 0x41080, 0x8f4200cc, +0xaee20050, 0x8f4200d0, 0xaee20054, 0x8f830120, +0x27623800, 0x24660020, 0xc2102b, 0x50400001, +0x27663000, 0x8f820128, 0x10c20004, 0x0, +0x8f820124, 0x14c20007, 0x0, 0x8ee201a4, +0x8021, 0x24420001, 0xaee201a4, 0x8001775, +0x8ee201a4, 0x8f440208, 0x8f45020c, 0x26e20030, +0xac620008, 0x24020400, 0xa462000e, 0x2402000f, +0xac620018, 0xac60001c, 0xac640000, 0xac650004, +0x8ee204c4, 0xac620010, 0xaf860120, 0x92e24e20, +0x14400037, 0x24100001, 0x8ee24e30, 0x210c0, +0x24425038, 0x2e22021, 0x8c830000, 0x24020007, +0x1462001f, 0x0, 0x8ee34e30, 0x8ee24e34, +0x1062001b, 0x24030040, 0x8c820004, 0x24420001, +0xac820004, 0x8ee24e34, 0x8ee54e30, 0x24420001, +0x10430007, 0x0, 0x8ee24e34, 0x24420001, +0x10a20005, 0x0, 0x800175f, 0x0, +0x14a00005, 0x0, 0x8f820128, 0x24420020, +0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011, +0x50400013, 0xac800000, 0x8001775, 0x0, +0x8ee24e30, 0x24030040, 0x24420001, 0x50430003, +0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30, +0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, +0x24020007, 0xac820000, 0x24020001, 0xac820004, +0x12000212, 0x3c020400, 0xafa20018, 0x3c020001, +0x571021, 0x904283b0, 0x1040010b, 0x0, +0x8ee20608, 0x8f430228, 0x24420001, 0x304a00ff, +0x514300fd, 0xafa00010, 0x8ee20608, 0x210c0, +0x571021, 0x8fa30018, 0x8fa4001c, 0xac43060c, +0xac440610, 0x8f830054, 0x8f820054, 0x24690032, +0x1221023, 0x2c420033, 0x1040006a, 0x5821, +0x24180008, 0x240f000d, 0x240d0007, 0x240c0040, +0x240e0001, 0x8f870120, 0x27623800, 0x24e80020, +0x102102b, 0x50400001, 0x27683000, 0x8f820128, +0x11020004, 0x0, 0x8f820124, 0x15020007, +0x1021, 0x8ee201a4, 0x8021, 0x24420001, +0xaee201a4, 0x80017f3, 0x8ee201a4, 0x8ee40608, +0x420c0, 0x801821, 0x8ee40430, 0x8ee50434, +0xa32821, 0xa3302b, 0x822021, 0x862021, +0xace40000, 0xace50004, 0x8ee20608, 0xa4f8000e, +0xacef0018, 0xacea001c, 0x210c0, 0x2442060c, +0x2e21021, 0xace20008, 0x8ee204c4, 0xace20010, +0xaf880120, 0x92e24e20, 0x14400033, 0x24100001, +0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, +0x8c820000, 0x144d001f, 0x0, 0x8ee34e30, +0x8ee24e34, 0x1062001b, 0x0, 0x8c820004, +0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30, +0x24420001, 0x104c0007, 0x0, 0x8ee24e34, +0x24420001, 0x10620005, 0x0, 0x80017e0, +0x0, 0x14600005, 0x0, 0x8f820128, +0x24420020, 0xaf820128, 0x8f820128, 0x8c820004, +0x2c420011, 0x50400010, 0xac800000, 0x80017f3, +0x0, 0x8ee24e30, 0x24420001, 0x504c0003, +0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30, +0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, +0xac8d0000, 0xac8e0004, 0x56000006, 0x240b0001, +0x8f820054, 0x1221023, 0x2c420033, 0x1440ff9d, +0x0, 0x316300ff, 0x24020001, 0x14620077, +0x3c050009, 0xaeea0608, 0x8f830054, 0x8f820054, +0x24690032, 0x1221023, 0x2c420033, 0x10400061, +0x5821, 0x240d0008, 0x240c0011, 0x24080012, +0x24070040, 0x240a0001, 0x8f830120, 0x27623800, +0x24660020, 0xc2102b, 0x50400001, 0x27663000, +0x8f820128, 0x10c20004, 0x0, 0x8f820124, +0x14c20007, 0x0, 0x8ee201a4, 0x8021, +0x24420001, 0xaee201a4, 0x800185f, 0x8ee201a4, +0x8ee20608, 0xac62001c, 0x8ee404a0, 0x8ee504a4, +0x2462001c, 0xac620008, 0xa46d000e, 0xac6c0018, +0xac640000, 0xac650004, 0x8ee204c4, 0xac620010, +0xaf860120, 0x92e24e20, 0x14400033, 0x24100001, +0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, +0x8c820000, 0x1448001f, 0x0, 0x8ee34e30, +0x8ee24e34, 0x1062001b, 0x0, 0x8c820004, +0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30, +0x24420001, 0x10470007, 0x0, 0x8ee24e34, +0x24420001, 0x10620005, 0x0, 0x800184c, +0x0, 0x14600005, 0x0, 0x8f820128, +0x24420020, 0xaf820128, 0x8f820128, 0x8c820004, +0x2c420011, 0x50400010, 0xac800000, 0x800185f, +0x0, 0x8ee24e30, 0x24420001, 0x50470003, +0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30, +0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, +0xac880000, 0xac8a0004, 0x56000006, 0x240b0001, +0x8f820054, 0x1221023, 0x2c420033, 0x1440ffa6, +0x0, 0x316300ff, 0x24020001, 0x14620003, +0x3c050009, 0x800197c, 0x24100001, 0x3c040001, +0x24844a74, 0xafa00010, 0xafa00014, 0x8f860120, +0x8f870124, 0x800187b, 0x34a5f011, 0x3c040001, +0x24844a80, 0xafa00010, 0xafa00014, 0x8f860120, +0x8f870124, 0x34a5f010, 0xc002407, 0x8021, +0x800197c, 0x0, 0x3c040001, 0x24844a8c, +0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009, +0x8001975, 0x34a5f00f, 0x8ee20608, 0x8f430228, +0x24420001, 0x304900ff, 0x512300e2, 0xafa00010, +0x8ee20608, 0x210c0, 0x571021, 0x8fa30018, +0x8fa4001c, 0xac43060c, 0xac440610, 0x8f870120, +0x27623800, 0x24e80020, 0x102102b, 0x50400001, +0x27683000, 0x8f820128, 0x11020004, 0x0, +0x8f820124, 0x15020007, 0x1021, 0x8ee201a4, +0x8021, 0x24420001, 0xaee201a4, 0x80018f7, +0x8ee201a4, 0x8ee40608, 0x420c0, 0x801821, +0x8ee40430, 0x8ee50434, 0xa32821, 0xa3302b, +0x822021, 0x862021, 0xace40000, 0xace50004, +0x8ee30608, 0x24020008, 0xa4e2000e, 0x2402000d, +0xace20018, 0xace9001c, 0x318c0, 0x2463060c, +0x2e31021, 0xace20008, 0x8ee204c4, 0xace20010, +0xaf880120, 0x92e24e20, 0x14400037, 0x24100001, +0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, +0x8c830000, 0x24020007, 0x1462001f, 0x0, +0x8ee34e30, 0x8ee24e34, 0x1062001b, 0x24030040, +0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34, +0x8ee54e30, 0x24420001, 0x10430007, 0x0, +0x8ee24e34, 0x24420001, 0x10a20005, 0x0, +0x80018e1, 0x0, 0x14a00005, 0x0, +0x8f820128, 0x24420020, 0xaf820128, 0x8f820128, +0x8c820004, 0x2c420011, 0x50400013, 0xac800000, +0x80018f7, 0x0, 0x8ee24e30, 0x24030040, +0x24420001, 0x50430003, 0x1021, 0x8ee24e30, +0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, +0x24425038, 0x2e22021, 0x24020007, 0xac820000, +0x24020001, 0xac820004, 0x5600000c, 0xaee90608, +0x3c040001, 0x24844a98, 0xafa00010, 0xafa00014, +0x8ee60608, 0x8f470228, 0x3c050009, 0xc002407, +0x34a5f000, 0x800197c, 0x0, 0x8f830120, +0x27623800, 0x24660020, 0xc2102b, 0x50400001, +0x27663000, 0x8f820128, 0x10c20004, 0x0, +0x8f820124, 0x14c20007, 0x0, 0x8ee201a4, +0x8021, 0x24420001, 0xaee201a4, 0x800195e, +0x8ee201a4, 0x8ee20608, 0xac62001c, 0x8ee404a0, +0x8ee504a4, 0x2462001c, 0xac620008, 0x24020008, +0xa462000e, 0x24020011, 0xac620018, 0xac640000, +0xac650004, 0x8ee204c4, 0xac620010, 0xaf860120, +0x92e24e20, 0x14400037, 0x24100001, 0x8ee24e30, +0x210c0, 0x24425038, 0x2e22021, 0x8c830000, +0x24020012, 0x1462001f, 0x0, 0x8ee34e30, +0x8ee24e34, 0x1062001b, 0x24030040, 0x8c820004, +0x24420001, 0xac820004, 0x8ee24e34, 0x8ee54e30, +0x24420001, 0x10430007, 0x0, 0x8ee24e34, +0x24420001, 0x10a20005, 0x0, 0x8001948, +0x0, 0x14a00005, 0x0, 0x8f820128, +0x24420020, 0xaf820128, 0x8f820128, 0x8c820004, +0x2c420011, 0x50400013, 0xac800000, 0x800195e, +0x0, 0x8ee24e30, 0x24030040, 0x24420001, +0x50430003, 0x1021, 0x8ee24e30, 0x24420001, +0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, +0x2e22021, 0x24020012, 0xac820000, 0x24020001, +0xac820004, 0x5600001d, 0x24100001, 0x3c040001, +0x24844aa0, 0xafa00010, 0xafa00014, 0x8ee60608, +0x8f470228, 0x3c050009, 0xc002407, 0x34a5f001, +0x8ee201b0, 0x24420001, 0xaee201b0, 0x800197c, +0x8ee201b0, 0x3c040001, 0x24844aac, 0xafa00014, +0x8ee60608, 0x8f470228, 0x3c050009, 0x34a5f005, +0xc002407, 0x0, 0x8ee201ac, 0x8021, +0x24420001, 0xaee201ac, 0x8ee201ac, 0x1200000c, +0x24020001, 0x3c010001, 0x370821, 0xa02083b0, +0x8f420238, 0x8ee30158, 0x24630001, 0xaee30158, +0x8ee30158, 0x800198c, 0xaee27278, 0x24020001, +0x3c010001, 0x370821, 0xa02283b0, 0x3c020001, +0x8c425488, 0x10400187, 0x0, 0x8ee27b84, +0x24430001, 0x284200c9, 0x144001a4, 0xaee37b84, +0x8ee204d4, 0x30420002, 0x14400119, 0xaee07b84, +0x8ee204d4, 0x3c030600, 0x34631000, 0x34420002, +0xaee204d4, 0xafa30018, 0x8ee20608, 0x8f430228, +0x24420001, 0x304a00ff, 0x514300fd, 0xafa00010, +0x8ee20608, 0x210c0, 0x571021, 0x8fa30018, +0x8fa4001c, 0xac43060c, 0xac440610, 0x8f830054, +0x8f820054, 0x24690032, 0x1221023, 0x2c420033, +0x1040006a, 0x5821, 0x24180008, 0x240f000d, +0x240d0007, 0x240c0040, 0x240e0001, 0x8f870120, +0x27623800, 0x24e80020, 0x102102b, 0x50400001, +0x27683000, 0x8f820128, 0x11020004, 0x0, +0x8f820124, 0x15020007, 0x1021, 0x8ee201a4, +0x8021, 0x24420001, 0xaee201a4, 0x8001a15, +0x8ee201a4, 0x8ee40608, 0x420c0, 0x801821, +0x8ee40430, 0x8ee50434, 0xa32821, 0xa3302b, +0x822021, 0x862021, 0xace40000, 0xace50004, +0x8ee20608, 0xa4f8000e, 0xacef0018, 0xacea001c, +0x210c0, 0x2442060c, 0x2e21021, 0xace20008, +0x8ee204c4, 0xace20010, 0xaf880120, 0x92e24e20, +0x14400033, 0x24100001, 0x8ee24e30, 0x210c0, +0x24425038, 0x2e22021, 0x8c820000, 0x144d001f, +0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b, +0x0, 0x8c820004, 0x24420001, 0xac820004, +0x8ee24e34, 0x8ee34e30, 0x24420001, 0x104c0007, +0x0, 0x8ee24e34, 0x24420001, 0x10620005, +0x0, 0x8001a02, 0x0, 0x14600005, +0x0, 0x8f820128, 0x24420020, 0xaf820128, +0x8f820128, 0x8c820004, 0x2c420011, 0x50400010, +0xac800000, 0x8001a15, 0x0, 0x8ee24e30, +0x24420001, 0x504c0003, 0x1021, 0x8ee24e30, +0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, +0x24425038, 0x2e22021, 0xac8d0000, 0xac8e0004, +0x56000006, 0x240b0001, 0x8f820054, 0x1221023, +0x2c420033, 0x1440ff9d, 0x0, 0x316300ff, +0x24020001, 0x54620078, 0xafa00010, 0xaeea0608, +0x8f830054, 0x8f820054, 0x24690032, 0x1221023, +0x2c420033, 0x10400061, 0x5821, 0x240d0008, +0x240c0011, 0x24080012, 0x24070040, 0x240a0001, +0x8f830120, 0x27623800, 0x24660020, 0xc2102b, +0x50400001, 0x27663000, 0x8f820128, 0x10c20004, +0x0, 0x8f820124, 0x14c20007, 0x0, +0x8ee201a4, 0x8021, 0x24420001, 0xaee201a4, +0x8001a81, 0x8ee201a4, 0x8ee20608, 0xac62001c, +0x8ee404a0, 0x8ee504a4, 0x2462001c, 0xac620008, +0xa46d000e, 0xac6c0018, 0xac640000, 0xac650004, +0x8ee204c4, 0xac620010, 0xaf860120, 0x92e24e20, +0x14400033, 0x24100001, 0x8ee24e30, 0x210c0, +0x24425038, 0x2e22021, 0x8c820000, 0x1448001f, +0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b, +0x0, 0x8c820004, 0x24420001, 0xac820004, +0x8ee24e34, 0x8ee34e30, 0x24420001, 0x10470007, +0x0, 0x8ee24e34, 0x24420001, 0x10620005, +0x0, 0x8001a6e, 0x0, 0x14600005, +0x0, 0x8f820128, 0x24420020, 0xaf820128, +0x8f820128, 0x8c820004, 0x2c420011, 0x50400010, +0xac800000, 0x8001a81, 0x0, 0x8ee24e30, +0x24420001, 0x50470003, 0x1021, 0x8ee24e30, +0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, +0x24425038, 0x2e22021, 0xac880000, 0xac8a0004, +0x56000006, 0x240b0001, 0x8f820054, 0x1221023, +0x2c420033, 0x1440ffa6, 0x0, 0x316300ff, +0x24020001, 0x10620022, 0x0, 0x3c040001, +0x24844a74, 0xafa00010, 0xafa00014, 0x8f860120, +0x8f870124, 0x3c050009, 0xc002407, 0x34a5f011, +0x8001aad, 0x0, 0x3c040001, 0x24844a80, +0xafa00014, 0x8f860120, 0x8f870124, 0x3c050009, +0xc002407, 0x34a5f010, 0x8001aad, 0x0, +0x3c040001, 0x24844a8c, 0xafa00014, 0x8ee60608, +0x8f470228, 0x3c050009, 0xc002407, 0x34a5f00f, +0x8ee201ac, 0x24420001, 0xaee201ac, 0x8ee201ac, +0x8ee2015c, 0x24420001, 0xaee2015c, 0x8ee2015c, +0x8ee204d4, 0x30420001, 0x10400055, 0x0, +0x8f420218, 0x30420080, 0x10400029, 0x0, +0x8f820044, 0x34420040, 0xaf820044, 0x8ee27b7c, +0x402821, 0x8ee200c0, 0x8ee300c4, 0x24060000, +0x2407ffff, 0x2021, 0x461024, 0x1444000d, +0x671824, 0x1465000b, 0x0, 0x8ee27b80, +0x402821, 0x8ee200e0, 0x8ee300e4, 0x2021, +0x461024, 0x14440003, 0x671824, 0x1065000b, +0x0, 0x8ee200c0, 0x8ee300c4, 0x8ee400e0, +0x8ee500e4, 0xaee37b7c, 0xaee57b80, 0x8f820044, +0x38420020, 0x8001b38, 0xaf820044, 0x8f820044, +0x2403ffdf, 0x431024, 0x8001b38, 0xaf820044, +0x8f820044, 0x2403ffdf, 0x431024, 0xaf820044, +0x8ee27b7c, 0x402821, 0x8ee200c0, 0x8ee300c4, +0x24060000, 0x2407ffff, 0x2021, 0x461024, +0x1444000d, 0x671824, 0x1465000b, 0x0, +0x8ee27b80, 0x402821, 0x8ee200e0, 0x8ee300e4, +0x2021, 0x461024, 0x14440003, 0x671824, +0x1065000b, 0x0, 0x8ee200c0, 0x8ee300c4, +0x8ee400e0, 0x8ee500e4, 0xaee37b7c, 0xaee57b80, +0x8f820044, 0x38420040, 0x8001b38, 0xaf820044, +0x8f820044, 0x34420040, 0x8001b38, 0xaf820044, +0x8f820044, 0x34420040, 0xaf820044, 0x8ee27b8c, +0x24430001, 0x28420015, 0x14400028, 0xaee37b8c, +0x8f820044, 0x38420020, 0xaf820044, 0x8001b38, +0xaee07b8c, 0x8ee204d4, 0x30420001, 0x10400011, +0x0, 0x8f420218, 0x30420080, 0x10400009, +0x0, 0x8f820044, 0x34420020, 0xaf820044, +0x8f820044, 0x2403ffbf, 0x431024, 0x8001b36, +0xaf820044, 0x8f820044, 0x34420060, 0x8001b36, +0xaf820044, 0x8f820044, 0x34420040, 0xaf820044, +0x8ee27b88, 0x24430001, 0x28421389, 0x14400005, +0xaee37b88, 0x8f820044, 0x38420020, 0xaf820044, +0xaee07b88, 0xc0045c1, 0x0, 0x8fbf0024, +0x8fb00020, 0x3e00008, 0x27bd0028, 0x27bdffb8, +0xafbf0044, 0xafb60040, 0xafb5003c, 0xafb40038, +0xafb30034, 0xafb20030, 0xafb1002c, 0xafb00028, +0x8f960064, 0x32c20004, 0x1040000c, 0x24020004, +0xaf820064, 0x8f420114, 0xaee204e0, 0x8f820060, +0x34420008, 0xaf820060, 0x8ee2016c, 0x24420001, +0xaee2016c, 0x80022f4, 0x8ee2016c, 0x32c20001, +0x10400004, 0x24020001, 0xaf820064, 0x80022f4, +0x0, 0x32c20002, 0x1440000c, 0x3c050003, +0x3c040001, 0x24844b24, 0x34a50001, 0x2c03021, +0x3821, 0xafa00010, 0xc002407, 0xafa00014, +0x2402fff8, 0x80022f4, 0xaf820064, 0x8f43022c, +0x8f42010c, 0x5062000c, 0xafa00010, 0x8f42022c, +0x21080, 0x5a1021, 0x8c420300, 0xafa20020, +0x8f42022c, 0x24070001, 0x24420001, 0x3042003f, +0x8001b80, 0xaf42022c, 0x3c040001, 0x24844b30, +0xafa00014, 0x8f46022c, 0x8f47010c, 0x3c050003, +0xc002407, 0x34a5f01f, 0x3821, 0x14e00003, +0x0, 0x80022ed, 0xaf960064, 0x93a20020, +0x2443ffff, 0x2c620011, 0x10400658, 0x31080, +0x3c010001, 0x220821, 0x8c224be8, 0x400008, +0x0, 0x8fa20020, 0x30420fff, 0xaee20e0c, +0x8f820060, 0x34420200, 0xaf820060, 0x8ee20118, +0x24420001, 0xaee20118, 0x80022e8, 0x8ee20118, +0x8fa20020, 0x24030001, 0x3c010001, 0x370821, +0xa02383b1, 0x30420fff, 0xaee25238, 0x8f820060, +0x34420100, 0xaf820060, 0x8ee20144, 0x24420001, +0xaee20144, 0x80022e8, 0x8ee20144, 0x8fa20020, +0x21200, 0x22502, 0x24020001, 0x10820005, +0x24020002, 0x10820009, 0x2402fffe, 0x8001bc9, +0xafa00010, 0x8ee204d4, 0xaee40070, 0xaee40074, +0x34420001, 0x8001bbd, 0xaee204d4, 0x8ee304d4, +0xaee40070, 0xaee40074, 0x621824, 0xaee304d4, +0x8f840054, 0x41442, 0x41c82, 0x431021, +0x41cc2, 0x431023, 0x41d02, 0x431021, +0x41d42, 0x431023, 0x8001bd0, 0xaee20078, +0x3c040001, 0x24844b3c, 0xafa00014, 0x8fa60020, +0x3c050003, 0xc002407, 0x34a50004, 0x8ee20110, +0x24420001, 0xaee20110, 0x80022e8, 0x8ee20110, +0x27440212, 0xc0022fe, 0x24050006, 0x3049001f, +0x920c0, 0x2e41021, 0x9442727c, 0x30424000, +0x1040000a, 0x971021, 0x97430212, 0xa443727e, +0x8f430214, 0x971021, 0xac437280, 0x2e41821, +0x34028000, 0x8001c79, 0xa462727c, 0x9443727e, +0x97420212, 0x14620006, 0x2e41021, 0x971021, +0x8c437280, 0x8f420214, 0x1062009f, 0x2e41021, +0x9442727c, 0x30428000, 0x1040002a, 0x2406ffff, +0x2021, 0x410c0, 0x2e21021, 0x9442737c, +0x30424000, 0x54400005, 0x803021, 0x24840001, +0x2c820080, 0x1440fff8, 0x410c0, 0x4c10010, +0x618c0, 0x610c0, 0x571821, 0x8c63737c, +0x571021, 0xafa30010, 0x8c427380, 0x3c040001, +0x24844b48, 0xafa20014, 0x8f470214, 0x3c050003, +0xc002407, 0x34a50013, 0x8001c90, 0x3c020800, +0x97440212, 0x771021, 0xa444737e, 0x8f440214, +0x771021, 0x2e31821, 0xac447380, 0x34028000, +0xa462737c, 0x910c0, 0x2e21021, 0x8001c79, +0xa446727c, 0x2e41021, 0x9445727c, 0x8001c2e, +0x510c0, 0x9443737e, 0x97420212, 0x14620006, +0x510c0, 0x971021, 0x8c437380, 0x8f420214, +0x10620065, 0x510c0, 0x2e21021, 0x9445737c, +0x510c0, 0x2e21021, 0x9442737c, 0x30428000, +0x1040fff0, 0x971021, 0x520c0, 0x971021, +0x9443737e, 0x97420212, 0x14620006, 0x2406ffff, +0x971021, 0x8c437380, 0x8f420214, 0x10620053, +0x3c020800, 0x2021, 0x410c0, 0x2e21021, +0x9442737c, 0x30424000, 0x54400005, 0x803021, +0x24840001, 0x2c820080, 0x1440fff8, 0x410c0, +0x4c10023, 0x618c0, 0x910c0, 0x571821, +0x8c63727c, 0x571021, 0xafa30010, 0x8c427280, +0x3c040001, 0x24844b54, 0xafa20014, 0x8f470214, +0x3c050003, 0xc002407, 0x34a5f017, 0x8001c90, +0x3c020800, 0x8f430210, 0xb71021, 0xac43777c, +0x8f430214, 0xb71021, 0xac437780, 0x3c020001, +0x571021, 0x8c4283b4, 0x24420001, 0x3c010001, +0x370821, 0xac2283b4, 0x3c030001, 0x771821, +0x8c6383b4, 0x2e51021, 0x8001c82, 0xa443777c, +0x97440212, 0x771021, 0xa444737e, 0x8f440214, +0x771021, 0x2e31821, 0xac447380, 0x34028000, +0xa462737c, 0x510c0, 0x2e21021, 0xa446737c, +0x2021, 0x428c0, 0x2e51021, 0x9442777c, +0x1040ffdc, 0x24840001, 0x2c820080, 0x5440fffa, +0x428c0, 0x92e204d8, 0x10400006, 0x24020001, +0x8ee304dc, 0x1221004, 0x621825, 0x8001c8f, +0xaee304dc, 0x8f830228, 0x24020001, 0x1221004, +0x621825, 0xaf830228, 0x3c020800, 0x34421000, +0xafa20018, 0x8ee20608, 0x8f430228, 0x24420001, +0x304a00ff, 0x514300fd, 0xafa00010, 0x8ee20608, +0x210c0, 0x571021, 0x8fa30018, 0x8fa4001c, +0xac43060c, 0xac440610, 0x8f830054, 0x8f820054, +0x24690032, 0x1221023, 0x2c420033, 0x1040006a, +0x5821, 0x24100008, 0x240f000d, 0x240d0007, +0x240c0040, 0x240e0001, 0x8f870120, 0x27623800, +0x24e80020, 0x102102b, 0x50400001, 0x27683000, +0x8f820128, 0x11020004, 0x0, 0x8f820124, +0x15020007, 0x1021, 0x8ee201a4, 0x3821, +0x24420001, 0xaee201a4, 0x8001d08, 0x8ee201a4, +0x8ee40608, 0x420c0, 0x801821, 0x8ee40430, +0x8ee50434, 0xa32821, 0xa3302b, 0x822021, +0x862021, 0xace40000, 0xace50004, 0x8ee20608, +0xa4f0000e, 0xacef0018, 0xacea001c, 0x210c0, +0x2442060c, 0x2e21021, 0xace20008, 0x8ee204c4, +0xace20010, 0xaf880120, 0x92e24e20, 0x14400033, +0x24070001, 0x8ee24e30, 0x210c0, 0x24425038, +0x2e22021, 0x8c820000, 0x144d001f, 0x0, +0x8ee34e30, 0x8ee24e34, 0x1062001b, 0x0, +0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34, +0x8ee34e30, 0x24420001, 0x104c0007, 0x0, +0x8ee24e34, 0x24420001, 0x10620005, 0x0, +0x8001cf5, 0x0, 0x14600005, 0x0, +0x8f820128, 0x24420020, 0xaf820128, 0x8f820128, +0x8c820004, 0x2c420011, 0x50400010, 0xac800000, +0x8001d08, 0x0, 0x8ee24e30, 0x24420001, +0x504c0003, 0x1021, 0x8ee24e30, 0x24420001, +0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, +0x2e22021, 0xac8d0000, 0xac8e0004, 0x54e00006, +0x240b0001, 0x8f820054, 0x1221023, 0x2c420033, +0x1440ff9d, 0x0, 0x316300ff, 0x24020001, +0x54620078, 0xafa00010, 0xaeea0608, 0x8f830054, +0x8f820054, 0x24690032, 0x1221023, 0x2c420033, +0x10400061, 0x5821, 0x240e0008, 0x240d0011, +0x240a0012, 0x24080040, 0x240c0001, 0x8f830120, +0x27623800, 0x24660020, 0xc2102b, 0x50400001, +0x27663000, 0x8f820128, 0x10c20004, 0x0, +0x8f820124, 0x14c20007, 0x0, 0x8ee201a4, +0x3821, 0x24420001, 0xaee201a4, 0x8001d74, +0x8ee201a4, 0x8ee20608, 0xac62001c, 0x8ee404a0, +0x8ee504a4, 0x2462001c, 0xac620008, 0xa46e000e, +0xac6d0018, 0xac640000, 0xac650004, 0x8ee204c4, +0xac620010, 0xaf860120, 0x92e24e20, 0x14400033, +0x24070001, 0x8ee24e30, 0x210c0, 0x24425038, +0x2e22021, 0x8c820000, 0x144a001f, 0x0, +0x8ee34e30, 0x8ee24e34, 0x1062001b, 0x0, +0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34, +0x8ee34e30, 0x24420001, 0x10480007, 0x0, +0x8ee24e34, 0x24420001, 0x10620005, 0x0, +0x8001d61, 0x0, 0x14600005, 0x0, +0x8f820128, 0x24420020, 0xaf820128, 0x8f820128, +0x8c820004, 0x2c420011, 0x50400010, 0xac800000, +0x8001d74, 0x0, 0x8ee24e30, 0x24420001, +0x50480003, 0x1021, 0x8ee24e30, 0x24420001, +0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, +0x2e22021, 0xac8a0000, 0xac8c0004, 0x54e00006, +0x240b0001, 0x8f820054, 0x1221023, 0x2c420033, +0x1440ffa6, 0x0, 0x316300ff, 0x24020001, +0x10620022, 0x0, 0x3c040001, 0x24844b60, +0xafa00010, 0xafa00014, 0x8f860120, 0x8f870124, +0x3c050009, 0xc002407, 0x34a5f011, 0x8001da0, +0x0, 0x3c040001, 0x24844b6c, 0xafa00014, +0x8f860120, 0x8f870124, 0x3c050009, 0xc002407, +0x34a5f010, 0x8001da0, 0x0, 0x3c040001, +0x24844b78, 0xafa00014, 0x8ee60608, 0x8f470228, +0x3c050009, 0xc002407, 0x34a5f00f, 0x8ee201ac, +0x24420001, 0xaee201ac, 0x8ee201ac, 0x8ee20124, +0x24420001, 0xaee20124, 0x8001f97, 0x8ee20124, +0x27440212, 0xc0022fe, 0x24050006, 0x3049001f, +0x928c0, 0x2e51021, 0x9442727c, 0x30428000, +0x1040002f, 0x2e51021, 0x9442727c, 0x30424000, +0x1440001c, 0xb71021, 0x9443727e, 0x97420212, +0x14620018, 0xb71021, 0x8c437280, 0x8f420214, +0x54620016, 0xafa20010, 0x92e204d8, 0x10400007, +0x24020001, 0x8ee304dc, 0x1221004, 0x21027, +0x621824, 0x8001dc9, 0xaee304dc, 0x8f830228, +0x1221004, 0x21027, 0x621824, 0xaf830228, +0x910c0, 0x2e21821, 0x3402c000, 0x8001e4e, +0xa462727c, 0x8f420214, 0xafa20010, 0x910c0, +0x571021, 0x8c42727c, 0x3c040001, 0x24844b84, +0x3c050003, 0xafa20014, 0x8f470210, 0x34a5f01c, +0xc002407, 0x1203021, 0x8001e83, 0x3c020800, +0xb71021, 0x9443727e, 0x97420212, 0x14620019, +0x918c0, 0xb71021, 0x8c437280, 0x8f420214, +0x14620014, 0x918c0, 0x2e51021, 0x9447727c, +0x720c0, 0x971021, 0x9443737e, 0xb71021, +0xa443727e, 0x971021, 0x8c437380, 0xb71021, +0xac437280, 0x2e41021, 0x9443737c, 0x2e51021, +0xa443727c, 0x2e41821, 0x3402c000, 0x8001e4e, +0xa462737c, 0x2e31021, 0x9447727c, 0x3021, +0x720c0, 0x2e41021, 0x9442737c, 0x4021, +0x30428000, 0x14400025, 0xe02821, 0x605021, +0x340bc000, 0x971021, 0x9443737e, 0x97420212, +0x54620015, 0xe02821, 0x971021, 0x8c437380, +0x8f420214, 0x54620010, 0xe02821, 0x11000006, +0x2e41021, 0x9443737c, 0x510c0, 0x2e21021, +0x8001e1a, 0xa443737c, 0x9443737c, 0x2ea1021, +0xa443727c, 0x710c0, 0x2e21021, 0xa44b737c, +0x8001e28, 0x24060001, 0x510c0, 0x2e21021, +0x9447737c, 0x720c0, 0x2e41021, 0x9442737c, +0x30428000, 0x1040ffdf, 0x25080001, 0x30c200ff, +0x14400025, 0x2021, 0x720c0, 0x971021, +0x9443737e, 0x97420212, 0x1462000f, 0x910c0, +0x971021, 0x8c437380, 0x8f420214, 0x1462000a, +0x910c0, 0x2e41821, 0x3402c000, 0x15000015, +0xa462737c, 0x910c0, 0x2e21821, 0x34028000, +0x8001e4e, 0xa462727c, 0x571021, 0x8c42727c, +0x3c040001, 0x24844b90, 0x3c050003, 0xafa20010, +0x710c0, 0x571021, 0x8c42737c, 0x34a5001e, +0x1203021, 0xc002407, 0xafa20014, 0x8001e83, +0x3c020800, 0x2021, 0x428c0, 0xb71021, +0x9443777e, 0x97420212, 0x5462002b, 0x24840001, +0xb71021, 0x8c437780, 0x8f420214, 0x54620026, +0x24840001, 0x3c020001, 0x571021, 0x8c4283b4, +0x2442ffff, 0x3c010001, 0x370821, 0xac2283b4, +0x3c020001, 0x571021, 0x8c4283b4, 0x809021, +0x242102b, 0x1040000e, 0x24b1777c, 0x24b07784, +0x2f02021, 0x2f12821, 0xc002494, 0x24060008, +0x26310008, 0x3c020001, 0x571021, 0x8c4283b4, +0x26520001, 0x242102b, 0x1440fff5, 0x26100008, +0x3c040001, 0x972021, 0x8c8483b4, 0x24050008, +0x420c0, 0x2484777c, 0xc00248c, 0x2e42021, +0x8001e83, 0x3c020800, 0x2c820080, 0x1440ffcf, +0x428c0, 0x3c020800, 0x34422000, 0xafa20018, +0x8ee20608, 0x8f430228, 0x24420001, 0x304a00ff, +0x514300fd, 0xafa00010, 0x8ee20608, 0x210c0, +0x571021, 0x8fa30018, 0x8fa4001c, 0xac43060c, +0xac440610, 0x8f830054, 0x8f820054, 0x24690032, +0x1221023, 0x2c420033, 0x1040006a, 0x5821, +0x24100008, 0x240f000d, 0x240d0007, 0x240c0040, +0x240e0001, 0x8f870120, 0x27623800, 0x24e80020, +0x102102b, 0x50400001, 0x27683000, 0x8f820128, +0x11020004, 0x0, 0x8f820124, 0x15020007, +0x1021, 0x8ee201a4, 0x3821, 0x24420001, +0xaee201a4, 0x8001efb, 0x8ee201a4, 0x8ee40608, +0x420c0, 0x801821, 0x8ee40430, 0x8ee50434, +0xa32821, 0xa3302b, 0x822021, 0x862021, +0xace40000, 0xace50004, 0x8ee20608, 0xa4f0000e, +0xacef0018, 0xacea001c, 0x210c0, 0x2442060c, +0x2e21021, 0xace20008, 0x8ee204c4, 0xace20010, +0xaf880120, 0x92e24e20, 0x14400033, 0x24070001, +0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, +0x8c820000, 0x144d001f, 0x0, 0x8ee34e30, +0x8ee24e34, 0x1062001b, 0x0, 0x8c820004, +0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30, +0x24420001, 0x104c0007, 0x0, 0x8ee24e34, +0x24420001, 0x10620005, 0x0, 0x8001ee8, +0x0, 0x14600005, 0x0, 0x8f820128, +0x24420020, 0xaf820128, 0x8f820128, 0x8c820004, +0x2c420011, 0x50400010, 0xac800000, 0x8001efb, +0x0, 0x8ee24e30, 0x24420001, 0x504c0003, +0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30, +0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, +0xac8d0000, 0xac8e0004, 0x54e00006, 0x240b0001, +0x8f820054, 0x1221023, 0x2c420033, 0x1440ff9d, +0x0, 0x316300ff, 0x24020001, 0x54620078, +0xafa00010, 0xaeea0608, 0x8f830054, 0x8f820054, +0x24690032, 0x1221023, 0x2c420033, 0x10400061, +0x5821, 0x240e0008, 0x240d0011, 0x240a0012, +0x24080040, 0x240c0001, 0x8f830120, 0x27623800, +0x24660020, 0xc2102b, 0x50400001, 0x27663000, +0x8f820128, 0x10c20004, 0x0, 0x8f820124, +0x14c20007, 0x0, 0x8ee201a4, 0x3821, +0x24420001, 0xaee201a4, 0x8001f67, 0x8ee201a4, +0x8ee20608, 0xac62001c, 0x8ee404a0, 0x8ee504a4, +0x2462001c, 0xac620008, 0xa46e000e, 0xac6d0018, +0xac640000, 0xac650004, 0x8ee204c4, 0xac620010, +0xaf860120, 0x92e24e20, 0x14400033, 0x24070001, +0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, +0x8c820000, 0x144a001f, 0x0, 0x8ee34e30, +0x8ee24e34, 0x1062001b, 0x0, 0x8c820004, +0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30, +0x24420001, 0x10480007, 0x0, 0x8ee24e34, +0x24420001, 0x10620005, 0x0, 0x8001f54, +0x0, 0x14600005, 0x0, 0x8f820128, +0x24420020, 0xaf820128, 0x8f820128, 0x8c820004, +0x2c420011, 0x50400010, 0xac800000, 0x8001f67, +0x0, 0x8ee24e30, 0x24420001, 0x50480003, +0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30, +0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, +0xac8a0000, 0xac8c0004, 0x54e00006, 0x240b0001, +0x8f820054, 0x1221023, 0x2c420033, 0x1440ffa6, +0x0, 0x316300ff, 0x24020001, 0x10620022, +0x0, 0x3c040001, 0x24844b60, 0xafa00010, +0xafa00014, 0x8f860120, 0x8f870124, 0x3c050009, +0xc002407, 0x34a5f011, 0x8001f93, 0x0, +0x3c040001, 0x24844b6c, 0xafa00014, 0x8f860120, +0x8f870124, 0x3c050009, 0xc002407, 0x34a5f010, +0x8001f93, 0x0, 0x3c040001, 0x24844b78, +0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009, +0xc002407, 0x34a5f00f, 0x8ee201ac, 0x24420001, +0xaee201ac, 0x8ee201ac, 0x8ee20128, 0x24420001, +0xaee20128, 0x8ee20128, 0x8ee20164, 0x24420001, +0xaee20164, 0x80022e8, 0x8ee20164, 0x8fa20020, +0x21200, 0x21d02, 0x24020001, 0x10620005, +0x24020002, 0x1062000d, 0x0, 0x8001fb7, +0xafa00010, 0x92e204d8, 0x14400006, 0x24020001, +0x8f820228, 0xaee204dc, 0x2402ffff, 0xaf820228, +0x24020001, 0x8001fbe, 0xa2e204d8, 0x92e204d8, +0x5040000c, 0xa2e004d8, 0x8ee204dc, 0xaf820228, +0x8001fbe, 0xa2e004d8, 0x3c040001, 0x24844b98, +0xafa00014, 0x8fa60020, 0x3c050003, 0xc002407, +0x34a5f009, 0x8ee2013c, 0x24420001, 0xaee2013c, +0x80022e8, 0x8ee2013c, 0x8fa20020, 0x21200, +0x22502, 0x24020001, 0x10820005, 0x24020002, +0x1082000f, 0x0, 0x8001fe3, 0xafa00010, +0x8f820220, 0x3c0308ff, 0x3463ffff, 0x431024, +0x34420008, 0xaf820220, 0x24020001, 0x3c010001, +0x370821, 0xa02283b2, 0x8001fea, 0xaee40108, +0x8f820220, 0x3c0308ff, 0x3463fff7, 0x431024, +0xaf820220, 0x3c010001, 0x370821, 0xa02083b2, +0x8001fea, 0xaee40108, 0x3c040001, 0x24844ba4, +0xafa00014, 0x8fa60020, 0x3c050003, 0xc002407, +0x34a5f00a, 0x8ee2012c, 0x24420001, 0xaee2012c, +0x80022e8, 0x8ee2012c, 0x8fa20020, 0x21200, +0x21d02, 0x24020001, 0x10620005, 0x24020002, +0x1062000e, 0x0, 0x8002011, 0xafa00010, +0x8f820220, 0x3c0308ff, 0x3463ffff, 0x431024, +0x34420008, 0xaf820220, 0x24020001, 0x3c010001, +0x370821, 0x8002018, 0xa02283b3, 0x3c020001, +0x571021, 0x904283b2, 0x3c010001, 0x370821, +0x1440000e, 0xa02083b3, 0x8f820220, 0x3c0308ff, +0x3463fff7, 0x431024, 0x8002018, 0xaf820220, +0x3c040001, 0x24844bb0, 0xafa00014, 0x8fa60020, +0x3c050003, 0xc002407, 0x34a5f00b, 0x8ee20114, +0x24420001, 0xaee20114, 0x80022e8, 0x8ee20114, +0x27840208, 0x27450200, 0xc00249e, 0x24060008, +0x26e40094, 0x27450200, 0xc00249e, 0x24060008, +0x8ee20134, 0x24420001, 0xaee20134, 0x80022e8, +0x8ee20134, 0x8f460248, 0x2021, 0xc004fa4, +0x24050004, 0x8ee20130, 0x24420001, 0xaee20130, +0x80022e8, 0x8ee20130, 0x8ef301cc, 0x8ef401d0, +0x8ef501d8, 0x8ee20140, 0x26e40030, 0x24420001, +0xaee20140, 0x8ef00140, 0x8ef10074, 0x8ef20070, +0xc00248c, 0x24050400, 0xaef301cc, 0xaef401d0, +0xaef501d8, 0xaef00140, 0xaef10074, 0xaef20070, +0x8f42025c, 0x26e40094, 0xaee20060, 0x8f420260, +0x27450200, 0x24060008, 0xaee20068, 0x24020006, +0xc00249e, 0xaee20064, 0x3c023b9a, 0x3442ca00, +0xaee2006c, 0x240203e8, 0x24040002, 0x24030001, +0xaee20104, 0xaee40100, 0xaee3010c, 0x8f820220, +0x30420008, 0x10400004, 0x0, 0xaee30108, +0x8002061, 0x2021, 0xaee40108, 0x2021, +0x3c030001, 0x641821, 0x906353e0, 0x2e41021, +0x24840001, 0xa043009c, 0x2c82000f, 0x1440fff8, +0x0, 0x8f820040, 0x2e41821, 0x24840001, +0x21702, 0x24420030, 0xa062009c, 0x2e41021, +0x80022e8, 0xa040009c, 0x24020001, 0x3c010001, +0x370821, 0xa02283e0, 0x240b0400, 0x24080014, +0x240a0040, 0x24090001, 0x8f830100, 0x27623000, +0x24660020, 0xc2102b, 0x50400001, 0x27662800, +0x8f820108, 0x10c20004, 0x0, 0x8f820104, +0x14c20007, 0x26e20030, 0x8ee201a8, 0x3821, +0x24420001, 0xaee201a8, 0x80020a8, 0x8ee201a8, +0x8ee404b8, 0x8ee504bc, 0xac620008, 0xa46b000e, +0xac680018, 0xac60001c, 0xac640000, 0xac650004, +0x8ee204cc, 0xac620010, 0xaf860100, 0x92e204ec, +0x1440000e, 0x24070001, 0x8ee24e28, 0x24420001, +0x504a0003, 0x1021, 0x8ee24e28, 0x24420001, +0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38, +0x2e21021, 0xac480000, 0xac490004, 0x10e0ffd2, +0x0, 0x80022e8, 0x0, 0x3c020900, +0xaee05238, 0xaee0523c, 0xaee05240, 0xaee05244, +0xaee001d0, 0x3c010001, 0x370821, 0xa02083b1, +0xafa20018, 0x8ee20608, 0x8f430228, 0x24420001, +0x304a00ff, 0x514300fd, 0xafa00010, 0x8ee20608, +0x210c0, 0x571021, 0x8fa30018, 0x8fa4001c, +0xac43060c, 0xac440610, 0x8f830054, 0x8f820054, +0x24690032, 0x1221023, 0x2c420033, 0x1040006a, +0x5821, 0x24100008, 0x240f000d, 0x240d0007, +0x240c0040, 0x240e0001, 0x8f870120, 0x27623800, +0x24e80020, 0x102102b, 0x50400001, 0x27683000, +0x8f820128, 0x11020004, 0x0, 0x8f820124, +0x15020007, 0x1021, 0x8ee201a4, 0x3821, +0x24420001, 0xaee201a4, 0x800212c, 0x8ee201a4, +0x8ee40608, 0x420c0, 0x801821, 0x8ee40430, +0x8ee50434, 0xa32821, 0xa3302b, 0x822021, +0x862021, 0xace40000, 0xace50004, 0x8ee20608, +0xa4f0000e, 0xacef0018, 0xacea001c, 0x210c0, +0x2442060c, 0x2e21021, 0xace20008, 0x8ee204c4, +0xace20010, 0xaf880120, 0x92e24e20, 0x14400033, +0x24070001, 0x8ee24e30, 0x210c0, 0x24425038, +0x2e22021, 0x8c820000, 0x144d001f, 0x0, +0x8ee34e30, 0x8ee24e34, 0x1062001b, 0x0, +0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34, +0x8ee34e30, 0x24420001, 0x104c0007, 0x0, +0x8ee24e34, 0x24420001, 0x10620005, 0x0, +0x8002119, 0x0, 0x14600005, 0x0, +0x8f820128, 0x24420020, 0xaf820128, 0x8f820128, +0x8c820004, 0x2c420011, 0x50400010, 0xac800000, +0x800212c, 0x0, 0x8ee24e30, 0x24420001, +0x504c0003, 0x1021, 0x8ee24e30, 0x24420001, +0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, +0x2e22021, 0xac8d0000, 0xac8e0004, 0x54e00006, +0x240b0001, 0x8f820054, 0x1221023, 0x2c420033, +0x1440ff9d, 0x0, 0x316300ff, 0x24020001, +0x54620078, 0xafa00010, 0xaeea0608, 0x8f830054, +0x8f820054, 0x24690032, 0x1221023, 0x2c420033, +0x10400061, 0x5821, 0x240e0008, 0x240d0011, +0x240a0012, 0x24080040, 0x240c0001, 0x8f830120, +0x27623800, 0x24660020, 0xc2102b, 0x50400001, +0x27663000, 0x8f820128, 0x10c20004, 0x0, +0x8f820124, 0x14c20007, 0x0, 0x8ee201a4, +0x3821, 0x24420001, 0xaee201a4, 0x8002198, +0x8ee201a4, 0x8ee20608, 0xac62001c, 0x8ee404a0, +0x8ee504a4, 0x2462001c, 0xac620008, 0xa46e000e, +0xac6d0018, 0xac640000, 0xac650004, 0x8ee204c4, +0xac620010, 0xaf860120, 0x92e24e20, 0x14400033, +0x24070001, 0x8ee24e30, 0x210c0, 0x24425038, +0x2e22021, 0x8c820000, 0x144a001f, 0x0, +0x8ee34e30, 0x8ee24e34, 0x1062001b, 0x0, +0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34, +0x8ee34e30, 0x24420001, 0x10480007, 0x0, +0x8ee24e34, 0x24420001, 0x10620005, 0x0, +0x8002185, 0x0, 0x14600005, 0x0, +0x8f820128, 0x24420020, 0xaf820128, 0x8f820128, +0x8c820004, 0x2c420011, 0x50400010, 0xac800000, +0x8002198, 0x0, 0x8ee24e30, 0x24420001, +0x50480003, 0x1021, 0x8ee24e30, 0x24420001, +0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, +0x2e22021, 0xac8a0000, 0xac8c0004, 0x54e00006, +0x240b0001, 0x8f820054, 0x1221023, 0x2c420033, +0x1440ffa6, 0x0, 0x316300ff, 0x24020001, +0x10620022, 0x0, 0x3c040001, 0x24844b60, +0xafa00010, 0xafa00014, 0x8f860120, 0x8f870124, +0x3c050009, 0xc002407, 0x34a5f011, 0x80021c4, +0x0, 0x3c040001, 0x24844b6c, 0xafa00014, +0x8f860120, 0x8f870124, 0x3c050009, 0xc002407, +0x34a5f010, 0x80021c4, 0x0, 0x3c040001, +0x24844b78, 0xafa00014, 0x8ee60608, 0x8f470228, +0x3c050009, 0xc002407, 0x34a5f00f, 0x8ee201ac, +0x24420001, 0xaee201ac, 0x8ee201ac, 0x8ee20120, +0x24420001, 0xaee20120, 0x8ee20120, 0x8ee20168, +0x24420001, 0xaee20168, 0x80022e8, 0x8ee20168, +0x8f42025c, 0x26e40094, 0xaee20060, 0x8f420260, +0x27450200, 0x24060008, 0xc00249e, 0xaee20068, +0x8f820220, 0x30420008, 0x14400002, 0x24020001, +0x24020002, 0xaee20108, 0x8ee2011c, 0x24420001, +0xaee2011c, 0x80022e8, 0x8ee2011c, 0x3c040001, +0x24844bbc, 0xafa00010, 0xafa00014, 0x8fa60020, +0x3c050003, 0xc002407, 0x34a5f00f, 0x93a20020, +0x3c030700, 0x34631000, 0x431025, 0xafa20018, +0x8ee20608, 0x8f430228, 0x24420001, 0x304900ff, +0x512300e2, 0xafa00010, 0x8ee20608, 0x210c0, +0x571021, 0x8fa30018, 0x8fa4001c, 0xac43060c, +0xac440610, 0x8f870120, 0x27623800, 0x24e80020, +0x102102b, 0x50400001, 0x27683000, 0x8f820128, +0x11020004, 0x0, 0x8f820124, 0x15020007, +0x1021, 0x8ee201a4, 0x3821, 0x24420001, +0xaee201a4, 0x800225d, 0x8ee201a4, 0x8ee40608, +0x420c0, 0x801821, 0x8ee40430, 0x8ee50434, +0xa32821, 0xa3302b, 0x822021, 0x862021, +0xace40000, 0xace50004, 0x8ee30608, 0x24020008, +0xa4e2000e, 0x2402000d, 0xace20018, 0xace9001c, +0x318c0, 0x2463060c, 0x2e31021, 0xace20008, +0x8ee204c4, 0xace20010, 0xaf880120, 0x92e24e20, +0x14400037, 0x24070001, 0x8ee24e30, 0x210c0, +0x24425038, 0x2e22021, 0x8c830000, 0x24020007, +0x1462001f, 0x0, 0x8ee34e30, 0x8ee24e34, +0x1062001b, 0x24030040, 0x8c820004, 0x24420001, +0xac820004, 0x8ee24e34, 0x8ee54e30, 0x24420001, +0x10430007, 0x0, 0x8ee24e34, 0x24420001, +0x10a20005, 0x0, 0x8002247, 0x0, +0x14a00005, 0x0, 0x8f820128, 0x24420020, +0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011, +0x50400013, 0xac800000, 0x800225d, 0x0, +0x8ee24e30, 0x24030040, 0x24420001, 0x50430003, +0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30, +0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, +0x24020007, 0xac820000, 0x24020001, 0xac820004, +0x54e0000c, 0xaee90608, 0x3c040001, 0x24844bc4, +0xafa00010, 0xafa00014, 0x8ee60608, 0x8f470228, +0x3c050009, 0xc002407, 0x34a5f000, 0x80022e0, +0x0, 0x8f830120, 0x27623800, 0x24660020, +0xc2102b, 0x50400001, 0x27663000, 0x8f820128, +0x10c20004, 0x0, 0x8f820124, 0x14c20007, +0x0, 0x8ee201a4, 0x3821, 0x24420001, +0xaee201a4, 0x80022c4, 0x8ee201a4, 0x8ee20608, +0xac62001c, 0x8ee404a0, 0x8ee504a4, 0x2462001c, +0xac620008, 0x24020008, 0xa462000e, 0x24020011, +0xac620018, 0xac640000, 0xac650004, 0x8ee204c4, +0xac620010, 0xaf860120, 0x92e24e20, 0x14400037, +0x24070001, 0x8ee24e30, 0x210c0, 0x24425038, +0x2e22021, 0x8c830000, 0x24020012, 0x1462001f, +0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b, +0x24030040, 0x8c820004, 0x24420001, 0xac820004, +0x8ee24e34, 0x8ee54e30, 0x24420001, 0x10430007, +0x0, 0x8ee24e34, 0x24420001, 0x10a20005, +0x0, 0x80022ae, 0x0, 0x14a00005, +0x0, 0x8f820128, 0x24420020, 0xaf820128, +0x8f820128, 0x8c820004, 0x2c420011, 0x50400013, +0xac800000, 0x80022c4, 0x0, 0x8ee24e30, +0x24030040, 0x24420001, 0x50430003, 0x1021, +0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30, +0x210c0, 0x24425038, 0x2e22021, 0x24020012, +0xac820000, 0x24020001, 0xac820004, 0x14e0001b, +0x0, 0x3c040001, 0x24844bcc, 0xafa00010, +0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009, +0xc002407, 0x34a5f001, 0x8ee201b0, 0x24420001, +0xaee201b0, 0x80022e0, 0x8ee201b0, 0x3c040001, +0x24844bd8, 0xafa00014, 0x8ee60608, 0x8f470228, +0x3c050009, 0xc002407, 0x34a5f005, 0x8ee201ac, +0x24420001, 0xaee201ac, 0x8ee201ac, 0x8ee20150, +0x24420001, 0xaee20150, 0x8ee20150, 0x8ee20160, +0x24420001, 0xaee20160, 0x8ee20160, 0x8f43022c, +0x8f42010c, 0x14620009, 0x24020002, 0xaf820064, +0x8f820064, 0x14400005, 0x0, 0x8f43022c, +0x8f42010c, 0x1462f875, 0x0, 0x8fbf0044, +0x8fb60040, 0x8fb5003c, 0x8fb40038, 0x8fb30034, +0x8fb20030, 0x8fb1002c, 0x8fb00028, 0x3e00008, +0x27bd0048, 0x27bdfff8, 0x2408ffff, 0x10a00014, +0x4821, 0x3c0aedb8, 0x354a8320, 0x90870000, +0x24840001, 0x3021, 0x1071026, 0x30420001, +0x10400002, 0x81842, 0x6a1826, 0x604021, +0x24c60001, 0x2cc20008, 0x1440fff7, 0x73842, +0x25290001, 0x125102b, 0x1440fff0, 0x0, +0x1001021, 0x3e00008, 0x27bd0008, 0x27bdffe8, +0x27642800, 0xafbf0010, 0xc00248c, 0x24051000, +0x24020021, 0xaf800100, 0xaf800104, 0xaf800108, +0xaf800110, 0xaf800114, 0xaf800118, 0xaf800120, +0xaf800124, 0xaf800128, 0xaf800130, 0xaf800134, +0xaf800138, 0xaee04e28, 0xaee04e2c, 0xaee04e30, +0xaee04e34, 0xaf82011c, 0x8f420218, 0x30420040, +0x10400004, 0x0, 0x8f82011c, 0x34420004, +0xaf82011c, 0x8fbf0010, 0x3e00008, 0x27bd0018, +0x27bdffe0, 0xafbf0018, 0x8f820104, 0xafa20010, +0x8f820100, 0x3c050002, 0xafa20014, 0x8f8600b0, +0x8f87011c, 0x3c040001, 0x24844c8c, 0xc002407, +0x34a5f000, 0x8f8300b0, 0x3c027f00, 0x621824, +0x3c020400, 0x1062002b, 0x43102b, 0x14400008, +0x3c022000, 0x3c020100, 0x10620026, 0x3c020200, +0x10620013, 0x0, 0x8002376, 0x0, +0x1062000a, 0x43102b, 0x1040001e, 0x3c024000, +0x1462001c, 0x0, 0x8ee20190, 0x24420001, +0xaee20190, 0x8002376, 0x8ee20190, 0x8ee2018c, +0x24420001, 0xaee2018c, 0x8002376, 0x8ee2018c, +0x8f82011c, 0x34420002, 0xaf82011c, 0x8f830104, +0x8f8200b0, 0x34420001, 0xaf8200b0, 0xaf830104, +0x8f82011c, 0x2403fffd, 0x431024, 0xaf82011c, +0x8ee201a0, 0x24420001, 0xaee201a0, 0x8002379, +0x8ee201a0, 0x8f8200b0, 0x34420001, 0xaf8200b0, +0x8fbf0018, 0x3e00008, 0x27bd0020, 0x27bdffe0, +0xafbf001c, 0xafb00018, 0x8f820120, 0xafa20010, +0x8f820124, 0x3c050001, 0xafa20014, 0x8f8600a0, +0x8f87011c, 0x3c040001, 0x24844c98, 0xc002407, +0x34a5f000, 0x8f8300a0, 0x3c027f00, 0x621824, +0x3c020400, 0x10620055, 0x8021, 0x43102b, +0x14400008, 0x3c042000, 0x3c020100, 0x1062004f, +0x3c020200, 0x1062003c, 0x0, 0x80023e4, +0x0, 0x10640005, 0x83102b, 0x10400047, +0x3c024000, 0x14620045, 0x0, 0x8f8200a0, +0x441024, 0x10400006, 0x0, 0x8ee20194, +0x24420001, 0xaee20194, 0x80023ad, 0x8ee20194, +0x8ee20198, 0x24420001, 0xaee20198, 0x8ee20198, +0x8f82011c, 0x34420002, 0xaf82011c, 0x8f82011c, +0x30420200, 0x1040001b, 0x0, 0x8f8300a0, +0x8f840124, 0x8f8200ac, 0x14400007, 0x24020001, +0x3c020001, 0x3442f000, 0x621024, 0x50400001, +0x24100001, 0x24020001, 0x1200000d, 0xaf8200a0, +0x8f820124, 0x2442ffe0, 0xaf820124, 0x8f820124, +0x8f820124, 0x27633000, 0x43102b, 0x10400005, +0x276237e0, 0xaf820124, 0x80023ce, 0x0, +0xaf840124, 0x8f82011c, 0x2403fffd, 0x431024, +0x80023e7, 0xaf82011c, 0x8f82011c, 0x34420002, +0xaf82011c, 0x8f830124, 0x8f8200a0, 0x34420001, +0xaf8200a0, 0xaf830124, 0x8f82011c, 0x2403fffd, +0x431024, 0xaf82011c, 0x8ee2019c, 0x24420001, +0xaee2019c, 0x80023e7, 0x8ee2019c, 0x8f8200a0, +0x34420001, 0xaf8200a0, 0x8fbf001c, 0x8fb00018, +0x3e00008, 0x27bd0020, 0x0, 0x3c020001, +0x8c425408, 0x27bdffe8, 0xafbf0014, 0x14400012, +0xafb00010, 0x3c100001, 0x26105550, 0x2002021, +0xc00248c, 0x24052000, 0x26021fe0, 0x3c010001, +0xac225524, 0x3c010001, 0xac225520, 0xaf420250, +0x24022000, 0xaf500254, 0xaf420258, 0x24020001, +0x3c010001, 0xac225408, 0x8fbf0014, 0x8fb00010, +0x3e00008, 0x27bd0018, 0x3c030001, 0x8c635524, +0x8c820000, 0x8fa80010, 0x8fa90014, 0xac620000, +0x3c020001, 0x8c425524, 0x8c830004, 0xac430004, +0xac450008, 0x8f840054, 0x2443ffe0, 0xac460010, +0xac470014, 0xac480018, 0xac49001c, 0x3c010001, +0xac235524, 0xac44000c, 0x3c020001, 0x24425550, +0x62182b, 0x10600005, 0x0, 0x3c020001, +0x8c425520, 0x3c010001, 0xac225524, 0x3c030001, +0x8c635524, 0x3c020001, 0x8c4253f0, 0xac620000, +0x3c030001, 0x8c635524, 0x3c020001, 0x8c4253f0, +0xac620004, 0x3e00008, 0xaf430250, 0x3c030001, +0x8c635524, 0x3c020001, 0x8c4253f0, 0x27bdffd0, +0xafb40020, 0x8fb40040, 0xafb00010, 0x808021, +0xafb50024, 0x8fb50044, 0x8fa40048, 0xafb10014, +0xa08821, 0xafbf0028, 0xafb3001c, 0xafb20018, +0xac620000, 0x3c050001, 0x8ca55524, 0x3c020001, +0x8c4253f0, 0xc09021, 0xe09821, 0x10800006, +0xaca20004, 0x24a50008, 0xc002494, 0x24060018, +0x8002452, 0x0, 0x24a40008, 0xc00248c, +0x24050018, 0x3c020001, 0x8c425524, 0x3c050001, +0x24a55550, 0x2442ffe0, 0x3c010001, 0xac225524, +0x45102b, 0x10400005, 0x0, 0x3c020001, +0x8c425520, 0x3c010001, 0xac225524, 0x3c030001, +0x8c635524, 0x8e020000, 0xac620000, 0x3c030001, +0x8c635524, 0x8e020004, 0xac620004, 0xac710008, +0x8f840054, 0x2462ffe0, 0x3c010001, 0xac225524, +0x45102b, 0xac720010, 0xac730014, 0xac740018, +0xac75001c, 0x10400005, 0xac64000c, 0x3c020001, +0x8c425520, 0x3c010001, 0xac225524, 0x3c030001, +0x8c635524, 0x3c020001, 0x8c4253f0, 0xac620000, +0x3c030001, 0x8c635524, 0x3c020001, 0x8c4253f0, +0xac620004, 0xaf430250, 0x8fbf0028, 0x8fb50024, +0x8fb40020, 0x8fb3001c, 0x8fb20018, 0x8fb10014, +0x8fb00010, 0x3e00008, 0x27bd0030, 0x10a00005, +0x0, 0xac800000, 0x24a5fffc, 0x14a0fffd, +0x24840004, 0x3e00008, 0x0, 0x10c00007, +0x0, 0x8c820000, 0x24840004, 0x24c6fffc, +0xaca20000, 0x14c0fffb, 0x24a50004, 0x3e00008, +0x0, 0x10c00007, 0x0, 0x8ca20000, +0x24a50004, 0x24c6fffc, 0xac820000, 0x14c0fffb, +0x24840004, 0x3e00008, 0x0, 0x3e00008, +0x0, 0x27bdffd8, 0xafbf0020, 0x8ee304e4, +0x8ee204e0, 0x10620436, 0x0, 0x8ee204e4, +0x8ee304fc, 0x21100, 0x626021, 0x95870008, +0x8d8a0000, 0x8d8b0004, 0x958d000a, 0x8ee2725c, +0x8ee3726c, 0x30e4ffff, 0x441021, 0x62182b, +0x10600015, 0x31a20004, 0x8f8200d8, 0x8ee37258, +0x431023, 0xaee2726c, 0x8ee2726c, 0x1c400003, +0x3c030001, 0x431021, 0xaee2726c, 0x8ee2725c, +0x8ee3726c, 0x441021, 0x62182b, 0x10600006, +0x31a20004, 0x8ee201b8, 0x24420001, 0xaee201b8, +0x80028e5, 0x8ee201b8, 0x10400240, 0x31a20200, +0x1040014d, 0x4821, 0x96e2045a, 0x30420010, +0x10400149, 0x0, 0x8f840100, 0x27623000, +0x24850020, 0xa2102b, 0x50400001, 0x27652800, +0x8f820108, 0x10a20004, 0x0, 0x8f820104, +0x14a20006, 0x2402000c, 0x8ee201a8, 0x24420001, +0xaee201a8, 0x8002530, 0x8ee201a8, 0xac8a0000, +0xac8b0004, 0x8ee37264, 0x24060005, 0xa482000e, +0xac860018, 0xac830008, 0x8ee204e4, 0xac82001c, +0x8ee204c8, 0xac820010, 0xaf850100, 0x92e204ec, +0x14400036, 0x24090001, 0x8ee24e28, 0x210c0, +0x24424e38, 0x2e22021, 0x8c820000, 0x1446001f, +0x0, 0x8ee34e28, 0x8ee24e2c, 0x1062001b, +0x24030040, 0x8c820004, 0x24420001, 0xac820004, +0x8ee24e2c, 0x8ee54e28, 0x24420001, 0x10430007, +0x0, 0x8ee24e2c, 0x24420001, 0x10a20005, +0x0, 0x800251a, 0x0, 0x14a00005, +0x0, 0x8f820108, 0x24420020, 0xaf820108, +0x8f820108, 0x8c820004, 0x2c420011, 0x50400013, +0xac800000, 0x8002530, 0x0, 0x8ee24e28, +0x24030040, 0x24420001, 0x50430003, 0x1021, +0x8ee24e28, 0x24420001, 0xaee24e28, 0x8ee24e28, +0x210c0, 0x24424e38, 0x2e22021, 0x24020005, +0xac820000, 0x24020001, 0xac820004, 0x1520000a, +0x3c040001, 0xafab0010, 0x8ee27264, 0x3c040001, +0x24844f00, 0x3c050004, 0xafa20014, 0x8ee604e4, +0x80028c2, 0x34a5f114, 0x8ee27264, 0x34843800, +0x3641821, 0x24420010, 0x43102b, 0x14400073, +0x0, 0x8ee27264, 0x24480010, 0x3641021, +0x102102b, 0x14400002, 0x3c02ffff, 0x1024021, +0x8f850100, 0x27623000, 0x24a60020, 0xc2102b, +0x50400001, 0x27662800, 0x8f820108, 0x10c20004, +0x0, 0x8f820104, 0x14c20007, 0x2563000c, +0x8ee201a8, 0x4821, 0x24420001, 0xaee201a8, +0x80025a4, 0x8ee201a8, 0x2c64000c, 0x1441021, +0xaca20000, 0xaca30004, 0x24e2fff4, 0xa4a2000e, +0x24020006, 0xaca80008, 0xaca20018, 0x8ee204e4, +0xaca2001c, 0x8ee204c8, 0x3c030002, 0x431025, +0xaca20010, 0xaf860100, 0x92e204ec, 0x14400037, +0x24090001, 0x8ee24e28, 0x210c0, 0x24424e38, +0x2e22021, 0x8c830000, 0x24020005, 0x1462001f, +0x0, 0x8ee34e28, 0x8ee24e2c, 0x1062001b, +0x24030040, 0x8c820004, 0x24420001, 0xac820004, +0x8ee24e2c, 0x8ee54e28, 0x24420001, 0x10430007, +0x0, 0x8ee24e2c, 0x24420001, 0x10a20005, +0x0, 0x800258e, 0x0, 0x14a00005, +0x0, 0x8f820108, 0x24420020, 0xaf820108, +0x8f820108, 0x8c820004, 0x2c420011, 0x50400013, +0xac800000, 0x80025a4, 0x0, 0x8ee24e28, +0x24030040, 0x24420001, 0x50430003, 0x1021, +0x8ee24e28, 0x24420001, 0xaee24e28, 0x8ee24e28, +0x210c0, 0x24424e38, 0x2e22021, 0x24020005, +0xac820000, 0x24020001, 0xac820004, 0x1520000a, +0x2508fffc, 0xafab0010, 0x8ee27264, 0x3c040001, +0x24844f00, 0x3c050004, 0xafa20014, 0x8ee604e4, +0x80028c2, 0x34a5f125, 0x34028100, 0xa5020000, +0x9582000e, 0x8002621, 0xa5020002, 0x8f850100, +0x27623000, 0x24a60020, 0xc2102b, 0x50400001, +0x27662800, 0x8f820108, 0x10c20004, 0x0, +0x8f820104, 0x14c20007, 0x2563000c, 0x8ee201a8, +0x4821, 0x24420001, 0xaee201a8, 0x8002611, +0x8ee201a8, 0x2c64000c, 0x1441021, 0xaca20000, +0xaca30004, 0x8ee37264, 0x24e2fff4, 0xa4a2000e, +0x24020006, 0xaca20018, 0x24630010, 0xaca30008, +0x8ee204e4, 0xaca2001c, 0x8ee204c8, 0x3c030002, +0x431025, 0xaca20010, 0xaf860100, 0x92e204ec, +0x14400037, 0x24090001, 0x8ee24e28, 0x210c0, +0x24424e38, 0x2e22021, 0x8c830000, 0x24020005, +0x1462001f, 0x0, 0x8ee34e28, 0x8ee24e2c, +0x1062001b, 0x24030040, 0x8c820004, 0x24420001, +0xac820004, 0x8ee24e2c, 0x8ee54e28, 0x24420001, +0x10430007, 0x0, 0x8ee24e2c, 0x24420001, +0x10a20005, 0x0, 0x80025fb, 0x0, +0x14a00005, 0x0, 0x8f820108, 0x24420020, +0xaf820108, 0x8f820108, 0x8c820004, 0x2c420011, +0x50400013, 0xac800000, 0x8002611, 0x0, +0x8ee24e28, 0x24030040, 0x24420001, 0x50430003, +0x1021, 0x8ee24e28, 0x24420001, 0xaee24e28, +0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021, +0x24020005, 0xac820000, 0x24020001, 0xac820004, +0x1520000a, 0x34028100, 0xafab0010, 0x8ee27264, +0x3c040001, 0x24844f00, 0x3c050004, 0xafa20014, +0x8ee604e4, 0x80028c2, 0x34a5f015, 0x8ee37264, +0xa462000c, 0x8ee37264, 0x9582000e, 0xa462000e, +0x8002685, 0x24e70004, 0x8f840100, 0x27623000, +0x24850020, 0xa2102b, 0x50400001, 0x27652800, +0x8f820108, 0x10a20004, 0x0, 0x8f820104, +0x14a20007, 0x24020006, 0x8ee201a8, 0x4821, +0x24420001, 0xaee201a8, 0x800267b, 0x8ee201a8, +0xac8a0000, 0xac8b0004, 0x8ee37264, 0xa487000e, +0xac820018, 0xac830008, 0x8ee204e4, 0xac82001c, +0x8ee204c8, 0x3c030002, 0x431025, 0xac820010, +0xaf850100, 0x92e204ec, 0x14400037, 0x24090001, +0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021, +0x8c830000, 0x24020005, 0x1462001f, 0x0, +0x8ee34e28, 0x8ee24e2c, 0x1062001b, 0x24030040, +0x8c820004, 0x24420001, 0xac820004, 0x8ee24e2c, +0x8ee54e28, 0x24420001, 0x10430007, 0x0, +0x8ee24e2c, 0x24420001, 0x10a20005, 0x0, +0x8002665, 0x0, 0x14a00005, 0x0, +0x8f820108, 0x24420020, 0xaf820108, 0x8f820108, +0x8c820004, 0x2c420011, 0x50400013, 0xac800000, +0x800267b, 0x0, 0x8ee24e28, 0x24030040, +0x24420001, 0x50430003, 0x1021, 0x8ee24e28, +0x24420001, 0xaee24e28, 0x8ee24e28, 0x210c0, +0x24424e38, 0x2e22021, 0x24020005, 0xac820000, +0x24020001, 0xac820004, 0x15200009, 0x3c050004, +0xafab0010, 0x8ee27264, 0x3c040001, 0x24844f00, +0xafa20014, 0x8ee604e4, 0x80028c2, 0x34a5f004, +0x8ee2725c, 0x30e7ffff, 0x471021, 0xaee2725c, +0x8ee204e4, 0x8ee304fc, 0x8ee47258, 0x21100, +0x431021, 0xac44000c, 0x8ee27258, 0xafa20018, +0x8ee3725c, 0xafa3001c, 0x8ee2725c, 0x2c42003c, +0x10400004, 0x24620001, 0x2403fffe, 0x431024, +0xafa2001c, 0x8ee27264, 0x3c060001, 0x34c63800, +0x8ee3725c, 0x2405fff8, 0x471021, 0x24420007, +0x451024, 0x24630007, 0xaee27258, 0x8ee2726c, +0x8ee47258, 0x651824, 0x431023, 0xaee2726c, +0x3661021, 0x82202b, 0x14800004, 0x3c03ffff, +0x8ee27258, 0x431021, 0xaee27258, 0x8ee27258, +0xaee27264, 0x8f8200f0, 0x24470008, 0x27621800, +0xe2102b, 0x50400001, 0x27671000, 0x8f8200f4, +0x14e20007, 0x0, 0x8ee201b4, 0x4821, +0x24420001, 0xaee201b4, 0x80026c8, 0x8ee201b4, +0x8f8200f0, 0x24090001, 0x8fa30018, 0x8fa4001c, +0xac430000, 0xac440004, 0xaf8700f0, 0x15200012, +0xd1142, 0x8f8200f0, 0xafa20010, 0x8f8200f4, +0x3c040001, 0x24844f0c, 0xafa20014, 0x8fa60018, +0x8fa7001c, 0x3c050004, 0xc002407, 0x34a5f005, +0x8ee20088, 0x24420001, 0xaee20088, 0x8ee20088, +0x80028d7, 0xaee0725c, 0x30430003, 0x24020002, +0x10620016, 0x28620003, 0x10400005, 0x24020001, +0x10620008, 0x0, 0x8002707, 0x0, +0x24020003, 0x10620017, 0x0, 0x8002707, +0x0, 0x8ee200e8, 0x8ee300ec, 0x24630001, +0x2c640001, 0x441021, 0xaee200e8, 0xaee300ec, +0x8ee200e8, 0x8002707, 0x8ee300ec, 0x8ee200f0, +0x8ee300f4, 0x24630001, 0x2c640001, 0x441021, +0xaee200f0, 0xaee300f4, 0x8ee200f0, 0x8002707, +0x8ee300f4, 0x8ee200f8, 0x8ee300fc, 0x24630001, +0x2c640001, 0x441021, 0xaee200f8, 0xaee300fc, +0x8ee200f8, 0x8ee300fc, 0x8ee2725c, 0x8ee400e0, +0x8ee500e4, 0x401821, 0x1021, 0xa32821, +0xa3302b, 0x822021, 0x862021, 0xaee400e0, +0xaee500e4, 0x80028d7, 0xaee0725c, 0x30e2ffff, +0x104001c1, 0x31a20200, 0x1040014d, 0x4821, +0x96e2045a, 0x30420010, 0x10400149, 0x0, +0x8f840100, 0x27623000, 0x24850020, 0xa2102b, +0x50400001, 0x27652800, 0x8f820108, 0x10a20004, +0x0, 0x8f820104, 0x14a20006, 0x2402000c, +0x8ee201a8, 0x24420001, 0xaee201a8, 0x8002772, +0x8ee201a8, 0xac8a0000, 0xac8b0004, 0x8ee37264, +0x24060005, 0xa482000e, 0xac860018, 0xac830008, +0x8ee204e4, 0xac82001c, 0x8ee204c8, 0xac820010, +0xaf850100, 0x92e204ec, 0x14400036, 0x24090001, +0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021, +0x8c820000, 0x1446001f, 0x0, 0x8ee34e28, +0x8ee24e2c, 0x1062001b, 0x24030040, 0x8c820004, +0x24420001, 0xac820004, 0x8ee24e2c, 0x8ee54e28, +0x24420001, 0x10430007, 0x0, 0x8ee24e2c, +0x24420001, 0x10a20005, 0x0, 0x800275c, +0x0, 0x14a00005, 0x0, 0x8f820108, +0x24420020, 0xaf820108, 0x8f820108, 0x8c820004, +0x2c420011, 0x50400013, 0xac800000, 0x8002772, +0x0, 0x8ee24e28, 0x24030040, 0x24420001, +0x50430003, 0x1021, 0x8ee24e28, 0x24420001, +0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38, +0x2e22021, 0x24020005, 0xac820000, 0x24020001, +0xac820004, 0x1520000a, 0x3c040001, 0xafab0010, +0x8ee27264, 0x3c040001, 0x24844f00, 0x3c050004, +0xafa20014, 0x8ee604e4, 0x80028c2, 0x34a5f014, +0x8ee27264, 0x34843800, 0x3641821, 0x24420010, +0x43102b, 0x14400073, 0x0, 0x8ee27264, +0x24480010, 0x3641021, 0x102102b, 0x14400002, +0x3c02ffff, 0x1024021, 0x8f850100, 0x27623000, +0x24a60020, 0xc2102b, 0x50400001, 0x27662800, +0x8f820108, 0x10c20004, 0x0, 0x8f820104, +0x14c20007, 0x2563000c, 0x8ee201a8, 0x4821, +0x24420001, 0xaee201a8, 0x80027e6, 0x8ee201a8, +0x2c64000c, 0x1441021, 0xaca20000, 0xaca30004, +0x24e2fff4, 0xa4a2000e, 0x24020006, 0xaca80008, +0xaca20018, 0x8ee204e4, 0xaca2001c, 0x8ee204c8, +0x3c030002, 0x431025, 0xaca20010, 0xaf860100, +0x92e204ec, 0x14400037, 0x24090001, 0x8ee24e28, +0x210c0, 0x24424e38, 0x2e22021, 0x8c830000, +0x24020005, 0x1462001f, 0x0, 0x8ee34e28, +0x8ee24e2c, 0x1062001b, 0x24030040, 0x8c820004, +0x24420001, 0xac820004, 0x8ee24e2c, 0x8ee54e28, +0x24420001, 0x10430007, 0x0, 0x8ee24e2c, +0x24420001, 0x10a20005, 0x0, 0x80027d0, +0x0, 0x14a00005, 0x0, 0x8f820108, +0x24420020, 0xaf820108, 0x8f820108, 0x8c820004, +0x2c420011, 0x50400013, 0xac800000, 0x80027e6, +0x0, 0x8ee24e28, 0x24030040, 0x24420001, +0x50430003, 0x1021, 0x8ee24e28, 0x24420001, +0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38, +0x2e22021, 0x24020005, 0xac820000, 0x24020001, +0xac820004, 0x1520000a, 0x2508fffc, 0xafab0010, +0x8ee27264, 0x3c040001, 0x24844f00, 0x3c050004, +0xafa20014, 0x8ee604e4, 0x80028c2, 0x34a5f015, +0x34028100, 0xa5020000, 0x9582000e, 0x8002863, +0xa5020002, 0x8f850100, 0x27623000, 0x24a60020, +0xc2102b, 0x50400001, 0x27662800, 0x8f820108, +0x10c20004, 0x0, 0x8f820104, 0x14c20007, +0x2563000c, 0x8ee201a8, 0x4821, 0x24420001, +0xaee201a8, 0x8002853, 0x8ee201a8, 0x2c64000c, +0x1441021, 0xaca20000, 0xaca30004, 0x8ee37264, +0x24e2fff4, 0xa4a2000e, 0x24020006, 0xaca20018, +0x24630010, 0xaca30008, 0x8ee204e4, 0xaca2001c, +0x8ee204c8, 0x3c030002, 0x431025, 0xaca20010, +0xaf860100, 0x92e204ec, 0x14400037, 0x24090001, +0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021, +0x8c830000, 0x24020005, 0x1462001f, 0x0, +0x8ee34e28, 0x8ee24e2c, 0x1062001b, 0x24030040, +0x8c820004, 0x24420001, 0xac820004, 0x8ee24e2c, +0x8ee54e28, 0x24420001, 0x10430007, 0x0, +0x8ee24e2c, 0x24420001, 0x10a20005, 0x0, +0x800283d, 0x0, 0x14a00005, 0x0, +0x8f820108, 0x24420020, 0xaf820108, 0x8f820108, +0x8c820004, 0x2c420011, 0x50400013, 0xac800000, +0x8002853, 0x0, 0x8ee24e28, 0x24030040, +0x24420001, 0x50430003, 0x1021, 0x8ee24e28, +0x24420001, 0xaee24e28, 0x8ee24e28, 0x210c0, +0x24424e38, 0x2e22021, 0x24020005, 0xac820000, +0x24020001, 0xac820004, 0x1520000a, 0x34028100, +0xafab0010, 0x8ee27264, 0x3c040001, 0x24844f00, +0x3c050004, 0xafa20014, 0x8ee604e4, 0x80028c2, +0x34a5f016, 0x8ee37264, 0xa462000c, 0x8ee37264, +0x9582000e, 0xa462000e, 0x80028c6, 0x24e70004, +0x8f830100, 0x27623000, 0x24640020, 0x82102b, +0x50400001, 0x27642800, 0x8f820108, 0x10820004, +0x0, 0x8f820104, 0x14820007, 0x24050005, +0x8ee201a8, 0x4821, 0x24420001, 0xaee201a8, +0x80028ba, 0x8ee201a8, 0xac6a0000, 0xac6b0004, +0x8ee27264, 0xa467000e, 0xac650018, 0xac620008, +0x8ee204e4, 0xac62001c, 0x8ee204c8, 0xac620010, +0xaf840100, 0x92e204ec, 0x14400036, 0x24090001, +0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021, +0x8c820000, 0x1445001f, 0x0, 0x8ee34e28, +0x8ee24e2c, 0x1062001b, 0x24030040, 0x8c820004, +0x24420001, 0xac820004, 0x8ee24e2c, 0x8ee54e28, +0x24420001, 0x10430007, 0x0, 0x8ee24e2c, +0x24420001, 0x10a20005, 0x0, 0x80028a4, +0x0, 0x14a00005, 0x0, 0x8f820108, +0x24420020, 0xaf820108, 0x8f820108, 0x8c820004, +0x2c420011, 0x50400013, 0xac800000, 0x80028ba, +0x0, 0x8ee24e28, 0x24030040, 0x24420001, +0x50430003, 0x1021, 0x8ee24e28, 0x24420001, +0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38, +0x2e22021, 0x24020005, 0xac820000, 0x24020001, +0xac820004, 0x1520000b, 0x3c050004, 0x3c040001, +0x24844f18, 0xafab0010, 0xafa00014, 0x8ee604e4, +0x34a5f017, 0xc002407, 0x30e7ffff, 0x80028e5, +0x0, 0x8ee27264, 0x3c050001, 0x30e4ffff, +0x441021, 0xaee27264, 0x8ee2725c, 0x8ee37264, +0x34a53800, 0x441021, 0xaee2725c, 0x3651021, +0x62182b, 0x14600004, 0x3c03ffff, 0x8ee27264, +0x431021, 0xaee27264, 0x8ee304e4, 0x96e20458, +0x24630001, 0x2442ffff, 0x621824, 0xaee304e4, +0x8ee304e4, 0x8ee204e0, 0x14620005, 0x0, +0x8f820060, 0x2403fff7, 0x431024, 0xaf820060, +0x8fbf0020, 0x3e00008, 0x27bd0028, 0x27bdffe0, +0xafbf0018, 0x8ee304e8, 0x8ee204e0, 0x10620189, +0x0, 0x8ee204e8, 0x8ee304fc, 0x21100, +0x621821, 0x94670008, 0x92e204ed, 0x8c680000, +0x8c690004, 0x10400023, 0x946a000a, 0x8ee204c8, +0x34460400, 0x31420200, 0x1040001f, 0x0, +0x96e2045a, 0x30420010, 0x1040001b, 0x3c028000, +0x3c010001, 0x370821, 0xac2283d8, 0x8ee27264, +0x9464000e, 0x3c050001, 0x34a53800, 0x24420004, +0xaee27264, 0x8ee37264, 0x42400, 0x3651021, +0x3c010001, 0x370821, 0xac2483dc, 0x62182b, +0x14600005, 0x24e70004, 0x8ee27264, 0x3c03ffff, +0x431021, 0xaee27264, 0x8ee27264, 0x800291b, +0xaee27258, 0x8ee604c8, 0x8ee2726c, 0x30e4ffff, +0x44102a, 0x10400015, 0x0, 0x8f8200d8, +0x8ee37258, 0x431023, 0xaee2726c, 0x8ee2726c, +0x1c400007, 0x44102a, 0x8ee2726c, 0x3c030001, +0x431021, 0xaee2726c, 0x8ee2726c, 0x44102a, +0x10400006, 0x0, 0x8ee201b8, 0x24420001, +0xaee201b8, 0x8002a76, 0x8ee201b8, 0x3c020001, +0x571021, 0x8c4283d8, 0x54400001, 0x24e7fffc, +0x31420004, 0x104000b9, 0x30e2ffff, 0x3c020001, +0x571021, 0x8c4283d8, 0x1040002f, 0x5021, +0x8f840100, 0x27623000, 0x24850020, 0xa2102b, +0x50400001, 0x27652800, 0x8f820108, 0x10a20032, +0x0, 0x8f820104, 0x10a2002f, 0x24020015, +0xac880000, 0xac890004, 0x8ee37264, 0xa487000e, +0xac820018, 0xac830008, 0x8ee204e8, 0x3c030001, +0x771821, 0x8c6383dc, 0xac860010, 0x431025, +0xac82001c, 0xaf850100, 0x92e204ec, 0x14400066, +0x240a0001, 0x8ee24e28, 0x24030040, 0x24420001, +0x50430003, 0x1021, 0x8ee24e28, 0x24420001, +0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38, +0x2e21821, 0x24020015, 0xac620000, 0x24020001, +0x80029c3, 0xac620004, 0x8f840100, 0x27623000, +0x24850020, 0xa2102b, 0x50400001, 0x27652800, +0x8f820108, 0x10a20004, 0x0, 0x8f820104, +0x14a20006, 0x24020006, 0x8ee201a8, 0x24420001, +0xaee201a8, 0x80029c3, 0x8ee201a8, 0xac880000, +0xac890004, 0x8ee37264, 0xa487000e, 0xac820018, +0xac830008, 0x8ee204e8, 0xac860010, 0xac82001c, +0xaf850100, 0x92e204ec, 0x14400037, 0x240a0001, +0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021, +0x8c830000, 0x24020005, 0x1462001f, 0x0, +0x8ee34e28, 0x8ee24e2c, 0x1062001b, 0x24030040, +0x8c820004, 0x24420001, 0xac820004, 0x8ee24e2c, +0x8ee54e28, 0x24420001, 0x10430007, 0x0, +0x8ee24e2c, 0x24420001, 0x10a20005, 0x0, +0x80029ad, 0x0, 0x14a00005, 0x0, +0x8f820108, 0x24420020, 0xaf820108, 0x8f820108, +0x8c820004, 0x2c420011, 0x50400013, 0xac800000, +0x80029c3, 0x0, 0x8ee24e28, 0x24030040, +0x24420001, 0x50430003, 0x1021, 0x8ee24e28, +0x24420001, 0xaee24e28, 0x8ee24e28, 0x210c0, +0x24424e38, 0x2e22021, 0x24020005, 0xac820000, +0x24020001, 0xac820004, 0x1540000a, 0x24020001, +0xafa90010, 0x8ee27264, 0x3c040001, 0x24844f00, +0x3c050004, 0xafa20014, 0x8ee604e4, 0x8002a53, +0x34a5f204, 0xa2e204ed, 0x8ee204e8, 0x8ee304fc, +0x8ee47258, 0x3c060001, 0x34c63800, 0x3c010001, +0x370821, 0xac2083d8, 0x3c010001, 0x370821, +0xac2083dc, 0x21100, 0x431021, 0xac44000c, +0x8ee27264, 0x2405fff8, 0x30e3ffff, 0x431021, +0x24420007, 0x451024, 0x24630007, 0xaee27258, +0x8ee2726c, 0x8ee47258, 0x651824, 0x431023, +0xaee2726c, 0x3661021, 0x82202b, 0x14800004, +0x3c03ffff, 0x8ee27258, 0x431021, 0xaee27258, +0x8ee27258, 0x8002a68, 0xaee27264, 0x10400073, +0x0, 0x8f830100, 0x27623000, 0x24640020, +0x82102b, 0x14400002, 0x5021, 0x27642800, +0x8f820108, 0x10820004, 0x0, 0x8f820104, +0x14820006, 0x24050005, 0x8ee201a8, 0x24420001, +0xaee201a8, 0x8002a4a, 0x8ee201a8, 0xac680000, +0xac690004, 0x8ee27264, 0xa467000e, 0xac650018, +0xac620008, 0x8ee204e8, 0xac660010, 0xac62001c, +0xaf840100, 0x92e204ec, 0x14400036, 0x240a0001, +0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021, +0x8c820000, 0x1445001f, 0x0, 0x8ee34e28, +0x8ee24e2c, 0x1062001b, 0x24030040, 0x8c820004, +0x24420001, 0xac820004, 0x8ee24e2c, 0x8ee54e28, +0x24420001, 0x10430007, 0x0, 0x8ee24e2c, +0x24420001, 0x10a20005, 0x0, 0x8002a34, +0x0, 0x14a00005, 0x0, 0x8f820108, +0x24420020, 0xaf820108, 0x8f820108, 0x8c820004, +0x2c420011, 0x50400013, 0xac800000, 0x8002a4a, +0x0, 0x8ee24e28, 0x24030040, 0x24420001, +0x50430003, 0x1021, 0x8ee24e28, 0x24420001, +0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38, +0x2e22021, 0x24020005, 0xac820000, 0x24020001, +0xac820004, 0x1540000c, 0x30e5ffff, 0x3c040001, +0x24844f18, 0x3c050004, 0xafa90010, 0xafa00014, +0x8ee604e4, 0x34a5f237, 0xc002407, 0x30e7ffff, +0x8002a76, 0x0, 0x8ee27264, 0x451021, +0xaee27264, 0x8ee2726c, 0x8ee37264, 0x3c040001, +0x34843800, 0xa2e004ed, 0x451023, 0xaee2726c, +0x3641021, 0x62182b, 0x14600004, 0x3c03ffff, +0x8ee27264, 0x431021, 0xaee27264, 0x8ee304e8, +0x96e20458, 0x24630001, 0x2442ffff, 0x621824, +0xaee304e8, 0x8ee304e8, 0x8ee204e0, 0x14620005, +0x0, 0x8f820060, 0x2403fff7, 0x431024, +0xaf820060, 0x8fbf0018, 0x3e00008, 0x27bd0020, +0x27bdffe0, 0xafbf001c, 0xafb00018, 0x8f820100, +0x8ee34e2c, 0x8f820104, 0x8f850108, 0x24020040, +0x24630001, 0x50620003, 0x1021, 0x8ee24e2c, +0x24420001, 0xaee24e2c, 0x8ee24e2c, 0x8ee34e2c, +0x210c0, 0x24424e38, 0x2e22021, 0x8ee24e28, +0x8c870004, 0x14620007, 0xa03021, 0x8f820108, +0x24420020, 0xaf820108, 0x8f820108, 0x8002aa6, +0xac800000, 0x8ee24e2c, 0x24030040, 0x24420001, +0x50430003, 0x1021, 0x8ee24e2c, 0x24420001, +0x210c0, 0x24424e38, 0x2e22021, 0x8c820004, +0x8f830108, 0x21140, 0x621821, 0xaf830108, +0xac800000, 0x8cc20018, 0x2443fffe, 0x2c620013, +0x104000c1, 0x31080, 0x3c010001, 0x220821, +0x8c224f40, 0x400008, 0x0, 0x8ee204f0, +0x471021, 0xaee204f0, 0x8ee204f0, 0x8f43023c, +0x43102b, 0x144000be, 0x0, 0x8ee304e4, +0x8ee204f8, 0x506200ba, 0xa2e004f4, 0x8f830120, +0x27623800, 0x24660020, 0xc2102b, 0x50400001, +0x27663000, 0x8f820128, 0x10c20004, 0x0, +0x8f820124, 0x14c20007, 0x0, 0x8ee201a4, +0x8021, 0x24420001, 0xaee201a4, 0x8002b16, +0x8ee201a4, 0x8ee204e4, 0xac62001c, 0x8ee404b0, +0x8ee504b4, 0x2462001c, 0xac620008, 0x24020008, +0xa462000e, 0x24020011, 0xac620018, 0xac640000, +0xac650004, 0x8ee204c4, 0xac620010, 0xaf860120, +0x92e24e20, 0x14400037, 0x24100001, 0x8ee24e30, +0x210c0, 0x24425038, 0x2e22021, 0x8c830000, +0x24020012, 0x1462001f, 0x0, 0x8ee34e30, +0x8ee24e34, 0x1062001b, 0x24030040, 0x8c820004, +0x24420001, 0xac820004, 0x8ee24e34, 0x8ee54e30, +0x24420001, 0x10430007, 0x0, 0x8ee24e34, +0x24420001, 0x10a20005, 0x0, 0x8002b00, +0x0, 0x14a00005, 0x0, 0x8f820128, +0x24420020, 0xaf820128, 0x8f820128, 0x8c820004, +0x2c420011, 0x50400013, 0xac800000, 0x8002b16, +0x0, 0x8ee24e30, 0x24030040, 0x24420001, +0x50430003, 0x1021, 0x8ee24e30, 0x24420001, +0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, +0x2e22021, 0x24020012, 0xac820000, 0x24020001, +0xac820004, 0x5600000b, 0x24100001, 0x8ee204e4, +0x3c040001, 0x24844f24, 0xafa00014, 0xafa20010, +0x8ee60608, 0x8f470228, 0x3c050009, 0xc002407, +0x34a5f006, 0x16000003, 0x24020001, 0x8002b75, +0xa2e204f4, 0x8ee20170, 0x24420001, 0xaee20170, +0x8ee20170, 0x8ee204e4, 0xa2e004f4, 0xaee004f0, +0xaee204f8, 0x8f42023c, 0x50400045, 0xaee07274, +0x8ee20184, 0x24420001, 0xaee20184, 0x8ee20184, +0x8002b75, 0xaee07274, 0x8ee20504, 0x24030040, +0x24420001, 0x50430003, 0x1021, 0x8ee20504, +0x24420001, 0xaee20504, 0x8ee20504, 0x8cc30018, +0x21080, 0x571021, 0x8c440508, 0x24020003, +0x1462000f, 0x0, 0x3c020001, 0x571021, +0x904283b1, 0x10400014, 0x0, 0x8ee201d0, +0x8ee35240, 0x441021, 0xaee201d0, 0x8ee201d8, +0x641821, 0x306300ff, 0x8002b5d, 0xaee35240, +0x8ee201cc, 0x8ee30e10, 0x441021, 0xaee201cc, +0x8ee201d8, 0x641821, 0x306301ff, 0xaee30e10, +0x441021, 0xaee201d8, 0x8ee20000, 0x34420040, +0x8002b75, 0xaee20000, 0x8ee2014c, 0x3c010001, +0x370821, 0xa02083e0, 0x24420001, 0xaee2014c, +0x8002b75, 0x8ee2014c, 0x94c7000e, 0x8cc2001c, +0x3c040001, 0x24844f30, 0xafa60014, 0xafa20010, +0x8cc60018, 0x3c050008, 0xc002407, 0x34a50910, +0x8fbf001c, 0x8fb00018, 0x3e00008, 0x27bd0020, +0x27bdff98, 0xafbf0060, 0xafbe005c, 0xafb60058, +0xafb50054, 0xafb40050, 0xafb3004c, 0xafb20048, +0xafb10044, 0xafb00040, 0x8f830108, 0x8f820104, +0xafa00024, 0x106203e7, 0xafa0002c, 0x3c1e0001, +0x37de3800, 0x3c0bffff, 0x8f930108, 0x8e620018, +0x8f830104, 0x2443fffe, 0x2c620014, 0x104003cf, +0x31080, 0x3c010001, 0x220821, 0x8c224f90, +0x400008, 0x0, 0x9663000e, 0x8ee2725c, +0x8ee404f0, 0x431021, 0xaee2725c, 0x8e63001c, +0x96e20458, 0x24840001, 0xaee404f0, 0x24630001, +0x2442ffff, 0x621824, 0xaee304e4, 0x8f42023c, +0x82202b, 0x148003b9, 0x0, 0x8f830120, +0x27623800, 0x24660020, 0xc2102b, 0x50400001, +0x27663000, 0x8f820128, 0x10c20004, 0x0, +0x8f820124, 0x14c20007, 0x0, 0x8ee201a4, +0x8021, 0x24420001, 0xaee201a4, 0x8002c02, +0x8ee201a4, 0x8ee204e4, 0xac62001c, 0x8ee404b0, +0x8ee504b4, 0x2462001c, 0xac620008, 0x24020008, +0xa462000e, 0x24020011, 0xac620018, 0xac640000, +0xac650004, 0x8ee204c4, 0xac620010, 0xaf860120, +0x92e24e20, 0x14400037, 0x24100001, 0x8ee24e30, +0x210c0, 0x24425038, 0x2e22021, 0x8c830000, +0x24020012, 0x1462001f, 0x0, 0x8ee34e30, +0x8ee24e34, 0x1062001b, 0x240c0040, 0x8c820004, +0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30, +0x24420001, 0x104c0007, 0x0, 0x8ee24e34, +0x24420001, 0x10620005, 0x0, 0x8002bec, +0x0, 0x14600005, 0x0, 0x8f820128, +0x24420020, 0xaf820128, 0x8f820128, 0x8c820004, +0x2c420011, 0x50400013, 0xac800000, 0x8002c02, +0x0, 0x8ee24e30, 0x240c0040, 0x24420001, +0x504c0003, 0x1021, 0x8ee24e30, 0x24420001, +0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, +0x2e22021, 0x24020012, 0x240c0001, 0xac820000, +0xac8c0004, 0x5600000d, 0x24100001, 0x8ee204e4, +0x3c040001, 0x24844f24, 0xafa00014, 0xafa20010, +0x8ee60608, 0x8f470228, 0x3c050009, 0x34a5f006, +0xc002407, 0xafab0038, 0x8fab0038, 0x1200030a, +0x240c0001, 0x8002f1d, 0x0, 0x966c001c, +0xafac002c, 0x9662001e, 0x3c0c8000, 0xafac0024, +0xae62001c, 0x8e75001c, 0x8ee204fc, 0x8ee404fc, +0x151900, 0x621021, 0x8c52000c, 0x92e27b98, +0x641821, 0x9476000a, 0x14400003, 0x32c20002, +0xaef27ba4, 0xaef57b9c, 0x1040004b, 0x8021, +0x96e2045a, 0x30420002, 0x10400047, 0x0, +0x8e63001c, 0x8ee204fc, 0x32100, 0x821021, +0x8c42000c, 0x37e1821, 0x24420022, 0x43102b, +0x1440000a, 0x24050014, 0x8ee204fc, 0x821021, +0x8c44000c, 0xafab0038, 0xc002f79, 0x2484000e, +0x8fab0038, 0x8002c56, 0x3050ffff, 0x8ee204fc, +0x821021, 0x8c42000c, 0x9450000e, 0x94430010, +0x94440012, 0x94450014, 0x2038021, 0x2048021, +0x2058021, 0x94430016, 0x94440018, 0x9445001a, +0x2038021, 0x2048021, 0x2058021, 0x9443001c, +0x9444001e, 0x94420020, 0x2038021, 0x2048021, +0x2028021, 0x101c02, 0x3202ffff, 0x628021, +0x8e63001c, 0x8ee204fc, 0x102402, 0x32900, +0xa21021, 0x8c43000c, 0x3202ffff, 0x828021, +0x37e1021, 0x24630018, 0x62182b, 0x14600009, +0x0, 0x8ee204fc, 0xa21021, 0x8c43000c, +0x101027, 0x3c01ffff, 0x230821, 0x8002c73, +0xa4220018, 0x8ee204fc, 0xa21021, 0x8c43000c, +0x101027, 0xa4620018, 0x96e2045a, 0x8821, +0x30420008, 0x14400063, 0xa021, 0x8e63001c, +0x8ee204fc, 0x33100, 0xc21021, 0x8c42000c, +0x37e1821, 0x24420022, 0x43102b, 0x14400035, +0x0, 0x8ee204fc, 0xc21021, 0x8c42000c, +0x24470010, 0x37e1021, 0xe2102b, 0x50400001, +0xeb3821, 0x8ee204fc, 0x94f10000, 0xc21021, +0x8c42000c, 0x24470016, 0x37e1021, 0xe2102b, +0x14400002, 0x2634ffec, 0xeb3821, 0x8ee204fc, +0x90e30001, 0xc21021, 0x8c42000c, 0x2447001a, +0x37e1021, 0xe2102b, 0x14400002, 0x2838821, +0xeb3821, 0x94e20000, 0x24e70002, 0x2228821, +0x37e1021, 0xe2102b, 0x50400001, 0xeb3821, +0x94e20000, 0x24e70002, 0x2228821, 0x37e1021, +0xe2102b, 0x50400001, 0xeb3821, 0x94e20000, +0x24e70002, 0x2228821, 0x37e1021, 0xe2102b, +0x50400001, 0xeb3821, 0x94e20000, 0x8002cd4, +0x2228821, 0x8ee204fc, 0xc21021, 0x8c43000c, +0x8ee204fc, 0x94710010, 0x8ee304fc, 0xc21021, +0x8c44000c, 0xc31821, 0x8c62000c, 0x2634ffec, +0x90840017, 0x8ee304fc, 0x9442001a, 0x2848821, +0xc31821, 0x8c65000c, 0x8ee304fc, 0x2228821, +0x8ee204fc, 0xc31821, 0xc21021, 0x8c44000c, +0x8c62000c, 0x94a3001c, 0x9484001e, 0x94420020, +0x2238821, 0x2248821, 0x2228821, 0x111c02, +0x3222ffff, 0x628821, 0x111c02, 0x3222ffff, +0x628821, 0x32c20001, 0x104000b2, 0x0, +0x96e2045a, 0x30420001, 0x104000ae, 0x32c20080, +0x10400008, 0x0, 0x92e27b98, 0x14400005, +0x0, 0x240c0001, 0xa2ec7b98, 0xaef57b9c, +0xaef27ba4, 0x8ee304fc, 0x151100, 0x431021, +0x8c47000c, 0x37e1821, 0x24e2000e, 0x43102b, +0x14400008, 0xe02021, 0x2405000e, 0xc002f79, +0xafab0038, 0x3042ffff, 0x8fab0038, 0x8002d0d, +0x2028021, 0x94e60000, 0x24e70002, 0x94e50000, +0x24e70002, 0x94e30000, 0x24e70002, 0x94e20000, +0x24e70002, 0x94e40000, 0x24e70002, 0x2068021, +0x2058021, 0x2038021, 0x2028021, 0x94e20000, +0x94e30002, 0x2048021, 0x2028021, 0x2038021, +0x101c02, 0x3202ffff, 0x628021, 0x101c02, +0x3202ffff, 0x8ee47b9c, 0x628021, 0x14950004, +0x3205ffff, 0x96620016, 0x8002d1b, 0x512021, +0x96620016, 0x542021, 0x41402, 0x3083ffff, +0x432021, 0x852023, 0x41402, 0x822021, +0x3084ffff, 0x50800001, 0x3404ffff, 0x8ee27ba4, +0x24430017, 0x37e1021, 0x62102b, 0x50400001, +0x6b1821, 0x90630000, 0x24020011, 0x14620031, +0x24020006, 0x8ee27ba4, 0x37e1821, 0x24420028, +0x43102b, 0x14400018, 0x0, 0x8ee27b9c, +0x12a2000a, 0x32c20100, 0x8ee27ba4, 0x3c01ffff, +0x220821, 0x94220028, 0x822021, 0x41c02, +0x3082ffff, 0x622021, 0x32c20100, 0x14400004, +0x41027, 0x92e27b98, 0x14400002, 0x41027, +0x3044ffff, 0x8ee27ba4, 0x3c01ffff, 0x220821, +0x8002d8e, 0xa4240028, 0x8ee27b9c, 0x12a20008, +0x32c20100, 0x8ee27ba4, 0x94420028, 0x822021, +0x41c02, 0x3082ffff, 0x622021, 0x32c20100, +0x14400004, 0x41027, 0x92e27b98, 0x14400002, +0x41027, 0x3044ffff, 0x8ee27ba4, 0x8002d8e, +0xa4440028, 0x1462002f, 0x37e1821, 0x8ee27ba4, +0x24420032, 0x43102b, 0x14400018, 0x0, +0x8ee27b9c, 0x12a2000a, 0x32c20100, 0x8ee27ba4, +0x3c01ffff, 0x220821, 0x94220032, 0x822021, +0x41c02, 0x3082ffff, 0x622021, 0x32c20100, +0x14400004, 0x41027, 0x92e27b98, 0x14400002, +0x41027, 0x3044ffff, 0x8ee27ba4, 0x3c01ffff, +0x220821, 0x8002d8e, 0xa4240032, 0x8ee27b9c, +0x12a20008, 0x32c20100, 0x8ee27ba4, 0x94420032, +0x822021, 0x41c02, 0x3082ffff, 0x622021, +0x32c20100, 0x14400004, 0x41027, 0x92e27b98, +0x14400002, 0x41027, 0x3044ffff, 0x8ee27ba4, +0xa4440032, 0x8fac0024, 0x1180002c, 0x37e1821, +0x8e420000, 0xae42fffc, 0x2642000a, 0x43102b, +0x1440001b, 0x34038100, 0x26430004, 0x37e1021, +0x62102b, 0x14400003, 0x602021, 0x6b1821, +0x602021, 0x8c620000, 0x24630004, 0xae420000, +0x37e1021, 0x62102b, 0x50400001, 0x6b1821, +0x8c620000, 0xac820000, 0x34028100, 0xa4620000, +0x24630002, 0x37e1021, 0x62102b, 0x50400001, +0x6b1821, 0x97ac002e, 0x8002db8, 0xa46c0000, +0x8e420004, 0x8e440008, 0xa6430008, 0x97ac002e, +0xa64c000a, 0xae420000, 0xae440004, 0x9662000e, +0x2652fffc, 0x24420004, 0xa662000e, 0x9662000e, +0x8ee3725c, 0x621821, 0xaee3725c, 0xafb20018, +0x8ee3725c, 0xafa3001c, 0x8ee2725c, 0x2c42003c, +0x10400004, 0x24620001, 0x2403fffe, 0x431024, +0xafa2001c, 0x32c20080, 0x1040000c, 0x32c20100, +0x8ee27ba8, 0x24430001, 0x210c0, 0x571021, +0xaee37ba8, 0x8fa30018, 0x8fa4001c, 0xac437bac, +0xac447bb0, 0x8002ea4, 0xaee0725c, 0x10400072, +0x0, 0x8ee27ba8, 0x24430001, 0x210c0, +0x571021, 0xaee37ba8, 0x8fa30018, 0x8fa4001c, +0xac437bac, 0xac447bb0, 0x8ee27ba8, 0x10400063, +0x4821, 0x5021, 0x8f8200f0, 0x24480008, +0x27621800, 0x102102b, 0x50400001, 0x27681000, +0x8f8200f4, 0x15020007, 0x0, 0x8ee201b4, +0x8021, 0x24420001, 0xaee201b4, 0x8002dfe, +0x8ee201b4, 0x8f8300f0, 0x24100001, 0x1571021, +0x8c447bac, 0x8c457bb0, 0xac640000, 0xac650004, +0xaf8800f0, 0x16000006, 0x2ea1021, 0x8ee20088, +0x24420001, 0xaee20088, 0x8002e43, 0x8ee20088, +0x8c427bb0, 0x8ee400e0, 0x8ee500e4, 0x8ee67b9c, +0x401821, 0x1021, 0xa32821, 0xa3382b, +0x822021, 0x872021, 0x8ee204fc, 0xc93021, +0x63100, 0xaee400e0, 0xaee500e4, 0xc23021, +0x94c2000a, 0x240c0002, 0x21142, 0x30430003, +0x106c0016, 0x28620003, 0x10400005, 0x240c0001, +0x106c0008, 0x0, 0x8002e43, 0x0, +0x240c0003, 0x106c0017, 0x0, 0x8002e43, +0x0, 0x8ee200e8, 0x8ee300ec, 0x24630001, +0x2c640001, 0x441021, 0xaee200e8, 0xaee300ec, +0x8ee200e8, 0x8002e43, 0x8ee300ec, 0x8ee200f0, +0x8ee300f4, 0x24630001, 0x2c640001, 0x441021, +0xaee200f0, 0xaee300f4, 0x8ee200f0, 0x8002e43, +0x8ee300f4, 0x8ee200f8, 0x8ee300fc, 0x24630001, +0x2c640001, 0x441021, 0xaee200f8, 0xaee300fc, +0x8ee200f8, 0x8ee300fc, 0x8ee27ba8, 0x25290001, +0x122102b, 0x1440ffa0, 0x254a0008, 0xa2e07b98, +0x8002ea3, 0xaee07ba8, 0x8f8200f0, 0x24470008, +0x27621800, 0xe2102b, 0x50400001, 0x27671000, +0x8f8200f4, 0x14e20007, 0x0, 0x8ee201b4, +0x8021, 0x24420001, 0xaee201b4, 0x8002e61, +0x8ee201b4, 0x8f8200f0, 0x24100001, 0x8fa30018, +0x8fa4001c, 0xac430000, 0xac440004, 0xaf8700f0, +0x16000007, 0x0, 0x8ee20088, 0x24420001, +0xaee20088, 0x8ee20088, 0x8002ea4, 0xaee0725c, +0x8ee2725c, 0x8ee400e0, 0x8ee500e4, 0x240c0002, +0x401821, 0x1021, 0xa32821, 0xa3302b, +0x822021, 0x862021, 0x161142, 0x30430003, +0xaee400e0, 0xaee500e4, 0x106c0017, 0x2c620003, +0x10400005, 0x240c0001, 0x106c0008, 0x0, +0x8002ea4, 0xaee0725c, 0x240c0003, 0x106c0019, +0x0, 0x8002ea4, 0xaee0725c, 0x8ee200e8, +0x8ee300ec, 0x24630001, 0x2c640001, 0x441021, +0xaee200e8, 0xaee300ec, 0x8ee200e8, 0x8ee300ec, +0x8002ea4, 0xaee0725c, 0x8ee200f0, 0x8ee300f4, +0x24630001, 0x2c640001, 0x441021, 0xaee200f0, +0xaee300f4, 0x8ee200f0, 0x8ee300f4, 0x8002ea4, +0xaee0725c, 0x8ee200f8, 0x8ee300fc, 0x24630001, +0x2c640001, 0x441021, 0xaee200f8, 0xaee300fc, +0x8ee200f8, 0x8ee300fc, 0xaee0725c, 0x8e62001c, +0x96e30458, 0x8ee404f0, 0x24420001, 0x2463ffff, +0x431024, 0x24840001, 0xaee204e4, 0xaee404f0, +0x8f42023c, 0x82202b, 0x148000b0, 0x0, +0x8f830120, 0x27623800, 0x24660020, 0xc2102b, +0x50400001, 0x27663000, 0x8f820128, 0x10c20004, +0x0, 0x8f820124, 0x14c20007, 0x0, +0x8ee201a4, 0x8021, 0x24420001, 0xaee201a4, +0x8002f0b, 0x8ee201a4, 0x8ee204e4, 0xac62001c, +0x8ee404b0, 0x8ee504b4, 0x2462001c, 0xac620008, +0x24020008, 0xa462000e, 0x24020011, 0xac620018, +0xac640000, 0xac650004, 0x8ee204c4, 0xac620010, +0xaf860120, 0x92e24e20, 0x14400037, 0x24100001, +0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, +0x8c830000, 0x24020012, 0x1462001f, 0x0, +0x8ee34e30, 0x8ee24e34, 0x1062001b, 0x240c0040, +0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34, +0x8ee34e30, 0x24420001, 0x104c0007, 0x0, +0x8ee24e34, 0x24420001, 0x10620005, 0x0, +0x8002ef5, 0x0, 0x14600005, 0x0, +0x8f820128, 0x24420020, 0xaf820128, 0x8f820128, +0x8c820004, 0x2c420011, 0x50400013, 0xac800000, +0x8002f0b, 0x0, 0x8ee24e30, 0x240c0040, +0x24420001, 0x504c0003, 0x1021, 0x8ee24e30, +0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, +0x24425038, 0x2e22021, 0x24020012, 0x240c0001, +0xac820000, 0xac8c0004, 0x5600000d, 0x24100001, +0x8ee204e4, 0x3c040001, 0x24844f24, 0xafa00014, +0xafa20010, 0x8ee60608, 0x8f470228, 0x3c050009, +0x34a5f006, 0xc002407, 0xafab0038, 0x8fab0038, +0x16000003, 0x240c0001, 0x8002f60, 0xa2ec04f4, +0x8ee20170, 0x24420001, 0xaee20170, 0x8ee20170, +0x8ee204e4, 0xa2e004f4, 0xaee004f0, 0xaee07274, +0xaee204f8, 0x8f42023c, 0x10400038, 0x0, +0x8ee20184, 0x24420001, 0xaee20184, 0x8002f60, +0x8ee20184, 0x8ee20504, 0x240c0040, 0x24420001, +0x504c0003, 0x1021, 0x8ee20504, 0x24420001, +0xaee20504, 0x8ee20504, 0x8e630018, 0x240c0003, +0x21080, 0x571021, 0x146c000f, 0x8c440508, +0x3c020001, 0x571021, 0x904283b1, 0x10400014, +0x0, 0x8ee201d0, 0x8ee35240, 0x441021, +0xaee201d0, 0x8ee201d8, 0x641821, 0x306300ff, +0x8002f53, 0xaee35240, 0x8ee201cc, 0x8ee30e10, +0x441021, 0xaee201cc, 0x8ee201d8, 0x641821, +0x306301ff, 0xaee30e10, 0x441021, 0xaee201d8, +0x8ee20000, 0x34420040, 0x8002f60, 0xaee20000, +0x8ee2014c, 0x3c010001, 0x370821, 0xa02083e0, +0x24420001, 0xaee2014c, 0x8ee2014c, 0x8f820108, +0x24420020, 0xaf820108, 0x8f820108, 0x8f820108, +0x27633000, 0x43102b, 0x14400002, 0x27622800, +0xaf820108, 0x8f830108, 0x8f820104, 0x1462fc1e, +0x0, 0x8fbf0060, 0x8fbe005c, 0x8fb60058, +0x8fb50054, 0x8fb40050, 0x8fb3004c, 0x8fb20048, +0x8fb10044, 0x8fb00040, 0x3e00008, 0x27bd0068, +0x52843, 0x10a0000d, 0x3021, 0x3c030001, +0x34633800, 0x3c07ffff, 0x3631021, 0x82102b, +0x50400001, 0x872021, 0x94820000, 0x24840002, +0x24a5ffff, 0x14a0fff8, 0xc23021, 0x61c02, +0x30c2ffff, 0x623021, 0x61c02, 0x30c2ffff, +0x623021, 0x3e00008, 0x30c2ffff, 0x27bdff88, +0x240f0001, 0xafbf0070, 0xafbe006c, 0xafb60068, +0xafb50064, 0xafb40060, 0xafb3005c, 0xafb20058, +0xafb10054, 0xafb00050, 0xa3a00027, 0xafaf002c, +0x8ee204d4, 0x8021, 0x30420001, 0x1440002a, +0xa3a00037, 0x8f8700e0, 0x8f8800c4, 0x8f8200e8, +0xe22023, 0x2c821000, 0x50400001, 0x24841000, +0x420c2, 0x801821, 0x8ee400c8, 0x8ee500cc, +0x1021, 0xa32821, 0xa3302b, 0x822021, +0x862021, 0xaee400c8, 0xaee500cc, 0x8f8300c8, +0x3c02000a, 0x3442efff, 0x1032023, 0x44102b, +0x10400003, 0x3c02000a, 0x3442f000, 0x822021, +0x801821, 0x8ee400c0, 0x8ee500c4, 0x1021, +0xa32821, 0xa3302b, 0x822021, 0x862021, +0xaee400c0, 0xaee500c4, 0xaf8800c8, 0xaf8700e4, +0x80034d0, 0xaf8700e8, 0x3c020001, 0x571021, +0x904283c0, 0x1040000b, 0x0, 0x3c140001, +0x297a021, 0x8e9483c4, 0x3c130001, 0x2779821, +0x8e7383c8, 0x3c120001, 0x2579021, 0x8003197, +0x8e5283cc, 0x8f8300e0, 0x8f8200e4, 0x10430007, +0x8821, 0x8f8200e4, 0x24110001, 0x8c430000, +0x8c440004, 0xafa30018, 0xafa4001c, 0x1620000e, +0x3c02ffff, 0x8f8200c4, 0xafa20010, 0x8f8200c8, +0x3c040001, 0x24845040, 0xafa20014, 0x8f8600e0, +0x8f8700e4, 0x3c050006, 0xc002407, 0x34a5f000, +0x80034d0, 0x0, 0x8fa3001c, 0x8fb20018, +0x3074ffff, 0x2694fffc, 0x621024, 0x10400058, +0x2409821, 0x3c020080, 0x621024, 0x1040000a, +0x3c040040, 0x8ee2007c, 0x24420001, 0xaee2007c, +0x8ee2007c, 0x8ee201fc, 0x24420001, 0xaee201fc, +0x80034ca, 0x8ee201fc, 0x3c060004, 0x3c0b0001, +0x3c0a0002, 0x3c050010, 0x3c090008, 0x8ee20080, +0x3c080020, 0x34078000, 0x24420001, 0xaee20080, +0x8ee20080, 0x8fa2001c, 0x441824, 0x10660021, +0xc3102b, 0x14400007, 0x0, 0x106b0011, +0x0, 0x106a0015, 0x0, 0x800304d, +0x42042, 0x10650023, 0xa3102b, 0x14400005, +0x0, 0x10690019, 0x0, 0x800304d, +0x42042, 0x10680021, 0x0, 0x800304d, +0x42042, 0x8ee20034, 0x24420001, 0xaee20034, +0x8ee20034, 0x800304d, 0x42042, 0x8ee201ec, +0x24420001, 0xaee201ec, 0x8ee201ec, 0x800304d, +0x42042, 0x8ee201f0, 0x24420001, 0xaee201f0, +0x8ee201f0, 0x800304d, 0x42042, 0x8ee201f4, +0x24420001, 0xaee201f4, 0x8ee201f4, 0x800304d, +0x42042, 0x8ee20030, 0x24420001, 0xaee20030, +0x8ee20030, 0x800304d, 0x42042, 0x8ee201f8, +0x24420001, 0xaee201f8, 0x8ee201f8, 0x42042, +0x1087047c, 0x0, 0x8003012, 0x0, +0x3c020001, 0x571021, 0x904283b2, 0x14400084, +0x24020001, 0x3c030001, 0x771821, 0x906383b3, +0x1462007f, 0x3c020100, 0x8e430000, 0x621024, +0x1040006f, 0x2402ffff, 0x14620005, 0x24100001, +0x96430004, 0x3402ffff, 0x10620075, 0x0, +0x92e204d8, 0x14400072, 0x0, 0x3c020001, +0x571021, 0x8c4283b4, 0x28420005, 0x10400020, +0x3821, 0x3c020001, 0x571021, 0x8c4283b4, +0x18400016, 0x2821, 0x96660000, 0x520c0, +0x971021, 0x9442777e, 0x14460009, 0x971021, +0x94437780, 0x96620002, 0x14620005, 0x971021, +0x94437782, 0x96620004, 0x50620008, 0x24070001, +0x3c020001, 0x571021, 0x8c4283b4, 0x24a50001, +0xa2102a, 0x5440ffee, 0x520c0, 0x30e200ff, +0x10400440, 0x0, 0x80030d9, 0x0, +0x2402021, 0xc0022fe, 0x24050006, 0x3044001f, +0x428c0, 0x2e51021, 0x9442727c, 0x30424000, +0x14400434, 0xb71021, 0x9443727e, 0x96620000, +0x1462000b, 0x418c0, 0xb71021, 0x94437280, +0x96620002, 0x14620006, 0x418c0, 0xb71021, +0x94437282, 0x96620004, 0x10620035, 0x418c0, +0x2e31021, 0x9442727c, 0x30428000, 0x14400421, +0x2e31021, 0x944b727c, 0x96670000, 0xb28c0, +0xb71021, 0x9442737e, 0x80030bb, 0x3021, +0x420c0, 0x2e41021, 0x9443737c, 0x2e41021, +0x944b737c, 0x30638000, 0x14600010, 0xb28c0, +0xb71021, 0x9442737e, 0x1447fff5, 0x1602021, +0xb71021, 0x94437380, 0x96620002, 0x5462fff1, +0x420c0, 0xb71021, 0x94437382, 0x96620004, +0x5462ffec, 0x420c0, 0x24060001, 0x30c200ff, +0x10400400, 0x0, 0x80030d9, 0x0, +0x97430202, 0x96420000, 0x146203fa, 0x0, +0x97430204, 0x96420002, 0x146203f6, 0x0, +0x97430206, 0x96420004, 0x146203f2, 0x0, +0x92420000, 0x3a030001, 0x30420001, 0x431024, +0x10400074, 0x2402ffff, 0x8e630000, 0x14620004, +0x3402ffff, 0x96630004, 0x1062006f, 0x240f0002, +0x3c020001, 0x571021, 0x904283b2, 0x1440006a, +0x240f0003, 0x92e204d8, 0x54400068, 0xafaf002c, +0x3c020001, 0x571021, 0x8c4283b4, 0x28420005, +0x10400020, 0x3821, 0x3c020001, 0x571021, +0x8c4283b4, 0x18400016, 0x2821, 0x96660000, +0x520c0, 0x971021, 0x9442777e, 0x14460009, +0x971021, 0x94437780, 0x96620002, 0x14620005, +0x971021, 0x94437782, 0x96620004, 0x50620008, +0x24070001, 0x3c020001, 0x571021, 0x8c4283b4, +0x24a50001, 0xa2102a, 0x5440ffee, 0x520c0, +0x30e200ff, 0x14400044, 0x240f0003, 0x80034ca, +0x0, 0x2402021, 0xc0022fe, 0x24050006, +0x3044001f, 0x428c0, 0x2e51021, 0x9442727c, +0x30424000, 0x144003af, 0xb71021, 0x9443727e, +0x96620000, 0x1462000b, 0x418c0, 0xb71021, +0x94437280, 0x96620002, 0x14620006, 0x418c0, +0xb71021, 0x94437282, 0x96620004, 0x10620027, +0x418c0, 0x2e31021, 0x9442727c, 0x30428000, +0x1440039c, 0x2e31021, 0x944b727c, 0x96670000, +0xb28c0, 0xb71021, 0x9442737e, 0x8003140, +0x3021, 0x420c0, 0x2e41021, 0x9443737c, +0x2e41021, 0x944b737c, 0x30638000, 0x14600010, +0xb28c0, 0xb71021, 0x9442737e, 0x1447fff5, +0x1602021, 0xb71021, 0x94437380, 0x96620002, +0x5462fff1, 0x420c0, 0xb71021, 0x94437382, +0x96620004, 0x5462ffec, 0x420c0, 0x24060001, +0x30c200ff, 0x1040037b, 0x0, 0x8003153, +0x240f0003, 0x240f0001, 0xafaf002c, 0x8f420260, +0x54102b, 0x1040003a, 0x0, 0x8f8300e4, +0x8f8200e0, 0x10620003, 0x24630008, 0xaf8300e4, +0xaf8300e8, 0x8ee400c0, 0x8ee500c4, 0x2801821, +0x1021, 0xa32821, 0xa3302b, 0x822021, +0x862021, 0xaee400c0, 0xaee500c4, 0x8ee20058, +0x24420001, 0xaee20058, 0x8ee20058, 0x8ee2007c, +0x24420001, 0xaee2007c, 0x8ee2007c, 0x8f8200e0, +0xafa20010, 0x8f8200e4, 0x3c040001, 0x24845048, +0xafa20014, 0x8fa60018, 0x8fa7001c, 0x3c050006, +0xc002407, 0x34a5f003, 0x80034d0, 0x0, +0x8ee25240, 0xafa20010, 0x8ee25244, 0x3c040001, +0x24845054, 0xafa20014, 0x8ee60e10, 0x8ee70e18, +0x3c050006, 0xc002407, 0x34a5f002, 0x8ee201c0, +0x24420001, 0xaee201c0, 0x8ee20000, 0x8ee301c0, +0x2403ffbf, 0x431024, 0x8003474, 0xaee20000, +0x96e20468, 0x54102b, 0x10400003, 0x0, +0x240f0001, 0xa3af0027, 0x12800301, 0x24160007, +0x24150040, 0x241e0001, 0x240e0012, 0x8ee2724c, +0x8f430280, 0x24420001, 0x304207ff, 0x106202d3, +0x0, 0x93a20027, 0x10400014, 0x0, +0x8ee35240, 0x8ee25244, 0x10620009, 0x26ed5244, +0x8ee65244, 0x8ee35244, 0x21140, 0x24425248, +0x2e28021, 0x24630001, 0x80031c3, 0x306b00ff, +0x92e27248, 0x1440ffca, 0x0, 0x8ee201e0, +0x24420001, 0xaee201e0, 0x8ee201e0, 0x8ee30e10, +0x8ee20e18, 0x1062ffc2, 0x26ed0e18, 0x8ee60e18, +0x8ee30e18, 0x21140, 0x24420e20, 0x2e28021, +0x24630001, 0x306b01ff, 0x96e2046a, 0x30420010, +0x10400019, 0x0, 0x9642000c, 0x340f8100, +0x144f0015, 0x0, 0x3c020001, 0x571021, +0x904283c0, 0x14400010, 0x0, 0x9642000e, +0xa6020016, 0x8e420008, 0x8e430004, 0x8e440000, +0x2694fffc, 0xae42000c, 0xae430008, 0xae440004, +0x9602000e, 0x26730004, 0x240f0001, 0xa3af0037, +0x34420200, 0xa602000e, 0x8e020000, 0x8e030004, +0x3c040001, 0x34843800, 0x306a0007, 0x26a9823, +0x3641021, 0x262102b, 0x10400005, 0x28aa021, +0x2641023, 0x3621823, 0x3c020020, 0x439823, +0x26820007, 0x2404fff8, 0x9603000a, 0x446024, +0x6a1821, 0x6c102b, 0x10400002, 0x1803821, +0x603821, 0xae130018, 0x8f880120, 0x24e20007, +0x443824, 0x27623800, 0x25090020, 0x122102b, +0x50400001, 0x27693000, 0x8f820128, 0x11220004, +0x0, 0x8f820124, 0x15220007, 0x1401821, +0x8ee201a4, 0x8821, 0x24420001, 0xaee201a4, +0x8003250, 0x8ee201a4, 0x8e040000, 0x8e050004, +0x1021, 0xad130008, 0xa507000e, 0xad160018, +0xad06001c, 0xa3302b, 0xa32823, 0x822023, +0x862023, 0xad040000, 0xad050004, 0x8ee204c0, +0xad020010, 0xaf890120, 0x92e24e20, 0x14400033, +0x24110001, 0x8ee24e30, 0x210c0, 0x24425038, +0x2e22021, 0x8c820000, 0x1456001f, 0x0, +0x8ee34e30, 0x8ee24e34, 0x1062001b, 0x0, +0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34, +0x8ee34e30, 0x24420001, 0x10550007, 0x0, +0x8ee24e34, 0x24420001, 0x10620005, 0x0, +0x800323d, 0x0, 0x14600005, 0x0, +0x8f820128, 0x24420020, 0xaf820128, 0x8f820128, +0x8c820004, 0x2c420011, 0x50400010, 0xac800000, +0x8003250, 0x0, 0x8ee24e30, 0x24420001, +0x50550003, 0x1021, 0x8ee24e30, 0x24420001, +0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, +0x2e22021, 0xac960000, 0xac9e0004, 0x16200018, +0x3c050006, 0x8e020018, 0x3c040001, 0x24845060, +0xafa20010, 0x8e020000, 0x8e030004, 0x34a5f009, +0x2003021, 0xc002407, 0xafa30014, 0x93a20037, +0x10400216, 0x340f8100, 0x8e420004, 0x8e430008, +0x8e44000c, 0xa64f000c, 0xae420000, 0xae430004, +0xae440008, 0x96020016, 0x8003474, 0xa642000e, +0x14ec0168, 0x28a1823, 0x960c000a, 0x9603000e, +0x28a1023, 0xa602000a, 0x34620004, 0xa602000e, +0x8f880120, 0x27623800, 0x25090020, 0x122102b, +0x14400002, 0x306affff, 0x27693000, 0x8f820128, +0x11220004, 0x0, 0x8f820124, 0x15220007, +0x24040020, 0x8ee201a4, 0x8821, 0x24420001, +0xaee201a4, 0x80032ce, 0x8ee201a4, 0x8ee5724c, +0x8ee60490, 0x8ee70494, 0xa504000e, 0x24040004, +0xad100008, 0xad040018, 0x52940, 0xa01821, +0x1021, 0xe33821, 0xe3202b, 0xc23021, +0xc43021, 0xad060000, 0xad070004, 0x8ee2724c, +0xad02001c, 0x8ee204c4, 0xad020010, 0xaf890120, +0x92e24e20, 0x14400033, 0x24110001, 0x8ee24e30, +0x210c0, 0x24425038, 0x2e22021, 0x8c820000, +0x1456001f, 0x0, 0x8ee34e30, 0x8ee24e34, +0x1062001b, 0x0, 0x8c820004, 0x24420001, +0xac820004, 0x8ee24e34, 0x8ee34e30, 0x24420001, +0x10550007, 0x0, 0x8ee24e34, 0x24420001, +0x10620005, 0x0, 0x80032bb, 0x0, +0x14600005, 0x0, 0x8f820128, 0x24420020, +0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011, +0x50400010, 0xac800000, 0x80032ce, 0x0, +0x8ee24e30, 0x24420001, 0x50550003, 0x1021, +0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30, +0x210c0, 0x24425038, 0x2e22021, 0xac960000, +0xac9e0004, 0x1620000d, 0x0, 0xa60c000a, +0xa60a000e, 0x8f820100, 0xafa20010, 0x8f820104, +0x3c040001, 0x2484506c, 0x3c050006, 0xafa20014, +0x8ee6724c, 0x800343f, 0x34a5f00b, 0x3c010001, +0x370821, 0xa02083c0, 0xadab0000, 0x8ee201d8, +0x8ee3724c, 0x2442ffff, 0xaee201d8, 0x8ee201d8, +0x24630001, 0x306307ff, 0x26e25244, 0x15a20006, +0xaee3724c, 0x8ee201d0, 0x2442ffff, 0xaee201d0, +0x80032f3, 0x8ee201d0, 0x8ee201cc, 0x2442ffff, +0xaee201cc, 0x8ee201cc, 0x8f420240, 0x10400073, +0x0, 0x8ee20e1c, 0x24420001, 0xaee20e1c, +0x8f430240, 0x43102b, 0x14400176, 0xa021, +0x8f830120, 0x27623800, 0x24660020, 0xc2102b, +0x50400001, 0x27663000, 0x8f820128, 0x10c20004, +0x0, 0x8f820124, 0x14c20007, 0x0, +0x8ee201a4, 0x8821, 0x24420001, 0xaee201a4, +0x8003353, 0x8ee201a4, 0x8ee2724c, 0xac62001c, +0x8ee404a8, 0x8ee504ac, 0x2462001c, 0xac620008, +0x24020008, 0xa462000e, 0x24020011, 0xac620018, +0xac640000, 0xac650004, 0x8ee204c4, 0xac620010, +0xaf860120, 0x92e24e20, 0x14400033, 0x24110001, +0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, +0x8c820000, 0x144e001f, 0x0, 0x8ee34e30, +0x8ee24e34, 0x1062001b, 0x0, 0x8c820004, +0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30, +0x24420001, 0x10550007, 0x0, 0x8ee24e34, +0x24420001, 0x10620005, 0x0, 0x8003340, +0x0, 0x14600005, 0x0, 0x8f820128, +0x24420020, 0xaf820128, 0x8f820128, 0x8c820004, +0x2c420011, 0x50400010, 0xac800000, 0x8003353, +0x0, 0x8ee24e30, 0x24420001, 0x50550003, +0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30, +0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, +0xac8e0000, 0xac9e0004, 0x5620000d, 0x24110001, +0x8ee2724c, 0x3c040001, 0x24845078, 0xafa00014, +0xafa20010, 0x8ee6724c, 0x8f470280, 0x3c050009, +0x34a5f008, 0xc002407, 0xafae0048, 0x8fae0048, +0x56200001, 0xaee00e1c, 0x8ee20188, 0x24420001, +0xaee20188, 0x80033cc, 0x8ee20188, 0x8f830120, +0x27623800, 0x24660020, 0xc2102b, 0x50400001, +0x27663000, 0x8f820128, 0x10c20004, 0x0, +0x8f820124, 0x14c20007, 0x0, 0x8ee201a4, +0x8821, 0x24420001, 0xaee201a4, 0x80033be, +0x8ee201a4, 0x8ee2724c, 0xac62001c, 0x8ee404a8, +0x8ee504ac, 0x2462001c, 0xac620008, 0x24020008, +0xa462000e, 0x24020011, 0xac620018, 0xac640000, +0xac650004, 0x8ee204c4, 0xac620010, 0xaf860120, +0x92e24e20, 0x14400033, 0x24110001, 0x8ee24e30, +0x210c0, 0x24425038, 0x2e22021, 0x8c820000, +0x144e001f, 0x0, 0x8ee34e30, 0x8ee24e34, +0x1062001b, 0x0, 0x8c820004, 0x24420001, +0xac820004, 0x8ee24e34, 0x8ee34e30, 0x24420001, +0x10550007, 0x0, 0x8ee24e34, 0x24420001, +0x10620005, 0x0, 0x80033ab, 0x0, +0x14600005, 0x0, 0x8f820128, 0x24420020, +0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011, +0x50400010, 0xac800000, 0x80033be, 0x0, +0x8ee24e30, 0x24420001, 0x50550003, 0x1021, +0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30, +0x210c0, 0x24425038, 0x2e22021, 0xac8e0000, +0xac9e0004, 0x1620000d, 0x0, 0x8ee2724c, +0x3c040001, 0x24845078, 0xafa00014, 0xafa20010, +0x8ee6724c, 0x8f470280, 0x3c050009, 0x34a5f008, +0xc002407, 0xafae0048, 0x8fae0048, 0x8ee20174, +0x24420001, 0xaee20174, 0x8ee20174, 0x8003472, +0xa021, 0x960c000a, 0x183102b, 0x54400001, +0x1801821, 0xa603000a, 0x8f880120, 0x27623800, +0x25090020, 0x122102b, 0x50400001, 0x27693000, +0x8f820128, 0x11220004, 0x0, 0x8f820124, +0x15220007, 0x24040020, 0x8ee201a4, 0x8821, +0x24420001, 0xaee201a4, 0x8003433, 0x8ee201a4, +0x8ee5724c, 0x8ee60490, 0x8ee70494, 0xa504000e, +0x24040004, 0xad100008, 0xad040018, 0x52940, +0xa01821, 0x1021, 0xe33821, 0xe3202b, +0xc23021, 0xc43021, 0xad060000, 0xad070004, +0x8ee2724c, 0xad02001c, 0x8ee204c4, 0xad020010, +0xaf890120, 0x92e24e20, 0x14400033, 0x24110001, +0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, +0x8c820000, 0x1456001f, 0x0, 0x8ee34e30, +0x8ee24e34, 0x1062001b, 0x0, 0x8c820004, +0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30, +0x24420001, 0x10550007, 0x0, 0x8ee24e34, +0x24420001, 0x10620005, 0x0, 0x8003420, +0x0, 0x14600005, 0x0, 0x8f820128, +0x24420020, 0xaf820128, 0x8f820128, 0x8c820004, +0x2c420011, 0x50400010, 0xac800000, 0x8003433, +0x0, 0x8ee24e30, 0x24420001, 0x50550003, +0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30, +0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, +0xac960000, 0xac9e0004, 0x1620001d, 0x0, +0xa60c000a, 0x8f820100, 0xafa20010, 0x8f820104, +0x3c040001, 0x2484506c, 0x3c050006, 0xafa20014, +0x8ee6724c, 0x34a5f00d, 0xc002407, 0x2003821, +0x93a20037, 0x10400031, 0x340f8100, 0x8e420004, +0x8e430008, 0x8e44000c, 0xa64f000c, 0xae420000, +0xae430004, 0xae440008, 0x96020016, 0xa642000e, +0x9602000e, 0x3042fdff, 0x8003474, 0xa602000e, +0x8ee201d8, 0x2442ffff, 0xaee201d8, 0x8ee201d8, +0x8ee201cc, 0x3c04001f, 0x3c010001, 0x370821, +0xa03e83c0, 0x2442ffff, 0xaee201cc, 0x9603000a, +0x3484ffff, 0x8ee201cc, 0x6a1821, 0x2639821, +0x93202b, 0x10800003, 0x3c02fff5, 0x34421000, +0x2629821, 0xadab0000, 0x8ee2724c, 0x24420001, +0x304207ff, 0xaee2724c, 0x8f420240, 0x10400004, +0x283a023, 0x8ee20e1c, 0x24420001, 0xaee20e1c, +0xa3a00027, 0x1680fd29, 0x0, 0x12800024, +0x0, 0x3c010001, 0x370821, 0xac3483c4, +0x3c010001, 0x370821, 0xac3383c8, 0x3c010001, +0x370821, 0xac3283cc, 0x93a20037, 0x10400008, +0x0, 0x3c020001, 0x571021, 0x8c4283cc, +0x24420004, 0x3c010001, 0x370821, 0xac2283cc, +0x8ee2724c, 0x8f430280, 0x24420001, 0x304207ff, +0x14620006, 0x0, 0x8ee201c4, 0x24420001, +0xaee201c4, 0x80034d0, 0x8ee201c4, 0x8ee201bc, +0x24420001, 0xaee201bc, 0x80034d0, 0x8ee201bc, +0x97a4001e, 0x2484fffc, 0x801821, 0x8ee400c0, +0x8ee500c4, 0x1021, 0xa32821, 0xa3302b, +0x822021, 0x862021, 0xaee400c0, 0xaee500c4, +0x8faf002c, 0x24020002, 0x11e2000f, 0x29e20003, +0x14400017, 0x24020003, 0x15e20015, 0x0, +0x8ee200d0, 0x8ee300d4, 0x24630001, 0x2c640001, +0x441021, 0xaee200d0, 0xaee300d4, 0x8ee200d0, +0x80034ca, 0x8ee300d4, 0x8ee200d8, 0x8ee300dc, +0x24630001, 0x2c640001, 0x441021, 0xaee200d8, +0xaee300dc, 0x8ee200d8, 0x80034ca, 0x8ee300dc, +0x8ee200c8, 0x8ee300cc, 0x24630001, 0x2c640001, +0x441021, 0xaee200c8, 0xaee300cc, 0x8ee200c8, +0x8ee300cc, 0x8f8300e4, 0x8f8200e0, 0x10620003, +0x24630008, 0xaf8300e4, 0xaf8300e8, 0x8fbf0070, +0x8fbe006c, 0x8fb60068, 0x8fb50064, 0x8fb40060, +0x8fb3005c, 0x8fb20058, 0x8fb10054, 0x8fb00050, +0x3e00008, 0x27bd0078, 0x27bdffb0, 0xafb50044, +0xa821, 0xafb00030, 0x8021, 0xafbf004c, +0xafb60048, 0xafb40040, 0xafb3003c, 0xafb20038, +0xafb10034, 0x8ee204d4, 0x24140001, 0x30420001, +0x1440002a, 0xb021, 0x8f8700e0, 0x8f8800c4, +0x8f8200e8, 0xe22023, 0x2c821000, 0x50400001, +0x24841000, 0x420c2, 0x801821, 0x8ee400c8, +0x8ee500cc, 0x1021, 0xa32821, 0xa3302b, +0x822021, 0x862021, 0xaee400c8, 0xaee500cc, +0x8f8300c8, 0x3c02000a, 0x3442efff, 0x1032023, +0x44102b, 0x10400003, 0x3c02000a, 0x3442f000, +0x822021, 0x801821, 0x8ee400c0, 0x8ee500c4, +0x1021, 0xa32821, 0xa3302b, 0x822021, +0x862021, 0xaee400c0, 0xaee500c4, 0xaf8800c8, +0xaf8700e4, 0x8003854, 0xaf8700e8, 0x3c020001, +0x571021, 0x904283c0, 0x1040000b, 0x0, +0x3c130001, 0x2779821, 0x8e7383c4, 0x3c110001, +0x2378821, 0x8e3183c8, 0x3c120001, 0x2579021, +0x80036ec, 0x8e5283cc, 0x8f8300e0, 0x8f8200e4, +0x10430007, 0x4821, 0x8f8200e4, 0x24090001, +0x8c430000, 0x8c440004, 0xafa30018, 0xafa4001c, +0x1520000e, 0x3c02ffff, 0x8f8200c4, 0xafa20010, +0x8f8200c8, 0x3c040001, 0x24845040, 0xafa20014, +0x8f8600e0, 0x8f8700e4, 0x3c050006, 0xc002407, +0x34a5f000, 0x8003854, 0x0, 0x8fa3001c, +0x8fb20018, 0x3073ffff, 0x2673fffc, 0x621024, +0x10400058, 0x2408821, 0x3c020080, 0x621024, +0x1040000a, 0x3c040040, 0x8ee2007c, 0x24420001, +0xaee2007c, 0x8ee2007c, 0x8ee201fc, 0x24420001, +0xaee201fc, 0x800384e, 0x8ee201fc, 0x3c060004, +0x3c0b0001, 0x3c0a0002, 0x3c050010, 0x3c090008, +0x8ee20080, 0x3c080020, 0x34078000, 0x24420001, +0xaee20080, 0x8ee20080, 0x8fa2001c, 0x441824, +0x10660021, 0xc3102b, 0x14400007, 0x0, +0x106b0011, 0x0, 0x106a0015, 0x0, +0x8003596, 0x42042, 0x10650023, 0xa3102b, +0x14400005, 0x0, 0x10690019, 0x0, +0x8003596, 0x42042, 0x10680021, 0x0, +0x8003596, 0x42042, 0x8ee20034, 0x24420001, +0xaee20034, 0x8ee20034, 0x8003596, 0x42042, +0x8ee201ec, 0x24420001, 0xaee201ec, 0x8ee201ec, +0x8003596, 0x42042, 0x8ee201f0, 0x24420001, +0xaee201f0, 0x8ee201f0, 0x8003596, 0x42042, +0x8ee201f4, 0x24420001, 0xaee201f4, 0x8ee201f4, +0x8003596, 0x42042, 0x8ee20030, 0x24420001, +0xaee20030, 0x8ee20030, 0x8003596, 0x42042, +0x8ee201f8, 0x24420001, 0xaee201f8, 0x8ee201f8, +0x42042, 0x108702b7, 0x0, 0x800355b, +0x0, 0x3c020001, 0x571021, 0x904283b2, +0x14400084, 0x24020001, 0x3c030001, 0x771821, +0x906383b3, 0x1462007f, 0x3c020100, 0x8e430000, +0x621024, 0x1040006f, 0x2402ffff, 0x14620005, +0x24100001, 0x96430004, 0x3402ffff, 0x10620075, +0x0, 0x92e204d8, 0x14400072, 0x0, +0x3c020001, 0x571021, 0x8c4283b4, 0x28420005, +0x10400020, 0x3821, 0x3c020001, 0x571021, +0x8c4283b4, 0x18400016, 0x2821, 0x96260000, +0x520c0, 0x971021, 0x9442777e, 0x14460009, +0x971021, 0x94437780, 0x96220002, 0x14620005, +0x971021, 0x94437782, 0x96220004, 0x50620008, +0x24070001, 0x3c020001, 0x571021, 0x8c4283b4, +0x24a50001, 0xa2102a, 0x5440ffee, 0x520c0, +0x30e200ff, 0x1040027b, 0x0, 0x8003622, +0x0, 0x2402021, 0xc0022fe, 0x24050006, +0x3044001f, 0x428c0, 0x2e51021, 0x9442727c, +0x30424000, 0x1440026f, 0xb71021, 0x9443727e, +0x96220000, 0x1462000b, 0x418c0, 0xb71021, +0x94437280, 0x96220002, 0x14620006, 0x418c0, +0xb71021, 0x94437282, 0x96220004, 0x10620035, +0x418c0, 0x2e31021, 0x9442727c, 0x30428000, +0x1440025c, 0x2e31021, 0x9448727c, 0x96270000, +0x828c0, 0xb71021, 0x9442737e, 0x8003604, +0x3021, 0x420c0, 0x2e41021, 0x9443737c, +0x2e41021, 0x9448737c, 0x30638000, 0x14600010, +0x828c0, 0xb71021, 0x9442737e, 0x1447fff5, +0x1002021, 0xb71021, 0x94437380, 0x96220002, +0x5462fff1, 0x420c0, 0xb71021, 0x94437382, +0x96220004, 0x5462ffec, 0x420c0, 0x24060001, +0x30c200ff, 0x1040023b, 0x0, 0x8003622, +0x0, 0x97430202, 0x96420000, 0x14620235, +0x0, 0x97430204, 0x96420002, 0x14620231, +0x0, 0x97430206, 0x96420004, 0x1462022d, +0x0, 0x92420000, 0x3a030001, 0x30420001, +0x431024, 0x10400074, 0x2402ffff, 0x8e230000, +0x14620004, 0x3402ffff, 0x96230004, 0x1062006f, +0x24140002, 0x3c020001, 0x571021, 0x904283b2, +0x1440006a, 0x24140003, 0x92e204d8, 0x14400067, +0x0, 0x3c020001, 0x571021, 0x8c4283b4, +0x28420005, 0x10400020, 0x3821, 0x3c020001, +0x571021, 0x8c4283b4, 0x18400016, 0x2821, +0x96260000, 0x520c0, 0x971021, 0x9442777e, +0x14460009, 0x971021, 0x94437780, 0x96220002, +0x14620005, 0x971021, 0x94437782, 0x96220004, +0x50620008, 0x24070001, 0x3c020001, 0x571021, +0x8c4283b4, 0x24a50001, 0xa2102a, 0x5440ffee, +0x520c0, 0x30e200ff, 0x14400044, 0x24140003, +0x800384e, 0x0, 0x2402021, 0xc0022fe, +0x24050006, 0x3044001f, 0x428c0, 0x2e51021, +0x9442727c, 0x30424000, 0x144001ea, 0xb71021, +0x9443727e, 0x96220000, 0x1462000b, 0x418c0, +0xb71021, 0x94437280, 0x96220002, 0x14620006, +0x418c0, 0xb71021, 0x94437282, 0x96220004, +0x10620027, 0x418c0, 0x2e31021, 0x9442727c, +0x30428000, 0x144001d7, 0x2e31021, 0x9448727c, +0x96270000, 0x828c0, 0xb71021, 0x9442737e, +0x8003689, 0x3021, 0x420c0, 0x2e41021, +0x9443737c, 0x2e41021, 0x9448737c, 0x30638000, +0x14600010, 0x828c0, 0xb71021, 0x9442737e, +0x1447fff5, 0x1002021, 0xb71021, 0x94437380, +0x96220002, 0x5462fff1, 0x420c0, 0xb71021, +0x94437382, 0x96220004, 0x5462ffec, 0x420c0, +0x24060001, 0x30c200ff, 0x104001b6, 0x0, +0x800369c, 0x24140003, 0x24140001, 0x8f420260, +0x53102b, 0x10400049, 0x0, 0x8f8300e4, +0x8f8200e0, 0x10620003, 0x24630008, 0xaf8300e4, +0xaf8300e8, 0x8ee400c0, 0x8ee500c4, 0x2601821, +0x1021, 0xa32821, 0xa3302b, 0x822021, +0x862021, 0xaee400c0, 0xaee500c4, 0x8ee20058, +0x24420001, 0xaee20058, 0x8ee20058, 0x8ee2007c, +0x24420001, 0xaee2007c, 0x8ee2007c, 0x8f8200e0, +0xafa20010, 0x8f8200e4, 0x3c040001, 0x24845048, +0xafa20014, 0x8fa60018, 0x8fa7001c, 0x3c050006, +0xc002407, 0x34a5f003, 0x8003854, 0x0, +0x8ee25240, 0xafa20010, 0x8ee25244, 0x3c040001, +0x24845054, 0xafa20014, 0x8ee60e10, 0x8ee70e18, +0xc002407, 0x34a5f002, 0x8ee201c0, 0x24420001, +0xaee201c0, 0x8ee20000, 0x8ee301c0, 0x2403ffbf, +0x431024, 0x80037fc, 0xaee20000, 0x8ee25240, +0xafa20010, 0x8ee25244, 0x3c040001, 0x24845054, +0xafa20014, 0x8ee60e10, 0x8ee70e18, 0x3c050006, +0xc002407, 0x34a5f002, 0x8ee201c0, 0x24420001, +0xaee201c0, 0x80037fc, 0x8ee201c0, 0x96e20468, +0x53102b, 0x54400001, 0x3c158000, 0x12600131, +0x3c0c001f, 0x358cffff, 0x8ee2724c, 0x8f430280, +0x24420001, 0x304207ff, 0x10620108, 0x0, +0x12a00014, 0x0, 0x8ee35240, 0x8ee25244, +0x10620009, 0x26ee5244, 0x8eeb5244, 0x8ee35244, +0x21140, 0x24425248, 0x2e28021, 0x24630001, +0x8003716, 0x306800ff, 0x92e27248, 0x1440ffc0, +0x3c050006, 0x8ee201e0, 0x24420001, 0xaee201e0, +0x8ee201e0, 0x8ee30e10, 0x8ee20e18, 0x1062ffcb, +0x26ee0e18, 0x8eeb0e18, 0xa821, 0x8ee30e18, +0x21140, 0x24420e20, 0x2e28021, 0x24630001, +0x306801ff, 0x96e2046a, 0x30420010, 0x10400017, +0x34028100, 0x9643000c, 0x14620014, 0x0, +0x3c020001, 0x571021, 0x904283c0, 0x1440000f, +0x0, 0x9642000e, 0xa6020016, 0x8e420008, +0x8e430004, 0x8e440000, 0x2673fffc, 0xae42000c, +0xae430008, 0xae440004, 0x9602000e, 0x26310004, +0x24160001, 0x34420200, 0xa602000e, 0x9603000a, +0x2605021, 0x73102b, 0x10400002, 0x2606821, +0x605021, 0x2d42003d, 0x1040002a, 0x3821, +0x9623000c, 0x24020800, 0x54620027, 0xae110018, +0x3c020001, 0x571021, 0x904283c0, 0x54400022, +0xae110018, 0x26220017, 0x182102b, 0x10400013, +0x0, 0x3c02fff5, 0x511021, 0x90421017, +0x38430006, 0x2c630001, 0x38420011, 0x2c420001, +0x621825, 0x10600013, 0x26220010, 0x182102b, +0x1040000e, 0x0, 0x3c07fff5, 0xf13821, +0x94e71010, 0x8003762, 0x24e7000e, 0x92220017, +0x38430006, 0x2c630001, 0x38420011, 0x2c420001, +0x621825, 0x50600004, 0xae110018, 0x96270010, +0x24e7000e, 0xae110018, 0x3c020001, 0x571021, +0x904283c0, 0x2102b, 0x14e00002, 0x24ec0, +0x1403821, 0x8f830120, 0x27623800, 0x24660020, +0xc2102b, 0x50400001, 0x27663000, 0x8f820128, +0x10c20004, 0x0, 0x8f820124, 0x14c20007, +0x2402000b, 0x8ee201a4, 0x4821, 0x24420001, +0xaee201a4, 0x80037c3, 0x8ee201a4, 0x8e040000, +0x8e050004, 0xac620018, 0x1751025, 0x491025, +0xac710008, 0xa467000e, 0xac62001c, 0xac640000, +0xac650004, 0x8ee204c0, 0xac620010, 0xaf860120, +0x92e24e20, 0x14400038, 0x24090001, 0x8ee24e30, +0x210c0, 0x24425038, 0x2e22021, 0x8c830000, +0x24020007, 0x14620020, 0x0, 0x8ee34e30, +0x8ee24e34, 0x1062001c, 0x0, 0x8c820004, +0x24420001, 0xac820004, 0x8ee34e34, 0x8ee54e30, +0x24020040, 0x24630001, 0x10620007, 0x0, +0x8ee24e34, 0x24420001, 0x10a20005, 0x0, +0x80037ad, 0x0, 0x14a00005, 0x0, +0x8f820128, 0x24420020, 0xaf820128, 0x8f820128, +0x8c820004, 0x2c420011, 0x50400013, 0xac800000, +0x80037c3, 0x0, 0x8ee24e30, 0x24030040, +0x24420001, 0x50430003, 0x1021, 0x8ee24e30, +0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, +0x24425038, 0x2e22021, 0x24020007, 0xac820000, +0x24020001, 0xac820004, 0x15200018, 0x3c050006, +0x8e020018, 0x3c040001, 0x24845060, 0xafa20010, +0x8e020000, 0x8e030004, 0x34a5f009, 0x2003021, +0xc002407, 0xafa30014, 0x32c200ff, 0x1040002b, +0x34028100, 0x8e430004, 0x8e440008, 0x8e45000c, +0xa642000c, 0xae430000, 0xae440004, 0xae450008, +0x96020016, 0x80037fc, 0xa642000e, 0x154d000a, +0x0, 0x9602000e, 0xa613000a, 0x34420004, +0xa602000e, 0x3c010001, 0x370821, 0xa02083c0, +0x80037fa, 0x9821, 0x9604000a, 0x93102b, +0x10400002, 0x2601821, 0x801821, 0x24020001, +0xa603000a, 0x3c010001, 0x370821, 0xa02283c0, +0x9604000a, 0x2248821, 0x191102b, 0x10400003, +0x3c02fff5, 0x34421000, 0x2228821, 0x2649823, +0xa821, 0x1660fef4, 0xadc80000, 0x12600021, +0x32c200ff, 0x3c010001, 0x370821, 0xac3383c4, +0x3c010001, 0x370821, 0xac3183c8, 0x3c010001, +0x370821, 0x10400008, 0xac3283cc, 0x3c020001, +0x571021, 0x8c4283cc, 0x24420004, 0x3c010001, +0x370821, 0xac2283cc, 0x8ee2724c, 0x8f430280, +0x24420001, 0x14620006, 0x0, 0x8ee201c4, +0x24420001, 0xaee201c4, 0x8003854, 0x8ee201c4, +0x8ee201bc, 0x24420001, 0xaee201bc, 0x8003854, +0x8ee201bc, 0x97a4001e, 0x2484fffc, 0x801821, +0x8ee400c0, 0x8ee500c4, 0x1021, 0xa32821, +0xa3302b, 0x822021, 0x862021, 0x24020002, +0xaee400c0, 0xaee500c4, 0x1282000f, 0x2a820003, +0x14400017, 0x24020003, 0x16820015, 0x0, +0x8ee200d0, 0x8ee300d4, 0x24630001, 0x2c640001, +0x441021, 0xaee200d0, 0xaee300d4, 0x8ee200d0, +0x800384e, 0x8ee300d4, 0x8ee200d8, 0x8ee300dc, +0x24630001, 0x2c640001, 0x441021, 0xaee200d8, +0xaee300dc, 0x8ee200d8, 0x800384e, 0x8ee300dc, +0x8ee200c8, 0x8ee300cc, 0x24630001, 0x2c640001, +0x441021, 0xaee200c8, 0xaee300cc, 0x8ee200c8, +0x8ee300cc, 0x8f8300e4, 0x8f8200e0, 0x10620003, +0x24630008, 0xaf8300e4, 0xaf8300e8, 0x8fbf004c, +0x8fb60048, 0x8fb50044, 0x8fb40040, 0x8fb3003c, +0x8fb20038, 0x8fb10034, 0x8fb00030, 0x3e00008, +0x27bd0050, 0x27bdff90, 0xafb60060, 0xb021, +0xafbf0068, 0xafbe0064, 0xafb5005c, 0xafb40058, +0xafb30054, 0xafb20050, 0xafb1004c, 0xafb00048, +0x8ee204d4, 0x8821, 0x24150001, 0x30420001, +0x1440002a, 0xa3a0002f, 0x8f8700e0, 0x8f8800c4, +0x8f8200e8, 0xe22023, 0x2c821000, 0x50400001, +0x24841000, 0x420c2, 0x801821, 0x8ee400c8, +0x8ee500cc, 0x1021, 0xa32821, 0xa3302b, +0x822021, 0x862021, 0xaee400c8, 0xaee500cc, +0x8f8300c8, 0x3c02000a, 0x3442efff, 0x1032023, +0x44102b, 0x10400003, 0x3c02000a, 0x3442f000, +0x822021, 0x801821, 0x8ee400c0, 0x8ee500c4, +0x1021, 0xa32821, 0xa3302b, 0x822021, +0x862021, 0xaee400c0, 0xaee500c4, 0xaf8800c8, +0xaf8700e4, 0x8003c5f, 0xaf8700e8, 0x3c020001, +0x571021, 0x904283c0, 0x1040000b, 0x0, +0x3c130001, 0x2779821, 0x8e7383c4, 0x3c100001, +0x2178021, 0x8e1083c8, 0x3c120001, 0x2579021, +0x8003a5d, 0x8e5283cc, 0x8f8300e0, 0x8f8200e4, +0x10430007, 0x3821, 0x8f8200e4, 0x24070001, +0x8c430000, 0x8c440004, 0xafa30018, 0xafa4001c, +0x14e0000e, 0x3c02ffff, 0x8f8200c4, 0xafa20010, +0x8f8200c8, 0x3c040001, 0x24845084, 0xafa20014, +0x8f8600e0, 0x8f8700e4, 0x3c050006, 0xc002407, +0x34a5f200, 0x8003c5f, 0x0, 0x8fa3001c, +0x8fb20018, 0x3073ffff, 0x2673fffc, 0x621024, +0x10400058, 0x2408021, 0x3c020080, 0x621024, +0x1040000a, 0x3c040040, 0x8ee2007c, 0x24420001, +0xaee2007c, 0x8ee2007c, 0x8ee201fc, 0x24420001, +0xaee201fc, 0x8003c59, 0x8ee201fc, 0x3c060004, +0x3c0b0001, 0x3c0a0002, 0x3c050010, 0x3c090008, +0x8ee20080, 0x3c080020, 0x34078000, 0x24420001, +0xaee20080, 0x8ee20080, 0x8fa2001c, 0x441824, +0x10660021, 0xc3102b, 0x14400007, 0x0, +0x106b0011, 0x0, 0x106a0015, 0x0, +0x800391a, 0x42042, 0x10650023, 0xa3102b, +0x14400005, 0x0, 0x10690019, 0x0, +0x800391a, 0x42042, 0x10680021, 0x0, +0x800391a, 0x42042, 0x8ee20034, 0x24420001, +0xaee20034, 0x8ee20034, 0x800391a, 0x42042, +0x8ee201ec, 0x24420001, 0xaee201ec, 0x8ee201ec, +0x800391a, 0x42042, 0x8ee201f0, 0x24420001, +0xaee201f0, 0x8ee201f0, 0x800391a, 0x42042, +0x8ee201f4, 0x24420001, 0xaee201f4, 0x8ee201f4, +0x800391a, 0x42042, 0x8ee20030, 0x24420001, +0xaee20030, 0x8ee20030, 0x800391a, 0x42042, +0x8ee201f8, 0x24420001, 0xaee201f8, 0x8ee201f8, +0x42042, 0x1087033e, 0x0, 0x80038df, +0x0, 0x3c020001, 0x571021, 0x904283b2, +0x14400084, 0x24020001, 0x3c030001, 0x771821, +0x906383b3, 0x1462007f, 0x3c020100, 0x8e430000, +0x621024, 0x1040006f, 0x2402ffff, 0x14620005, +0x24110001, 0x96430004, 0x3402ffff, 0x10620075, +0x0, 0x92e204d8, 0x14400072, 0x0, +0x3c020001, 0x571021, 0x8c4283b4, 0x28420005, +0x10400020, 0x3821, 0x3c020001, 0x571021, +0x8c4283b4, 0x18400016, 0x2821, 0x96060000, +0x520c0, 0x971021, 0x9442777e, 0x14460009, +0x971021, 0x94437780, 0x96020002, 0x14620005, +0x971021, 0x94437782, 0x96020004, 0x50620008, +0x24070001, 0x3c020001, 0x571021, 0x8c4283b4, +0x24a50001, 0xa2102a, 0x5440ffee, 0x520c0, +0x30e200ff, 0x10400302, 0x0, 0x80039a6, +0x0, 0x2402021, 0xc0022fe, 0x24050006, +0x3044001f, 0x428c0, 0x2e51021, 0x9442727c, +0x30424000, 0x144002f6, 0xb71021, 0x9443727e, +0x96020000, 0x1462000b, 0x418c0, 0xb71021, +0x94437280, 0x96020002, 0x14620006, 0x418c0, +0xb71021, 0x94437282, 0x96020004, 0x10620035, +0x418c0, 0x2e31021, 0x9442727c, 0x30428000, +0x144002e3, 0x2e31021, 0x944d727c, 0x96070000, +0xd28c0, 0xb71021, 0x9442737e, 0x8003988, +0x3021, 0x420c0, 0x2e41021, 0x9443737c, +0x2e41021, 0x944d737c, 0x30638000, 0x14600010, +0xd28c0, 0xb71021, 0x9442737e, 0x1447fff5, +0x1a02021, 0xb71021, 0x94437380, 0x96020002, +0x5462fff1, 0x420c0, 0xb71021, 0x94437382, +0x96020004, 0x5462ffec, 0x420c0, 0x24060001, +0x30c200ff, 0x104002c2, 0x0, 0x80039a6, +0x0, 0x97430202, 0x96420000, 0x146202bc, +0x0, 0x97430204, 0x96420002, 0x146202b8, +0x0, 0x97430206, 0x96420004, 0x146202b4, +0x0, 0x92420000, 0x3a230001, 0x30420001, +0x431024, 0x10400074, 0x2402ffff, 0x8e030000, +0x14620004, 0x3402ffff, 0x96030004, 0x1062006f, +0x24150002, 0x3c020001, 0x571021, 0x904283b2, +0x1440006a, 0x24150003, 0x92e204d8, 0x14400067, +0x0, 0x3c020001, 0x571021, 0x8c4283b4, +0x28420005, 0x10400020, 0x3821, 0x3c020001, +0x571021, 0x8c4283b4, 0x18400016, 0x2821, +0x96060000, 0x520c0, 0x971021, 0x9442777e, +0x14460009, 0x971021, 0x94437780, 0x96020002, +0x14620005, 0x971021, 0x94437782, 0x96020004, +0x50620008, 0x24070001, 0x3c020001, 0x571021, +0x8c4283b4, 0x24a50001, 0xa2102a, 0x5440ffee, +0x520c0, 0x30e200ff, 0x14400044, 0x24150003, +0x8003c59, 0x0, 0x2402021, 0xc0022fe, +0x24050006, 0x3044001f, 0x428c0, 0x2e51021, +0x9442727c, 0x30424000, 0x14400271, 0xb71021, +0x9443727e, 0x96020000, 0x1462000b, 0x418c0, +0xb71021, 0x94437280, 0x96020002, 0x14620006, +0x418c0, 0xb71021, 0x94437282, 0x96020004, +0x10620027, 0x418c0, 0x2e31021, 0x9442727c, +0x30428000, 0x1440025e, 0x2e31021, 0x944d727c, +0x96070000, 0xd28c0, 0xb71021, 0x9442737e, +0x8003a0d, 0x3021, 0x420c0, 0x2e41021, +0x9443737c, 0x2e41021, 0x944d737c, 0x30638000, +0x14600010, 0xd28c0, 0xb71021, 0x9442737e, +0x1447fff5, 0x1a02021, 0xb71021, 0x94437380, +0x96020002, 0x5462fff1, 0x420c0, 0xb71021, +0x94437382, 0x96020004, 0x5462ffec, 0x420c0, +0x24060001, 0x30c200ff, 0x1040023d, 0x0, +0x8003a20, 0x24150003, 0x24150001, 0x8f420260, +0x53102b, 0x10400036, 0x0, 0x8f8300e4, +0x8f8200e0, 0x10620003, 0x24630008, 0xaf8300e4, +0xaf8300e8, 0x8ee400c0, 0x8ee500c4, 0x2601821, +0x1021, 0xa32821, 0xa3302b, 0x822021, +0x862021, 0xaee400c0, 0xaee500c4, 0x8ee20058, +0x24420001, 0xaee20058, 0x8ee20058, 0x8ee2007c, +0x24420001, 0xaee2007c, 0x8ee2007c, 0x8f8200e0, +0xafa20010, 0x8f8200e4, 0x3c040001, 0x24845090, +0xafa20014, 0x8fa60018, 0x8fa7001c, 0x3c050006, +0xc002407, 0x34a5f203, 0x8003c5f, 0x0, +0x8ee25240, 0xafa20010, 0x8ee25244, 0x3c040001, +0x2484509c, 0xafa20014, 0x8ee60e10, 0x8ee70e18, +0x3c050006, 0xc002407, 0x34a5f202, 0x8ee201c0, +0x24420001, 0xaee201c0, 0x8003c06, 0x8ee201c0, +0x96e20468, 0x53102b, 0x54400001, 0x3c168000, +0x126001cb, 0x3c0e001f, 0x35ceffff, 0x3c0ffff5, +0x35ef1000, 0x241e0040, 0x8ee2724c, 0x8f430280, +0x24420001, 0x304207ff, 0x1062019e, 0x0, +0x12c00012, 0x0, 0x8ee35240, 0x8ee25244, +0x1062000a, 0x26f85244, 0x8ef45244, 0xafb80024, +0x8ee35244, 0x21140, 0x24425248, 0x2e28821, +0x24630001, 0x8003a89, 0x306d00ff, 0x8ee201e0, +0x24420001, 0xaee201e0, 0x8ee201e0, 0x8ee30e10, +0x8ee20e18, 0x1062ffca, 0x26f80e18, 0x8ef40e18, +0xb021, 0xafb80024, 0x8ee30e18, 0x21140, +0x24420e20, 0x2e28821, 0x24630001, 0x306d01ff, +0x96e2046a, 0x30420010, 0x10400018, 0x34028100, +0x9643000c, 0x14620015, 0x0, 0x3c020001, +0x571021, 0x904283c0, 0x14400010, 0x0, +0x9642000e, 0xa6220016, 0x8e420008, 0x8e430004, +0x8e440000, 0x2673fffc, 0xae42000c, 0xae430008, +0xae440004, 0x9622000e, 0x26100004, 0x24180001, +0xa3b8002f, 0x34420200, 0xa622000e, 0x8e220000, +0x8e230004, 0x3c040001, 0x34843800, 0x2003021, +0x306a0007, 0x20a8023, 0x3641021, 0x202102b, +0x10400005, 0x26a9821, 0x2041023, 0x3621823, +0x3c020020, 0x438023, 0x26620007, 0x9623000a, +0x2418fff8, 0x58c824, 0x6a1821, 0x79102b, +0x10400002, 0x3206021, 0x606021, 0x1801821, +0x24620007, 0x2418fff8, 0x586024, 0x26c102b, +0x14400004, 0x1932823, 0x1832823, 0x8003ac7, +0xc31021, 0xd31021, 0x4a2023, 0x1c4102b, +0x54400001, 0x8f2021, 0x25420040, 0x4c102b, +0x14400035, 0x5821, 0x94c3000c, 0x24020800, +0x54620032, 0xae260018, 0x3c020001, 0x571021, +0x904283c0, 0x5440002d, 0xae260018, 0x24c20017, +0x1c2102b, 0x10400013, 0x0, 0x3c02fff5, +0x461021, 0x90421017, 0x38430006, 0x2c630001, +0x38420011, 0x2c420001, 0x621825, 0x10600014, +0x24c20010, 0x1c2102b, 0x1040000e, 0x0, +0x3c0bfff5, 0x1665821, 0x956b1010, 0x8003af8, +0x2562000e, 0x90c20017, 0x38430006, 0x2c630001, +0x38420011, 0x2c420001, 0x621825, 0x10600005, +0x1601821, 0x94cb0010, 0x2562000e, 0x4a5821, +0x1601821, 0x24620007, 0x2418fff8, 0x585824, +0xc31021, 0x4a2023, 0x1c4102b, 0x10400002, +0x1632823, 0x8f2021, 0xae260018, 0x3c020001, +0x571021, 0x904283c0, 0x2102b, 0x216c0, +0x15600002, 0xafa20044, 0x1805821, 0x30820001, +0x10400007, 0x4021, 0x90880000, 0x24840001, +0x1c4102b, 0x10400002, 0x24a5ffff, 0x8f2021, +0x50a00012, 0x81c02, 0x2ca20002, 0x54400009, +0x24a5ffff, 0x94820000, 0x24840002, 0x1024021, +0x1c4102b, 0x10400006, 0x24a5fffe, 0x8003b25, +0x8f2021, 0x90820000, 0x21200, 0x1024021, +0x14a0fff2, 0x2ca20002, 0x81c02, 0x3102ffff, +0x624021, 0x3108ffff, 0x1402821, 0x11400011, +0x2002021, 0x2ca20002, 0x54400009, 0x24a5ffff, +0x94820000, 0x24840002, 0x1024021, 0x1c4102b, +0x10400006, 0x24a5fffe, 0x8003b3c, 0x8f2021, +0x90820000, 0x21200, 0x1024021, 0x14a0fff2, +0x2ca20002, 0x81c02, 0x3102ffff, 0x624021, +0x81c02, 0x3102ffff, 0x8f890120, 0x624021, +0x27623800, 0x25230020, 0x62102b, 0x14400002, +0x3108ffff, 0x27633000, 0x8f820128, 0x10620004, +0x0, 0x8f820124, 0x14620007, 0x1402821, +0x8ee201a4, 0x3821, 0x24420001, 0xaee201a4, +0x8003bcd, 0x8ee201a4, 0x8e260000, 0x8e270004, +0x81400, 0x3448000b, 0xad300008, 0xa52b000e, +0xad280018, 0x8fb80044, 0x2021, 0x2961025, +0x581025, 0xad22001c, 0xe5102b, 0xe53823, +0xc43023, 0xc23023, 0xad260000, 0xad270004, +0x8ee204c0, 0xad220010, 0xaf830120, 0x92e24e20, +0x1440005f, 0x24070001, 0x2502ffee, 0x2c420002, +0x14400003, 0x24020011, 0x15020024, 0x0, +0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, +0x8c830000, 0x24020012, 0x1462000f, 0x0, +0x8ee34e30, 0x8ee24e34, 0x1062000b, 0x0, +0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34, +0x8ee34e30, 0x24420001, 0x105e002a, 0x0, +0x8003bac, 0x0, 0x8ee24e30, 0x24420001, +0x505e0003, 0x1021, 0x8ee24e30, 0x24420001, +0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, +0x2e22021, 0x8003bca, 0x24020012, 0x8ee24e30, +0x210c0, 0x24425038, 0x2e22021, 0x8c830000, +0x24020007, 0x1462001f, 0x0, 0x8ee34e30, +0x8ee24e34, 0x1062001b, 0x0, 0x8c820004, +0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30, +0x24420001, 0x105e0007, 0x0, 0x8ee24e34, +0x24420001, 0x10620005, 0x0, 0x8003bb8, +0x0, 0x14600005, 0x0, 0x8f820128, +0x24420020, 0xaf820128, 0x8f820128, 0x8c820004, +0x2c420011, 0x50400012, 0xac800000, 0x8003bcd, +0x0, 0x8ee24e30, 0x24420001, 0x505e0003, +0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30, +0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, +0x24020007, 0xac820000, 0x24020001, 0xac820004, +0x14e00019, 0x3c050006, 0x3c040001, 0x24845060, +0x8e220018, 0x34a5f209, 0xafa20010, 0x8e220000, +0x8e230004, 0x2203021, 0x1603821, 0xc002407, +0xafa30014, 0x93a2002f, 0x1040002a, 0x34028100, +0x8e430004, 0x8e440008, 0x8e45000c, 0xa642000c, +0xae430000, 0xae440004, 0xae450008, 0x96220016, +0x8003c06, 0xa642000e, 0x1599000a, 0x26a1823, +0x9622000e, 0xa623000a, 0x34420004, 0xa622000e, +0x3c010001, 0x370821, 0xa02083c0, 0x8003c03, +0x9821, 0x9624000a, 0x83102b, 0x54400001, +0x801821, 0x24020001, 0xa623000a, 0x3c010001, +0x370821, 0xa02283c0, 0x9622000a, 0x4a1821, +0x2038021, 0x1d0102b, 0x54400001, 0x20f8021, +0x2639823, 0xb021, 0x8fb80024, 0x1660fe5e, +0xaf0d0000, 0x12600022, 0x0, 0x3c010001, +0x370821, 0xac3383c4, 0x3c010001, 0x370821, +0xac3083c8, 0x3c010001, 0x370821, 0xac3283cc, +0x93a2002f, 0x10400008, 0x0, 0x3c020001, +0x571021, 0x8c4283cc, 0x24420004, 0x3c010001, +0x370821, 0xac2283cc, 0x8f430280, 0x8ee2724c, +0x14620006, 0x0, 0x8ee201c4, 0x24420001, +0xaee201c4, 0x8003c5f, 0x8ee201c4, 0x8ee201bc, +0x24420001, 0xaee201bc, 0x8003c5f, 0x8ee201bc, +0x97a4001e, 0x2484fffc, 0x801821, 0x8ee400c0, +0x8ee500c4, 0x1021, 0xa32821, 0xa3302b, +0x822021, 0x862021, 0x24020002, 0xaee400c0, +0xaee500c4, 0x12a2000f, 0x2aa20003, 0x14400017, +0x24020003, 0x16a20015, 0x0, 0x8ee200d0, +0x8ee300d4, 0x24630001, 0x2c640001, 0x441021, +0xaee200d0, 0xaee300d4, 0x8ee200d0, 0x8003c59, +0x8ee300d4, 0x8ee200d8, 0x8ee300dc, 0x24630001, +0x2c640001, 0x441021, 0xaee200d8, 0xaee300dc, +0x8ee200d8, 0x8003c59, 0x8ee300dc, 0x8ee200c8, +0x8ee300cc, 0x24630001, 0x2c640001, 0x441021, +0xaee200c8, 0xaee300cc, 0x8ee200c8, 0x8ee300cc, +0x8f8300e4, 0x8f8200e0, 0x10620003, 0x24630008, +0xaf8300e4, 0xaf8300e8, 0x8fbf0068, 0x8fbe0064, +0x8fb60060, 0x8fb5005c, 0x8fb40058, 0x8fb30054, +0x8fb20050, 0x8fb1004c, 0x8fb00048, 0x3e00008, +0x27bd0070, 0x27bdffe0, 0xafbf0018, 0x8ee30e14, +0x8ee20e0c, 0x10620074, 0x0, 0x8ee30e0c, +0x8ee20e14, 0x622023, 0x4820001, 0x24840200, +0x8ee30e18, 0x8ee20e14, 0x43102b, 0x14400004, +0x24020200, 0x8ee30e14, 0x8003c81, 0x431823, +0x8ee20e18, 0x8ee30e14, 0x431023, 0x2443ffff, +0x804821, 0x69102a, 0x54400001, 0x604821, +0x8f870100, 0x27623000, 0x24e80020, 0x102102b, +0x50400001, 0x27682800, 0x8f820108, 0x11020004, +0x0, 0x8f820104, 0x15020007, 0x1021, +0x8ee201a8, 0x2021, 0x24420001, 0xaee201a8, +0x8003cc3, 0x8ee201a8, 0x8ee40e14, 0x42140, +0x801821, 0x8ee40460, 0x8ee50464, 0xa32821, +0xa3302b, 0x822021, 0x862021, 0xace40000, +0xace50004, 0x8ee30e14, 0x91140, 0xa4e2000e, +0x24020002, 0xace20018, 0x31940, 0x24630e20, +0x2e31021, 0xace20008, 0x8ee20e14, 0xace2001c, +0x8ee204cc, 0xace20010, 0xaf880100, 0x92e204ec, +0x14400011, 0x24040001, 0x8ee24e28, 0x24030040, +0x24420001, 0x50430003, 0x1021, 0x8ee24e28, +0x24420001, 0xaee24e28, 0x8ee24e28, 0x210c0, +0x24424e38, 0x2e21821, 0x24020002, 0xac620000, +0x24020001, 0xac620004, 0x1480000e, 0x24030040, +0x8ee20e14, 0xafa20010, 0x8ee20e18, 0x3c050007, +0xafa20014, 0x8ee60e0c, 0x8ee70e10, 0x3c040001, +0x248450a4, 0xc002407, 0x34a5f001, 0x8003ce1, +0x0, 0x8ee20500, 0x24420001, 0x50430003, +0x1021, 0x8ee20500, 0x24420001, 0xaee20500, +0x8ee20500, 0x21080, 0x571021, 0xac490508, +0x8ee20e14, 0x491021, 0x304201ff, 0xaee20e14, +0x8ee30e14, 0x8ee20e0c, 0x14620005, 0x0, +0x8f820060, 0x2403fdff, 0x431024, 0xaf820060, +0x8fbf0018, 0x3e00008, 0x27bd0020, 0x27bdffe0, +0xafbf0018, 0x8ee3523c, 0x8ee25238, 0x10620074, +0x0, 0x8ee35238, 0x8ee2523c, 0x622023, +0x4820001, 0x24840100, 0x8ee35244, 0x8ee2523c, +0x43102b, 0x14400004, 0x24020100, 0x8ee3523c, +0x8003d03, 0x431823, 0x8ee25244, 0x8ee3523c, +0x431023, 0x2443ffff, 0x804821, 0x69102a, +0x54400001, 0x604821, 0x8f870100, 0x27623000, +0x24e80020, 0x102102b, 0x50400001, 0x27682800, +0x8f820108, 0x11020004, 0x0, 0x8f820104, +0x15020007, 0x1021, 0x8ee201a8, 0x2021, +0x24420001, 0xaee201a8, 0x8003d45, 0x8ee201a8, +0x8ee4523c, 0x42140, 0x801821, 0x8ee40470, +0x8ee50474, 0xa32821, 0xa3302b, 0x822021, +0x862021, 0xace40000, 0xace50004, 0x8ee3523c, +0x91140, 0xa4e2000e, 0x24020003, 0xace20018, +0x31940, 0x24635248, 0x2e31021, 0xace20008, +0x8ee2523c, 0xace2001c, 0x8ee204cc, 0xace20010, +0xaf880100, 0x92e204ec, 0x14400011, 0x24040001, +0x8ee24e28, 0x24030040, 0x24420001, 0x50430003, +0x1021, 0x8ee24e28, 0x24420001, 0xaee24e28, +0x8ee24e28, 0x210c0, 0x24424e38, 0x2e21821, +0x24020003, 0xac620000, 0x24020001, 0xac620004, +0x1480000e, 0x24030040, 0x8ee2523c, 0xafa20010, +0x8ee25244, 0x3c050007, 0xafa20014, 0x8ee65238, +0x8ee75240, 0x3c040001, 0x248450b0, 0xc002407, +0x34a5f010, 0x8003d63, 0x0, 0x8ee20500, +0x24420001, 0x50430003, 0x1021, 0x8ee20500, +0x24420001, 0xaee20500, 0x8ee20500, 0x21080, +0x571021, 0xac490508, 0x8ee2523c, 0x491021, +0x304200ff, 0xaee2523c, 0x8ee3523c, 0x8ee25238, +0x14620005, 0x0, 0x8f820060, 0x2403feff, +0x431024, 0xaf820060, 0x8fbf0018, 0x3e00008, +0x27bd0020, 0x8f820120, 0x8ee34e34, 0x8f820124, +0x8f860128, 0x24020040, 0x24630001, 0x50620003, +0x1021, 0x8ee24e34, 0x24420001, 0xaee24e34, +0x8ee24e34, 0x8ee44e34, 0x8ee34e30, 0x210c0, +0x24425038, 0x14830007, 0x2e22821, 0x8f820128, +0x24420020, 0xaf820128, 0x8f820128, 0x8003d96, +0xaca00000, 0x8ee24e34, 0x24030040, 0x24420001, +0x50430003, 0x1021, 0x8ee24e34, 0x24420001, +0x210c0, 0x24425038, 0x2e22821, 0x8ca20004, +0x8f830128, 0x21140, 0x621821, 0xaf830128, +0xaca00000, 0x8cc20018, 0x2443fffe, 0x2c620012, +0x10400008, 0x31080, 0x3c010001, 0x220821, +0x8c2250c0, 0x400008, 0x0, 0x24020001, +0xaee24e24, 0x3e00008, 0x0, 0x27bdffc8, +0xafbf0030, 0xafb5002c, 0xafb40028, 0xafb30024, +0xafb20020, 0xafb1001c, 0xafb00018, 0x8f830128, +0x8f820124, 0x106202b0, 0x9821, 0x3c11001f, +0x3631ffff, 0x3c12fff5, 0x36521000, 0x24150012, +0x24140040, 0x8f8c0128, 0x8f820128, 0x24420020, +0xaf820128, 0x9182001b, 0x8f830128, 0x2443fffe, +0x2c620012, 0x1040029c, 0x31080, 0x3c010001, +0x220821, 0x8c225118, 0x400008, 0x0, +0x8f420218, 0x30420100, 0x10400007, 0x0, +0x95830016, 0x95820018, 0x621823, 0x31402, +0x431021, 0xa5820016, 0x8d82001c, 0x3c038000, +0x3044ffff, 0x436824, 0x3c030800, 0x431824, +0x11a00004, 0xad84001c, 0x41140, 0x8003ddc, +0x24425248, 0x41140, 0x24420e20, 0x2e25821, +0x9562000e, 0x3042fffc, 0x10600004, 0xa562000e, +0x95840016, 0x8003ec4, 0x0, 0x8d690018, +0x4021, 0x952a0000, 0x25290002, 0x95270000, +0x25290002, 0x95260000, 0x25290002, 0x95250000, +0x25290002, 0x95240000, 0x25290002, 0x95230000, +0x25290002, 0x95220000, 0x25290002, 0x1475021, +0x1465021, 0x1455021, 0x1445021, 0x1435021, +0x1425021, 0xa1c02, 0x3142ffff, 0x625021, +0xa1c02, 0x3142ffff, 0x625021, 0x96e2046a, +0x314effff, 0x30420002, 0x10400044, 0x5021, +0x25220014, 0x222102b, 0x10400014, 0x1201821, +0x2405000a, 0x2021, 0x223102b, 0x54400001, +0x721821, 0x94620000, 0x24630002, 0x24a5ffff, +0x14a0fff9, 0x822021, 0x41c02, 0x3082ffff, +0x622021, 0x41402, 0x3083ffff, 0x431021, +0x3042ffff, 0x8003e37, 0x1425021, 0x952a0000, +0x25290002, 0x95280000, 0x25290002, 0x95270000, +0x25290002, 0x95260000, 0x25290002, 0x95250000, +0x25290002, 0x95230000, 0x25290002, 0x95220000, +0x25290002, 0x95240000, 0x25290002, 0x1485021, +0x1475021, 0x1465021, 0x1455021, 0x1435021, +0x1425021, 0x95220000, 0x95230002, 0x1445021, +0x1425021, 0x1435021, 0xa1c02, 0x3142ffff, +0x625021, 0xa1c02, 0x3142ffff, 0x625021, +0x3148ffff, 0x51000001, 0x3408ffff, 0x8d620018, +0x9443000c, 0x24020800, 0x54620005, 0xa5680010, +0x9562000e, 0x34420002, 0xa562000e, 0xa5680010, +0x96e2046a, 0x2821, 0x30420008, 0x14400056, +0x3021, 0x8d630018, 0x24620024, 0x222102b, +0x10400034, 0x24690010, 0x229102b, 0x54400001, +0x1324821, 0x95250000, 0x24690014, 0x229102b, +0x10400002, 0x24a5ffec, 0x1324821, 0x95220000, +0x30420fff, 0x14400003, 0x25290002, 0x8003e64, +0x24130001, 0x9821, 0xa03021, 0x229102b, +0x54400001, 0x1324821, 0x91220001, 0x25290002, +0xa22821, 0x229102b, 0x54400001, 0x1324821, +0x25290002, 0x229102b, 0x54400001, 0x1324821, +0x95220000, 0x25290002, 0xa22821, 0x229102b, +0x54400001, 0x1324821, 0x95220000, 0x25290002, +0xa22821, 0x229102b, 0x54400001, 0x1324821, +0x95220000, 0x25290002, 0xa22821, 0x229102b, +0x54400001, 0x1324821, 0x95220000, 0x8003e9d, +0xa22821, 0x94650010, 0x94620014, 0x24690016, +0x30420fff, 0x14400003, 0x24a5ffec, 0x8003e90, +0x24130001, 0x9821, 0xa03021, 0x91230001, +0x25290004, 0x95220000, 0x25290002, 0x95240000, +0x25290002, 0xa32821, 0xa22821, 0x95220000, +0x95230002, 0xa42821, 0xa22821, 0xa32821, +0x51c02, 0x30a2ffff, 0x622821, 0x51c02, +0x30a2ffff, 0x622821, 0x96e2046a, 0x30420001, +0x1040001e, 0x2021, 0x95820016, 0x4e2023, +0x41402, 0x822021, 0x326200ff, 0x50400002, +0x862021, 0x852021, 0x41402, 0x822021, +0x3084ffff, 0x50800001, 0x3404ffff, 0x8d620018, +0x24430017, 0x223102b, 0x54400001, 0x721821, +0x90620000, 0x38430011, 0x2c630001, 0x38420006, +0x2c420001, 0x621825, 0x10600004, 0x0, +0x9562000e, 0x34420001, 0xa562000e, 0x9562000e, +0x240a0002, 0x30420004, 0x10400002, 0xa5640012, +0x240a0004, 0x8f880120, 0x27623800, 0x25090020, +0x122102b, 0x50400001, 0x27693000, 0x8f820128, +0x11220004, 0x0, 0x8f820124, 0x15220007, +0x24040020, 0x8ee201a4, 0x8021, 0x24420001, +0xaee201a4, 0x8003f53, 0x8ee201a4, 0x8ee5724c, +0x8ee60490, 0x8ee70494, 0xad0b0008, 0xa504000e, +0xad0a0018, 0x52940, 0xa01821, 0x1021, +0xe33821, 0xe3202b, 0xc23021, 0xc43021, +0xad060000, 0xad070004, 0x8ee2724c, 0x4d1025, +0xad02001c, 0x8ee204c4, 0xad020010, 0xaf890120, +0x92e24e20, 0x14400060, 0x24100001, 0x2543ffee, +0x2c630002, 0x39420011, 0x2c420001, 0x621825, +0x10600024, 0x0, 0x8ee24e30, 0x210c0, +0x24425038, 0x2e22021, 0x8c820000, 0x1455000f, +0x0, 0x8ee34e30, 0x8ee24e34, 0x1062000b, +0x0, 0x8c820004, 0x24420001, 0xac820004, +0x8ee24e34, 0x8ee34e30, 0x24420001, 0x1054002b, +0x0, 0x8003f32, 0x0, 0x8ee24e30, +0x24420001, 0x50540003, 0x1021, 0x8ee24e30, +0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, +0x24425038, 0x2e22021, 0x24020001, 0x8003f52, +0xac950000, 0x8ee24e30, 0x210c0, 0x24425038, +0x2e22021, 0x8c830000, 0x24020007, 0x1462001f, +0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b, +0x0, 0x8c820004, 0x24420001, 0xac820004, +0x8ee24e34, 0x8ee34e30, 0x24420001, 0x10540007, +0x0, 0x8ee24e34, 0x24420001, 0x10620005, +0x0, 0x8003f3e, 0x0, 0x14600005, +0x0, 0x8f820128, 0x24420020, 0xaf820128, +0x8f820128, 0x8c820004, 0x2c420011, 0x50400012, +0xac800000, 0x8003f53, 0x0, 0x8ee24e30, +0x24420001, 0x50540003, 0x1021, 0x8ee24e30, +0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, +0x24425038, 0x2e22021, 0x24020007, 0xac820000, +0x24020001, 0xac820004, 0x1600000d, 0x0, +0x8f820120, 0x3c040001, 0x24845108, 0xafa00014, +0xafa20010, 0x8d86001c, 0x8f870124, 0x3c050008, +0xc002407, 0x34a50001, 0x800405b, 0x0, +0x8ee2724c, 0x24420001, 0x304207ff, 0x11a00006, +0xaee2724c, 0x8ee201d0, 0x2442ffff, 0xaee201d0, +0x8003f6f, 0x8ee201d0, 0x8ee201cc, 0x2442ffff, +0xaee201cc, 0x8ee201cc, 0x8ee201d8, 0x2442ffff, +0xaee201d8, 0x800405b, 0x8ee201d8, 0x8f420240, +0x104000e5, 0x0, 0x8ee20e1c, 0x24420001, +0x800405b, 0xaee20e1c, 0x9582001e, 0xad82001c, +0x8f420240, 0x10400072, 0x0, 0x8ee20e1c, +0x24420001, 0xaee20e1c, 0x8f430240, 0x43102b, +0x144000d5, 0x0, 0x8f830120, 0x27623800, +0x24660020, 0xc2102b, 0x50400001, 0x27663000, +0x8f820128, 0x10c20004, 0x0, 0x8f820124, +0x14c20007, 0x0, 0x8ee201a4, 0x8021, +0x24420001, 0xaee201a4, 0x8003fde, 0x8ee201a4, +0x8ee2724c, 0xac62001c, 0x8ee404a8, 0x8ee504ac, +0x2462001c, 0xac620008, 0x24020008, 0xa462000e, +0x24020011, 0xac620018, 0xac640000, 0xac650004, +0x8ee204c4, 0xac620010, 0xaf860120, 0x92e24e20, +0x14400034, 0x24100001, 0x8ee24e30, 0x210c0, +0x24425038, 0x2e22021, 0x8c820000, 0x1455001f, +0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b, +0x0, 0x8c820004, 0x24420001, 0xac820004, +0x8ee24e34, 0x8ee34e30, 0x24420001, 0x10540007, +0x0, 0x8ee24e34, 0x24420001, 0x10620005, +0x0, 0x8003fca, 0x0, 0x14600005, +0x0, 0x8f820128, 0x24420020, 0xaf820128, +0x8f820128, 0x8c820004, 0x2c420011, 0x50400011, +0xac800000, 0x8003fde, 0x0, 0x8ee24e30, +0x24420001, 0x50540003, 0x1021, 0x8ee24e30, +0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, +0x24425038, 0x2e22021, 0x24020001, 0xac950000, +0xac820004, 0x5600000b, 0x24100001, 0x8ee2724c, +0x3c040001, 0x24845078, 0xafa00014, 0xafa20010, +0x8ee6724c, 0x8f470280, 0x3c050009, 0xc002407, +0x34a5f008, 0x56000001, 0xaee00e1c, 0x8ee20188, +0x24420001, 0xaee20188, 0x8004054, 0x8ee20188, +0x8f830120, 0x27623800, 0x24660020, 0xc2102b, +0x50400001, 0x27663000, 0x8f820128, 0x10c20004, +0x0, 0x8f820124, 0x14c20007, 0x0, +0x8ee201a4, 0x8021, 0x24420001, 0xaee201a4, +0x8004048, 0x8ee201a4, 0x8ee2724c, 0xac62001c, +0x8ee404a8, 0x8ee504ac, 0x2462001c, 0xac620008, +0x24020008, 0xa462000e, 0x24020011, 0xac620018, +0xac640000, 0xac650004, 0x8ee204c4, 0xac620010, +0xaf860120, 0x92e24e20, 0x14400034, 0x24100001, +0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, +0x8c820000, 0x1455001f, 0x0, 0x8ee34e30, +0x8ee24e34, 0x1062001b, 0x0, 0x8c820004, +0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30, +0x24420001, 0x10540007, 0x0, 0x8ee24e34, +0x24420001, 0x10620005, 0x0, 0x8004034, +0x0, 0x14600005, 0x0, 0x8f820128, +0x24420020, 0xaf820128, 0x8f820128, 0x8c820004, +0x2c420011, 0x50400011, 0xac800000, 0x8004048, +0x0, 0x8ee24e30, 0x24420001, 0x50540003, +0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30, +0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, +0x24020001, 0xac950000, 0xac820004, 0x1600000b, +0x0, 0x8ee2724c, 0x3c040001, 0x24845078, +0xafa00014, 0xafa20010, 0x8ee6724c, 0x8f470280, +0x3c050009, 0xc002407, 0x34a5f008, 0x8ee20174, +0x24420001, 0xaee20174, 0x800405b, 0x8ee20174, +0x24020001, 0xaee24e24, 0x8f830128, 0x8f820124, +0x1462fd58, 0x0, 0x8fbf0030, 0x8fb5002c, +0x8fb40028, 0x8fb30024, 0x8fb20020, 0x8fb1001c, +0x8fb00018, 0x3e00008, 0x27bd0038, 0x27bdffe8, +0x27840208, 0x27450200, 0x24060008, 0xafbf0014, +0xc00249e, 0xafb00010, 0x2021, 0x24100001, +0x2402241f, 0xaf900210, 0xaf900200, 0xaf800204, +0xaf820214, 0x8f460248, 0x24030004, 0x3c020040, +0x3c010001, 0xac235474, 0x3c010001, 0xac235478, +0x3c010001, 0xac20552c, 0x3c010001, 0xac225470, +0x3c010001, 0xac235478, 0xc004fa4, 0x24050004, +0xc004784, 0x0, 0x8ee20000, 0x3c03feff, +0x3463fffd, 0x431024, 0xaee20000, 0x3c023c00, +0xaf82021c, 0x3c010001, 0x370821, 0xac3083ac, +0x8fbf0014, 0x8fb00010, 0x3e00008, 0x27bd0018, +0x27bdffe0, 0x3c050008, 0x34a50400, 0xafbf0018, +0xafa00010, 0xafa00014, 0x8f860200, 0x3c040001, +0x248451c0, 0xc002407, 0x3821, 0x8ee20280, +0x24420001, 0xaee20280, 0x8ee20280, 0x8f830200, +0x3c023f00, 0x621824, 0x8fbf0018, 0x3c020400, +0x3e00008, 0x27bd0020, 0x27bdffd8, 0xafbf0020, +0xafb1001c, 0xafb00018, 0x8f900220, 0x8ee20214, +0x3821, 0x24420001, 0xaee20214, 0x8ee20214, +0x3c020300, 0x2021024, 0x10400027, 0x3c110400, +0xc00429f, 0x0, 0x3c020100, 0x2021024, +0x10400007, 0x0, 0x8ee20218, 0x24420001, +0xaee20218, 0x8ee20218, 0x80040ca, 0x3c03fdff, +0x8ee2021c, 0x24420001, 0xaee2021c, 0x8ee2021c, +0x3c03fdff, 0x3463ffff, 0x3c0808ff, 0x3508ffff, +0x8ee20000, 0x3c040001, 0x248451cc, 0x3c050008, +0x2003021, 0x431024, 0xaee20000, 0x8f820220, +0x3821, 0x3c030300, 0x481024, 0x431025, +0xaf820220, 0xafa00010, 0xc002407, 0xafa00014, +0x800429a, 0x0, 0x2111024, 0x1040001f, +0x3c024000, 0x8f830224, 0x24021402, 0x1462000b, +0x3c03fdff, 0x3c040001, 0x248451d8, 0x3c050008, +0xafa00010, 0xafa00014, 0x8f860224, 0x34a5ffff, +0xc002407, 0x3821, 0x3c03fdff, 0x8ee20000, +0x3463ffff, 0x2002021, 0x431024, 0xc004cf0, +0xaee20000, 0x8ee20220, 0x24420001, 0xaee20220, +0x8ee20220, 0x8f820220, 0x3c0308ff, 0x3463ffff, +0x431024, 0x8004299, 0x511025, 0x2021024, +0x10400142, 0x0, 0x8ee2022c, 0x24420001, +0xaee2022c, 0x8ee2022c, 0x8f820220, 0x3c0308ff, +0x3463ffff, 0x431024, 0x34420004, 0xaf820220, +0x8f830054, 0x8f820054, 0x8004112, 0x24630002, +0x8f820054, 0x621023, 0x2c420003, 0x1440fffc, +0x0, 0x8f8600e0, 0x8f8400e4, 0x30c20007, +0x10400012, 0x0, 0x8f8300e4, 0x2402fff8, +0xc21024, 0x1043000d, 0x0, 0x8f820054, +0x8f8300e0, 0x14c30009, 0x24440050, 0x8f820054, +0x821023, 0x2c420051, 0x10400004, 0x0, +0x8f8200e0, 0x10c2fff9, 0x0, 0x8f820220, +0x3c0308ff, 0x3463fffd, 0x431024, 0xaf820220, +0x8f8600e0, 0x30c20007, 0x10400003, 0x2402fff8, +0xc23024, 0xaf8600e0, 0x8f8300c4, 0x3c02001f, +0x3442ffff, 0x24680008, 0x48102b, 0x10400003, +0x3c02fff5, 0x34421000, 0x1024021, 0x8f8b00c8, +0x8f850120, 0x8f840124, 0x8004149, 0x6021, +0x27623800, 0x82102b, 0x50400001, 0x27643000, +0x10a40010, 0x318200ff, 0x8c820018, 0x38430007, +0x2c630001, 0x3842000b, 0x2c420001, 0x621825, +0x5060fff3, 0x24840020, 0x8ee20240, 0x240c0001, +0x24420001, 0xaee20240, 0x8ee20240, 0x8c8b0008, +0x318200ff, 0x14400065, 0x0, 0x3c020001, +0x571021, 0x904283c0, 0x14400060, 0x0, +0x8f8400e4, 0xc41023, 0x218c3, 0x4620001, +0x24630200, 0x8f8900c4, 0x10600005, 0x24020001, +0x10620009, 0x0, 0x800418b, 0x0, +0x8ee20230, 0x1205821, 0x24420001, 0xaee20230, +0x80041c0, 0x8ee20230, 0x8ee20234, 0x3c05000a, +0x24420001, 0xaee20234, 0x8c8b0000, 0x34a5f000, +0x8ee20234, 0x12b1823, 0xa3102b, 0x54400001, +0x651821, 0x2c62233f, 0x14400040, 0x0, +0x8f8200e8, 0x24420008, 0xaf8200e8, 0x8f8200e8, +0x8f8200e4, 0x1205821, 0x24420008, 0xaf8200e4, +0x80041c0, 0x8f8200e4, 0x8ee20238, 0x3c03000a, +0x24420001, 0xaee20238, 0x8c840000, 0x3463f000, +0x8ee20238, 0x883823, 0x67102b, 0x54400001, +0xe33821, 0x3c020003, 0x34420d40, 0x47102b, +0x10400003, 0x0, 0x80041c0, 0x805821, +0x8f8200e4, 0x24440008, 0xaf8400e4, 0x8f8400e4, +0x10860018, 0x3c05000a, 0x34a5f000, 0x3c0a0003, +0x354a0d40, 0x8ee2007c, 0x24420001, 0xaee2007c, +0x8c830000, 0x8ee2007c, 0x683823, 0xa7102b, +0x54400001, 0xe53821, 0x147102b, 0x54400007, +0x605821, 0x8f8200e4, 0x24440008, 0xaf8400e4, +0x8f8400e4, 0x1486ffef, 0x0, 0x14860005, +0x0, 0x1205821, 0xaf8600e4, 0x80041c0, +0xaf8600e8, 0xaf8400e4, 0xaf8400e8, 0x8f8200c8, +0x3c03000a, 0x3463f000, 0x483823, 0x67102b, +0x54400001, 0xe33821, 0x3c020003, 0x34420d3f, +0x47102b, 0x54400007, 0x6021, 0x1683823, +0x67102b, 0x54400003, 0xe33821, 0x80041d3, +0x3c020003, 0x3c020003, 0x34420d3f, 0x47102b, +0x14400016, 0x318200ff, 0x14400006, 0x0, +0x3c020001, 0x571021, 0x904283c0, 0x1040000f, +0x0, 0x8ee2023c, 0x3c04fdff, 0x8ee30000, +0x3484ffff, 0x24420001, 0xaee2023c, 0x8ee2023c, +0x24020001, 0x641824, 0x3c010001, 0x370821, +0xa02283b8, 0x8004230, 0xaee30000, 0xaf8b00c8, +0x8f8300c8, 0x8f8200c4, 0x3c04000a, 0x3484f000, +0x623823, 0x87102b, 0x54400001, 0xe43821, +0x3c020003, 0x34420d40, 0x47102b, 0x2ce30001, +0x431025, 0x10400008, 0x0, 0x8f820220, +0x3c0308ff, 0x3463ffff, 0x431024, 0x3c034000, +0x431025, 0xaf820220, 0x8f8600e0, 0x8f8400e4, +0x10c4002a, 0x0, 0x8ee2007c, 0x24420001, +0xaee2007c, 0x8ee2007c, 0x24c2fff8, 0xaf8200e0, +0x3c020001, 0x8c4275b0, 0x3c030008, 0x8f8600e0, +0x431024, 0x1040001d, 0x0, 0x10c4001b, +0x240dfff8, 0x3c0a000a, 0x354af000, 0x3c0c0080, +0x24850008, 0x27622800, 0x50a20001, 0x27651800, +0x8c880004, 0x8c820000, 0x8ca90000, 0x3103ffff, +0x431021, 0x4d1024, 0x24430010, 0x6b102b, +0x54400001, 0x6a1821, 0x12b102b, 0x54400001, +0x12a4821, 0x10690002, 0x10c1025, 0xac820004, +0xa02021, 0x14c4ffeb, 0x24850008, 0x8f820220, +0x3c0308ff, 0x3463ffff, 0x431024, 0x34420002, +0xaf820220, 0x8f830054, 0x8f820054, 0x800423b, +0x24630001, 0x8f820054, 0x621023, 0x2c420002, +0x1440fffc, 0x0, 0x8f820220, 0x3c0308ff, +0x3463fffb, 0x431024, 0xaf820220, 0x6010055, +0x0, 0x8ee20228, 0x24420001, 0xaee20228, +0x8ee20228, 0x8f820220, 0x3c0308ff, 0x3463ffff, +0x431024, 0x34420004, 0xaf820220, 0x8f830054, +0x8f820054, 0x8004255, 0x24630002, 0x8f820054, +0x621023, 0x2c420003, 0x1440fffc, 0x0, +0x8f8600e0, 0x30c20007, 0x10400012, 0x0, +0x8f8300e4, 0x2402fff8, 0xc21024, 0x1043000d, +0x0, 0x8f820054, 0x8f8300e0, 0x14c30009, +0x24440032, 0x8f820054, 0x821023, 0x2c420033, +0x10400004, 0x0, 0x8f8200e0, 0x10c2fff9, +0x0, 0x8f820220, 0x3c0308ff, 0x3463fffd, +0x431024, 0xaf820220, 0x8f8600e0, 0x30c20007, +0x10400003, 0x2402fff8, 0xc23024, 0xaf8600e0, +0x240301f5, 0x8f8200e8, 0x673823, 0x718c0, +0x431021, 0xaf8200e8, 0x8f8200e8, 0xaf8200e4, +0x8ee2007c, 0x3c0408ff, 0x3484ffff, 0x471021, +0xaee2007c, 0x8f820220, 0x3c038000, 0x34630002, +0x441024, 0x431025, 0xaf820220, 0x8f830054, +0x8f820054, 0x8004291, 0x24630001, 0x8f820054, +0x621023, 0x2c420002, 0x1440fffc, 0x0, +0x8f820220, 0x3c0308ff, 0x3463fffb, 0x431024, +0xaf820220, 0x8fbf0020, 0x8fb1001c, 0x8fb00018, +0x3e00008, 0x27bd0028, 0x3c020001, 0x8c425488, +0x27bdffd8, 0x10400012, 0xafbf0020, 0x3c040001, +0x248451e4, 0x3c050008, 0x24020001, 0x3c010001, +0x370821, 0xac2283ac, 0xafa00010, 0xafa00014, +0x8f860220, 0x34a50498, 0x3c010001, 0xac205488, +0x3c010001, 0xac22547c, 0xc002407, 0x3821, +0x8f420268, 0x3c037fff, 0x3463ffff, 0x431024, +0xaf420268, 0x8ee204d0, 0x8ee404d4, 0x2403fffe, +0x431024, 0x30840002, 0x1080011e, 0xaee204d0, +0x8ee204d4, 0x2403fffd, 0x431024, 0xaee204d4, +0x8f820044, 0x3c030600, 0x34632000, 0x34420020, +0xaf820044, 0xafa30018, 0x8ee20608, 0x8f430228, +0x24420001, 0x304a00ff, 0x514300fe, 0xafa00010, +0x8ee20608, 0x210c0, 0x571021, 0x8fa30018, +0x8fa4001c, 0xac43060c, 0xac440610, 0x8f830054, +0x8f820054, 0x24690032, 0x1221023, 0x2c420033, +0x1040006a, 0x5821, 0x24180008, 0x240f000d, +0x240d0007, 0x240c0040, 0x240e0001, 0x8f870120, +0x27623800, 0x24e80020, 0x102102b, 0x50400001, +0x27683000, 0x8f820128, 0x11020004, 0x0, +0x8f820124, 0x15020007, 0x1021, 0x8ee201a4, +0x2821, 0x24420001, 0xaee201a4, 0x8004341, +0x8ee201a4, 0x8ee40608, 0x420c0, 0x801821, +0x8ee40430, 0x8ee50434, 0xa32821, 0xa3302b, +0x822021, 0x862021, 0xace40000, 0xace50004, +0x8ee20608, 0xa4f8000e, 0xacef0018, 0xacea001c, +0x210c0, 0x2442060c, 0x2e21021, 0xace20008, +0x8ee204c4, 0xace20010, 0xaf880120, 0x92e24e20, +0x14400033, 0x24050001, 0x8ee24e30, 0x210c0, +0x24425038, 0x2e22021, 0x8c820000, 0x144d001f, +0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b, +0x0, 0x8c820004, 0x24420001, 0xac820004, +0x8ee24e34, 0x8ee34e30, 0x24420001, 0x104c0007, +0x0, 0x8ee24e34, 0x24420001, 0x10620005, +0x0, 0x800432e, 0x0, 0x14600005, +0x0, 0x8f820128, 0x24420020, 0xaf820128, +0x8f820128, 0x8c820004, 0x2c420011, 0x50400010, +0xac800000, 0x8004341, 0x0, 0x8ee24e30, +0x24420001, 0x504c0003, 0x1021, 0x8ee24e30, +0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, +0x24425038, 0x2e22021, 0xac8d0000, 0xac8e0004, +0x54a00006, 0x240b0001, 0x8f820054, 0x1221023, +0x2c420033, 0x1440ff9d, 0x0, 0x316300ff, +0x24020001, 0x54620079, 0xafa00010, 0xaeea0608, +0x8f830054, 0x8f820054, 0x24690032, 0x1221023, +0x2c420033, 0x10400061, 0x5821, 0x240d0008, +0x240c0011, 0x24080012, 0x24070040, 0x240a0001, +0x8f830120, 0x27623800, 0x24660020, 0xc2102b, +0x50400001, 0x27663000, 0x8f820128, 0x10c20004, +0x0, 0x8f820124, 0x14c20007, 0x0, +0x8ee201a4, 0x2821, 0x24420001, 0xaee201a4, +0x80043ad, 0x8ee201a4, 0x8ee20608, 0xac62001c, +0x8ee404a0, 0x8ee504a4, 0x2462001c, 0xac620008, +0xa46d000e, 0xac6c0018, 0xac640000, 0xac650004, +0x8ee204c4, 0xac620010, 0xaf860120, 0x92e24e20, +0x14400033, 0x24050001, 0x8ee24e30, 0x210c0, +0x24425038, 0x2e22021, 0x8c820000, 0x1448001f, +0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b, +0x0, 0x8c820004, 0x24420001, 0xac820004, +0x8ee24e34, 0x8ee34e30, 0x24420001, 0x10470007, +0x0, 0x8ee24e34, 0x24420001, 0x10620005, +0x0, 0x800439a, 0x0, 0x14600005, +0x0, 0x8f820128, 0x24420020, 0xaf820128, +0x8f820128, 0x8c820004, 0x2c420011, 0x50400010, +0xac800000, 0x80043ad, 0x0, 0x8ee24e30, +0x24420001, 0x50470003, 0x1021, 0x8ee24e30, +0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, +0x24425038, 0x2e22021, 0xac880000, 0xac8a0004, +0x54a00006, 0x240b0001, 0x8f820054, 0x1221023, +0x2c420033, 0x1440ffa6, 0x0, 0x316300ff, +0x24020001, 0x54620003, 0xafa00010, 0x80043da, +0x0, 0x3c040001, 0x248451f0, 0xafa00014, +0x8f860120, 0x8f870124, 0x3c050009, 0xc002407, +0x34a5f011, 0x80043da, 0x0, 0x3c040001, +0x248451fc, 0xafa00014, 0x8f860120, 0x8f870124, +0x3c050009, 0xc002407, 0x34a5f010, 0x80043da, +0x0, 0x3c040001, 0x24845208, 0xafa00014, +0x8ee60608, 0x8f470228, 0x3c050009, 0xc002407, +0x34a5f00f, 0x8ee201ac, 0x24420001, 0xaee201ac, +0x8ee201ac, 0x8ee2015c, 0x24420001, 0xaee2015c, +0x8ee2015c, 0x8fbf0020, 0x3e00008, 0x27bd0028, +0x3c020001, 0x8c425488, 0x27bdffe0, 0x1440000d, +0xafbf0018, 0x3c040001, 0x24845214, 0x3c050008, +0xafa00010, 0xafa00014, 0x8f860220, 0x34a50499, +0x24020001, 0x3c010001, 0xac225488, 0xc002407, +0x3821, 0x8ee204d0, 0x3c030001, 0x771821, +0x946383b2, 0x34420001, 0x10600007, 0xaee204d0, +0x8f820220, 0x3c0308ff, 0x3463ffff, 0x431024, +0x34420008, 0xaf820220, 0x2021, 0xc0050af, +0x24050004, 0xaf420268, 0x8fbf0018, 0x3e00008, +0x27bd0020, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x3c120001, +0x26521200, 0x3c140001, 0x8e945400, 0x3c100001, +0x26101120, 0x3c15c000, 0x36b50060, 0x8e8a0000, +0x8eb30000, 0x26a400b, 0x248000a, 0x200f821, +0x0, 0xd, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x80014d6, +0x0, 0x80014d8, 0x3c0a0001, 0x80014d8, +0x3c0a0002, 0x80014d8, 0x0, 0x80024aa, +0x0, 0x80014d8, 0x3c0a0003, 0x80014d8, +0x3c0a0004, 0x8002f90, 0x0, 0x80014d8, +0x3c0a0005, 0x8003cec, 0x0, 0x8003c6a, +0x0, 0x80014d8, 0x3c0a0006, 0x80014d8, +0x3c0a0007, 0x80014d8, 0x0, 0x80014d8, +0x0, 0x80014d8, 0x0, 0x8002a79, +0x0, 0x80014d8, 0x3c0a000b, 0x80014d8, +0x3c0a000c, 0x80014d8, 0x3c0a000d, 0x800237c, +0x0, 0x8002339, 0x0, 0x80014d8, +0x3c0a000e, 0x8001b3c, 0x0, 0x80024a8, +0x0, 0x80014d8, 0x3c0a000f, 0x80040ab, +0x0, 0x8004095, 0x0, 0x80014d8, +0x3c0a0010, 0x80014ee, 0x0, 0x80014d8, +0x3c0a0011, 0x80014d8, 0x3c0a0012, 0x80014d8, +0x3c0a0013, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x3c030001, +0x34633800, 0x24050080, 0x2404001f, 0x2406ffff, +0x24020001, 0xaf80021c, 0xaf820200, 0xaf820220, +0x3631021, 0xaf8200c0, 0x3631021, 0xaf8200c4, +0x3631021, 0xaf8200c8, 0x27623800, 0xaf8200d0, +0x27623800, 0xaf8200d4, 0x27623800, 0xaf8200d8, +0x27621800, 0xaf8200e0, 0x27621800, 0xaf8200e4, +0x27621800, 0xaf8200e8, 0x27621000, 0xaf8200f0, +0x27621000, 0xaf8200f4, 0x27621000, 0xaf8200f8, +0xaca00000, 0x2484ffff, 0x1486fffd, 0x24a50004, +0x8f830040, 0x3c02f000, 0x621824, 0x3c025000, +0x1062000c, 0x43102b, 0x14400006, 0x3c026000, +0x3c024000, 0x10620008, 0x24020800, 0x8004539, +0x0, 0x10620004, 0x24020800, 0x8004539, +0x0, 0x24020700, 0x3c010001, 0xac22548c, +0x3e00008, 0x0, 0x27bdffd0, 0xafbf0028, +0x3c010001, 0xc004ccd, 0xac205474, 0x24040001, +0x2821, 0x27a60020, 0x34028000, 0xc0048ea, +0xa7a20020, 0x8f830054, 0x8f820054, 0x800454b, +0x24630064, 0x8f820054, 0x621023, 0x2c420065, +0x1440fffc, 0x24040001, 0x24050001, 0xc0048a8, +0x27a60020, 0x8f830054, 0x8f820054, 0x8004557, +0x24630064, 0x8f820054, 0x621023, 0x2c420065, +0x1440fffc, 0x24040001, 0x24050001, 0xc0048a8, +0x27a60020, 0x8f830054, 0x8f820054, 0x8004563, +0x24630064, 0x8f820054, 0x621023, 0x2c420065, +0x1440fffc, 0x24040001, 0x24050002, 0xc0048a8, +0x27a60018, 0x8f830054, 0x8f820054, 0x800456f, +0x24630064, 0x8f820054, 0x621023, 0x2c420065, +0x1440fffc, 0x24040001, 0x24050003, 0xc0048a8, +0x27a6001a, 0x97a20020, 0x10400027, 0x24030001, +0x3c020001, 0x8c425474, 0x97a30018, 0x34420001, +0x3c010001, 0xac225474, 0x24020015, 0x1462000d, +0x0, 0x97a2001a, 0x3843f423, 0x2c630001, +0x3842f430, 0x2c420001, 0x621825, 0x10600005, +0x24020003, 0x3c010001, 0xac225540, 0x80045a7, +0x3c08fff0, 0x97a30018, 0x24027810, 0x1462000a, +0x24020002, 0x97a3001a, 0x24020001, 0x14620006, +0x24020002, 0x24020004, 0x3c010001, 0xac225540, +0x80045a7, 0x3c08fff0, 0x3c010001, 0xac225540, +0x80045a7, 0x3c08fff0, 0x3c020001, 0x8c425474, +0x3c010001, 0xac235540, 0x34420004, 0x3c010001, +0xac225474, 0x3c08fff0, 0x3508bdc0, 0x8f830054, +0x97a60018, 0x3c070001, 0x8ce75540, 0x3c040001, +0x24845280, 0x24020001, 0x3c010001, 0xac22547c, +0xafa60010, 0x3c060001, 0x8cc65474, 0x97a2001a, +0x3c05000d, 0x34a50100, 0x3c010001, 0xac205478, +0x681821, 0x3c010001, 0xac235538, 0xc002407, +0xafa20014, 0x8fbf0028, 0x3e00008, 0x27bd0030, +0x27bdffe8, 0x24070004, 0x3c040001, 0x8c845478, +0x3021, 0x24020001, 0x1482000a, 0xafbf0010, +0x3c020001, 0x8c4275bc, 0x3c050004, 0x30428000, +0x1040000c, 0x34a593e0, 0x3c05000f, 0x80045da, +0x34a54240, 0x3c020001, 0x8c4275bc, 0x3c05000f, +0x30428000, 0x10400003, 0x34a54240, 0x3c05001e, +0x34a58480, 0x3c020001, 0x8c425538, 0x8f830054, +0x451021, 0x431023, 0x45102b, 0x1440002e, +0x0, 0x3c020001, 0x8c425480, 0x1440002a, +0x2cc20001, 0x7182b, 0x431024, 0x1040001d, +0x0, 0x3c090001, 0x8d295474, 0x240b0001, +0x3c054000, 0x3c080001, 0x250875bc, 0x250afffc, +0x42042, 0x14800002, 0x24e7ffff, 0x24040008, +0x891024, 0x5040000b, 0x2cc20001, 0x148b0004, +0x0, 0x8d020000, 0x80045ff, 0x451024, +0x8d420000, 0x451024, 0x54400001, 0x24060001, +0x2cc20001, 0x7182b, 0x431024, 0x5440ffed, +0x42042, 0x3c010001, 0x10c00024, 0xac245478, +0x8f830054, 0x24020001, 0x3c010001, 0xac22547c, +0x3c010001, 0xac235538, 0x3c020001, 0x8c42547c, +0x10400006, 0x24020001, 0x3c010001, 0xac20547c, +0x3c010001, 0x370821, 0xac2283ac, 0x3c030001, +0x771821, 0x8c6383ac, 0x24020008, 0x10620005, +0x24020001, 0xc00462f, 0x0, 0x800462c, +0x0, 0x3c030001, 0x8c635478, 0x10620007, +0x2402000e, 0x3c030001, 0x8c637550, 0x10620003, +0x0, 0xc004cf0, 0x8f840220, 0x8fbf0010, +0x3e00008, 0x27bd0018, 0x27bdffe0, 0x3c02fdff, +0xafbf0018, 0x8ee30000, 0x3c050001, 0x8ca55478, +0x3c040001, 0x8c845498, 0x3442ffff, 0x621824, +0x14a40008, 0xaee30000, 0x3c030001, 0x771821, +0x8c6383ac, 0x3c020001, 0x8c42549c, 0x10620008, +0x0, 0x3c020001, 0x571021, 0x8c4283ac, +0x3c010001, 0xac255498, 0x3c010001, 0xac22549c, +0x3c030001, 0x8c635478, 0x24020002, 0x10620131, +0x2c620003, 0x10400005, 0x24020001, 0x10620008, +0x0, 0x800477e, 0x0, 0x24020004, +0x10620079, 0x24020001, 0x800477f, 0x0, +0x3c020001, 0x571021, 0x8c4283ac, 0x2443ffff, +0x2c620008, 0x10400122, 0x31080, 0x3c010001, +0x220821, 0x8c225298, 0x400008, 0x0, +0xc004784, 0x0, 0x3c020001, 0x8c425484, +0x3c010001, 0xac205410, 0x104000bd, 0x24020002, +0x3c010001, 0x370821, 0xac2283ac, 0x3c010001, +0x8004781, 0xac205484, 0xc00492b, 0x0, +0x3c030001, 0x8c6354a0, 0x80046f0, 0x24020011, +0x3c050001, 0x8ca55478, 0x3c060001, 0x8cc675bc, +0xc004fa4, 0x2021, 0x24020005, 0x3c010001, +0xac205484, 0x3c010001, 0x370821, 0x8004781, +0xac2283ac, 0x3c040001, 0x2484528c, 0x3c05000f, +0x34a50100, 0x3021, 0x3821, 0xafa00010, +0xc002407, 0xafa00014, 0x8004781, 0x0, +0x8f820220, 0x3c03f700, 0x431025, 0x8004719, +0xaf820220, 0x8f820220, 0x3c030004, 0x431024, +0x14400090, 0x24020007, 0x8f830054, 0x3c020001, +0x8c425530, 0x2463d8f0, 0x431023, 0x2c422710, +0x144000df, 0x24020001, 0x800477f, 0x0, +0x3c050001, 0x8ca55478, 0xc0050af, 0x2021, +0xc00517a, 0x2021, 0x3c030001, 0x8c6375b4, +0x46100d1, 0x24020001, 0x3c020008, 0x621024, +0x10400006, 0x0, 0x8f820214, 0x3c03ffff, +0x431024, 0x80046bc, 0x3442251f, 0x8f820214, +0x3c03ffff, 0x431024, 0x3442241f, 0xaf820214, +0x8ee20000, 0x3c030200, 0x431025, 0xaee20000, +0x8f820220, 0x2403fffb, 0x431024, 0xaf820220, +0x8f820220, 0x34420002, 0xaf820220, 0x24020008, +0x3c010001, 0x370821, 0xc0043e1, 0xac2283ac, +0x8004781, 0x0, 0x3c020001, 0x571021, +0x8c4283ac, 0x2443ffff, 0x2c620008, 0x104000ac, +0x31080, 0x3c010001, 0x220821, 0x8c2252b8, +0x400008, 0x0, 0xc00429f, 0x0, +0x3c010001, 0xac20547c, 0xaf800204, 0x3c010001, +0xc004784, 0xac2075a0, 0x24020001, 0x3c010001, +0xac225490, 0x24020002, 0x3c010001, 0x370821, +0x8004781, 0xac2283ac, 0xc004801, 0x0, +0x3c030001, 0x8c635490, 0x24020009, 0x14620090, +0x24020003, 0x3c010001, 0x370821, 0x8004781, +0xac2283ac, 0x3c020001, 0x8c4275b8, 0x30424000, +0x10400005, 0x0, 0x8f820044, 0x3c03ffff, +0x8004701, 0x34637fff, 0x8f820044, 0x2403ff7f, +0x431024, 0xaf820044, 0x8f830054, 0x800471b, +0x24020004, 0x8f830054, 0x3c020001, 0x8c425530, +0x2463d8f0, 0x431023, 0x2c422710, 0x14400074, +0x24020005, 0x3c010001, 0x370821, 0x8004781, +0xac2283ac, 0x8f820220, 0x3c03f700, 0x431025, +0xaf820220, 0xaf800204, 0x3c010001, 0xac2075a0, +0x8f830054, 0x24020006, 0x3c010001, 0x370821, +0xac2283ac, 0x3c010001, 0x8004781, 0xac235530, +0x8f830054, 0x3c020001, 0x8c425530, 0x2463fff6, +0x431023, 0x2c42000a, 0x14400059, 0x0, +0x24020007, 0x3c010001, 0x370821, 0x8004781, +0xac2283ac, 0x8f820220, 0x3c04f700, 0x441025, +0xaf820220, 0x8f820220, 0x3c030300, 0x431024, +0x14400005, 0x1821, 0x8f820220, 0x24030001, +0x441025, 0xaf820220, 0x10600043, 0x24020001, +0x8f820214, 0x3c03ffff, 0x3c040001, 0x8c845528, +0x431024, 0x3442251f, 0xaf820214, 0x24020008, +0x3c010001, 0x370821, 0x1080000b, 0xac2283ac, +0x3c020001, 0x8c425504, 0x14400007, 0x24020001, +0x3c010001, 0xac227550, 0xc004cf0, 0x8f840220, +0x800476e, 0x0, 0x8f820220, 0x3c030008, +0x431024, 0x14400017, 0x2402000e, 0x3c010001, +0xac227550, 0x8ee20000, 0x2021, 0x3c030200, +0x431025, 0xc00517a, 0xaee20000, 0x8f820220, +0x2403fffb, 0x431024, 0xaf820220, 0x8f820220, +0x34420002, 0xc0043e1, 0xaf820220, 0x3c050001, +0x8ca55478, 0xc0050af, 0x2021, 0x8004781, +0x0, 0x3c020001, 0x8c425504, 0x10400010, +0x0, 0x3c020001, 0x8c425500, 0x2442ffff, +0x3c010001, 0xac225500, 0x14400009, 0x24020002, +0x3c010001, 0xac205504, 0x3c010001, 0x8004781, +0xac225500, 0x24020001, 0x3c010001, 0xac22547c, +0x8fbf0018, 0x3e00008, 0x27bd0020, 0x8f820200, +0x8f820220, 0x8f820220, 0x34420004, 0xaf820220, +0x8f820200, 0x3c060001, 0x8cc65478, 0x34420004, +0xaf820200, 0x24020002, 0x10c2003a, 0x2cc20003, +0x10400005, 0x24020001, 0x10c20008, 0x0, +0x80047ca, 0x0, 0x24020004, 0x10c20013, +0x24020001, 0x80047ca, 0x0, 0x3c030001, +0x8c635468, 0x3c020001, 0x8c425470, 0x3c040001, +0x8c84548c, 0x3c050001, 0x8ca5546c, 0xaf860200, +0xaf860220, 0x34630022, 0x441025, 0x451025, +0x34420002, 0x80047c9, 0xaf830200, 0x3c030001, +0x8c635528, 0xaf820200, 0x10600009, 0xaf820220, +0x3c020001, 0x8c425504, 0x14400005, 0x3c033f00, +0x3c020001, 0x8c425460, 0x80047bd, 0x346300e0, +0x3c020001, 0x8c425460, 0x3c033f00, 0x346300e2, +0x431025, 0xaf820200, 0x3c030001, 0x8c635464, +0x3c04f700, 0x3c020001, 0x8c425470, 0x3c050001, +0x8ca5548c, 0x641825, 0x431025, 0x451025, +0xaf820220, 0x3e00008, 0x0, 0x8f820220, +0x3c030001, 0x8c635478, 0x34420004, 0xaf820220, +0x24020001, 0x1062000f, 0x0, 0x8f830054, +0x8f820054, 0x24630002, 0x621023, 0x2c420003, +0x10400011, 0x0, 0x8f820054, 0x621023, +0x2c420003, 0x1040000c, 0x0, 0x80047db, +0x0, 0x8f830054, 0x8f820054, 0x80047e7, +0x24630007, 0x8f820054, 0x621023, 0x2c420008, +0x1440fffc, 0x0, 0x8f8400e0, 0x30820007, +0x1040000d, 0x0, 0x8f820054, 0x8f8300e0, +0x14830009, 0x24450032, 0x8f820054, 0xa21023, +0x2c420033, 0x10400004, 0x0, 0x8f8200e0, +0x1082fff9, 0x0, 0x8f820220, 0x2403fffd, +0x431024, 0xaf820220, 0x3e00008, 0x0, +0x3c030001, 0x8c635490, 0x3c020001, 0x8c425494, +0x50620004, 0x2463ffff, 0x3c010001, 0xac235494, +0x2463ffff, 0x2c620009, 0x10400099, 0x31080, +0x3c010001, 0x220821, 0x8c2252d8, 0x400008, +0x0, 0x8f820044, 0x34428080, 0xaf820044, +0x8f830054, 0x8004896, 0x24020002, 0x8f830054, +0x3c020001, 0x8c425534, 0x2463d8f0, 0x431023, +0x2c422710, 0x14400086, 0x24020003, 0x80048a3, +0x0, 0x8f820044, 0x3c03ffff, 0x34637fff, +0x431024, 0xaf820044, 0x8f830054, 0x8004896, +0x24020004, 0x8f830054, 0x3c020001, 0x8c425534, +0x2463fff6, 0x431023, 0x2c42000a, 0x14400074, +0x24020005, 0x80048a3, 0x0, 0x8f820220, +0x3c03f700, 0x431025, 0xaf820220, 0x8f820220, +0x2403fffb, 0x431024, 0xaf820220, 0x8f820220, +0x34420002, 0xaf820220, 0x3c023f00, 0x344200e0, +0xaf820200, 0x8f820200, 0x2403fffd, 0x431024, +0xaf820200, 0x24040001, 0x3405ffff, 0xaf840204, +0x8f830054, 0x8f820054, 0x800484e, 0x24630001, +0x8f820054, 0x621023, 0x2c420002, 0x1440fffc, +0x0, 0x8f820224, 0x42040, 0xa4102b, +0x1040fff2, 0x0, 0x8f820220, 0x3c03f700, +0x431025, 0xaf820220, 0x8f820214, 0x3c03ffff, +0x431024, 0x3442251f, 0xaf820214, 0x8f820220, +0x2403fffb, 0x431024, 0xaf820220, 0x8f820220, +0x3c04f700, 0x34840008, 0x34420002, 0xaf820220, +0x8f820220, 0x3c033f00, 0x346300e2, 0x441025, +0xaf820220, 0xaf830200, 0x8f8400f0, 0x276217f8, +0x14820002, 0x24850008, 0x27651000, 0x8f8200f4, +0x10a20007, 0x3c038000, 0x34630040, 0x3c020001, +0x24425420, 0xac820000, 0xac830004, 0xaf8500f0, +0x8f830054, 0x8004896, 0x24020006, 0x8f830054, +0x3c020001, 0x8c425534, 0x2463fff6, 0x431023, +0x2c42000a, 0x1440001e, 0x24020007, 0x80048a3, +0x0, 0x8f8200e0, 0xaf8200e4, 0x8f8200e0, +0xaf8200e8, 0x8f820220, 0x34420004, 0xaf820220, +0x8f820044, 0x34428080, 0xaf820044, 0x8f830054, +0x24020008, 0x3c010001, 0xac225490, 0x3c010001, +0x80048a5, 0xac235534, 0x8f830054, 0x3c020001, +0x8c425534, 0x2463d8f0, 0x431023, 0x2c422710, +0x14400003, 0x24020009, 0x3c010001, 0xac225490, +0x3e00008, 0x0, 0x0, 0x27bdffd8, +0xafb20018, 0x809021, 0xafb3001c, 0xa09821, +0xafb10014, 0xc08821, 0xafb00010, 0x8021, +0xafbf0020, 0xa6200000, 0xc004ca7, 0x24040001, +0x26100001, 0x2e020020, 0x1440fffb, 0x0, +0xc004ca7, 0x2021, 0xc004ca7, 0x24040001, +0xc004ca7, 0x24040001, 0xc004ca7, 0x2021, +0x24100010, 0x2501024, 0x10400002, 0x2021, +0x24040001, 0xc004ca7, 0x108042, 0x1600fffa, +0x2501024, 0x24100010, 0x2701024, 0x10400002, +0x2021, 0x24040001, 0xc004ca7, 0x108042, +0x1600fffa, 0x2701024, 0xc004ccd, 0x34108000, +0xc004ccd, 0x0, 0xc004c87, 0x0, +0x50400005, 0x108042, 0x96220000, 0x501025, +0xa6220000, 0x108042, 0x1600fff7, 0x0, +0xc004ccd, 0x0, 0x8fbf0020, 0x8fb3001c, +0x8fb20018, 0x8fb10014, 0x8fb00010, 0x3e00008, +0x27bd0028, 0x27bdffd8, 0xafb10014, 0x808821, +0xafb20018, 0xa09021, 0xafb3001c, 0xc09821, +0xafb00010, 0x8021, 0xafbf0020, 0xc004ca7, +0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, +0x0, 0xc004ca7, 0x2021, 0xc004ca7, +0x24040001, 0xc004ca7, 0x2021, 0xc004ca7, +0x24040001, 0x24100010, 0x2301024, 0x10400002, +0x2021, 0x24040001, 0xc004ca7, 0x108042, +0x1600fffa, 0x2301024, 0x24100010, 0x2501024, +0x10400002, 0x2021, 0x24040001, 0xc004ca7, +0x108042, 0x1600fffa, 0x2501024, 0xc004ca7, +0x24040001, 0xc004ca7, 0x2021, 0x34108000, +0x96620000, 0x501024, 0x10400002, 0x2021, +0x24040001, 0xc004ca7, 0x108042, 0x1600fff8, +0x0, 0xc004ccd, 0x0, 0x8fbf0020, +0x8fb3001c, 0x8fb20018, 0x8fb10014, 0x8fb00010, +0x3e00008, 0x27bd0028, 0x3c030001, 0x8c6354a0, +0x3c020001, 0x8c4254e4, 0x27bdffd8, 0xafbf0020, +0xafb1001c, 0x10620003, 0xafb00018, 0x3c010001, +0xac2354e4, 0x2463ffff, 0x2c620013, 0x10400349, +0x31080, 0x3c010001, 0x220821, 0x8c225300, +0x400008, 0x0, 0xc004ccd, 0x8021, +0x34028000, 0xa7a20010, 0x27b10010, 0xc004ca7, +0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, +0x0, 0xc004ca7, 0x2021, 0xc004ca7, +0x24040001, 0xc004ca7, 0x2021, 0xc004ca7, +0x24040001, 0x24100010, 0x32020001, 0x10400002, +0x2021, 0x24040001, 0xc004ca7, 0x108042, +0x1600fffa, 0x32020001, 0x24100010, 0xc004ca7, +0x2021, 0x108042, 0x1600fffc, 0x0, +0xc004ca7, 0x24040001, 0xc004ca7, 0x2021, +0x34108000, 0x96220000, 0x501024, 0x10400002, +0x2021, 0x24040001, 0xc004ca7, 0x108042, +0x1600fff8, 0x0, 0xc004ccd, 0x0, +0x8004c80, 0x24020002, 0x27b10010, 0xa7a00010, +0x8021, 0xc004ca7, 0x24040001, 0x26100001, +0x2e020020, 0x1440fffb, 0x0, 0xc004ca7, +0x2021, 0xc004ca7, 0x24040001, 0xc004ca7, +0x24040001, 0xc004ca7, 0x2021, 0x24100010, +0x32020001, 0x10400002, 0x2021, 0x24040001, +0xc004ca7, 0x108042, 0x1600fffa, 0x32020001, +0x24100010, 0xc004ca7, 0x2021, 0x108042, +0x1600fffc, 0x0, 0xc004ccd, 0x34108000, +0xc004ccd, 0x0, 0xc004c87, 0x0, +0x50400005, 0x108042, 0x96220000, 0x501025, +0xa6220000, 0x108042, 0x1600fff7, 0x0, +0xc004ccd, 0x0, 0x97a20010, 0x30428000, +0x144002dc, 0x24020003, 0x8004c80, 0x0, +0x24021200, 0xa7a20010, 0x27b10010, 0x8021, +0xc004ca7, 0x24040001, 0x26100001, 0x2e020020, +0x1440fffb, 0x0, 0xc004ca7, 0x2021, +0xc004ca7, 0x24040001, 0xc004ca7, 0x2021, +0xc004ca7, 0x24040001, 0x24100010, 0x32020001, +0x10400002, 0x2021, 0x24040001, 0xc004ca7, +0x108042, 0x1600fffa, 0x32020001, 0x24100010, +0xc004ca7, 0x2021, 0x108042, 0x1600fffc, +0x0, 0xc004ca7, 0x24040001, 0xc004ca7, +0x2021, 0x34108000, 0x96220000, 0x501024, +0x10400002, 0x2021, 0x24040001, 0xc004ca7, +0x108042, 0x1600fff8, 0x0, 0xc004ccd, +0x0, 0x8f830054, 0x8004c72, 0x24020004, +0x8f830054, 0x3c020001, 0x8c42553c, 0x2463ff9c, +0x431023, 0x2c420064, 0x1440029e, 0x24020002, +0x3c030001, 0x8c635540, 0x10620297, 0x2c620003, +0x14400296, 0x24020011, 0x24020003, 0x10620005, +0x24020004, 0x10620291, 0x2402000f, 0x8004c80, +0x24020011, 0x8004c80, 0x24020005, 0x24020014, +0xa7a20010, 0x27b10010, 0x8021, 0xc004ca7, +0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, +0x0, 0xc004ca7, 0x2021, 0xc004ca7, +0x24040001, 0xc004ca7, 0x2021, 0xc004ca7, +0x24040001, 0x24100010, 0x32020001, 0x10400002, +0x2021, 0x24040001, 0xc004ca7, 0x108042, +0x1600fffa, 0x32020001, 0x24100010, 0x32020012, +0x10400002, 0x2021, 0x24040001, 0xc004ca7, +0x108042, 0x1600fffa, 0x32020012, 0xc004ca7, +0x24040001, 0xc004ca7, 0x2021, 0x34108000, +0x96220000, 0x501024, 0x10400002, 0x2021, +0x24040001, 0xc004ca7, 0x108042, 0x1600fff8, +0x0, 0xc004ccd, 0x0, 0x8f830054, +0x8004c72, 0x24020006, 0x8f830054, 0x3c020001, +0x8c42553c, 0x2463ff9c, 0x431023, 0x2c420064, +0x14400250, 0x24020007, 0x8004c80, 0x0, +0x24020006, 0xa7a20010, 0x27b10010, 0x8021, +0xc004ca7, 0x24040001, 0x26100001, 0x2e020020, +0x1440fffb, 0x0, 0xc004ca7, 0x2021, +0xc004ca7, 0x24040001, 0xc004ca7, 0x2021, +0xc004ca7, 0x24040001, 0x24100010, 0x32020001, +0x10400002, 0x2021, 0x24040001, 0xc004ca7, +0x108042, 0x1600fffa, 0x32020001, 0x24100010, +0x32020013, 0x10400002, 0x2021, 0x24040001, +0xc004ca7, 0x108042, 0x1600fffa, 0x32020013, +0xc004ca7, 0x24040001, 0xc004ca7, 0x2021, +0x34108000, 0x96220000, 0x501024, 0x10400002, +0x2021, 0x24040001, 0xc004ca7, 0x108042, +0x1600fff8, 0x0, 0xc004ccd, 0x0, +0x8f830054, 0x8004c72, 0x24020008, 0x8f830054, +0x3c020001, 0x8c42553c, 0x2463ff9c, 0x431023, +0x2c420064, 0x1440020f, 0x24020009, 0x8004c80, +0x0, 0x27b10010, 0xa7a00010, 0x8021, +0xc004ca7, 0x24040001, 0x26100001, 0x2e020020, +0x1440fffb, 0x0, 0xc004ca7, 0x2021, +0xc004ca7, 0x24040001, 0xc004ca7, 0x24040001, +0xc004ca7, 0x2021, 0x24100010, 0x32020001, +0x10400002, 0x2021, 0x24040001, 0xc004ca7, +0x108042, 0x1600fffa, 0x32020001, 0x24100010, +0x32020018, 0x10400002, 0x2021, 0x24040001, +0xc004ca7, 0x108042, 0x1600fffa, 0x32020018, +0xc004ccd, 0x34108000, 0xc004ccd, 0x0, +0xc004c87, 0x0, 0x50400005, 0x108042, +0x96220000, 0x501025, 0xa6220000, 0x108042, +0x1600fff7, 0x0, 0xc004ccd, 0x8021, +0x97a20010, 0x27b10010, 0x34420001, 0xa7a20010, +0xc004ca7, 0x24040001, 0x26100001, 0x2e020020, +0x1440fffb, 0x0, 0xc004ca7, 0x2021, +0xc004ca7, 0x24040001, 0xc004ca7, 0x2021, +0xc004ca7, 0x24040001, 0x24100010, 0x32020001, +0x10400002, 0x2021, 0x24040001, 0xc004ca7, +0x108042, 0x1600fffa, 0x32020001, 0x24100010, +0x32020018, 0x10400002, 0x2021, 0x24040001, +0xc004ca7, 0x108042, 0x1600fffa, 0x32020018, +0xc004ca7, 0x24040001, 0xc004ca7, 0x2021, +0x34108000, 0x96220000, 0x501024, 0x10400002, +0x2021, 0x24040001, 0xc004ca7, 0x108042, +0x1600fff8, 0x0, 0xc004ccd, 0x0, +0x8f830054, 0x8004c72, 0x2402000a, 0x8f830054, +0x3c020001, 0x8c42553c, 0x2463ff9c, 0x431023, +0x2c420064, 0x1440019b, 0x2402000b, 0x8004c80, +0x0, 0x27b10010, 0xa7a00010, 0x8021, +0xc004ca7, 0x24040001, 0x26100001, 0x2e020020, +0x1440fffb, 0x0, 0xc004ca7, 0x2021, +0xc004ca7, 0x24040001, 0xc004ca7, 0x24040001, +0xc004ca7, 0x2021, 0x24100010, 0x32020001, +0x10400002, 0x2021, 0x24040001, 0xc004ca7, +0x108042, 0x1600fffa, 0x32020001, 0x24100010, +0x32020017, 0x10400002, 0x2021, 0x24040001, +0xc004ca7, 0x108042, 0x1600fffa, 0x32020017, +0xc004ccd, 0x34108000, 0xc004ccd, 0x0, +0xc004c87, 0x0, 0x50400005, 0x108042, +0x96220000, 0x501025, 0xa6220000, 0x108042, +0x1600fff7, 0x0, 0xc004ccd, 0x8021, +0x97a20010, 0x27b10010, 0x34420700, 0xa7a20010, +0xc004ca7, 0x24040001, 0x26100001, 0x2e020020, +0x1440fffb, 0x0, 0xc004ca7, 0x2021, +0xc004ca7, 0x24040001, 0xc004ca7, 0x2021, +0xc004ca7, 0x24040001, 0x24100010, 0x32020001, +0x10400002, 0x2021, 0x24040001, 0xc004ca7, +0x108042, 0x1600fffa, 0x32020001, 0x24100010, +0x32020017, 0x10400002, 0x2021, 0x24040001, +0xc004ca7, 0x108042, 0x1600fffa, 0x32020017, +0xc004ca7, 0x24040001, 0xc004ca7, 0x2021, +0x34108000, 0x96220000, 0x501024, 0x10400002, +0x2021, 0x24040001, 0xc004ca7, 0x108042, +0x1600fff8, 0x0, 0xc004ccd, 0x0, +0x8f830054, 0x8004c72, 0x2402000c, 0x8f830054, +0x3c020001, 0x8c42553c, 0x2463ff9c, 0x431023, +0x2c420064, 0x14400127, 0x24020012, 0x8004c80, +0x0, 0x27b10010, 0xa7a00010, 0x8021, +0xc004ca7, 0x24040001, 0x26100001, 0x2e020020, +0x1440fffb, 0x0, 0xc004ca7, 0x2021, +0xc004ca7, 0x24040001, 0xc004ca7, 0x24040001, +0xc004ca7, 0x2021, 0x24100010, 0x32020001, +0x10400002, 0x2021, 0x24040001, 0xc004ca7, +0x108042, 0x1600fffa, 0x32020001, 0x24100010, +0x32020014, 0x10400002, 0x2021, 0x24040001, +0xc004ca7, 0x108042, 0x1600fffa, 0x32020014, +0xc004ccd, 0x34108000, 0xc004ccd, 0x0, +0xc004c87, 0x0, 0x50400005, 0x108042, +0x96220000, 0x501025, 0xa6220000, 0x108042, +0x1600fff7, 0x0, 0xc004ccd, 0x8021, +0x97a20010, 0x27b10010, 0x34420010, 0xa7a20010, +0xc004ca7, 0x24040001, 0x26100001, 0x2e020020, +0x1440fffb, 0x0, 0xc004ca7, 0x2021, +0xc004ca7, 0x24040001, 0xc004ca7, 0x2021, +0xc004ca7, 0x24040001, 0x24100010, 0x32020001, +0x10400002, 0x2021, 0x24040001, 0xc004ca7, +0x108042, 0x1600fffa, 0x32020001, 0x24100010, +0x32020014, 0x10400002, 0x2021, 0x24040001, +0xc004ca7, 0x108042, 0x1600fffa, 0x32020014, +0xc004ca7, 0x24040001, 0xc004ca7, 0x2021, +0x34108000, 0x96220000, 0x501024, 0x10400002, +0x2021, 0x24040001, 0xc004ca7, 0x108042, +0x1600fff8, 0x0, 0xc004ccd, 0x0, +0x8f830054, 0x8004c72, 0x24020013, 0x8f830054, +0x3c020001, 0x8c42553c, 0x2463ff9c, 0x431023, +0x2c420064, 0x144000b3, 0x2402000d, 0x8004c80, +0x0, 0x27b10010, 0xa7a00010, 0x8021, +0xc004ca7, 0x24040001, 0x26100001, 0x2e020020, +0x1440fffb, 0x0, 0xc004ca7, 0x2021, +0xc004ca7, 0x24040001, 0xc004ca7, 0x24040001, +0xc004ca7, 0x2021, 0x24100010, 0x32020001, +0x10400002, 0x2021, 0x24040001, 0xc004ca7, +0x108042, 0x1600fffa, 0x32020001, 0x24100010, +0x32020018, 0x10400002, 0x2021, 0x24040001, +0xc004ca7, 0x108042, 0x1600fffa, 0x32020018, +0xc004ccd, 0x34108000, 0xc004ccd, 0x0, +0xc004c87, 0x0, 0x50400005, 0x108042, +0x96220000, 0x501025, 0xa6220000, 0x108042, +0x1600fff7, 0x0, 0xc004ccd, 0x8021, +0x97a20010, 0x27b10010, 0x3042fffe, 0xa7a20010, +0xc004ca7, 0x24040001, 0x26100001, 0x2e020020, +0x1440fffb, 0x0, 0xc004ca7, 0x2021, +0xc004ca7, 0x24040001, 0xc004ca7, 0x2021, +0xc004ca7, 0x24040001, 0x24100010, 0x32020001, +0x10400002, 0x2021, 0x24040001, 0xc004ca7, +0x108042, 0x1600fffa, 0x32020001, 0x24100010, +0x32020018, 0x10400002, 0x2021, 0x24040001, +0xc004ca7, 0x108042, 0x1600fffa, 0x32020018, +0xc004ca7, 0x24040001, 0xc004ca7, 0x2021, +0x34108000, 0x96220000, 0x501024, 0x10400002, +0x2021, 0x24040001, 0xc004ca7, 0x108042, +0x1600fff8, 0x0, 0xc004ccd, 0x0, +0x8f830054, 0x8004c72, 0x2402000e, 0x24020840, +0xa7a20010, 0x27b10010, 0x8021, 0xc004ca7, +0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, +0x0, 0xc004ca7, 0x2021, 0xc004ca7, +0x24040001, 0xc004ca7, 0x2021, 0xc004ca7, +0x24040001, 0x24100010, 0x32020001, 0x10400002, +0x2021, 0x24040001, 0xc004ca7, 0x108042, +0x1600fffa, 0x32020001, 0x24100010, 0x32020013, +0x10400002, 0x2021, 0x24040001, 0xc004ca7, +0x108042, 0x1600fffa, 0x32020013, 0xc004ca7, +0x24040001, 0xc004ca7, 0x2021, 0x34108000, +0x96220000, 0x501024, 0x10400002, 0x2021, +0x24040001, 0xc004ca7, 0x108042, 0x1600fff8, +0x0, 0xc004ccd, 0x0, 0x8f830054, +0x24020010, 0x3c010001, 0xac2254a0, 0x3c010001, +0x8004c82, 0xac23553c, 0x8f830054, 0x3c020001, +0x8c42553c, 0x2463ff9c, 0x431023, 0x2c420064, +0x14400004, 0x0, 0x24020011, 0x3c010001, +0xac2254a0, 0x8fbf0020, 0x8fb1001c, 0x8fb00018, +0x3e00008, 0x27bd0028, 0x8f850044, 0x8f820044, +0x3c030001, 0x431025, 0x3c030008, 0xaf820044, +0x8f840054, 0x8f820054, 0xa32824, 0x8004c93, +0x24840001, 0x8f820054, 0x821023, 0x2c420002, +0x1440fffc, 0x0, 0x8f820044, 0x3c03fffe, +0x3463ffff, 0x431024, 0xaf820044, 0x8f830054, +0x8f820054, 0x8004ca1, 0x24630001, 0x8f820054, +0x621023, 0x2c420002, 0x1440fffc, 0x0, +0x3e00008, 0xa01021, 0x8f830044, 0x3c02fff0, +0x3442ffff, 0x42480, 0x621824, 0x3c020002, +0x822025, 0x641825, 0xaf830044, 0x8f820044, +0x3c030001, 0x431025, 0xaf820044, 0x8f830054, +0x8f820054, 0x8004cb9, 0x24630001, 0x8f820054, +0x621023, 0x2c420002, 0x1440fffc, 0x0, +0x8f820044, 0x3c03fffe, 0x3463ffff, 0x431024, +0xaf820044, 0x8f830054, 0x8f820054, 0x8004cc7, +0x24630001, 0x8f820054, 0x621023, 0x2c420002, +0x1440fffc, 0x0, 0x3e00008, 0x0, +0x8f820044, 0x3c03fff0, 0x3463ffff, 0x431024, +0xaf820044, 0x8f820044, 0x3c030001, 0x431025, +0xaf820044, 0x8f830054, 0x8f820054, 0x8004cdb, +0x24630001, 0x8f820054, 0x621023, 0x2c420002, +0x1440fffc, 0x0, 0x8f820044, 0x3c03fffe, +0x3463ffff, 0x431024, 0xaf820044, 0x8f830054, +0x8f820054, 0x8004ce9, 0x24630001, 0x8f820054, +0x621023, 0x2c420002, 0x1440fffc, 0x0, +0x3e00008, 0x0, 0x0, 0x27bdffe8, +0xafbf0010, 0x3c030001, 0x771821, 0x8c6383ac, +0x24020008, 0x1462022c, 0x803021, 0x3c020001, +0x8c425528, 0x14400033, 0x0, 0x8f850224, +0x38a30020, 0x2c630001, 0x38a20010, 0x2c420001, +0x621825, 0x1460000d, 0x38a30030, 0x2c630001, +0x38a20400, 0x2c420001, 0x621825, 0x14600007, +0x38a30402, 0x2c630001, 0x38a20404, 0x2c420001, +0x621825, 0x10600005, 0x0, 0xc00429f, +0x0, 0x8004d29, 0x2402000e, 0xc0043e1, +0x0, 0x3c050001, 0x8ca55478, 0xc0050af, +0x2021, 0x3c030001, 0x8c635478, 0x24020004, +0x14620005, 0x2403fffb, 0x3c020001, 0x8c425474, +0x8004d25, 0x2403fff7, 0x3c020001, 0x8c425474, +0x431024, 0x3c010001, 0xac225474, 0x2402000e, +0x3c010001, 0xc00429f, 0xac227550, 0x8004f23, +0x0, 0x8f820220, 0x3c030400, 0x431024, +0x10400027, 0x2403ffbf, 0x8f850224, 0x3c020001, +0x8c42755c, 0xa32024, 0x431024, 0x1482000c, +0x0, 0x3c020001, 0x8c427560, 0x24420001, +0x3c010001, 0xac227560, 0x2c420002, 0x14400008, +0x24020001, 0x3c010001, 0x8004d49, 0xac227580, +0x3c010001, 0xac207560, 0x3c010001, 0xac207580, +0x3c020001, 0x8c427580, 0x10400006, 0x30a20040, +0x10400004, 0x24020001, 0x3c010001, 0x8004d54, +0xac227584, 0x3c010001, 0xac207584, 0x3c010001, +0xac25755c, 0x3c010001, 0x8004d64, 0xac207590, +0x24020001, 0x3c010001, 0xac227590, 0x3c010001, +0xac207580, 0x3c010001, 0xac207560, 0x3c010001, +0xac207584, 0x3c010001, 0xac20755c, 0x3c030001, +0x8c637550, 0x3c020001, 0x8c427554, 0x10620003, +0x3c020200, 0x3c010001, 0xac237554, 0xc21024, +0x10400007, 0x2463ffff, 0x8f820220, 0x24030001, +0x3c010001, 0xac23547c, 0x8004f21, 0x3c03f700, +0x2c62000e, 0x104001a8, 0x31080, 0x3c010001, +0x220821, 0x8c225350, 0x400008, 0x0, +0x3c010001, 0xac207580, 0x3c010001, 0xac207560, +0x3c010001, 0xac20755c, 0x3c010001, 0xac207584, +0x3c010001, 0xac207578, 0x3c010001, 0xac207570, +0xc0047cc, 0xaf800224, 0x24020002, 0x3c010001, +0xac227550, 0x3c020001, 0x8c427590, 0x14400056, +0x3c03fdff, 0x8ee20000, 0x3463ffff, 0x431024, +0xc00429f, 0xaee20000, 0xaf800204, 0x8f820200, +0x2403fffd, 0x431024, 0xaf820200, 0x3c010001, +0xac2075a0, 0x8f830054, 0x3c020001, 0x8c427578, +0x24040001, 0x3c010001, 0xac24758c, 0x24420001, +0x3c010001, 0xac227578, 0x2c420004, 0x3c010001, +0xac237574, 0x14400006, 0x24020003, 0x3c010001, +0xac24547c, 0x3c010001, 0x8004f1f, 0xac207578, +0x3c010001, 0x8004f1f, 0xac227550, 0x8f830054, +0x3c020001, 0x8c427574, 0x2463d8f0, 0x431023, +0x2c422710, 0x14400003, 0x24020004, 0x3c010001, +0xac227550, 0x3c020001, 0x8c427590, 0x14400026, +0x3c03fdff, 0x8ee20000, 0x3463ffff, 0x431024, +0x8004f1f, 0xaee20000, 0x3c040001, 0x8c84552c, +0x3c010001, 0xc004f26, 0xac207568, 0x3c020001, +0x8c42759c, 0xaf820204, 0x3c020001, 0x8c427590, +0x14400015, 0x3c03fdff, 0x8ee20000, 0x3463ffff, +0x431024, 0xaee20000, 0x8f820204, 0x30420030, +0x1440013c, 0x24020002, 0x3c030001, 0x8c63759c, +0x24020005, 0x3c010001, 0xac227550, 0x3c010001, +0x8004f1f, 0xac2375a0, 0x3c020001, 0x8c427590, +0x10400010, 0x3c03fdff, 0x3c020001, 0x8c4254fc, +0x24420001, 0x3c010001, 0xac2254fc, 0x2c420002, +0x14400131, 0x24020001, 0x3c010001, 0xac225504, +0x3c010001, 0xac2054fc, 0x3c010001, 0x8004f1f, +0xac22547c, 0x8ee20000, 0x3463ffff, 0x431024, +0xaee20000, 0x3c020001, 0x8c427580, 0x10400122, +0x0, 0x3c020001, 0x8c42755c, 0x1040011e, +0x0, 0x3c010001, 0xac227588, 0x24020003, +0x3c010001, 0xac227560, 0x8004ec0, 0x24020006, +0x3c010001, 0xac207568, 0x8f820204, 0x34420040, +0xaf820204, 0x3c020001, 0x8c4275a0, 0x24030007, +0x3c010001, 0xac237550, 0x34420040, 0x3c010001, +0xac2275a0, 0x3c020001, 0x8c427580, 0x10400005, +0x0, 0x3c020001, 0x8c42755c, 0x104000f9, +0x24020002, 0x3c050001, 0x24a57560, 0x8ca20000, +0x2c424e21, 0x104000f3, 0x24020002, 0x3c020001, +0x8c427584, 0x104000f8, 0x2404ffbf, 0x3c020001, +0x8c42755c, 0x3c030001, 0x8c637588, 0x441024, +0x641824, 0x10430004, 0x24020001, 0x3c010001, +0x8004f1f, 0xac227550, 0x24020003, 0xaca20000, +0x24020008, 0x3c010001, 0xac227550, 0x3c020001, +0x8c42758c, 0x1040000c, 0x24020001, 0x3c040001, +0xc004f33, 0x8c84755c, 0x3c020001, 0x8c4275a8, +0x14400005, 0x24020001, 0x3c020001, 0x8c4275a4, +0x10400006, 0x24020001, 0x3c010001, 0xac22547c, +0x3c010001, 0x8004f1f, 0xac207578, 0x3c020001, +0x8c427570, 0x3c030001, 0x8c63755c, 0x2c420001, +0x210c0, 0x30630008, 0x3c010001, 0xac227570, +0x3c010001, 0xac23756c, 0x8f830054, 0x24020009, +0x3c010001, 0xac227550, 0x3c010001, 0x8004f1f, +0xac237574, 0x8f830054, 0x3c020001, 0x8c427574, +0x2463d8f0, 0x431023, 0x2c422710, 0x144000a8, +0x0, 0x3c020001, 0x8c427580, 0x10400005, +0x0, 0x3c020001, 0x8c42755c, 0x104000a9, +0x24020002, 0x3c030001, 0x24637560, 0x8c620000, +0x2c424e21, 0x104000a3, 0x24020002, 0x3c020001, +0x8c42758c, 0x1040000e, 0x0, 0x3c020001, +0x8c42755c, 0x3c010001, 0xac20758c, 0x30420080, +0x1040002f, 0x2402000c, 0x8f820204, 0x30420080, +0x1440000c, 0x24020003, 0x8004ead, 0x2402000c, +0x3c020001, 0x8c42755c, 0x30420080, 0x14400005, +0x24020003, 0x8f820204, 0x30420080, 0x1040001f, +0x24020003, 0xac620000, 0x2402000a, 0x3c010001, +0xac227550, 0x3c040001, 0x24847598, 0x8c820000, +0x3c030001, 0x8c637570, 0x431025, 0xaf820204, +0x8c830000, 0x3c040001, 0x8c847570, 0x2402000b, +0x3c010001, 0xac227550, 0x641825, 0x3c010001, +0xac2375a0, 0x3c050001, 0x24a57560, 0x8ca20000, +0x2c424e21, 0x1040006f, 0x24020002, 0x3c020001, +0x8c427590, 0x10400005, 0x0, 0x2402000c, +0x3c010001, 0x8004f1f, 0xac227550, 0x3c020001, +0x8c427580, 0x1040006c, 0x0, 0x3c040001, +0x8c84755c, 0x1080005e, 0x30820008, 0x3c030001, +0x8c63756c, 0x10620064, 0x24020003, 0x3c010001, +0xac247588, 0xaca20000, 0x24020006, 0x3c010001, +0x8004f1f, 0xac227550, 0x8f820200, 0x34420002, +0xaf820200, 0x8f830054, 0x2402000d, 0x3c010001, +0xac227550, 0x3c010001, 0xac237574, 0x8f830054, +0x3c020001, 0x8c427574, 0x2463d8f0, 0x431023, +0x2c422710, 0x1440003a, 0x0, 0x3c020001, +0x8c427590, 0x10400029, 0x2402000e, 0x3c030001, +0x8c6375a4, 0x3c010001, 0x14600015, 0xac227550, +0xc0043e1, 0x0, 0x3c050001, 0x8ca55478, +0xc0050af, 0x2021, 0x3c030001, 0x8c635478, +0x24020004, 0x14620005, 0x2403fffb, 0x3c020001, +0x8c425474, 0x8004eee, 0x2403fff7, 0x3c020001, +0x8c425474, 0x431024, 0x3c010001, 0xac225474, +0x8ee20000, 0x3c030200, 0x431025, 0xaee20000, +0x8f820224, 0x3c010001, 0xac2275ac, 0x8f820220, +0x2403fffb, 0x431024, 0xaf820220, 0x8f820220, +0x34420002, 0x8004f1f, 0xaf820220, 0x3c020001, +0x8c427580, 0x10400005, 0x0, 0x3c020001, +0x8c42755c, 0x1040000f, 0x24020002, 0x3c020001, +0x8c427560, 0x2c424e21, 0x1040000a, 0x24020002, +0x3c020001, 0x8c427580, 0x1040000f, 0x0, +0x3c020001, 0x8c42755c, 0x1440000b, 0x0, +0x24020002, 0x3c010001, 0x8004f1f, 0xac227550, +0x3c020001, 0x8c427580, 0x10400003, 0x0, +0xc00429f, 0x0, 0x8f820220, 0x3c03f700, +0x431025, 0xaf820220, 0x8fbf0010, 0x3e00008, +0x27bd0018, 0x3c030001, 0x246375a8, 0x8c620000, +0x10400005, 0x34422000, 0x3c010001, 0xac22759c, +0x8004f31, 0xac600000, 0x3c010001, 0xac24759c, +0x3e00008, 0x0, 0x27bdffe0, 0x30820030, +0xafbf0018, 0x3c010001, 0xac2275a4, 0x14400067, +0x3c02ffff, 0x34421f0e, 0x821024, 0x14400061, +0x24020030, 0x30822000, 0x1040005d, 0x30838000, +0x31a02, 0x30820001, 0x21200, 0x3c040001, +0x8c84552c, 0x621825, 0x331c2, 0x3c030001, +0x24635508, 0x30828000, 0x21202, 0x30840001, +0x42200, 0x441025, 0x239c2, 0x61080, +0x431021, 0x471021, 0x90430000, 0x24020001, +0x10620025, 0x0, 0x10600007, 0x24020002, +0x10620013, 0x24020003, 0x1062002c, 0x3c05000f, +0x8004f95, 0x0, 0x8f820200, 0x2403feff, +0x431024, 0xaf820200, 0x8f820220, 0x3c03fffe, +0x3463ffff, 0x431024, 0xaf820220, 0x3c010001, +0xac2075c4, 0x3c010001, 0x8004fa0, 0xac2075cc, +0x8f820200, 0x34420100, 0xaf820200, 0x8f820220, +0x3c03fffe, 0x3463ffff, 0x431024, 0xaf820220, +0x24020100, 0x3c010001, 0xac2275c4, 0x3c010001, +0x8004fa0, 0xac2075cc, 0x8f820200, 0x2403feff, +0x431024, 0xaf820200, 0x8f820220, 0x3c030001, +0x431025, 0xaf820220, 0x3c010001, 0xac2075c4, +0x3c010001, 0x8004fa0, 0xac2375cc, 0x8f820200, +0x34420100, 0xaf820200, 0x8f820220, 0x3c030001, +0x431025, 0xaf820220, 0x24020100, 0x3c010001, +0xac2275c4, 0x3c010001, 0x8004fa0, 0xac2375cc, +0x34a5ffff, 0x3c040001, 0x24845388, 0xafa30010, +0xc002407, 0xafa00014, 0x8004fa0, 0x0, +0x24020030, 0x3c010001, 0xac2275a8, 0x8fbf0018, +0x3e00008, 0x27bd0020, 0x0, 0x27bdffc8, +0xafb10024, 0x808821, 0xafb3002c, 0xa09821, +0xafb00020, 0xc08021, 0x3c040001, 0x248453a0, +0x3c050009, 0x3c020001, 0x8c425478, 0x34a59001, +0x2203021, 0x2603821, 0xafbf0030, 0xafb20028, +0xa7a0001a, 0xafb00014, 0xc002407, 0xafa20010, +0x24020002, 0x126200ed, 0x2e620003, 0x10400005, +0x24020001, 0x1262000a, 0x3c02fffb, 0x80050a8, +0x0, 0x24020004, 0x1262006d, 0x24020008, +0x1262006c, 0x3c02ffec, 0x80050a8, 0x0, +0x3442ffff, 0x2028024, 0x119140, 0x3c010001, +0x320821, 0xac3075bc, 0x3c024000, 0x2021024, +0x10400046, 0x1023c2, 0x30840030, 0x101382, +0x3042000c, 0x3c030001, 0x246354a4, 0x431021, +0x823821, 0x3c020020, 0x2021024, 0x10400006, +0x24020100, 0x3c010001, 0x320821, 0xac2275c0, +0x8004fe7, 0x3c020080, 0x3c010001, 0x320821, +0xac2075c0, 0x3c020080, 0x2021024, 0x10400006, +0x111940, 0x3c020001, 0x3c010001, 0x230821, +0x8004ff3, 0xac2275c8, 0x111140, 0x3c010001, +0x220821, 0xac2075c8, 0x94e30000, 0x32024000, +0x10400003, 0xa7a30018, 0x34624000, 0xa7a20018, +0x24040001, 0x94e20002, 0x24050004, 0x24e60002, +0x34420001, 0xc0048ea, 0xa4e20002, 0x24040001, +0x2821, 0xc0048ea, 0x27a60018, 0x3c020001, +0x8c425478, 0x24110001, 0x3c010001, 0xac315484, +0x14530004, 0x32028000, 0xc00429f, 0x0, +0x32028000, 0x10400099, 0x0, 0xc00429f, +0x0, 0x24020002, 0x3c010001, 0xac31547c, +0x3c010001, 0x80050a8, 0xac225478, 0x24040001, +0x24050004, 0x27b0001a, 0xc0048ea, 0x2003021, +0x24040001, 0x2821, 0xc0048ea, 0x2003021, +0x3c020001, 0x521021, 0x8c4275b4, 0x3c040001, +0x8c845478, 0x3c03bfff, 0x3463ffff, 0x3c010001, +0xac335484, 0x431024, 0x3c010001, 0x320821, +0x10930078, 0xac2275b4, 0x80050a8, 0x0, +0x3c02ffec, 0x3442ffff, 0x2028024, 0x3c020008, +0x2028025, 0x111140, 0x3c010001, 0x220821, +0xac3075b8, 0x3c022000, 0x2021024, 0x10400009, +0x0, 0x3c020001, 0x8c425504, 0x14400005, +0x24020001, 0x3c010001, 0xac225528, 0x8005049, +0x3c024000, 0x3c010001, 0xac205528, 0x3c024000, +0x2021024, 0x1440001c, 0x0, 0x3c020001, +0x8c425528, 0x10400007, 0x24022020, 0x3c010001, +0xac22552c, 0x24020001, 0x3c010001, 0x370821, +0xac2283ac, 0x3c04bfff, 0x111940, 0x3c020001, +0x431021, 0x8c4275b0, 0x3c050001, 0x8ca55478, +0x3484ffff, 0x441024, 0x3c010001, 0x230821, +0xac2275b0, 0x24020001, 0x10a20044, 0x0, +0x80050a6, 0x0, 0x3c020001, 0x8c425528, +0x1040001c, 0x24022000, 0x3c010001, 0xac22552c, +0x3c0300a0, 0x2031024, 0x14430005, 0x111140, +0x3402a000, 0x3c010001, 0x80050a1, 0xac22552c, +0x3c030001, 0x621821, 0x8c6375b8, 0x3c020020, +0x621024, 0x10400004, 0x24022001, 0x3c010001, +0x80050a1, 0xac22552c, 0x3c020080, 0x621024, +0x1040001f, 0x3402a001, 0x3c010001, 0x80050a1, +0xac22552c, 0x3c020020, 0x2021024, 0x10400007, +0x111940, 0x24020100, 0x3c010001, 0x230821, +0xac2275c4, 0x8005095, 0x3c020080, 0x111140, +0x3c010001, 0x220821, 0xac2075c4, 0x3c020080, +0x2021024, 0x10400006, 0x111940, 0x3c020001, +0x3c010001, 0x230821, 0x80050a1, 0xac2275cc, +0x111140, 0x3c010001, 0x220821, 0xac2075cc, +0x3c030001, 0x8c635478, 0x24020001, 0x10620003, +0x0, 0xc00429f, 0x0, 0x8fbf0030, +0x8fb3002c, 0x8fb20028, 0x8fb10024, 0x8fb00020, +0x3e00008, 0x27bd0038, 0x27bdffd0, 0xafb40028, +0x80a021, 0xafb20020, 0x9021, 0xafb30024, +0x9821, 0xafb1001c, 0x8821, 0x24020002, +0xafbf002c, 0xafb00018, 0xa7a00012, 0x10a20068, +0xa7a00010, 0x2ca20003, 0x10400005, 0x24020001, +0x10a2000a, 0x148140, 0x8005172, 0x2201021, +0x24020004, 0x10a2005e, 0x24020008, 0x10a2005d, +0x142940, 0x8005172, 0x2201021, 0x3c030001, +0x701821, 0x8c6375bc, 0x3c024000, 0x621024, +0x14400009, 0x24040001, 0x3c027fff, 0x3442ffff, +0x628824, 0x3c010001, 0x300821, 0xac3175b4, +0x8005172, 0x2201021, 0x24050001, 0xc0048a8, +0x27a60010, 0x24040001, 0x24050001, 0xc0048a8, +0x27a60010, 0x97a20010, 0x30420004, 0x10400034, +0x3c114000, 0x3c030001, 0x8c635540, 0x24020003, +0x10620008, 0x2c620004, 0x14400029, 0x3c028000, +0x24020004, 0x10620014, 0x24040001, 0x8005115, +0x3c028000, 0x24040001, 0x24050011, 0x27b00012, +0xc0048a8, 0x2003021, 0x24040001, 0x24050011, +0xc0048a8, 0x2003021, 0x97a30012, 0x30624000, +0x10400002, 0x3c130010, 0x3c130008, 0x3c120001, +0x8005112, 0x30628000, 0x24050014, 0x27b00012, +0xc0048a8, 0x2003021, 0x24040001, 0x24050014, +0xc0048a8, 0x2003021, 0x97a30012, 0x30621000, +0x10400002, 0x3c130010, 0x3c130008, 0x3c120001, +0x30620800, 0x54400001, 0x3c120002, 0x3c028000, +0x2221025, 0x2531825, 0x800511f, 0x438825, +0x3c110001, 0x2308821, 0x8e3175bc, 0x3c027fff, +0x3442ffff, 0x2228824, 0x141140, 0x3c010001, +0x220821, 0xac3175b4, 0x8005172, 0x2201021, +0x142940, 0x3c030001, 0x651821, 0x8c6375b8, +0x3c024000, 0x621024, 0x14400008, 0x3c027fff, +0x3442ffff, 0x628824, 0x3c010001, 0x250821, +0xac3175b0, 0x8005172, 0x2201021, 0x3c020001, +0x8c425488, 0x10400033, 0x3c11c00c, 0x3c020001, +0x8c425504, 0x3c04c00c, 0x34842000, 0x3c030001, +0x8c635528, 0x2102b, 0x21023, 0x441024, +0x10600003, 0x518825, 0x3c022000, 0x2228825, +0x3c020001, 0x451021, 0x8c4275c4, 0x10400003, +0x3c020020, 0x800514f, 0x2228825, 0x3c02ffdf, +0x3442ffff, 0x2228824, 0x141140, 0x3c010001, +0x220821, 0x8c2275cc, 0x10400003, 0x3c020080, +0x800515a, 0x2228825, 0x3c02ff7f, 0x3442ffff, +0x2228824, 0x3c020001, 0x8c4254f0, 0x10400002, +0x3c020800, 0x2228825, 0x3c020001, 0x8c4254f4, +0x10400002, 0x3c020400, 0x2228825, 0x3c020001, +0x8c4254f8, 0x10400006, 0x3c020100, 0x800516d, +0x2228825, 0x3c027fff, 0x3442ffff, 0x628824, +0x141140, 0x3c010001, 0x220821, 0xac3175b0, +0x2201021, 0x8fbf002c, 0x8fb40028, 0x8fb30024, +0x8fb20020, 0x8fb1001c, 0x8fb00018, 0x3e00008, +0x27bd0030, 0x27bdffd8, 0xafb40020, 0x80a021, +0xafbf0024, 0xafb3001c, 0xafb20018, 0xafb10014, +0xafb00010, 0x8f900200, 0x3c030001, 0x8c635478, +0x8f930220, 0x24020002, 0x106200b4, 0x2c620003, +0x10400005, 0x24020001, 0x1062000a, 0x141940, +0x800523c, 0x0, 0x24020004, 0x1062005a, +0x24020008, 0x10620059, 0x149140, 0x800523c, +0x0, 0x3c040001, 0x832021, 0x8c8475bc, +0x3c110001, 0x2238821, 0x8e3175b4, 0x3c024000, +0x821024, 0x1040003e, 0x3c020008, 0x2221024, +0x10400020, 0x36100002, 0x3c020001, 0x431021, +0x8c4275c0, 0x10400005, 0x36100020, 0x36100100, +0x3c020020, 0x80051b1, 0x2228825, 0x2402feff, +0x2028024, 0x3c02ffdf, 0x3442ffff, 0x2228824, +0x141140, 0x3c010001, 0x220821, 0x8c2275c8, +0x10400005, 0x3c020001, 0x2629825, 0x3c020080, +0x80051d0, 0x2228825, 0x3c02fffe, 0x3442ffff, +0x2629824, 0x3c02ff7f, 0x3442ffff, 0x80051d0, +0x2228824, 0x2402fedf, 0x2028024, 0x3c02fffe, +0x3442ffff, 0x2629824, 0x3c02ff5f, 0x3442ffff, +0x2228824, 0x3c010001, 0x230821, 0xac2075c0, +0x3c010001, 0x230821, 0xac2075c8, 0xc0047cc, +0x0, 0xaf900200, 0xaf930220, 0x8f820220, +0x2403fffb, 0x431024, 0xaf820220, 0x8f820220, +0x34420002, 0xaf820220, 0x80051e7, 0x141140, +0x8f820200, 0x2403fffd, 0x431024, 0xc0047cc, +0xaf820200, 0x3c02bfff, 0x3442ffff, 0xc00429f, +0x2228824, 0x141140, 0x3c010001, 0x220821, +0x800523c, 0xac3175b4, 0x149140, 0x3c040001, +0x922021, 0x8c8475b8, 0x3c110001, 0x2328821, +0x8e3175b0, 0x3c024000, 0x821024, 0x14400011, +0x0, 0x3c020001, 0x8c425528, 0x14400006, +0x3c02bfff, 0x8f820200, 0x34420002, 0xc0047cc, +0xaf820200, 0x3c02bfff, 0x3442ffff, 0xc00429f, +0x2228824, 0x3c010001, 0x320821, 0x800523c, +0xac3175b0, 0x3c020001, 0x8c425528, 0x10400005, +0x3c020020, 0x3c020001, 0x8c425504, 0x1040002b, +0x3c020020, 0x821024, 0x10400007, 0x36100020, +0x24020100, 0x3c010001, 0x320821, 0xac2275c4, +0x800521c, 0x36100100, 0x3c010001, 0x320821, +0xac2075c4, 0x2402feff, 0x2028024, 0x3c020080, +0x821024, 0x10400007, 0x141940, 0x3c020001, +0x3c010001, 0x230821, 0xac2275cc, 0x800522d, +0x2629825, 0x141140, 0x3c010001, 0x220821, +0xac2075cc, 0x3c02fffe, 0x3442ffff, 0x2629824, +0xc0047cc, 0x0, 0xaf900200, 0xaf930220, +0x8f820220, 0x2403fffb, 0x431024, 0xaf820220, +0x8f820220, 0x34420002, 0xaf820220, 0x141140, +0x3c010001, 0x220821, 0xac3175b0, 0x8fbf0024, +0x8fb40020, 0x8fb3001c, 0x8fb20018, 0x8fb10014, +0x8fb00010, 0x3e00008, 0x27bd0028, 0x0 }; u32 tigonFwRodata[(MAX_RODATA_LEN/4) + 1] __initdata = { -0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563, 0x74732f72, 0x63732f73, -0x772f6765, 0x2f6e6963, 0x2f66772f, 0x636f6d6d, 0x6f6e2f66, 0x776d6169, -0x6e2e632c, 0x7620312e, 0x312e322e, 0x31312031, 0x3939382f, 0x30342f32, -0x37203232, 0x3a31333a, 0x34322073, 0x6875616e, 0x67204578, 0x70202400, -0x7468655f, 0x4441574e, 0x0, 0x53544143, 0x4b5f3120, 0x0, -0x42616453, 0x6e64526e, 0x67000000, 0x3f456e71, 0x45767400, 0x3f6e6f51, -0x64457650, 0x0, 0x6576526e, 0x6746756c, 0x6c000000, 0x496c6c43, -0x6f6e6652, 0x78000000, 0x53656e64, 0x436b5375, 0x6d000000, 0x52656376, -0x566c616e, 0x0, 0x0, 0x0, 0x24486561, 0x6465723a, -0x202f7072, 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, 0x2f6e6963, -0x2f66772f, 0x636f6d6d, 0x6f6e2f74, 0x696d6572, 0x2e632c76, 0x20312e31, -0x2e322e37, 0x20313939, 0x382f3034, 0x2f323720, 0x32323a31, 0x333a3439, -0x20736875, 0x616e6720, 0x45787020, 0x24000000, 0x542d446d, 0x61526431, -0x0, 0x542d446d, 0x61424200, 0x542d446d, 0x61320000, 0x3f6e6f51, -0x64547845, 0x0, 0x3f6e6f51, 0x64527845, 0x0, 0x656e714d, -0x45765046, 0x61696c00, 0x656e714d, 0x45764661, 0x696c0000, 0x6661696c, -0x456e454d, 0x0, 0x3f456e71, 0x45767400, 0x3f6e6f51, 0x64457650, -0x0, 0x6576526e, 0x6746756c, 0x6c000000, 0x0, 0x0, -0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563, 0x74732f72, 0x63732f73, -0x772f6765, 0x2f6e6963, 0x2f66772f, 0x636f6d6d, 0x6f6e2f63, 0x6f6d6d61, -0x6e642e63, 0x2c762031, 0x2e312e31, 0x362e3120, 0x31393938, 0x2f31312f, -0x31392030, 0x323a3339, 0x3a323520, 0x73687561, 0x6e672045, 0x78702024, -0x0, 0x3f4d626f, 0x78457674, 0x0, 0x4e4f636f, 0x6d616e64, -0x0, 0x68737465, 0x5f455252, 0x0, 0x412d4572, 0x72427563, -0x0, 0x4552524f, 0x522d4164, 0x64000000, 0x656e714d, 0x45765046, -0x61696c00, 0x656e714d, 0x45764661, 0x696c0000, 0x6661696c, 0x456e454d, -0x0, 0x442d4572, 0x724c6173, 0x74000000, 0x442d4572, 0x72320000, -0x6d437374, 0x4d644552, 0x52000000, 0x70726f6d, 0x4d644552, 0x52000000, -0x46696c74, 0x4d644552, 0x52000000, 0x636d645f, 0x45525200, 0x3f456e71, -0x45767400, 0x3f6e6f51, 0x64457650, 0x0, 0x6576526e, 0x6746756c, -0x6c000000, 0x0, 0x6e90, 0x7fac, 0x6e28, 0x871c, -0x8298, 0x8768, 0x8768, 0x6f44, 0x7684, 0x7efc, -0x8098, 0x8064, 0x8768, 0x7e60, 0x80bc, 0x6e54, -0x81bc, 0x0, 0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563, -0x74732f72, 0x63732f73, 0x772f6765, 0x2f6e6963, 0x2f66772f, 0x636f6d6d, -0x6f6e2f64, 0x6d612e63, 0x2c762031, 0x2e312e32, 0x2e332031, 0x3939382f, -0x30342f32, 0x37203232, 0x3a31333a, 0x34312073, 0x6875616e, 0x67204578, -0x70202400, 0x646d6172, 0x6441544e, 0x0, 0x646d6177, 0x7241544e, -0x0, 0x0, 0x0, 0x0, 0x24486561, 0x6465723a, -0x202f7072, 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, 0x2f6e6963, -0x2f66772f, 0x636f6d6d, 0x6f6e2f74, 0x72616365, 0x2e632c76, 0x20312e31, -0x2e322e32, 0x20313939, 0x382f3034, 0x2f323720, 0x32323a31, 0x333a3530, -0x20736875, 0x616e6720, 0x45787020, 0x24000000, 0x24486561, 0x6465723a, -0x202f7072, 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, 0x2f6e6963, -0x2f66772f, 0x636f6d6d, 0x6f6e2f64, 0x6174612e, 0x632c7620, 0x312e312e, -0x322e3220, 0x31393938, 0x2f30342f, 0x32372032, 0x323a3133, 0x3a343020, -0x73687561, 0x6e672045, 0x78702024, 0x0, 0x46575f56, 0x45525349, -0x4f4e3a20, 0x2331204d, 0x6f6e2044, 0x65632037, 0x2031343a, 0x35363a33, -0x30205053, 0x54203139, 0x39380000, 0x46575f43, 0x4f4d5049, 0x4c455f54, -0x494d453a, 0x2031343a, 0x35363a33, 0x30000000, 0x46575f43, 0x4f4d5049, -0x4c455f42, 0x593a2064, 0x65767263, 0x73000000, 0x46575f43, 0x4f4d5049, -0x4c455f48, 0x4f53543a, 0x20636f6d, 0x70757465, 0x0, 0x46575f43, -0x4f4d5049, 0x4c455f44, 0x4f4d4149, 0x4e3a2065, 0x6e672e61, 0x6374656f, -0x6e2e636f, 0x6d000000, 0x46575f43, 0x4f4d5049, 0x4c45523a, 0x20676363, -0x20766572, 0x73696f6e, 0x20322e37, 0x2e320000, 0x0, 0x0, -0x0, 0x0, 0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563, -0x74732f72, 0x63732f73, 0x772f6765, 0x2f6e6963, 0x2f66772f, 0x636f6d6d, -0x6f6e2f6d, 0x656d2e63, 0x2c762031, 0x2e312e32, 0x2e322031, 0x3939382f, -0x30342f32, 0x37203232, 0x3a31333a, 0x34342073, 0x6875616e, 0x67204578, -0x70202400, 0x0, 0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563, -0x74732f72, 0x63732f73, 0x772f6765, 0x2f6e6963, 0x2f66772f, 0x636f6d6d, -0x6f6e2f73, 0x656e642e, 0x632c7620, 0x312e312e, 0x322e3820, 0x31393938, -0x2f30342f, 0x32372032, 0x323a3133, 0x3a343820, 0x73687561, 0x6e672045, -0x78702024, 0x0, 0x736e6464, 0x654e6f51, 0x20000000, 0x6e6f454e, -0x515f5458, 0x0, 0x736e6464, 0x744e6f51, 0x20000000, 0x3f6e6f51, -0x64547845, 0x0, 0x756e6b72, 0x64747970, 0x65000000, 0x0, -0xbc88, 0xbc88, 0xbd30, 0xae2c, 0xb038, 0xbd30, -0xbd30, 0xbd30, 0xbd30, 0xbd30, 0xbd30, 0xbd30, -0xbd30, 0xbd30, 0xbd30, 0xbd30, 0xbd30, 0xbd30, -0xbd30, 0xb020, 0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563, -0x74732f72, 0x63732f73, 0x772f6765, 0x2f6e6963, 0x2f66772f, 0x636f6d6d, -0x6f6e2f72, 0x6563762e, 0x632c7620, 0x312e312e, 0x322e3139, 0x20313939, -0x382f3037, 0x2f323420, 0x32313a33, 0x303a3035, 0x20736875, 0x616e6720, -0x45787020, 0x24000000, 0x706b5278, 0x45525200, 0x66726d32, 0x4c617267, -0x65000000, 0x72784e6f, 0x52784264, 0x0, 0x72785144, 0x6d614446, -0x0, 0x72785144, 0x6d614246, 0x0, 0x3f6e6f51, 0x64527845, -0x0, 0x706b5278, 0x45525273, 0x0, 0x66726d32, 0x4c726753, -0x0, 0x72784e6f, 0x42645300, 0x3f724264, 0x446d6146, 0x0, -0x3f724a42, 0x64446d46, 0x0, 0x0, 0xf638, 0xf638, -0xf638, 0xf638, 0xf638, 0xf638, 0xf638, 0xf638, -0xf638, 0xf638, 0xf638, 0xf638, 0xf638, 0xf638, -0xf638, 0xf630, 0xf630, 0xf630, 0x572d444d, 0x41456e46, -0x0, 0x0, 0xfd80, 0x1011c, 0xfd9c, 0x1011c, -0x1011c, 0x1011c, 0x1011c, 0x1011c, 0x1011c, 0xf6c4, -0x1011c, 0x1011c, 0x1011c, 0x1011c, 0x1011c, 0x10114, -0x10114, 0x10114, 0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563, -0x74732f72, 0x63732f73, 0x772f6765, 0x2f6e6963, 0x2f66772f, 0x636f6d6d, -0x6f6e2f6d, 0x61632e63, 0x2c762031, 0x2e312e32, 0x2e313220, 0x31393938, -0x2f30342f, 0x32372032, 0x323a3133, 0x3a343220, 0x73687561, 0x6e672045, -0x78702024, 0x0, 0x6d616374, 0x7841544e, 0x0, 0x4e745379, -0x6e264c6b, 0x0, 0x72656d61, 0x73737274, 0x0, 0x6c696e6b, -0x444f574e, 0x0, 0x656e714d, 0x45765046, 0x61696c00, 0x656e714d, -0x45764661, 0x696c0000, 0x6661696c, 0x456e454d, 0x0, 0x6c696e6b, -0x55500000, 0x0, 0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563, -0x74732f72, 0x63732f73, 0x772f6765, 0x2f6e6963, 0x2f66772f, 0x636f6d6d, -0x6f6e2f63, 0x6b73756d, 0x2e632c76, 0x20312e31, 0x2e322e32, 0x20313939, -0x382f3034, 0x2f323720, 0x32323a31, 0x333a3339, 0x20736875, 0x616e6720, -0x45787020, 0x24000000, 0x50726f62, 0x65506879, 0x0, 0x6c6e6b41, -0x53535254, 0x0, 0x11880, 0x118b8, 0x118dc, 0x11910, -0x1193c, 0x11950, 0x1198c, 0x11cc4, 0x11a64, 0x11aa4, -0x11ad4, 0x11b14, 0x11b44, 0x11b80, 0x11bc4, 0x11cc4, -0x0, 0x0, 0x1215c, 0x1222c, 0x12304, 0x123d4, -0x12430, 0x1250c, 0x12534, 0x12610, 0x12638, 0x127e0, -0x12808, 0x129b0, 0x12ba8, 0x12e3c, 0x12d50, 0x12e3c, -0x12e68, 0x129d8, 0x12b80, 0x0, 0x13254, 0x132b4, -0x13330, 0x1335c, 0x133ac, 0x133e8, 0x1341c, 0x134a8, -0x13560, 0x13630, 0x13670, 0x136f4, 0x13750, 0x13884, -0x646f4261, 0x73655067, 0x0, 0x0, 0x0, 0x0, -0x73746d61, 0x634c4e4b, 0x0, 0x0, 0x0 }; +0x24486561, 0x6465723a, 0x202f7072, +0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, +0x2f6e6963, 0x2f66772f, 0x636f6d6d, 0x6f6e2f66, +0x776d6169, 0x6e2e632c, 0x7620312e, 0x312e322e, +0x31312031, 0x3939382f, 0x30342f32, 0x37203232, +0x3a31333a, 0x34322073, 0x6875616e, 0x67204578, +0x70202400, 0x7468655f, 0x4441574e, 0x0, +0x53544143, 0x4b5f3120, 0x0, 0x42616453, +0x6e64526e, 0x67000000, 0x3f456e71, 0x45767400, +0x3f6e6f51, 0x64457650, 0x0, 0x6576526e, +0x6746756c, 0x6c000000, 0x496c6c43, 0x6f6e6652, +0x78000000, 0x53656e64, 0x436b5375, 0x6d000000, +0x52656376, 0x566c616e, 0x0, 0x0, +0x0, 0x24486561, 0x6465723a, 0x202f7072, +0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, +0x2f6e6963, 0x2f66772f, 0x636f6d6d, 0x6f6e2f74, +0x696d6572, 0x2e632c76, 0x20312e31, 0x2e322e38, +0x20313939, 0x382f3037, 0x2f333120, 0x31373a35, +0x383a3435, 0x20736875, 0x616e6720, 0x45787020, +0x24000000, 0x542d446d, 0x61526431, 0x0, +0x542d446d, 0x61424200, 0x542d446d, 0x61320000, +0x3f6e6f51, 0x64547845, 0x0, 0x3f6e6f51, +0x64527845, 0x0, 0x656e714d, 0x45765046, +0x61696c00, 0x656e714d, 0x45764661, 0x696c0000, +0x6661696c, 0x456e454d, 0x0, 0x3f456e71, +0x45767400, 0x3f6e6f51, 0x64457650, 0x0, +0x6576526e, 0x6746756c, 0x6c000000, 0x0, +0x0, 0x24486561, 0x6465723a, 0x202f7072, +0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, +0x2f6e6963, 0x2f66772f, 0x636f6d6d, 0x6f6e2f63, +0x6f6d6d61, 0x6e642e63, 0x2c762031, 0x2e312e32, +0x2e313020, 0x31393938, 0x2f31312f, 0x31382031, +0x373a3131, 0x3a313820, 0x73687561, 0x6e672045, +0x78702024, 0x0, 0x3f4d626f, 0x78457674, +0x0, 0x4e4f636f, 0x6d616e64, 0x0, +0x68737465, 0x5f455252, 0x0, 0x412d4572, +0x72427563, 0x0, 0x4552524f, 0x522d4164, +0x64000000, 0x656e714d, 0x45765046, 0x61696c00, +0x656e714d, 0x45764661, 0x696c0000, 0x6661696c, +0x456e454d, 0x0, 0x442d4572, 0x724c6173, +0x74000000, 0x442d4572, 0x72320000, 0x6d437374, +0x4d644552, 0x52000000, 0x70726f6d, 0x4d644552, +0x52000000, 0x46696c74, 0x4d644552, 0x52000000, +0x636d645f, 0x45525200, 0x3f456e71, 0x45767400, +0x3f6e6f51, 0x64457650, 0x0, 0x6576526e, +0x6746756c, 0x6c000000, 0x0, 0x6ea0, +0x7fbc, 0x6e38, 0x8734, 0x82b0, +0x8780, 0x8780, 0x6f54, 0x7694, +0x7f0c, 0x80a8, 0x8074, 0x8780, +0x7e70, 0x80cc, 0x6e64, 0x81cc, +0x0, 0x24486561, 0x6465723a, 0x202f7072, +0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, +0x2f6e6963, 0x2f66772f, 0x636f6d6d, 0x6f6e2f64, +0x6d612e63, 0x2c762031, 0x2e312e32, 0x2e332031, +0x3939382f, 0x30342f32, 0x37203232, 0x3a31333a, +0x34312073, 0x6875616e, 0x67204578, 0x70202400, +0x646d6172, 0x6441544e, 0x0, 0x646d6177, +0x7241544e, 0x0, 0x0, 0x0, +0x0, 0x24486561, 0x6465723a, 0x202f7072, +0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, +0x2f6e6963, 0x2f66772f, 0x636f6d6d, 0x6f6e2f74, +0x72616365, 0x2e632c76, 0x20312e31, 0x2e322e32, +0x20313939, 0x382f3034, 0x2f323720, 0x32323a31, +0x333a3530, 0x20736875, 0x616e6720, 0x45787020, +0x24000000, 0x24486561, 0x6465723a, 0x202f7072, +0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, +0x2f6e6963, 0x2f66772f, 0x636f6d6d, 0x6f6e2f64, +0x6174612e, 0x632c7620, 0x312e312e, 0x322e3220, +0x31393938, 0x2f30342f, 0x32372032, 0x323a3133, +0x3a343020, 0x73687561, 0x6e672045, 0x78702024, +0x0, 0x46575f56, 0x45525349, 0x4f4e3a20, +0x2331204d, 0x6f6e2046, 0x65622031, 0x2031363a, +0x35393a30, 0x31205053, 0x54203139, 0x39390000, +0x46575f43, 0x4f4d5049, 0x4c455f54, 0x494d453a, +0x2031363a, 0x35393a30, 0x31000000, 0x46575f43, +0x4f4d5049, 0x4c455f42, 0x593a2064, 0x65767263, +0x73000000, 0x46575f43, 0x4f4d5049, 0x4c455f48, +0x4f53543a, 0x20636f6d, 0x70757465, 0x0, +0x46575f43, 0x4f4d5049, 0x4c455f44, 0x4f4d4149, +0x4e3a2065, 0x6e672e61, 0x6374656f, 0x6e2e636f, +0x6d000000, 0x46575f43, 0x4f4d5049, 0x4c45523a, +0x20676363, 0x20766572, 0x73696f6e, 0x20322e37, +0x2e320000, 0x0, 0x0, 0x0, +0x0, 0x24486561, 0x6465723a, 0x202f7072, +0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, +0x2f6e6963, 0x2f66772f, 0x636f6d6d, 0x6f6e2f6d, +0x656d2e63, 0x2c762031, 0x2e312e32, 0x2e322031, +0x3939382f, 0x30342f32, 0x37203232, 0x3a31333a, +0x34342073, 0x6875616e, 0x67204578, 0x70202400, +0x0, 0x24486561, 0x6465723a, 0x202f7072, +0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, +0x2f6e6963, 0x2f66772f, 0x636f6d6d, 0x6f6e2f73, +0x656e642e, 0x632c7620, 0x312e312e, 0x322e3131, +0x20313939, 0x382f3132, 0x2f323220, 0x31373a31, +0x373a3535, 0x20736875, 0x616e6720, 0x45787020, +0x24000000, 0x736e6464, 0x654e6f51, 0x20000000, +0x6e6f454e, 0x515f5458, 0x0, 0x736e6464, +0x744e6f51, 0x20000000, 0x3f6e6f51, 0x64547845, +0x0, 0x756e6b72, 0x64747970, 0x65000000, +0x0, 0xacdc, 0xacdc, 0xadac, +0xaac0, 0xaac0, 0xadac, 0xadac, +0xadac, 0xadac, 0xadac, 0xadac, +0xadac, 0xadac, 0xadac, 0xadac, +0xadac, 0xadac, 0xadac, 0xad8c, +0x0, 0xbcb8, 0xbcb8, 0xbd80, +0xae5c, 0xb068, 0xbd80, 0xbd80, +0xbd80, 0xbd80, 0xbd80, 0xbd80, +0xbd80, 0xbd80, 0xbd80, 0xbd80, +0xbd80, 0xbd80, 0xbd80, 0xbd64, +0xb050, 0x24486561, 0x6465723a, 0x202f7072, +0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, +0x2f6e6963, 0x2f66772f, 0x636f6d6d, 0x6f6e2f72, +0x6563762e, 0x632c7620, 0x312e312e, 0x322e3139, +0x20313939, 0x382f3037, 0x2f323420, 0x32313a33, +0x303a3035, 0x20736875, 0x616e6720, 0x45787020, +0x24000000, 0x706b5278, 0x45525200, 0x66726d32, +0x4c617267, 0x65000000, 0x72784e6f, 0x52784264, +0x0, 0x72785144, 0x6d614446, 0x0, +0x72785144, 0x6d614246, 0x0, 0x3f6e6f51, +0x64527845, 0x0, 0x706b5278, 0x45525273, +0x0, 0x66726d32, 0x4c726753, 0x0, +0x72784e6f, 0x42645300, 0x3f724264, 0x446d6146, +0x0, 0x3f724a42, 0x64446d46, 0x0, +0x0, 0xf688, 0xf688, 0xf688, +0xf688, 0xf688, 0xf688, 0xf688, +0xf688, 0xf688, 0xf688, 0xf688, +0xf688, 0xf688, 0xf688, 0xf688, +0xf680, 0xf680, 0xf680, 0x572d444d, +0x41456e46, 0x0, 0x0, 0xfdd0, +0x1016c, 0xfdec, 0x1016c, 0x1016c, +0x1016c, 0x1016c, 0x1016c, 0x1016c, +0xf714, 0x1016c, 0x1016c, 0x1016c, +0x1016c, 0x1016c, 0x10164, 0x10164, +0x10164, 0x24486561, 0x6465723a, 0x202f7072, +0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, +0x2f6e6963, 0x2f66772f, 0x636f6d6d, 0x6f6e2f6d, +0x61632e63, 0x2c762031, 0x2e312e32, 0x2e313220, +0x31393938, 0x2f30342f, 0x32372032, 0x323a3133, +0x3a343220, 0x73687561, 0x6e672045, 0x78702024, +0x0, 0x6d616374, 0x7841544e, 0x0, +0x4e745379, 0x6e264c6b, 0x0, 0x72656d61, +0x73737274, 0x0, 0x6c696e6b, 0x444f574e, +0x0, 0x656e714d, 0x45765046, 0x61696c00, +0x656e714d, 0x45764661, 0x696c0000, 0x6661696c, +0x456e454d, 0x0, 0x6c696e6b, 0x55500000, +0x0, 0x24486561, 0x6465723a, 0x202f7072, +0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, +0x2f6e6963, 0x2f66772f, 0x636f6d6d, 0x6f6e2f63, +0x6b73756d, 0x2e632c76, 0x20312e31, 0x2e322e32, +0x20313939, 0x382f3034, 0x2f323720, 0x32323a31, +0x333a3339, 0x20736875, 0x616e6720, 0x45787020, +0x24000000, 0x50726f62, 0x65506879, 0x0, +0x6c6e6b41, 0x53535254, 0x0, 0x11994, +0x119cc, 0x119e4, 0x11a18, 0x11a44, +0x11a58, 0x11a94, 0x11e04, 0x11b6c, +0x11bac, 0x11bd8, 0x11c18, 0x11c48, +0x11c84, 0x11cb8, 0x11e04, 0x12048, +0x12060, 0x12088, 0x120a8, 0x120d0, +0x12200, 0x12228, 0x1226c, 0x12294, +0x0, 0x124fc, 0x125cc, 0x126a4, +0x12774, 0x127d0, 0x128ac, 0x128d4, +0x129b0, 0x129d8, 0x12b80, 0x12ba8, +0x12d50, 0x12f48, 0x131dc, 0x130f0, +0x131dc, 0x13208, 0x12d78, 0x12f20, +0x0, 0x135f4, 0x13638, 0x136d0, +0x1371c, 0x1378c, 0x13824, 0x13858, +0x138e0, 0x13978, 0x13a48, 0x13a88, +0x13b0c, 0x13b30, 0x13c64, 0x646f4261, +0x73655067, 0x0, 0x0, 0x0, +0x0, 0x73746d61, 0x634c4e4b, 0x0, +0x0, 0x0 }; +u32 tigonFwData[(MAX_DATA_LEN/4) + 1] __initdata = { +0x416c7465, +0x6f6e2041, 0x63654e49, 0x43205600, 0x416c7465, +0x6f6e2041, 0x63654e49, 0x43205600, 0x42424242, +0x0, 0x0, 0x0, 0x135418, +0x13e7fc, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x60cf00, +0x60, 0xcf000000, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x3, 0x0, +0x1, 0x0, 0x0, 0x1, +0x0, 0x0, 0x0, 0x1, +0x0, 0x0, 0x0, 0x0, +0x0, 0x1000000, 0x21000000, 0x12000140, +0x0, 0x0, 0x20000000, 0x120000a0, +0x0, 0x12000060, 0x12000180, 0x120001e0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x2, +0x0, 0x0, 0x30001, 0x1, +0x30201, 0x0, 0x0, 0x0 }; /* Generated by genfw.c */ int tigon2FwReleaseMajor = 0xc; -int tigon2FwReleaseMinor = 0x1; -int tigon2FwReleaseFix = 0x6; -u32 tigon2FwStartAddr = 0x4000; -u32 tigon2FwTextAddr = 0x4000; -int tigon2FwTextLen = 0xe5b0; -u32 tigon2FwDataAddr = 0x13330; +int tigon2FwReleaseMinor = 0x3; +int tigon2FwReleaseFix = 0x5; +u32 tigon2FwStartAddr = 0x00004000; +u32 tigon2FwTextAddr = 0x00004000; +int tigon2FwTextLen = 0xec80; +u32 tigon2FwRodataAddr = 0x00012c80; +int tigon2FwRodataLen = 0xfb0; +u32 tigon2FwDataAddr = 0x00013c50; int tigon2FwDataLen = 0x170; -u32 tigon2FwRodataAddr = 0x125b0; -int tigon2FwRodataLen = 0xd60; -u32 tigon2FwBssAddr = 0x13550; +u32 tigon2FwSbssAddr = 0x00013dc0; +int tigon2FwSbssLen = 0xbc; +u32 tigon2FwBssAddr = 0x00013e80; int tigon2FwBssLen = 0x20c0; -u32 tigon2FwSbssAddr = 0x134a0; -int tigon2FwSbssLen = 0xa8; u32 tigon2FwText[(MAX_TEXT_LEN/4) + 1] __initdata = { -0x0, 0x10000003, 0x0, 0xd, 0xd, 0x3c1d0001, -0x8fbd3380, 0x3a0f021, 0x3c100000, 0x26104000, 0xc0010c0, 0x0, -0xd, 0x3c1d0001, 0x8fbd3384, 0x3a0f021, 0x3c100000, 0x26104000, -0xc0016fe, 0x0, 0xd, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, 0x2000008, 0x0, -0x8001671, 0x3c0a0001, 0x8001671, 0x3c0a0002, 0x8001671, 0x0, -0x80029b8, 0x0, 0x8001671, 0x3c0a0003, 0x8001671, 0x3c0a0004, -0x8003134, 0x0, 0x80019ba, 0x0, 0x8003653, 0x0, -0x80035e2, 0x0, 0x8001671, 0x3c0a0006, 0x8001671, 0x3c0a0007, -0x8001671, 0x3c0a0008, 0x8001671, 0x3c0a0009, 0x80036c4, 0x0, -0x8002bf9, 0x0, 0x8001671, 0x3c0a000b, 0x8001671, 0x3c0a000c, -0x8001671, 0x3c0a000d, 0x80026ee, 0x0, 0x80026ad, 0x0, -0x8001671, 0x3c0a000e, 0x8001f40, 0x0, 0x80018c9, 0x0, -0x800196b, 0x0, 0x8003943, 0x0, 0x800392d, 0x0, -0x8001671, 0x0, 0x800184d, 0x0, 0x8001893, 0x0, -0x8001671, 0x3c0a0013, 0x8001671, 0x3c0a0014, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, 0x0, 0x0, -0x27bdffe0, 0x3c1cc000, 0xafbf0018, 0xc0028f4, 0xd021, 0x8f820040, -0x3c03f000, 0x431824, 0x3c025000, 0x10620005, 0x3c026000, 0x1062001a, -0x24020003, 0x10000030, 0x0, 0x8f820050, 0x3c030010, 0x431024, -0x50400013, 0x24020003, 0x3c030001, 0x2463c360, 0x3c020001, 0x2442c3e4, -0x431023, 0x3c010001, 0xac233518, 0x8f830140, 0x3c040001, 0x2484c3ec, -0x3c010001, 0xac223504, 0x3c020001, 0x2442c454, 0x3c010001, 0xac203338, -0x10000013, 0x441023, 0x3c030001, 0x2463c45c, 0xaf8200ec, 0x3c020001, -0x2442c498, 0x431023, 0x3c010001, 0xac233518, 0x8f830140, 0x3c040001, -0x2484c4a0, 0x3c010001, 0xac223504, 0x3c020001, 0x2442c4c8, 0x441023, -0x3c0100c0, 0xac203ffc, 0x3c010001, 0xac243510, 0x3c010001, 0xac22350c, -0x34630004, 0xaf830140, 0xc00169c, 0x0, 0x402821, 0x3c010001, -0xac2534b0, 0x3c020008, 0x10a2002c, 0x45102b, 0x14400006, 0x3c020010, -0x3c020004, 0x10a20007, 0x3c02ffff, 0x1000005b, 0x0, 0x10a20045, -0x3c030003, 0x10000057, 0x0, 0x34422e10, 0x3c030001, 0x24635610, -0x3c040001, 0x8c843334, 0xa31823, 0x14800002, 0x622821, 0x24a5faa8, -0x2403f000, 0xa32824, 0x51082, 0x431024, 0x3c010001, 0xac2234a0, -0xa21023, 0x3c010001, 0xac2234a8, 0x3402a000, 0x3c010001, 0xac2234b8, -0x24020008, 0x3c010001, 0xac2234c0, 0x2402001f, 0x3c010001, 0xac2234c8, -0x24020016, 0x3c010001, 0xac2234ac, 0x10000041, 0x3c08ffff, 0x3c02ffff, -0x34422e10, 0x3c030001, 0x24635610, 0x3c040001, 0x8c843334, 0xa31823, -0x14800002, 0x622821, 0x24a5faa8, 0x2403f000, 0xa32824, 0x3c040003, -0x34842000, 0x510c2, 0x431024, 0x3c010001, 0xac2234a0, 0xa21023, -0x3c010001, 0xac2234a8, 0x24020008, 0x3c010001, 0xac2234c0, 0x2402001f, -0x3c010001, 0xac2234c8, 0x24020016, 0x3c010001, 0xac2434b8, 0x3c010001, -0xac2234ac, 0x1000001f, 0x3c08ffff, 0x34632000, 0x3c020001, 0x3c010001, -0xac2234a0, 0x3c020007, 0x3c010001, 0xac2234a8, 0x24020008, 0x3c010001, -0xac2234c0, 0x2402001f, 0x3c010001, 0xac2234c8, 0x24020016, 0x3c010001, -0xac2334b8, 0x3c010001, 0xac2234ac, 0x1000000b, 0x3c08ffff, 0x3c040001, -0x24842670, 0x3c050001, 0x8ca534b0, 0x3021, 0x3821, 0xafa00010, -0xc00290f, 0xafa00014, 0x3c08ffff, 0x35087e10, 0x3c0500bf, 0x34a5f000, -0x3c0600bf, 0x34c6e000, 0x3c070001, 0x8ce734a0, 0x3c040001, 0x8c8434a8, -0x3c030020, 0x3c090001, 0x8d293330, 0x671023, 0x441023, 0x245bb000, -0x641823, 0x3c010001, 0xac2334b4, 0x671823, 0x27620ffc, 0x3c010001, -0xac223380, 0x27621ffc, 0xbb2823, 0xdb3023, 0x3c010001, 0xac2334a4, -0x3c010001, 0xac223384, 0xaf850150, 0xaf860250, 0x1120001b, 0x368b821, -0x33620fff, 0x10400008, 0x24050019, 0x3c040001, 0x2484267c, 0x3603021, -0x3821, 0xafa00010, 0xc00290f, 0xafa00014, 0x3c1d0001, 0x8fbd333c, -0x3a0f021, 0xc001684, 0x0, 0x3c020001, 0x8c423340, 0x3c030001, -0x8c633344, 0x2442fe00, 0x24630200, 0x3c010001, 0xac223340, 0x3c010001, -0x10000004, 0xac233344, 0x3c1d0001, 0x8fbd3380, 0x3a0f021, 0x3c020001, -0x8c423334, 0x1040000d, 0x26f6faa8, 0x3c020001, 0x8c423340, 0x3c030001, -0x8c633344, 0x3c160001, 0x8ed63344, 0x2442faa8, 0x24630558, 0x3c010001, -0xac223340, 0x3c010001, 0xac233344, 0x3c020001, 0x8c423338, 0x14400003, -0x0, 0x3c010001, 0xac203340, 0xc0011ca, 0x0, 0x8fbf0018, -0x3e00008, 0x27bd0020, 0x27bdff98, 0xafbf0060, 0xafbe005c, 0xafb50058, -0xafb30054, 0xafb10050, 0x8f820240, 0x3c030001, 0x431025, 0xaf820240, -0x3c020001, 0x8c423340, 0x3c030001, 0x8c633344, 0xaf800048, 0x8f840048, -0x3c120000, 0x26524100, 0xa3a00047, 0xafa20034, 0x14800005, 0xafa30030, -0xaf800048, 0x8f820048, 0x10400004, 0x0, 0xaf800048, 0x10000003, -0x2e02021, 0xaf80004c, 0x2e02021, 0xc002990, 0x340581f0, 0x2c02021, -0xc002990, 0x24050558, 0x3c020001, 0x8c4234a4, 0x3c030001, 0x8c6334a0, -0x3c040001, 0x8c8434a8, 0x3c050001, 0x8ca534b8, 0x3c060001, 0x8cc634c0, -0x3c070001, 0x8ce734c8, 0x3c080001, 0x8d0834ac, 0xaec20534, 0x3c020001, -0x8c4234b4, 0x8ec90534, 0xaec50544, 0x3c050001, 0x8ca534b0, 0xaec00000, -0xaec3053c, 0xaec40540, 0xaec60548, 0xaec7054c, 0xaec80550, 0xaec20538, -0xafa90010, 0x8ec20538, 0xafa20014, 0x8ec6053c, 0x8ec70540, 0x3c040001, -0xc00290f, 0x24842688, 0xafb70010, 0xafb60014, 0x8ec60544, 0x8ec70548, -0x3c040001, 0x24842690, 0xc00290f, 0x24050001, 0x3c040001, 0x24842698, -0x24050001, 0x24060001, 0x24070001, 0xafa00010, 0xc00290f, 0xafa00014, -0x3c020001, 0x8c4234b0, 0x3603821, 0x3c060001, 0x24c65610, 0x2448ffff, -0x1061824, 0xe81024, 0x43102b, 0x10400006, 0x24050002, 0x3c040001, -0x248426a0, 0xafa80010, 0xc00290f, 0xafa00014, 0x24020001, 0xa2c20529, -0xaf800054, 0xaf80011c, 0x8f420218, 0x30420002, 0x10400009, 0x0, -0x8f420220, 0x3c030002, 0x34630004, 0x431025, 0xaec20008, 0x8f42021c, -0x10000008, 0x34420004, 0x8f420220, 0x3c030002, 0x34630006, 0x431025, -0xaec20008, 0x8f42021c, 0x34420006, 0xaec20010, 0x8f420218, 0x30420010, -0x1040000a, 0x0, 0x8f42021c, 0x34420004, 0xaec2000c, 0x8f420220, -0x3c03000a, 0x34630004, 0x431025, 0x10000009, 0xaec20004, 0x8f420220, -0x3c03000a, 0x34630006, 0x431025, 0xaec20004, 0x8f42021c, 0x34420006, -0xaec2000c, 0x8f420218, 0x30420200, 0x10400003, 0x24020001, 0x10000002, -0xa2c20064, 0xa2c00064, 0x24020001, 0xaf8200a0, 0xaf8200b0, 0x8f830054, -0x8f820054, 0x10000002, 0x24630064, 0x8f820054, 0x621023, 0x2c420065, -0x1440fffc, 0x0, 0x8f440208, 0x8f45020c, 0x26e20028, 0xaee20020, -0x24020480, 0xaee20010, 0xaee40008, 0xaee5000c, 0x26e40008, 0x8c820000, -0x8c830004, 0x3802821, 0xaf820090, 0xaf830094, 0x8c820018, 0xaca200b4, -0x9482000a, 0xaca2009c, 0x8ca200b0, 0x8ec30010, 0x431025, 0xaca200b0, -0x8f8200b0, 0x30420004, 0x1440fffd, 0x0, 0x8ee20448, 0x8ee3044c, -0xaee304bc, 0x8ee204bc, 0x2442e000, 0x2c422001, 0x1440000d, 0x26c40128, -0x8ee20448, 0x8ee3044c, 0x3c040001, 0x248426ac, 0x3c050001, 0xafa00010, -0xafa00014, 0x8ee704bc, 0x34a5f000, 0xc00290f, 0x603021, 0x26c40128, -0xc002990, 0x24050400, 0x27440080, 0xc002990, 0x24050080, 0x8f42025c, -0x26c4018c, 0xaec20158, 0x8f420260, 0x27450200, 0x24060008, 0xc0029a2, -0xaec20160, 0x3c043b9a, 0x3484ca00, 0x2821, 0x24020006, 0x24030002, -0xaec2015c, 0x240203e8, 0xaec3016c, 0xaec30168, 0xaec40164, 0xaec201fc, -0x24020001, 0xaec301f8, 0xaec20204, 0x3c030001, 0x651821, 0x90633348, -0x2c51021, 0x24a50001, 0xa0430194, 0x2ca2000f, 0x1440fff8, 0x2c51821, -0x8f820040, 0x24a50001, 0x21702, 0x24420030, 0xa0620194, 0x2c51021, -0xa0400194, 0xafa00010, 0x8fa20034, 0x3c040001, 0x248426b8, 0xafa20014, -0x8fa60030, 0x3821, 0xc00290f, 0x2821, 0x3c040000, 0x24845990, -0x24050010, 0x27b30030, 0x2603021, 0x27b10034, 0xc0016be, 0x2203821, -0x3c030001, 0x8c633338, 0x3c15f000, 0x1060000a, 0xafa2003c, 0x8fa30030, -0x2405ff00, 0x8fa20034, 0x246400ff, 0x852024, 0x831823, 0x431023, -0xafa20034, 0xafa40030, 0x3c040000, 0x24844100, 0x24050108, 0x2603021, -0xc0016be, 0x2203821, 0x96e30452, 0x30630003, 0x1060005f, 0x409021, -0x8f820050, 0x3c030010, 0x431024, 0x10400021, 0x0, 0x8f820040, -0x3c035000, 0x551024, 0x14430009, 0x0, 0x96e60452, 0x8f820050, -0xafa00014, 0xafa20010, 0x8f870040, 0x3c040001, 0x1000000d, 0x248426c4, -0x8f420218, 0x30420040, 0x1040000d, 0x24020001, 0x8f820050, 0x96e60452, -0xafa20010, 0x8f420218, 0xafa20014, 0x8f870040, 0x3c040001, 0x248426cc, -0xc00290f, 0x2821, 0x10000004, 0x0, 0x3c010001, 0x370821, -0xa02281ec, 0x3c040001, 0x24849a34, 0x3c050001, 0x24a59aac, 0xa42823, -0x27b30030, 0x2603021, 0x8ec3000c, 0x27b10034, 0x2203821, 0x24020001, -0xa2c20020, 0xa2c20021, 0x34630a00, 0xc0016be, 0xaec3000c, 0x3c040001, -0x2484abf4, 0x3c050001, 0x24a5afdc, 0xa42823, 0x2603021, 0x2203821, -0xc0016be, 0xaec200a4, 0x3c040001, 0x2484b4a8, 0x3c050001, 0x24a5c358, -0xa42823, 0x2603021, 0x3c010001, 0xac2234fc, 0xc0016be, 0x2203821, -0x3c040001, 0x2484dbf8, 0x3c050001, 0x24a5e3bc, 0xa42823, 0x2603021, -0x3c010001, 0xac223500, 0xc0016be, 0x2203821, 0x3c040001, 0x248426d4, -0x96e60452, 0x24050011, 0x3821, 0x3c010001, 0xac22351c, 0xafa00010, -0xc00290f, 0xafa00014, 0x10000028, 0x0, 0x3c040001, 0x24849890, -0x3c050001, 0x24a59a2c, 0xa42823, 0x2603021, 0xc0016be, 0x2203821, -0x3c040001, 0x2484a6e0, 0x3c050001, 0x24a5abec, 0xa42823, 0x2603021, -0x2203821, 0xc0016be, 0xaec200a4, 0x3c040001, 0x2484afe4, 0x3c050001, -0x24a5b4a0, 0xa42823, 0x2603021, 0x3c010001, 0xac2234fc, 0xc0016be, -0x2203821, 0x3c040001, 0x2484db10, 0x3c050001, 0x24a5dbf0, 0xa42823, -0x2603021, 0x3c010001, 0xac223500, 0xc0016be, 0x2203821, 0x3c010001, -0xac22351c, 0x3c020001, 0x8c4234fc, 0x3c050fff, 0x34a5ffff, 0x3c030001, -0x8c633500, 0x3c040800, 0x451024, 0x21082, 0x441025, 0x651824, -0xae420020, 0x3c020001, 0x8c42351c, 0x31882, 0x641825, 0xae430080, -0x451024, 0x21082, 0x441025, 0xae420078, 0x96e20462, 0x30420003, -0x14400009, 0x0, 0x96e20472, 0x30420003, 0x1040007f, 0x27b30030, -0x96e20462, 0x30420003, 0x1040006d, 0x3c020700, 0x96e20472, 0x30420003, -0x10400069, 0x3c020700, 0x96e30472, 0x96e20462, 0x14620065, 0x3c020700, -0x8f82005c, 0x3c030080, 0x431024, 0x1040000b, 0x0, 0x8f820050, -0x96e60462, 0xafa20010, 0x8f82005c, 0xafa20014, 0x8f870040, 0x3c040001, -0x248426e0, 0xc00290f, 0x24051977, 0x8f820050, 0x3c030010, 0x431024, -0x10400022, 0x0, 0x8f820040, 0x3c03f000, 0x431024, 0x3c035000, -0x14430009, 0x0, 0x96e60462, 0x8f820050, 0xafa00014, 0xafa20010, -0x8f870040, 0x3c040001, 0x1000000d, 0x248426c4, 0x8f420218, 0x30420040, -0x1040000d, 0x24020001, 0x8f820050, 0x96e60462, 0xafa20010, 0x8f420218, -0xafa20014, 0x8f870040, 0x3c040001, 0x248426cc, 0xc00290f, 0x24050001, -0x10000004, 0x0, 0x3c010001, 0x370821, 0xa02281ec, 0x3c040001, -0x24849810, 0x3c050001, 0x24a59888, 0xa42823, 0x27b30030, 0x2603021, -0x8ec30004, 0x27b10034, 0x2203821, 0x24020001, 0xa2c2004c, 0x34630e00, -0xc0016be, 0xaec30004, 0x3c040001, 0x2484d058, 0x3c050001, 0x24a5d780, -0xa42823, 0x2603021, 0x2203821, 0xc0016be, 0xaec200a8, 0x3c040001, -0x2484dbf8, 0x3c050001, 0x24a5e3bc, 0xa42823, 0x2603021, 0x3c010001, -0xac223514, 0xc0016be, 0x2203821, 0x3c040001, 0x248426ec, 0x21900, -0x31982, 0x3c050800, 0x651825, 0xae430078, 0x96e60462, 0x24050012, -0x3c010001, 0xac22351c, 0x1000000a, 0x3821, 0x34423000, 0x240a0001, -0x3c040001, 0x248426f8, 0x3405f001, 0x3021, 0x3821, 0xa3aa0047, -0xafa20020, 0xafa00010, 0xc00290f, 0xafa00014, 0x10000015, 0x0, -0x3c040001, 0x2484960c, 0x3c050001, 0x24a59808, 0xa42823, 0x2603021, -0x27b10034, 0xc0016be, 0x2203821, 0x3c040001, 0x2484c57c, 0x3c050001, -0x24a5d050, 0xa42823, 0x2603021, 0x2203821, 0xc0016be, 0xaec200a8, -0x3c010001, 0xac223514, 0x3c020001, 0x8c423514, 0x3c030800, 0x21100, -0x21182, 0x431025, 0xae420038, 0x8f420218, 0x30420040, 0x14400004, -0x24020001, 0x3c010001, 0x370821, 0xa02281ec, 0x96e20462, 0x30420010, -0x14400009, 0x0, 0x96e20472, 0x30420010, 0x10400021, 0x0, -0x96e20462, 0x30420010, 0x10400005, 0x3c020700, 0x96e20472, 0x30420010, -0x14400011, 0x3c020700, 0x34423000, 0x240a0001, 0xa3aa0047, 0xafa20020, -0x8ee20154, 0x96e60462, 0x96e70472, 0x24420001, 0xaee20154, 0x8ee20154, -0x3c040001, 0x24842704, 0x3405f002, 0xafa00010, 0xc00290f, 0xafa00014, -0x96e60472, 0x96e70462, 0x3c040001, 0x2484270c, 0x24050012, 0xafa00010, -0xc00290f, 0xafa00014, 0x3c040001, 0x2484d788, 0x3c050001, 0x24a5d944, -0xa42823, 0x27b30030, 0x2603021, 0x27b10034, 0xc0016be, 0x2203821, -0x3c1e0fff, 0x37deffff, 0x3c040001, 0x2484d94c, 0x3c050001, 0x24a5db08, -0xa42823, 0x2603021, 0x2203821, 0x3c010001, 0xac223508, 0x5e1024, -0x21082, 0x3c150800, 0x551025, 0xc0016be, 0xae420050, 0x3c040000, -0x24847d00, 0x3c050000, 0x24a57f50, 0xa42823, 0x2603021, 0x2203821, -0x3c010001, 0xac223520, 0x5e1024, 0x21082, 0x551025, 0xc0016be, -0xae420048, 0x3c040000, 0x24846134, 0x3c050000, 0x24a56244, 0xa42823, -0x2603021, 0x2203821, 0x3c010001, 0xac2234e8, 0x5e1024, 0x21082, -0x551025, 0xc0016be, 0xae4200b8, 0x3c040000, 0x2484624c, 0x3c050000, -0x24a5631c, 0xa42823, 0x2603021, 0x2203821, 0x3c010001, 0xac2234dc, -0x5e1024, 0x21082, 0x551025, 0xc0016be, 0xae4200e8, 0x3c040000, -0x24846324, 0x3c050000, 0x24a565a4, 0xa42823, 0x2603021, 0x2203821, -0x3c010001, 0xac2234cc, 0x5e1024, 0x21082, 0x551025, 0xc0016be, -0xae4200f0, 0x3c040000, 0x248465ac, 0x3c050000, 0x24a566e0, 0xa42823, -0x2603021, 0x2203821, 0x3c010001, 0xac2234d4, 0x5e1024, 0x21082, -0x551025, 0xc0016be, 0xae4200c0, 0x3c040001, 0x2484e50c, 0x3c050001, -0x24a5eabc, 0xa42823, 0x2603021, 0x2203821, 0x3c010001, 0xac2234e0, -0x5e1024, 0x21082, 0x551025, 0xc0016be, 0xae4200c8, 0x3c040001, -0x2484ee30, 0x3c050001, 0x24a5ef08, 0xa42823, 0x2603021, 0x2203821, -0x3c010001, 0xac223524, 0x5e1024, 0x21082, 0x551025, 0xc0016be, -0xae4200d0, 0x3c040001, 0x8c843518, 0x3c050001, 0x8ca53504, 0x2603021, -0x2203821, 0xc0016be, 0xaec200ac, 0x3c040001, 0x8c843510, 0x3c050001, -0x8ca5350c, 0x2603021, 0x3c010001, 0xac223518, 0xc0016be, 0x2203821, -0x3c010001, 0xac223510, 0x3c070001, 0xf73821, 0x90e781ec, 0xafa00010, -0x8fa20034, 0xafa20014, 0x8fa60030, 0x3c040001, 0x24842718, 0xc00290f, -0x2821, 0x8faa003c, 0xc003c37, 0x1408021, 0xc0038f4, 0x0, -0xc002548, 0x0, 0xaec0002c, 0xaf400228, 0xaf40022c, 0xaee004a8, -0xaec00014, 0xaec00018, 0xaec00024, 0x96e20450, 0x2442ffff, 0xaec20028, -0x3c010001, 0x370821, 0xac2081d4, 0xaec00038, 0xaec00044, 0xaec0003c, -0xaec00040, 0xaec00048, 0x96e20480, 0x2442ffff, 0xaec2006c, 0x3c010001, -0x370821, 0xac2081e0, 0x8ec20534, 0x8ec30534, 0x8ec40534, 0x8ec50538, -0xaec00068, 0xaec00060, 0xaec0005c, 0xaec00058, 0xa2c000ed, 0xaec00078, -0xaec00084, 0xaec20074, 0xaec3007c, 0xaec40080, 0xaec5008c, 0xc002298, -0xa2c00115, 0x3c1433d8, 0x3694c348, 0x3c020800, 0x34420080, 0x3c040000, -0x248459dc, 0x3c050000, 0x24a55a08, 0xa42823, 0x2603021, 0x2203821, -0xaf820060, 0x2402ffff, 0xaec00030, 0xaec00034, 0xc0016be, 0xaf820064, -0x3c010001, 0xac2234c4, 0x5e1024, 0x21082, 0x551025, 0xc00181c, -0xae420000, 0x8f820240, 0x3c030001, 0x431025, 0xaf820240, 0x3c020000, -0x24424034, 0xaf820244, 0xaf800240, 0x8f820060, 0x551024, 0x14400005, -0x3c030800, 0x8f820060, 0x431024, 0x1040fffd, 0x0, 0xc003901, -0x0, 0x3c020100, 0xafa20028, 0x8ec3002c, 0x240200ff, 0x10620003, -0x8821, 0x8ec2002c, 0x24510001, 0x8f420228, 0x1622000f, 0x24070008, -0x3c040001, 0x2484262c, 0xafa00010, 0xafa00014, 0x8ec6002c, 0x8f470228, -0x3c050009, 0xc00290f, 0x34a5f005, 0x8ec202a0, 0x24420001, 0xaec202a0, -0x10000046, 0x8ec202a0, 0x8ec2002c, 0x210c0, 0x571021, 0x8fa30028, -0x8fa4002c, 0xac4304c0, 0xac4404c4, 0x8ec3002c, 0x8ee40428, 0x8ee5042c, -0x8ec6002c, 0x2402000d, 0xafa20010, 0xafb10014, 0x8ec20008, 0x318c0, -0x604821, 0x4021, 0xa92821, 0xa9182b, 0x882021, 0x832021, -0x630c0, 0xafa20018, 0x8ec200a8, 0x24c604c0, 0x40f809, 0x2e63021, -0x5440000c, 0xaed1002c, 0x3c040001, 0x24842638, 0xafa00010, 0xafa00014, -0x8ec6002c, 0x8f470228, 0x3c050009, 0xc00290f, 0x34a5f000, 0x1000001d, -0x0, 0x8ee40488, 0x8ee5048c, 0x8ec3002c, 0x8ec80008, 0x8f860120, -0x24020011, 0xafa20010, 0xafa30014, 0xafa80018, 0x8ec200a8, 0x24070008, -0x40f809, 0x24c6001c, 0x1440000e, 0x0, 0x3c040001, 0x24842640, -0xafa00010, 0xafa00014, 0x8ec6002c, 0x8f470228, 0x3c050009, 0xc00290f, -0x34a5f001, 0x8ec202a4, 0x24420001, 0xaec202a4, 0x8ec202a4, 0x8ec20248, -0x24420001, 0xaec20248, 0x8ec20248, 0x93a20047, 0x10400070, 0x240200ff, -0x8ec3002c, 0x10620004, 0x27a70020, 0x8ec2002c, 0x10000002, 0x24510001, -0x8821, 0x8f420228, 0x1622000f, 0x4021, 0x3c040001, 0x2484262c, -0xafa00010, 0xafa00014, 0x8ec6002c, 0x8f470228, 0x3c050009, 0xc00290f, -0x34a5f005, 0x8ec202a0, 0x24420001, 0xaec202a0, 0x10000046, 0x8ec202a0, -0x8ec2002c, 0x210c0, 0x571021, 0x8ce30000, 0x8ce40004, 0xac4304c0, -0xac4404c4, 0x8ec3002c, 0x8ee40428, 0x8ee5042c, 0x8ec6002c, 0x24070008, -0x2402000d, 0xafa20010, 0xafb10014, 0x8ec20008, 0x318c0, 0x604821, -0xa92821, 0xa9182b, 0x882021, 0x832021, 0x630c0, 0xafa20018, -0x8ec200a8, 0x24c604c0, 0x40f809, 0x2e63021, 0x5440000c, 0xaed1002c, -0x3c040001, 0x24842638, 0xafa00010, 0xafa00014, 0x8ec6002c, 0x8f470228, -0x3c050009, 0xc00290f, 0x34a5f000, 0x1000001d, 0x0, 0x8ee40488, -0x8ee5048c, 0x8ec3002c, 0x8ec80008, 0x8f860120, 0x24020011, 0xafa20010, -0xafa30014, 0xafa80018, 0x8ec200a8, 0x24070008, 0x40f809, 0x24c6001c, -0x1440000e, 0x0, 0x3c040001, 0x24842640, 0xafa00010, 0xafa00014, -0x8ec6002c, 0x8f470228, 0x3c050009, 0xc00290f, 0x34a5f001, 0x8ec202a4, -0x24420001, 0xaec202a4, 0x8ec202a4, 0x3c040001, 0x24842724, 0x8ec20254, -0x3c050009, 0x34a59999, 0x24420001, 0xaec20254, 0x8ec20254, 0x3021, -0x3821, 0xafa00010, 0xc00290f, 0xafa00014, 0x10000004, 0x0, -0x8f420264, 0x10400005, 0x0, 0x8f8200a0, 0x30420004, 0x1440fffa, -0x0, 0x8f820044, 0x34420004, 0xaf820044, 0x8ec2026c, 0x24420001, -0xaec2026c, 0x8ec2026c, 0x8f8200d8, 0x8f8300d4, 0x431023, 0x2442fff8, -0xaec20088, 0x8ec20088, 0x4410006, 0x24020001, 0x8ec20088, 0x8ec3053c, -0x431021, 0xaec20088, 0x24020001, 0xaec20070, 0x96e20452, 0x30420010, -0x10400005, 0x0, 0x8f820214, 0x3c038100, 0x431025, 0xaf820214, -0x3c020001, 0x8c423408, 0x30420001, 0x10400007, 0x0, 0x3c040000, -0x24846bb4, 0x3c050000, 0x24a570e8, 0x10000006, 0xa42823, 0x3c040000, -0x248466e8, 0x3c050000, 0x24a56bac, 0xa42823, 0x27a60030, 0xc0016be, -0x27a70034, 0x3c010001, 0xac2234d8, 0x3c020001, 0x8c4234d8, 0x3c030800, -0x21100, 0x21182, 0x431025, 0xae420040, 0x8f830060, 0x74100b, -0x242000a, 0x200f821, 0x0, 0xd, 0x8fbf0060, 0x8fbe005c, -0x8fb50058, 0x8fb30054, 0x8fb10050, 0x3e00008, 0x27bd0068, 0x3e00008, -0x0, 0x3e00008, 0x0, 0x3e00008, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x3e00008, 0x0, 0x3e00008, 0x0, -0x27bdfde0, 0x27a70018, 0x3c02dead, 0x3442beef, 0xafbf0218, 0x8f830150, -0x3c04001f, 0x3484ffff, 0xafa20018, 0xe33823, 0xe43824, 0x8ce30000, -0x10620008, 0x0, 0xafa30010, 0xafa00014, 0x8f860150, 0x3c040001, -0x24842730, 0xc00290f, 0x24050020, 0x8fbf0218, 0x3e00008, 0x27bd0220, -0x27bdffe0, 0x3c06abba, 0x34c6babe, 0xafb10018, 0x3c110004, 0x3c07007f, -0x34e7ffff, 0xafbf001c, 0x112840, 0x8e240000, 0x8ca30000, 0xaca00000, -0xae260000, 0x8ca20000, 0xaca30000, 0x10460005, 0xae240000, 0xa08821, -0xf1102b, 0x1040fff5, 0x112840, 0x3c040001, 0x2484273c, 0x2202821, -0x3021, 0x3821, 0xafa00010, 0xc00290f, 0xafa00014, 0x2201021, -0x8fbf001c, 0x8fb10018, 0x3e00008, 0x27bd0020, 0x27bdffc8, 0xafb30024, -0x809821, 0xafbe002c, 0xafb50028, 0xe0a821, 0x24a50003, 0xafbf0030, -0xafb10020, 0x8ea20000, 0x2403fffc, 0xa38824, 0x51102b, 0x14400020, -0xc0f021, 0x8fc80000, 0xafa00010, 0xafa8001c, 0x8ea20000, 0x3c040001, -0x24842748, 0xafa20014, 0x8fc60000, 0x2602821, 0xc00290f, 0x2203821, -0x8fc60000, 0x111882, 0x2463ffff, 0x2402ffff, 0x10620008, 0x2602021, -0x2405ffff, 0x8c820000, 0x24840004, 0x2463ffff, 0xacc20000, 0x1465fffb, -0x24c60004, 0x8ea20000, 0x511023, 0xaea20000, 0x8fc20000, 0x511021, -0x1000000b, 0xafc20000, 0xafa00010, 0x8ea20000, 0x3c040001, 0x24842750, -0xafa20014, 0x8fc60000, 0x2602821, 0x2203821, 0xc00290f, 0xafa5001c, -0x8fa2001c, 0x8fbf0030, 0x8fbe002c, 0x8fb50028, 0x8fb30024, 0x8fb10020, -0x3e00008, 0x27bd0038, 0x27bdffe8, 0x3c1cc000, 0xd021, 0x3c05ffff, -0x3c030001, 0x8c6334a0, 0x3c040001, 0x8c8434a8, 0x34a57e10, 0x24021ffc, -0x3c010001, 0xac223340, 0x3c0200c0, 0x3c010001, 0xac223344, 0x3c020020, -0xafbf0010, 0x3c0100c0, 0xac201ffc, 0x431023, 0x441023, 0x245bb000, -0x365b821, 0x3c1d0001, 0x8fbd333c, 0x3a0f021, 0x3c0400c0, 0x34840200, -0x3c1600c0, 0x3c0300c0, 0x34630758, 0x24021dfc, 0x3c010001, 0xac223340, -0x240218a4, 0x3c010001, 0xac243344, 0x3c010001, 0xac223340, 0x3c010001, -0xac233344, 0xc00172c, 0x36d60200, 0x8fbf0010, 0x3e00008, 0x27bd0018, -0x27bdffc8, 0x3c040001, 0x24842758, 0x2821, 0x3c020001, 0x8c423340, -0x3c030001, 0x8c633344, 0x3021, 0x3603821, 0xafbf0030, 0xafbe002c, -0xafb50028, 0xafb30024, 0xafb10020, 0xafa2001c, 0xafa30018, 0xafb70010, -0xc00290f, 0xafb60014, 0xc001849, 0x0, 0x8f820240, 0x34420004, -0xaf820240, 0x24020001, 0xaec20000, 0x3c020001, 0x571021, 0x904281ec, -0x10400090, 0x2402fffc, 0x3c110001, 0x2631a3c3, 0x3c150001, 0x26b59f70, -0x2351823, 0x8fa6001c, 0x628824, 0xd1102b, 0x1440001e, 0x27be0018, -0x8fb30018, 0x3c040001, 0x24842748, 0x2a02821, 0x2203821, 0xafa00010, -0xafa60014, 0xc00290f, 0x2603021, 0x8fa40018, 0x111882, 0x2463ffff, -0x2402ffff, 0x10620008, 0x2a02821, 0x2406ffff, 0x8ca20000, 0x24a50004, -0x2463ffff, 0xac820000, 0x1466fffb, 0x24840004, 0x8fa2001c, 0x511023, -0xafa2001c, 0x8fc20000, 0x511021, 0x1000000a, 0xafc20000, 0x3c040001, -0x24842750, 0x2a02821, 0xafa00010, 0xafa60014, 0x8fa60018, 0x2203821, -0xc00290f, 0xa09821, 0x8fa3001c, 0x24150020, 0x3c010001, 0xac3334bc, -0x2c620020, 0x1440001d, 0x27b30018, 0x8fb10018, 0x3c040001, 0x24842748, -0x3c050001, 0x24a53550, 0x24070020, 0xafa00010, 0xafa30014, 0xc00290f, -0x2203021, 0x3c050001, 0x24a53550, 0x8fa40018, 0x24030007, 0x2406ffff, -0x8ca20000, 0x24a50004, 0x2463ffff, 0xac820000, 0x1466fffb, 0x24840004, -0x8fa2001c, 0x551023, 0xafa2001c, 0x8e620000, 0x551021, 0x1000000c, -0xae620000, 0x3c040001, 0x24842750, 0x3c050001, 0x24a53550, 0xafa00010, -0xafa30014, 0x8fa60018, 0x3c110001, 0x26313550, 0xc00290f, 0x24070020, -0x8fa3001c, 0x24150020, 0x3c010001, 0xac3134f0, 0x2c620020, 0x1440001d, -0x27b30018, 0x8fb10018, 0x3c040001, 0x24842748, 0x3c050001, 0x24a53570, -0x24070020, 0xafa00010, 0xafa30014, 0xc00290f, 0x2203021, 0x3c050001, -0x24a53570, 0x8fa40018, 0x24030007, 0x2406ffff, 0x8ca20000, 0x24a50004, -0x2463ffff, 0xac820000, 0x1466fffb, 0x24840004, 0x8fa2001c, 0x551023, -0xafa2001c, 0x8e620000, 0x551021, 0x1000000c, 0xae620000, 0x3c040001, -0x24842750, 0x3c050001, 0x24a53570, 0xafa00010, 0xafa30014, 0x8fa60018, -0x3c110001, 0x26313570, 0xc00290f, 0x24070020, 0x3c010001, 0x10000033, -0xac3134ec, 0x3c110000, 0x26317cef, 0x3c150000, 0x26b57b3c, 0x2351823, -0x8fa6001c, 0x628824, 0xd1102b, 0x1440001e, 0x27be0018, 0x8fb30018, -0x3c040001, 0x24842748, 0x2a02821, 0x2203821, 0xafa00010, 0xafa60014, -0xc00290f, 0x2603021, 0x8fa40018, 0x111882, 0x2463ffff, 0x2402ffff, -0x10620008, 0x2a02821, 0x2406ffff, 0x8ca20000, 0x24a50004, 0x2463ffff, -0xac820000, 0x1466fffb, 0x24840004, 0x8fa2001c, 0x511023, 0xafa2001c, -0x8fc20000, 0x511021, 0x1000000a, 0xafc20000, 0x3c040001, 0x24842750, -0x2a02821, 0xafa00010, 0xafa60014, 0x8fa60018, 0x2203821, 0xc00290f, -0xa09821, 0x3c010001, 0xac3334bc, 0x3c030001, 0x8c6334bc, 0x24020400, -0x60f809, 0xaf820070, 0x8fbf0030, 0x8fbe002c, 0x8fb50028, 0x8fb30024, -0x8fb10020, 0x3e00008, 0x27bd0038, 0x0, 0x0, 0x0, -0x8f820040, 0x3c03f000, 0x431824, 0x3c025000, 0x10620005, 0x3c026000, -0x10620012, 0x0, 0x10000015, 0x0, 0x8f820050, 0x3c030010, -0x431024, 0x10400006, 0x0, 0x8f820050, 0x2403ff80, 0x431024, -0x1000000a, 0x34420063, 0x8f820050, 0x2403ff80, 0x431024, 0x10000005, -0x3442004f, 0x8f820050, 0x2403ff80, 0x431024, 0x34420055, 0xaf820050, -0x8f820054, 0x244203e8, 0xaf820058, 0x240201f4, 0xaec200c8, 0x24020004, -0xaec200d0, 0x24020002, 0xaec000a0, 0xaec000cc, 0xaec200c4, 0xaec000c0, -0xaec000bc, 0x3e00008, 0xaec000b8, 0x8f820054, 0x24420005, 0x3e00008, -0xaf820078, 0x27bdffe8, 0xafbf0010, 0x8f820054, 0x3c030001, 0x8c63341c, -0x244203e8, 0x1060001d, 0xaf820058, 0x3c020001, 0x8c423408, 0x30420001, -0x1440000c, 0x0, 0x3c020001, 0x8c423528, 0x10400008, 0x0, -0x8f830224, 0x3c020001, 0x8c4255ec, 0x10620003, 0x0, 0xc003ab1, -0x0, 0x92c200ec, 0x10400003, 0x3c0208ff, 0x1000000a, 0xa2c000ec, -0x3442fffb, 0x8f830220, 0x3c040200, 0x284a025, 0x621824, 0x10000003, -0xaf830220, 0xc003db9, 0x0, 0x8f420238, 0x1040000a, 0x0, -0x8ec200a0, 0x244203e8, 0xaec200a0, 0x8f430238, 0x43102b, 0x14400003, -0x0, 0xc001c3c, 0x0, 0x8f420218, 0x30420100, 0x10400003, -0x0, 0xc001e07, 0x0, 0x8ec200c0, 0x8ec300c4, 0x24420001, -0xaec200c0, 0x43102b, 0x14400003, 0x0, 0xaec000c0, 0x36940080, -0x8fbf0010, 0x3e00008, 0x27bd0018, 0x3e00008, 0x0, 0x8f820040, -0x30420001, 0x14400008, 0x2021, 0x8f430104, 0x24020001, 0x50620005, -0x24040001, 0x8f420264, 0x10400003, 0x801021, 0x24040001, 0x801021, -0x10400006, 0x0, 0x8ec20270, 0x24420001, 0xaec20270, 0x10000008, -0x8ec20270, 0x8f820044, 0x34420004, 0xaf820044, 0x8ec2026c, 0x24420001, -0xaec2026c, 0x8ec2026c, 0x8ec20000, 0x3c03dfff, 0x10400007, 0x3463ffff, -0xaf80004c, 0x8f82004c, 0x1040fffd, 0x0, 0x10000005, 0x0, -0xaf800048, 0x8f820048, 0x1040fffd, 0x0, 0x8f820060, 0x431024, -0xaf820060, 0x8ec20000, 0x10400003, 0x0, 0x10000002, 0xaf80004c, -0xaf800048, 0x3e00008, 0x0, 0x3e00008, 0x0, 0x27bdffd8, -0xafbf0024, 0xafb10020, 0x8ec30018, 0x8ec20028, 0x10620056, 0x0, -0x3c020001, 0x571021, 0x8c4281d4, 0x10400023, 0x24070008, 0x8ed10018, -0x8ee40498, 0x8ee5049c, 0x8ec30008, 0x8f860120, 0x24020012, 0xafa20010, -0xafb10014, 0xafa30018, 0x8ec200a8, 0x40f809, 0x24c6001c, 0x1440000b, -0x24020001, 0x3c040001, 0x248427c0, 0xafb10010, 0xafa00014, 0x8ec6002c, -0x8f470228, 0x3c050009, 0xc00290f, 0x34a5f006, 0x1021, 0x14400005, -0x24020001, 0x3c010001, 0x370821, 0x1000005c, 0xac2281d4, 0x3c010001, -0x370821, 0x10000022, 0xac2081d0, 0x8ed10018, 0x8ee40498, 0x8ee5049c, -0x8ec30008, 0x8f860120, 0x24020019, 0xafa20010, 0xafb10014, 0xafa30018, -0x8ec200a8, 0x40f809, 0x24c6001c, 0x1440000b, 0x24020001, 0x3c040001, -0x248427c0, 0xafb10010, 0xafa00014, 0x8ec6002c, 0x8f470228, 0x3c050009, -0xc00290f, 0x34a5f006, 0x1021, 0x14400005, 0x24020001, 0x3c010001, -0x370821, 0x1000003a, 0xac2281d8, 0x3c010001, 0x370821, 0xac2281d0, -0x3c010001, 0x370821, 0xac2081d8, 0x3c010001, 0x370821, 0xac2081d4, -0x8ec20264, 0xaec00024, 0xaed10028, 0x24420001, 0xaec20264, 0x1000002a, -0x8ec20264, 0x3c020001, 0x571021, 0x8c4281d0, 0x1040001f, 0x0, -0x8f820040, 0x30420001, 0x14400008, 0x2021, 0x8f430104, 0x24020001, -0x50620005, 0x24040001, 0x8f420264, 0x10400003, 0x801021, 0x24040001, -0x801021, 0x10400006, 0x0, 0x8ec20270, 0x24420001, 0xaec20270, -0x10000008, 0x8ec20270, 0x8f820044, 0x34420004, 0xaf820044, 0x8ec2026c, -0x24420001, 0xaec2026c, 0x8ec2026c, 0x3c010001, 0x370821, 0xac2081d0, -0x3c010001, 0x370821, 0xac2081d4, 0x3c010001, 0x370821, 0xac2081d8, -0x8ec20000, 0x3c03ff7f, 0x10400007, 0x3463ffff, 0xaf80004c, 0x8f82004c, -0x1040fffd, 0x0, 0x10000005, 0x0, 0xaf800048, 0x8f820048, -0x1040fffd, 0x0, 0x8f820060, 0x431024, 0xaf820060, 0x8ec20000, -0x10400003, 0x0, 0x10000002, 0xaf80004c, 0xaf800048, 0x8fbf0024, -0x8fb10020, 0x3e00008, 0x27bd0028, 0x3e00008, 0x0, 0x27bdffd8, -0xafbf0024, 0xafb10020, 0x8ec30068, 0x8ec2006c, 0x10620029, 0x24070008, -0x8ed10068, 0x8ee40490, 0x8ee50494, 0x8ec30008, 0x8f860120, 0x24020013, -0xafa20010, 0xafb10014, 0xafa30018, 0x8ec200a8, 0x40f809, 0x24c6001c, -0x1440000b, 0x24020001, 0x3c040001, 0x248427cc, 0xafb10010, 0xafa00014, -0x8ec60068, 0x8f470228, 0x3c050009, 0xc00290f, 0x34a5f008, 0x1021, -0x14400005, 0x24020001, 0x3c010001, 0x370821, 0x1000000e, 0xac2281e0, -0x3c010001, 0x370821, 0xac2081e0, 0x8ec20268, 0xaec00048, 0xaed1006c, -0x24420001, 0xaec20268, 0x10000004, 0x8ec20268, 0x3c010001, 0x370821, -0xac2081e0, 0x8ec20000, 0x3c03feff, 0x10400007, 0x3463ffff, 0xaf80004c, -0x8f82004c, 0x1040fffd, 0x0, 0x10000005, 0x0, 0xaf800048, -0x8f820048, 0x1040fffd, 0x0, 0x8f820060, 0x431024, 0xaf820060, -0x8ec20000, 0x10400003, 0x0, 0x10000002, 0xaf80004c, 0xaf800048, -0x8fbf0024, 0x8fb10020, 0x3e00008, 0x27bd0028, 0x3e00008, 0x0, -0x3c020001, 0x8c42341c, 0x27bdffc0, 0xafbf0038, 0xafbe0034, 0xafb50030, -0xafb3002c, 0x104000fe, 0xafb10028, 0x8ec200b8, 0x24430001, 0x2842000b, -0x1440011b, 0xaec300b8, 0xaec000b8, 0x8ee204a8, 0x30420002, 0x14400096, -0x0, 0x8ee204a8, 0x3c030001, 0x8c63340c, 0x34420002, 0xaee204a8, -0x24020001, 0x14620003, 0x3c020600, 0x10000002, 0x34423000, 0x34421000, -0xafa20020, 0x8ec3002c, 0x240200ff, 0x10620004, 0x27a70020, 0x8ec2002c, -0x10000002, 0x24530001, 0x9821, 0x8f420228, 0x1662000f, 0x0, -0x3c040001, 0x248427f8, 0xafa00010, 0xafa00014, 0x8ec6002c, 0x8f470228, -0x3c050009, 0xc00290f, 0x34a5f00f, 0x8ec202a0, 0x24420001, 0xaec202a0, -0x1000006d, 0x8ec202a0, 0x8ec2002c, 0x210c0, 0x571021, 0x8ce30000, -0x8ce40004, 0xac4304c0, 0xac4404c4, 0x8f830054, 0x8f820054, 0x247103e8, -0x2221023, 0x2c4203e9, 0x1040001e, 0xa821, 0x241e000c, 0x8ec8002c, -0x8ee40428, 0x8ee5042c, 0x8ec6002c, 0x24070008, 0xafbe0010, 0xafb30014, -0x840c0, 0x1001821, 0x1021, 0x8ec80008, 0xa32821, 0xa3482b, -0x822021, 0x892021, 0x630c0, 0xafa80018, 0x8ec200a8, 0x24c604c0, -0x40f809, 0x2e63021, 0x54400006, 0x24150001, 0x8f820054, 0x2221023, -0x2c4203e9, 0x1440ffe5, 0x0, 0x32a200ff, 0x54400011, 0xaed3002c, -0x3c040001, 0x24842804, 0xafa00010, 0xafa00014, 0x8f860120, 0x8f870124, -0x3c050009, 0x10000030, 0x34a5f010, 0x8ec2026c, 0x24150001, 0x24420001, -0xaec2026c, 0x8ec2026c, 0x1000001f, 0x32a200ff, 0x8f830054, 0x8f820054, -0x247103e8, 0x2221023, 0x2c4203e9, 0x10400017, 0xa821, 0x3c1e0020, -0x24130011, 0x8ec20008, 0x8ee40488, 0x8ee5048c, 0x8ec3002c, 0x8f860120, -0xafb30010, 0x5e1025, 0xafa30014, 0xafa20018, 0x8ec200a8, 0x24070008, -0x40f809, 0x24c6001c, 0x1440ffe2, 0x0, 0x8f820054, 0x2221023, -0x2c4203e9, 0x1440ffed, 0x0, 0x32a200ff, 0x1440000f, 0x0, -0x3c040001, 0x24842810, 0xafa00010, 0xafa00014, 0x8f860120, 0x8f870124, -0x3c050009, 0x34a5f011, 0xc00290f, 0x0, 0x8ec202d0, 0x24420001, -0xaec202d0, 0x8ec202d0, 0x8ec20250, 0x24420001, 0xaec20250, 0x8ec20250, -0x8ee204a8, 0x30420001, 0x10400054, 0x0, 0x8f420218, 0x30420080, -0x1040002b, 0x0, 0x8f820044, 0x34420040, 0xaf820044, 0x8ec200b0, -0x402821, 0x8ec201b8, 0x8ec301bc, 0x24060000, 0x2407ffff, 0x2021, -0x461024, 0x1444000d, 0x671824, 0x1465000b, 0x0, 0x8ec200b4, -0x402821, 0x8ec201d8, 0x8ec301dc, 0x2021, 0x461024, 0x14440003, -0x671824, 0x1065000c, 0x0, 0x8ec201b8, 0x8ec301bc, 0x8ec401d8, -0x8ec501dc, 0xaec300b0, 0xaec500b4, 0x8f820044, 0x38420020, 0xaf820044, -0x10000056, 0x2402ff7f, 0x8f820044, 0x2403ffdf, 0x431024, 0xaf820044, -0x10000050, 0x2402ff7f, 0x8f820044, 0x2403ffdf, 0x431024, 0xaf820044, -0x8ec200b0, 0x402821, 0x8ec201b8, 0x8ec301bc, 0x24060000, 0x2407ffff, -0x2021, 0x461024, 0x1444000d, 0x671824, 0x1465000b, 0x0, -0x8ec200b4, 0x402821, 0x8ec201d8, 0x8ec301dc, 0x2021, 0x461024, -0x14440003, 0x671824, 0x1065001f, 0x0, 0x8ec201b8, 0x8ec301bc, -0x8ec401d8, 0x8ec501dc, 0xaec300b0, 0xaec500b4, 0x8f820044, 0x38420040, -0xaf820044, 0x1000002b, 0x2402ff7f, 0x8f820044, 0x34420040, 0xaf820044, -0x8ec200bc, 0x24430001, 0x1000001d, 0x28420033, 0x8ee204a8, 0x30420001, -0x10400013, 0x0, 0x8f420218, 0x30420080, 0x1040000a, 0x0, -0x8f820044, 0x2403ffdf, 0x431024, 0xaf820044, 0x8f820044, 0x34420040, -0xaf820044, 0x10000013, 0x2402ff7f, 0x8f820044, 0x34420060, 0xaf820044, -0x1000000e, 0x2402ff7f, 0x8f820044, 0x34420040, 0xaf820044, 0x8ec200bc, -0x24430001, 0x284201f5, 0x14400005, 0xaec300bc, 0x8f820044, 0x38420020, -0xaf820044, 0xaec000bc, 0x2402ff7f, 0x282a024, 0x8fbf0038, 0x8fbe0034, -0x8fb50030, 0x8fb3002c, 0x8fb10028, 0x3e00008, 0x27bd0040, 0x3e00008, -0x0, 0x3c020001, 0x8c42341c, 0x27bdffc0, 0xafbf0038, 0xafbe0034, -0xafb50030, 0xafb3002c, 0x10400100, 0xafb10028, 0x8ec200b8, 0x3c040001, -0x8c84340c, 0x24430001, 0x2842000b, 0xaec400d0, 0x14400127, 0xaec300b8, -0xaec000b8, 0x8ee204a8, 0x30420002, 0x14400094, 0x0, 0x8ee204a8, -0x34420002, 0xaee204a8, 0x24020001, 0x14820003, 0x3c020600, 0x10000002, -0x34423000, 0x34421000, 0xafa20020, 0x8ec3002c, 0x240200ff, 0x10620004, -0x27a70020, 0x8ec2002c, 0x10000002, 0x24530001, 0x9821, 0x8f420228, -0x1662000f, 0x0, 0x3c040001, 0x248427f8, 0xafa00010, 0xafa00014, -0x8ec6002c, 0x8f470228, 0x3c050009, 0xc00290f, 0x34a5f00f, 0x8ec202a0, -0x24420001, 0xaec202a0, 0x1000006d, 0x8ec202a0, 0x8ec2002c, 0x210c0, -0x571021, 0x8ce30000, 0x8ce40004, 0xac4304c0, 0xac4404c4, 0x8f830054, -0x8f820054, 0x247103e8, 0x2221023, 0x2c4203e9, 0x1040001e, 0xa821, -0x241e000c, 0x8ec8002c, 0x8ee40428, 0x8ee5042c, 0x8ec6002c, 0x24070008, -0xafbe0010, 0xafb30014, 0x840c0, 0x1001821, 0x1021, 0x8ec80008, -0xa32821, 0xa3482b, 0x822021, 0x892021, 0x630c0, 0xafa80018, -0x8ec200a8, 0x24c604c0, 0x40f809, 0x2e63021, 0x54400006, 0x24150001, -0x8f820054, 0x2221023, 0x2c4203e9, 0x1440ffe5, 0x0, 0x32a200ff, -0x54400011, 0xaed3002c, 0x3c040001, 0x24842804, 0xafa00010, 0xafa00014, -0x8f860120, 0x8f870124, 0x3c050009, 0x10000030, 0x34a5f010, 0x8ec2026c, -0x24150001, 0x24420001, 0xaec2026c, 0x8ec2026c, 0x1000001f, 0x32a200ff, -0x8f830054, 0x8f820054, 0x247103e8, 0x2221023, 0x2c4203e9, 0x10400017, -0xa821, 0x3c1e0020, 0x24130011, 0x8ec20008, 0x8ee40488, 0x8ee5048c, -0x8ec3002c, 0x8f860120, 0xafb30010, 0x5e1025, 0xafa30014, 0xafa20018, -0x8ec200a8, 0x24070008, 0x40f809, 0x24c6001c, 0x1440ffe2, 0x0, -0x8f820054, 0x2221023, 0x2c4203e9, 0x1440ffed, 0x0, 0x32a200ff, -0x1440000f, 0x0, 0x3c040001, 0x24842810, 0xafa00010, 0xafa00014, -0x8f860120, 0x8f870124, 0x3c050009, 0x34a5f011, 0xc00290f, 0x0, -0x8ec202d0, 0x24420001, 0xaec202d0, 0x8ec202d0, 0x8ec20250, 0x24420001, -0xaec20250, 0x8ec20250, 0x8ee204a8, 0x30420001, 0x10400055, 0x0, -0x8f420218, 0x30420080, 0x10400027, 0x0, 0x8ec200b0, 0x3c040001, -0x908434d0, 0x24080000, 0x2409ffff, 0x403821, 0x8ec201b8, 0x8ec301bc, -0x3021, 0x34840020, 0x3c010001, 0xa02434d0, 0x481024, 0x1446000d, -0x691824, 0x1467000b, 0x0, 0x8ec200b4, 0x403821, 0x8ec201d8, -0x8ec301dc, 0x3021, 0x481024, 0x14460003, 0x691824, 0x10670009, -0x308200bf, 0x8ec201b8, 0x8ec301bc, 0x3c040001, 0x908434d0, 0x8ec601d8, -0x8ec701dc, 0x10000026, 0x38840040, 0x3c010001, 0x10000061, 0xa02234d0, -0x8ec200b0, 0x3c040001, 0x908434d0, 0x24080000, 0x2409ffff, 0x403821, -0x8ec201b8, 0x8ec301bc, 0x3021, 0x308400bf, 0x3c010001, 0xa02434d0, -0x481024, 0x1446000d, 0x691824, 0x1467000b, 0x0, 0x8ec200b4, -0x403821, 0x8ec201d8, 0x8ec301dc, 0x3021, 0x481024, 0x14460003, -0x691824, 0x1067000d, 0x34820020, 0x8ec201b8, 0x8ec301bc, 0x3c040001, -0x908434d0, 0x8ec601d8, 0x8ec701dc, 0x38840020, 0xaec300b0, 0xaec700b4, -0x3c010001, 0x1000003a, 0xa02434d0, 0x3c010001, 0x10000037, 0xa02234d0, -0x3c020001, 0x904234d0, 0x8ec300bc, 0x34440020, 0x24620001, 0x10000028, -0x28630033, 0x8ec200cc, 0x8ec300c8, 0x24420001, 0xaec200cc, 0x43102a, -0x14400006, 0x24030001, 0x8ec200d0, 0x14430002, 0xaec000cc, 0x24030004, -0xaec300d0, 0x8ee204a8, 0x30420001, 0x10400012, 0x0, 0x8f420218, -0x30420080, 0x10400008, 0x0, 0x3c020001, 0x904234d0, 0x34420040, -0x304200df, 0x3c010001, 0x10000015, 0xa02234d0, 0x3c020001, 0x904234d0, -0x34420060, 0x3c010001, 0x1000000f, 0xa02234d0, 0x3c020001, 0x904234d0, -0x8ec300bc, 0x34440020, 0x24620001, 0x286300fb, 0x3c010001, 0xa02434d0, -0x14600005, 0xaec200bc, 0x38820040, 0x3c010001, 0xa02234d0, 0xaec000bc, -0x3c020001, 0x904234d0, 0x8ec300d0, 0x3044007f, 0x24020001, 0x3c010001, -0xa02434d0, 0x54620003, 0x3484000f, 0x42102, 0x348400f0, 0xc004950, -0x0, 0x2402ff7f, 0x282a024, 0x8fbf0038, 0x8fbe0034, 0x8fb50030, -0x8fb3002c, 0x8fb10028, 0x3e00008, 0x27bd0040, 0x3e00008, 0x0, -0x27bdffc0, 0xafbf0038, 0xafbe0034, 0xafb50030, 0xafb3002c, 0xafb10028, -0x92c20528, 0x144001bc, 0x26c50128, 0x26e40028, 0x240300ff, 0x2406ffff, -0x8ca20000, 0x24a50004, 0x2463ffff, 0xac820000, 0x1466fffb, 0x24840004, -0x8f420080, 0xaee20044, 0x8f4200c0, 0xaee20040, 0x8f420084, 0xaee20030, -0x8f420084, 0xaee2022c, 0x8f420088, 0xaee20230, 0x8f42008c, 0xaee20234, -0x8f420090, 0xaee20238, 0x8f420094, 0xaee2023c, 0x8f420098, 0xaee20240, -0x8f42009c, 0xaee20244, 0x8f4200a0, 0xaee20248, 0x8f4200a4, 0xaee2024c, -0x8f4200a8, 0xaee20250, 0x8f4200ac, 0xaee20254, 0x8f4200b0, 0xaee20258, -0x8f4200b4, 0xaee2025c, 0x8f4200b8, 0xaee20260, 0x8f4200bc, 0x24040001, -0xaee20264, 0xaee00034, 0x41080, 0x571021, 0x8ee30034, 0x8c42022c, -0x24840001, 0x621821, 0x2c82000f, 0xaee30034, 0x1440fff8, 0x41080, -0x8f4200cc, 0xaee20048, 0x8f4200d0, 0xaee2004c, 0x8f4200e0, 0xaee201e8, -0x8f4200e4, 0xaee201ec, 0x8f4200e8, 0xaee201f0, 0x8f4200ec, 0xaee201f4, -0x8f4200f0, 0xaee201f8, 0x8f4200fc, 0x402821, 0x8ee200c0, 0x2021, -0x82102b, 0x1440000a, 0x0, 0x8ee200c0, 0x14440011, 0x0, -0x8ee200c4, 0xa2102b, 0x14400003, 0x0, 0x1000000b, 0x8ee200c4, -0x8ee200c0, 0x8ee300c4, 0x24040001, 0x24050000, 0x651821, 0x65302b, -0x441021, 0x461021, 0xaee200c0, 0xaee300c4, 0x8f4200fc, 0x8ee400c0, -0x8ee500c4, 0x2406ffff, 0x24070000, 0x401821, 0x1021, 0x862024, -0xa72824, 0x822025, 0xa32825, 0xaee400c0, 0xaee500c4, 0x8f4200f4, -0x402821, 0x8ee200d0, 0x2021, 0x82102b, 0x1440000a, 0x0, -0x8ee200d0, 0x14440011, 0x0, 0x8ee200d4, 0xa2102b, 0x14400003, -0x0, 0x1000000b, 0x8ee200d4, 0x8ee200d0, 0x8ee300d4, 0x24040001, -0x24050000, 0x651821, 0x65302b, 0x441021, 0x461021, 0xaee200d0, -0xaee300d4, 0x8f4200f4, 0x8ee400d0, 0x8ee500d4, 0x2406ffff, 0x24070000, -0x401821, 0x1021, 0x862024, 0xa72824, 0x822025, 0xa32825, -0xaee400d0, 0xaee500d4, 0x8f4200f8, 0x402821, 0x8ee200c8, 0x2021, -0x82102b, 0x1440000a, 0x0, 0x8ee200c8, 0x14440011, 0x0, -0x8ee200cc, 0xa2102b, 0x14400003, 0x0, 0x1000000b, 0x8ee200cc, -0x8ee200c8, 0x8ee300cc, 0x24040001, 0x24050000, 0x651821, 0x65302b, -0x441021, 0x461021, 0xaee200c8, 0xaee300cc, 0x8f4200f8, 0x8ee400c8, -0x8ee500cc, 0x2406ffff, 0x24070000, 0x401821, 0x1021, 0x862024, -0xa72824, 0x822025, 0xa32825, 0xaee400c8, 0xaee500cc, 0x8f440208, -0x8f45020c, 0x2402000f, 0xafa20010, 0xafa00014, 0x8ec20008, 0xafa20018, -0x8ec200a8, 0x26e60028, 0x40f809, 0x24070400, 0x104000f1, 0x3c020400, -0xafa20020, 0x92c20115, 0x10400080, 0x240200ff, 0x8ec3002c, 0x10620004, -0x27a70020, 0x8ec2002c, 0x10000002, 0x24530001, 0x9821, 0x8f420228, -0x1662000a, 0x0, 0x3c040001, 0x248427f8, 0xafa00010, 0xafa00014, -0x8ec6002c, 0x8f470228, 0x3c050009, 0x1000007f, 0x34a5f00f, 0x8ec2002c, -0x210c0, 0x571021, 0x8ce30000, 0x8ce40004, 0xac4304c0, 0xac4404c4, -0x8f830054, 0x8f820054, 0x247103e8, 0x2221023, 0x2c4203e9, 0x1040001e, -0xa821, 0x241e000d, 0x8ec8002c, 0x8ee40428, 0x8ee5042c, 0x8ec6002c, -0x24070008, 0xafbe0010, 0xafb30014, 0x840c0, 0x1001821, 0x1021, -0x8ec80008, 0xa32821, 0xa3482b, 0x822021, 0x892021, 0x630c0, -0xafa80018, 0x8ec200a8, 0x24c604c0, 0x40f809, 0x2e63021, 0x54400006, -0x24150001, 0x8f820054, 0x2221023, 0x2c4203e9, 0x1440ffe5, 0x0, -0x32a200ff, 0x54400018, 0xaed3002c, 0x3c040001, 0x24842804, 0xafa00010, -0xafa00014, 0x8f860120, 0x8f870124, 0x3c050009, 0x34a5f010, 0xc00290f, -0x0, 0x8ec202d0, 0x1821, 0x24420001, 0xaec202d0, 0x1000008f, -0x8ec202d0, 0x8ec2026c, 0x24150001, 0x24420001, 0xaec2026c, 0x8ec2026c, -0x1000001d, 0x32a200ff, 0x8f830054, 0x8f820054, 0x247103e8, 0x2221023, -0x2c4203e9, 0x10400015, 0xa821, 0x24130011, 0x8ec30008, 0x8ee40488, -0x8ee5048c, 0x8ec2002c, 0x8f860120, 0xafb30010, 0xafa20014, 0xafa30018, -0x8ec200a8, 0x24070008, 0x40f809, 0x24c6001c, 0x1440ffe4, 0x0, -0x8f820054, 0x2221023, 0x2c4203e9, 0x1440ffee, 0x0, 0x32a200ff, -0x1440006a, 0x24030001, 0x3c040001, 0x24842810, 0xafa00010, 0xafa00014, -0x8f860120, 0x8f870124, 0x3c050009, 0x1000ffcb, 0x34a5f011, 0x8ec3002c, -0x10620004, 0x27a70020, 0x8ec2002c, 0x10000002, 0x24510001, 0x8821, -0x8f420228, 0x16220011, 0x4021, 0x3c040001, 0x248427d8, 0xafa00010, -0xafa00014, 0x8ec6002c, 0x8f470228, 0x3c050009, 0x34a5f005, 0xc00290f, -0x0, 0x8ec202a0, 0x1821, 0x24420001, 0xaec202a0, 0x10000047, -0x8ec202a0, 0x8ec2002c, 0x210c0, 0x571021, 0x8ce30000, 0x8ce40004, -0xac4304c0, 0xac4404c4, 0x8ec3002c, 0x8ee40428, 0x8ee5042c, 0x8ec6002c, -0x24070008, 0x2402000d, 0xafa20010, 0xafb10014, 0x8ec20008, 0x318c0, -0x604821, 0xa92821, 0xa9182b, 0x882021, 0x832021, 0x630c0, -0xafa20018, 0x8ec200a8, 0x24c604c0, 0x40f809, 0x2e63021, 0x5440000c, -0xaed1002c, 0x3c040001, 0x248427e4, 0xafa00010, 0xafa00014, 0x8ec6002c, -0x8f470228, 0x3c050009, 0xc00290f, 0x34a5f000, 0x1000001e, 0x1821, -0x8ee40488, 0x8ee5048c, 0x8ec3002c, 0x8ec80008, 0x8f860120, 0x24020011, -0xafa20010, 0xafa30014, 0xafa80018, 0x8ec200a8, 0x24070008, 0x40f809, -0x24c6001c, 0x1440000f, 0x24030001, 0x3c040001, 0x248427ec, 0xafa00010, -0xafa00014, 0x8ec6002c, 0x8f470228, 0x3c050009, 0xc00290f, 0x34a5f001, -0x8ec202a4, 0x1821, 0x24420001, 0xaec202a4, 0x8ec202a4, 0x1060000d, -0x24020001, 0x8ec2024c, 0xa2c00115, 0xaec000a0, 0x24420001, 0xaec2024c, -0x8ec2024c, 0x8ee2014c, 0x24420001, 0xaee2014c, 0x10000003, 0x8ee2014c, -0x24020001, 0xa2c20115, 0x8fbf0038, 0x8fbe0034, 0x8fb50030, 0x8fb3002c, -0x8fb10028, 0x3e00008, 0x27bd0040, 0x27bdffd8, 0xafbf0020, 0x8f8200b0, -0x30420004, 0x1040005e, 0x0, 0x8ec30104, 0x8f820104, 0x14620005, -0x0, 0x8ec3010c, 0x8f8200b4, 0x10620006, 0x0, 0x8f820104, -0xaec20104, 0x8f8200b4, 0x10000051, 0xaec2010c, 0x8f8200b0, 0x3c030080, -0x431024, 0x1040000d, 0x0, 0x8f82011c, 0x34420002, 0xaf82011c, -0x8f8200b0, 0x2403fffb, 0x431024, 0xaf8200b0, 0x8f82011c, 0x2403fffd, -0x431024, 0x10000040, 0xaf82011c, 0x8ec30104, 0x8f820104, 0x14620005, -0x0, 0x8ec3010c, 0x8f8200b4, 0x5062000a, 0x3c050005, 0x8f820104, -0xaec20104, 0x8f8200b4, 0xaec2010c, 0x8ec2010c, 0x3c040001, 0x2484281c, -0x10000029, 0xafa00014, 0x8ec2010c, 0x3c040001, 0x24842828, 0xafa00014, -0xafa20010, 0x8f8600b0, 0x8ec70104, 0xc00290f, 0x34a50900, 0x8f82011c, -0x34420002, 0xaf82011c, 0x8f830104, 0x8f8200b0, 0x34420001, 0xaf8200b0, -0xaf830104, 0x8f440208, 0x8f45020c, 0x2402000f, 0xafa20010, 0xafa00014, -0x8ec20008, 0xafa20018, 0x8ec200a8, 0x26e60028, 0x40f809, 0x24070400, -0x8f82011c, 0x2403fffd, 0x431024, 0xaf82011c, 0x8ee201cc, 0x24420001, -0xaee201cc, 0x8ee201cc, 0x8ec2010c, 0x3c040001, 0x24842834, 0xafa00014, -0xafa20010, 0x8f8600b0, 0x8ec70104, 0x3c050005, 0xc00290f, 0x34a50900, -0x8f8200a0, 0x30420004, 0x1040005f, 0x0, 0x8ec30108, 0x8f820124, -0x14620005, 0x0, 0x8ec30110, 0x8f8200a4, 0x10620006, 0x0, -0x8f820124, 0xaec20108, 0x8f8200a4, 0x10000052, 0xaec20110, 0x8f8200a0, -0x3c030080, 0x431024, 0x1040000d, 0x0, 0x8f82011c, 0x34420002, -0xaf82011c, 0x8f8200a0, 0x2403fffb, 0x431024, 0xaf8200a0, 0x8f82011c, -0x2403fffd, 0x431024, 0x10000041, 0xaf82011c, 0x8ec30108, 0x8f820124, -0x14620005, 0x0, 0x8ec30110, 0x8f8200a4, 0x5062000a, 0x3c050005, -0x8f820124, 0xaec20108, 0x8f8200a4, 0xaec20110, 0x8ec20110, 0x3c040001, -0x24842840, 0x1000002a, 0xafa00014, 0x8ec20110, 0x3c040001, 0x2484284c, -0xafa00014, 0xafa20010, 0x8f8600a0, 0x8ec70108, 0xc00290f, 0x34a50900, -0x8f82011c, 0x34420002, 0xaf82011c, 0x8f830124, 0x8f8200a0, 0x34420001, -0xaf8200a0, 0xaf830124, 0x8f440208, 0x8f45020c, 0x24020010, 0xafa20010, -0xafa00014, 0x8ec20010, 0xafa20018, 0x8ec200a4, 0x3c060001, 0x24c634e4, -0x40f809, 0x24070004, 0x8f82011c, 0x2403fffd, 0x431024, 0xaf82011c, -0x8ee201cc, 0x24420001, 0xaee201cc, 0x8ee201cc, 0x8ec20110, 0x3c040001, -0x24842858, 0xafa00014, 0xafa20010, 0x8f8600a0, 0x8ec70108, 0x3c050005, -0xc00290f, 0x34a50900, 0x8fbf0020, 0x3e00008, 0x27bd0028, 0x3c091000, -0x24080001, 0x3c070080, 0x3c050100, 0x3c062000, 0x8f820070, 0x491024, -0x1040fffd, 0x0, 0x8f820054, 0x24420005, 0xaf820078, 0x8f420234, -0x10400017, 0x2021, 0x3c020001, 0x571021, 0x8c4281dc, 0x24420005, -0x3c010001, 0x370821, 0xac2281dc, 0x3c020001, 0x571021, 0x8c4281dc, -0x8f430234, 0x43102b, 0x14400009, 0x0, 0x3c040080, 0x3c010001, -0x370821, 0xac2881d4, 0x3c010001, 0x370821, 0x1000000b, 0xac2081dc, -0x3c020001, 0x571021, 0x8c4281d4, 0x54400006, 0x872025, 0x3c020001, -0x571021, 0x8c4281d8, 0x54400001, 0x872025, 0x8f420230, 0x10400014, -0x0, 0x3c020001, 0x571021, 0x8c4281e4, 0x24420005, 0x3c010001, -0x370821, 0xac2281e4, 0x3c020001, 0x571021, 0x8c4281e4, 0x8f430230, -0x43102b, 0x14400006, 0x0, 0x3c010001, 0x370821, 0xac2081e4, -0x10000006, 0x852025, 0x3c020001, 0x571021, 0x8c4281e0, 0x54400001, -0x852025, 0x3c020001, 0x571021, 0x8c4281e8, 0x10400005, 0x0, -0x862025, 0x3c010001, 0x370821, 0xac2081e8, 0x1080ffb1, 0x0, -0x8ec20000, 0x10400007, 0x0, 0xaf80004c, 0x8f82004c, 0x1040fffd, -0x0, 0x10000005, 0x0, 0xaf800048, 0x8f820048, 0x1040fffd, -0x0, 0x8f820060, 0x441025, 0xaf820060, 0x8ec20000, 0x10400003, -0x0, 0x1000ff9c, 0xaf80004c, 0x1000ff9a, 0xaf800048, 0x3e00008, -0x0, 0x0, 0x0, 0x0, 0x27bdffe0, 0xafbf0018, -0x8f860064, 0x30c20004, 0x1040001e, 0x24020004, 0xaf820064, 0x8f420114, -0x8ec30000, 0x10600007, 0xaec20014, 0xaf80004c, 0x8f82004c, 0x1040fffd, -0x0, 0x10000005, 0x0, 0xaf800048, 0x8f820048, 0x1040fffd, -0x0, 0x8f820060, 0x34420008, 0xaf820060, 0x8ec20000, 0x10400003, -0x0, 0x10000002, 0xaf80004c, 0xaf800048, 0x8ec20260, 0x24420001, -0xaec20260, 0x1000006f, 0x8ec20260, 0x30c20001, 0x10400004, 0x24020001, -0xaf820064, 0x10000069, 0x0, 0x30c20002, 0x1440000b, 0x3c050003, -0x3c040001, 0x24842930, 0x34a50001, 0x3821, 0xafa00010, 0xc00290f, -0xafa00014, 0x2402fff8, 0x1000005c, 0xaf820064, 0x8f43022c, 0x8f42010c, -0x1062004c, 0x0, 0x8f42022c, 0x21080, 0x5a1021, 0x8c440300, -0x8f42022c, 0x24420001, 0x3042003f, 0x41e02, 0xaf42022c, 0x24020003, -0x10620005, 0x24020010, 0x1062001f, 0x30830fff, 0x1000003a, 0x0, -0x8ec30000, 0x30820fff, 0x10600007, 0xaec20038, 0xaf80004c, 0x8f82004c, -0x1040fffd, 0x0, 0x10000005, 0x0, 0xaf800048, 0x8f820048, -0x1040fffd, 0x0, 0x8f820060, 0x34420200, 0xaf820060, 0x8ec20000, -0x10400003, 0x0, 0x10000002, 0xaf80004c, 0xaf800048, 0x8ec20210, -0x24420001, 0xaec20210, 0x10000020, 0x8ec20210, 0x8ec20000, 0xaec30054, -0x24030001, 0x10400007, 0xa2c30065, 0xaf80004c, 0x8f82004c, 0x1040fffd, -0x0, 0x10000005, 0x0, 0xaf800048, 0x8f820048, 0x1040fffd, -0x0, 0x8f820060, 0x34420100, 0xaf820060, 0x8ec20000, 0x10400003, -0x0, 0x10000002, 0xaf80004c, 0xaf800048, 0x8ec2023c, 0x24420001, -0xaec2023c, 0x10000003, 0x8ec2023c, 0xc001fd6, 0x0, 0x8f43022c, -0x8f42010c, 0x14620002, 0x24020002, 0xaf820064, 0x8f820064, 0x14400005, -0x0, 0x8f43022c, 0x8f42010c, 0x1462ffa6, 0x0, 0x8fbf0018, -0x3e00008, 0x27bd0020, 0x3e00008, 0x0, 0x27bdffc0, 0xafb10028, -0x808821, 0x111602, 0x2442ffff, 0x304300ff, 0x2c620011, 0xafbf0038, -0xafbe0034, 0xafb50030, 0x104001ab, 0xafb3002c, 0x31080, 0x3c010001, -0x220821, 0x8c222978, 0x400008, 0x0, 0x111302, 0x30440fff, -0x24020001, 0x10820006, 0x3c030800, 0x24020002, 0x1082000c, 0x3c050003, -0x10000022, 0x0, 0x3c020001, 0x8c423514, 0x21100, 0x21182, -0x431025, 0xae420038, 0x8ee204a8, 0x1000000a, 0x34420001, 0x3c020001, -0x2442c4d0, 0x21100, 0x21182, 0x431025, 0xae420038, 0x8ee204a8, -0x2403fffe, 0x431024, 0xaee204a8, 0xaec40168, 0xaec4016c, 0x8f840054, -0x41442, 0x41c82, 0x431021, 0x41cc2, 0x431023, 0x41d02, -0x431021, 0x41d42, 0x431023, 0x10000009, 0xaec20170, 0x3c040001, -0x2484293c, 0x34a50004, 0x2203021, 0x3821, 0xafa00010, 0xc00290f, -0xafa00014, 0x8ec20208, 0x24420001, 0xaec20208, 0x100001e1, 0x8ec20208, -0xc0022fe, 0x0, 0x100001dd, 0x0, 0xc002419, 0x0, -0x100001d9, 0x0, 0x111302, 0x30430fff, 0x24020001, 0x10620005, -0x24020002, 0x10620016, 0x3c050003, 0x10000021, 0x0, 0x92c2011c, -0x1440000f, 0x24020001, 0x8f820228, 0xaee204ac, 0x8f82022c, 0xaee204b0, -0x8f820230, 0xaee204b4, 0x8f820234, 0xaee204b8, 0x2402ffff, 0xaf820228, -0xaf82022c, 0xaf820230, 0xaf820234, 0x24020001, 0x10000016, 0xa2c2011c, -0x92c2011c, 0x50400013, 0xa2c0011c, 0x8ee204ac, 0xaf820228, 0x8ee204b0, -0xaf82022c, 0x8ee204b4, 0xaf820230, 0x8ee204b8, 0xaf820234, 0x10000009, -0xa2c0011c, 0x3c040001, 0x24842948, 0x34a5f009, 0x2203021, 0x3821, -0xafa00010, 0xc00290f, 0xafa00014, 0x8ec20234, 0x24420001, 0xaec20234, -0x100001a3, 0x8ec20234, 0x111302, 0x30440fff, 0x24020001, 0x10820005, -0x24020002, 0x1082000d, 0x3c050003, 0x10000013, 0x0, 0x8f820220, -0x3c0308ff, 0x3463ffff, 0x431024, 0x34420008, 0xaf820220, 0x24020001, -0xa2c2011d, 0x10000011, 0xaec40200, 0x8f820220, 0x3c0308ff, 0x3463fff7, -0x431024, 0xaf820220, 0xa2c0011d, 0x10000009, 0xaec40200, 0x3c040001, -0x24842954, 0x34a5f00a, 0x2203021, 0x3821, 0xafa00010, 0xc00290f, -0xafa00014, 0x8ec20224, 0x24420001, 0xaec20224, 0x1000017b, 0x8ec20224, -0x27840208, 0x27450200, 0xc0029a2, 0x24060008, 0x26c4018c, 0x27450200, -0xc0029a2, 0x24060008, 0x8ec2022c, 0x24420001, 0xaec2022c, 0x1000016e, -0x8ec2022c, 0x111302, 0x30430fff, 0x24020001, 0x10620011, 0x28620002, -0x50400005, 0x24020002, 0x10600007, 0x0, 0x10000017, 0x0, -0x1062000f, 0x0, 0x10000013, 0x0, 0x8f460248, 0x24040001, -0xc0046cc, 0x24050004, 0x10000007, 0x0, 0x8f460248, 0x24040001, -0xc0046cc, 0x24050004, 0x10000010, 0x0, 0x8f46024c, 0x24040001, -0xc0046cc, 0x24050001, 0x1000000a, 0x0, 0x3c040001, 0x24842960, -0x3c050003, 0x34a50005, 0x2203021, 0x3821, 0xafa00010, 0xc00290f, -0xafa00014, 0x8ec20228, 0x24420001, 0xaec20228, 0x1000013f, 0x8ec20228, -0xc002221, 0x0, 0x1000013b, 0x0, 0x24020001, 0xa2c20528, -0x24110014, 0x8ee404a0, 0x8ee504a4, 0xafb10010, 0xafa00014, 0x8ec20010, -0xafa20018, 0x8ec200a4, 0x26e60028, 0x40f809, 0x24070400, 0x1040fff5, -0x0, 0x1000012a, 0x0, 0x3c020900, 0xaec00054, 0xaec00058, -0xaec0005c, 0xaec00060, 0xaec002c0, 0xa2c00065, 0xafa20020, 0x8ec3002c, -0x240200ff, 0x10620004, 0x27a70020, 0x8ec2002c, 0x10000002, 0x24530001, -0x9821, 0x8f420228, 0x1662000f, 0x0, 0x3c040001, 0x2484290c, -0xafa00010, 0xafa00014, 0x8ec6002c, 0x8f470228, 0x3c050009, 0xc00290f, -0x34a5f00f, 0x8ec202a0, 0x24420001, 0xaec202a0, 0x1000006b, 0x8ec202a0, -0x8ec2002c, 0x210c0, 0x571021, 0x8ce30000, 0x8ce40004, 0xac4304c0, -0xac4404c4, 0x8f830054, 0x8f820054, 0x247103e8, 0x2221023, 0x2c4203e9, -0x1040001e, 0xa821, 0x241e000d, 0x8ec8002c, 0x8ee40428, 0x8ee5042c, -0x8ec6002c, 0x24070008, 0xafbe0010, 0xafb30014, 0x840c0, 0x1001821, -0x1021, 0x8ec80008, 0xa32821, 0xa3482b, 0x822021, 0x892021, -0x630c0, 0xafa80018, 0x8ec200a8, 0x24c604c0, 0x40f809, 0x2e63021, -0x54400006, 0x24150001, 0x8f820054, 0x2221023, 0x2c4203e9, 0x1440ffe5, -0x0, 0x32a200ff, 0x54400011, 0xaed3002c, 0x3c040001, 0x24842918, -0xafa00010, 0xafa00014, 0x8f860120, 0x8f870124, 0x3c050009, 0x1000002e, -0x34a5f010, 0x8ec2026c, 0x24150001, 0x24420001, 0xaec2026c, 0x8ec2026c, -0x1000001d, 0x32a200ff, 0x8f830054, 0x8f820054, 0x247103e8, 0x2221023, -0x2c4203e9, 0x10400015, 0xa821, 0x24130011, 0x8ec30008, 0x8ee40488, -0x8ee5048c, 0x8ec2002c, 0x8f860120, 0xafb30010, 0xafa20014, 0xafa30018, -0x8ec200a8, 0x24070008, 0x40f809, 0x24c6001c, 0x1440ffe4, 0x0, -0x8f820054, 0x2221023, 0x2c4203e9, 0x1440ffee, 0x0, 0x32a200ff, -0x1440000f, 0x0, 0x3c040001, 0x24842924, 0xafa00010, 0xafa00014, -0x8f860120, 0x8f870124, 0x3c050009, 0x34a5f011, 0xc00290f, 0x0, -0x8ec202d0, 0x24420001, 0xaec202d0, 0x8ec202d0, 0x8ec20218, 0x24420001, -0xaec20218, 0x8ec20218, 0x8ec2025c, 0x24420001, 0xaec2025c, 0x10000096, -0x8ec2025c, 0x8f42025c, 0x26c4018c, 0xaec20158, 0x8f420260, 0x27450200, -0x24060008, 0xc0029a2, 0xaec20160, 0x8f820220, 0x30420008, 0x14400002, -0x24020001, 0x24020002, 0xaec20200, 0x8ec20214, 0x24420001, 0xaec20214, -0x10000083, 0x8ec20214, 0x3c0200ff, 0x96e30462, 0x3442ffff, 0x2222024, -0x3402fffb, 0x44102b, 0x38420001, 0x30630003, 0x2c630001, 0x621824, -0x10600003, 0x0, 0x10000075, 0xaec40050, 0x3c040001, 0x2484296c, -0x3c050003, 0x34a5f00f, 0x2203021, 0x3821, 0xafa00010, 0xc00290f, -0xafa00014, 0x3c030700, 0x34631000, 0x111602, 0x431025, 0xafa20020, -0x8ec3002c, 0x240200ff, 0x10620004, 0x27a70020, 0x8ec2002c, 0x10000002, -0x24510001, 0x8821, 0x8f420228, 0x1622000f, 0x4021, 0x3c040001, -0x248428ec, 0xafa00010, 0xafa00014, 0x8ec6002c, 0x8f470228, 0x3c050009, -0xc00290f, 0x34a5f005, 0x8ec202a0, 0x24420001, 0xaec202a0, 0x10000046, -0x8ec202a0, 0x8ec2002c, 0x210c0, 0x571021, 0x8ce30000, 0x8ce40004, -0xac4304c0, 0xac4404c4, 0x8ec3002c, 0x8ee40428, 0x8ee5042c, 0x8ec6002c, -0x24070008, 0x2402000d, 0xafa20010, 0xafb10014, 0x8ec20008, 0x318c0, -0x604821, 0xa92821, 0xa9182b, 0x882021, 0x832021, 0x630c0, -0xafa20018, 0x8ec200a8, 0x24c604c0, 0x40f809, 0x2e63021, 0x5440000c, -0xaed1002c, 0x3c040001, 0x248428f8, 0xafa00010, 0xafa00014, 0x8ec6002c, -0x8f470228, 0x3c050009, 0xc00290f, 0x34a5f000, 0x1000001d, 0x0, -0x8ee40488, 0x8ee5048c, 0x8ec3002c, 0x8ec80008, 0x8f860120, 0x24020011, -0xafa20010, 0xafa30014, 0xafa80018, 0x8ec200a8, 0x24070008, 0x40f809, -0x24c6001c, 0x1440000e, 0x0, 0x3c040001, 0x24842900, 0xafa00010, -0xafa00014, 0x8ec6002c, 0x8f470228, 0x3c050009, 0xc00290f, 0x34a5f001, -0x8ec202a4, 0x24420001, 0xaec202a4, 0x8ec202a4, 0x8ec20244, 0x24420001, -0xaec20244, 0x8ec20244, 0x8ec20254, 0x24420001, 0xaec20254, 0x8ec20254, -0x8fbf0038, 0x8fbe0034, 0x8fb50030, 0x8fb3002c, 0x8fb10028, 0x3e00008, -0x27bd0040, 0x27bdfff8, 0x2408ffff, 0x10a00014, 0x4821, 0x3c0aedb8, -0x354a8320, 0x90870000, 0x24840001, 0x3021, 0x1071026, 0x30420001, -0x10400002, 0x81842, 0x6a1826, 0x604021, 0x24c60001, 0x2cc20008, -0x1440fff7, 0x73842, 0x25290001, 0x125102b, 0x1440fff0, 0x0, -0x1001021, 0x3e00008, 0x27bd0008, 0x27bdffb8, 0xafbf0040, 0xafbe003c, -0xafb50038, 0xafb30034, 0xafb10030, 0x8f870220, 0xafa70024, 0x8f870200, -0xafa7002c, 0x8f820220, 0x3c0308ff, 0x3463ffff, 0x431024, 0x34420004, -0xaf820220, 0x8f820200, 0x3c03c0ff, 0x3463ffff, 0x431024, 0x34420004, -0xaf820200, 0x8ede02bc, 0x8ec702c0, 0xafa70014, 0x8ec702c4, 0xafa7001c, -0x8ec20238, 0x26c40128, 0x24420001, 0xaec20238, 0x8ed10238, 0x8ed3016c, -0x8ed50168, 0xc002990, 0x24050400, 0xaede02bc, 0x8fa70014, 0xaec702c0, -0x8fa7001c, 0xaec702c4, 0xaed10238, 0xaed3016c, 0xaed50168, 0x8f42025c, -0x26c4018c, 0xaec20158, 0x8f420260, 0x27450200, 0x24060008, 0xaec20160, -0x24020006, 0xc0029a2, 0xaec2015c, 0x3c023b9a, 0x3442ca00, 0xaec20164, -0x240203e8, 0x24040002, 0x24030001, 0xaec201fc, 0xaec401f8, 0xaec30204, -0x8f820220, 0x30420008, 0x10400004, 0x0, 0xaec30200, 0x10000003, -0x3021, 0xaec40200, 0x3021, 0x3c030001, 0x661821, 0x90633360, -0x2c61021, 0x24c60001, 0xa0430194, 0x2cc2000f, 0x1440fff8, 0x2c61821, -0x24c60001, 0x8f820040, 0x27440080, 0x24050080, 0x21702, 0x24420030, -0xa0620194, 0x2c61021, 0xc002990, 0xa0400194, 0x8fa70024, 0x30e20004, -0x14400006, 0x0, 0x8f820220, 0x3c0308ff, 0x3463fffb, 0x431024, -0xaf820220, 0x8fa7002c, 0x30e20004, 0x14400006, 0x0, 0x8f820200, -0x3c03c0ff, 0x3463fffb, 0x431024, 0xaf820200, 0x8fbf0040, 0x8fbe003c, -0x8fb50038, 0x8fb30034, 0x8fb10030, 0x3e00008, 0x27bd0048, 0x0, -0x0, 0x0, 0x24040001, 0xa2c0011d, 0xa2c0011c, 0xaec00120, -0x410c0, 0x2e21821, 0x24820001, 0xa46275c0, 0x402021, 0x2c820080, -0x1440fffa, 0x410c0, 0x24020001, 0xa6e079c0, 0xaec20124, 0xaf800228, -0xaf80022c, 0xaf800230, 0xaf800234, 0x3e00008, 0x0, 0x27bdffe0, -0xafbf001c, 0xafb10018, 0x8ec20120, 0x28420005, 0x10400021, 0x808821, -0x8ec20120, 0x3021, 0x18400015, 0x26e371c0, 0x96270000, 0x24640006, -0x9482fffc, 0x14470009, 0x2821, 0x9483fffe, 0x96220002, 0x14620006, -0xa01021, 0x94820000, 0x96230004, 0x431026, 0x2c450001, 0xa01021, -0x1440000b, 0x24c60001, 0x8ec20120, 0xc2102a, 0x1440ffef, 0x24840008, -0x1021, 0x304200ff, 0x14400029, 0x24020001, 0x10000027, 0x1021, -0x1000fffa, 0x24020001, 0x2202021, 0xc002207, 0x24050006, 0x3042007f, -0x218c0, 0x2e31021, 0x944271c0, 0x1040fff4, 0x2e31021, 0x944671c0, -0x10c00019, 0x1021, 0x96270000, 0x610c0, 0x572021, 0x248475c2, -0x94820000, 0x14470009, 0x2821, 0x94830002, 0x96220002, 0x14620006, -0xa01021, 0x94820004, 0x96230004, 0x431026, 0x2c450001, 0xa01021, -0x14400005, 0x610c0, 0x2e21021, 0x944675c0, 0x14c0ffed, 0x610c0, -0x10c0ffd9, 0x24020001, 0x8fbf001c, 0x8fb10018, 0x3e00008, 0x27bd0020, -0x3e00008, 0x0, 0x27bdffc0, 0x27440212, 0x24050006, 0xafbf0038, -0xafbe0034, 0xafb50030, 0xafb3002c, 0xc002207, 0xafb10028, 0x3048007f, -0x810c0, 0x2e21021, 0x944571c0, 0x10a00017, 0x27470212, 0x94e90000, -0x510c0, 0x572021, 0x248475c2, 0x94820000, 0x14490009, 0x3021, -0x94830002, 0x94e20002, 0x14620006, 0xc01021, 0x94820004, 0x94e30004, -0x431026, 0x2c460001, 0xc01021, 0x14400005, 0x510c0, 0x2e21021, -0x944575c0, 0x14a0ffed, 0x510c0, 0xa03021, 0x10c00010, 0x610c0, -0x571821, 0x8c6375c0, 0x571021, 0xafa30010, 0x8c4275c4, 0x3c040001, -0x24842a7c, 0xafa20014, 0x8f460210, 0x8f470214, 0x3c050003, 0xc00290f, -0x34a5f012, 0x10000051, 0x3c020800, 0x8ec50124, 0x10a00004, 0x510c0, -0x2e21021, 0x944275c0, 0xaec20124, 0xa03021, 0x14c0000f, 0x27440212, -0x810c0, 0x2e21021, 0xafa80010, 0x944271c0, 0x3c040001, 0x24842a88, -0xafa20014, 0x8f460210, 0x8f470214, 0x3c050003, 0xc00290f, 0x34a5f013, -0x1000003a, 0x3c020800, 0x628c0, 0x94830000, 0xb71021, 0x244275c2, -0xa4430000, 0x8c830002, 0x820c0, 0xac430002, 0x2e41021, 0x944371c0, -0x2e51021, 0xa44375c0, 0x2e41021, 0xa44671c0, 0x8ec20120, 0x24420001, -0x28420080, 0x1040000c, 0x27440212, 0x8ec20120, 0x94830000, 0x210c0, -0x571021, 0x244271c2, 0xa4430000, 0x8c830002, 0xac430002, 0x8ec20120, -0x24420001, 0xaec20120, 0x92c2011c, 0x1040000d, 0x81942, 0x24020003, -0x431023, 0x21080, 0x572821, 0x571021, 0x3104001f, 0x8c4304ac, -0x24020001, 0x821004, 0x621825, 0x1000000c, 0xaca304ac, 0x24020003, -0x431023, 0x21080, 0x5c2821, 0x5c1021, 0x3104001f, 0x8c430228, -0x24020001, 0x821004, 0x621825, 0xaca30228, 0x3c020800, 0x34421000, -0xafa20020, 0x8ec3002c, 0x240200ff, 0x10620004, 0x27a70020, 0x8ec2002c, -0x10000002, 0x24530001, 0x9821, 0x8f420228, 0x1662000f, 0x0, -0x3c040001, 0x24842a58, 0xafa00010, 0xafa00014, 0x8ec6002c, 0x8f470228, -0x3c050009, 0xc00290f, 0x34a5f00f, 0x8ec202a0, 0x24420001, 0xaec202a0, -0x1000006b, 0x8ec202a0, 0x8ec2002c, 0x210c0, 0x571021, 0x8ce30000, -0x8ce40004, 0xac4304c0, 0xac4404c4, 0x8f830054, 0x8f820054, 0x247103e8, -0x2221023, 0x2c4203e9, 0x1040001e, 0xa821, 0x241e000d, 0x8ec8002c, -0x8ee40428, 0x8ee5042c, 0x8ec6002c, 0x24070008, 0xafbe0010, 0xafb30014, -0x840c0, 0x1001821, 0x1021, 0x8ec80008, 0xa32821, 0xa3482b, -0x822021, 0x892021, 0x630c0, 0xafa80018, 0x8ec200a8, 0x24c604c0, -0x40f809, 0x2e63021, 0x54400006, 0x24150001, 0x8f820054, 0x2221023, -0x2c4203e9, 0x1440ffe5, 0x0, 0x32a200ff, 0x54400011, 0xaed3002c, -0x3c040001, 0x24842a64, 0xafa00010, 0xafa00014, 0x8f860120, 0x8f870124, -0x3c050009, 0x1000002e, 0x34a5f010, 0x8ec2026c, 0x24150001, 0x24420001, -0xaec2026c, 0x8ec2026c, 0x1000001d, 0x32a200ff, 0x8f830054, 0x8f820054, -0x247103e8, 0x2221023, 0x2c4203e9, 0x10400015, 0xa821, 0x24130011, -0x8ec30008, 0x8ee40488, 0x8ee5048c, 0x8ec2002c, 0x8f860120, 0xafb30010, -0xafa20014, 0xafa30018, 0x8ec200a8, 0x24070008, 0x40f809, 0x24c6001c, -0x1440ffe4, 0x0, 0x8f820054, 0x2221023, 0x2c4203e9, 0x1440ffee, -0x0, 0x32a200ff, 0x1440000f, 0x0, 0x3c040001, 0x24842a70, -0xafa00010, 0xafa00014, 0x8f860120, 0x8f870124, 0x3c050009, 0x34a5f011, -0xc00290f, 0x0, 0x8ec202d0, 0x24420001, 0xaec202d0, 0x8ec202d0, -0x8ec2021c, 0x24420001, 0xaec2021c, 0x8ec2021c, 0x8ec20258, 0x24420001, -0xaec20258, 0x8ec20258, 0x8fbf0038, 0x8fbe0034, 0x8fb50030, 0x8fb3002c, -0x8fb10028, 0x3e00008, 0x27bd0040, 0x27bdffb0, 0x27440212, 0x24050006, -0xafbf0048, 0xafbe0044, 0xafb50040, 0xafb3003c, 0xc002207, 0xafb10038, -0x3044007f, 0x410c0, 0x2e21021, 0x944771c0, 0x4021, 0x10e00018, -0x27490212, 0x952a0000, 0x710c0, 0x572821, 0x24a575c2, 0x94a20000, -0x144a0009, 0x3021, 0x94a30002, 0x95220002, 0x14620006, 0xc01021, -0x94a20004, 0x95230004, 0x431026, 0x2c460001, 0xc01021, 0x14400006, -0x710c0, 0xe04021, 0x2e21021, 0x944775c0, 0x14e0ffec, 0x710c0, -0xe02821, 0x14a0000f, 0xafa80028, 0x410c0, 0x2e21021, 0xafa40010, -0x944271c0, 0x3c040001, 0x24842a94, 0xafa20014, 0x8f460210, 0x8f470214, -0x3c050003, 0xc00290f, 0x34a5f01c, 0x10000062, 0x3c020800, 0x11000007, -0x510c0, 0x2e21021, 0x944375c0, 0x810c0, 0x2e21021, 0x10000006, -0xa44375c0, 0x2e21021, 0x944375c0, 0x410c0, 0x2e21021, 0xa44371c0, -0x8ec30124, 0x510c0, 0x2e21021, 0x26e871c0, 0xa44375c0, 0x8ec20120, -0x3021, 0x27490212, 0x18400029, 0xaec50124, 0x25070006, 0x94e3fffc, -0x95220000, 0x14620009, 0x2821, 0x94e3fffe, 0x95220002, 0x14620006, -0xa01021, 0x94e20000, 0x95230004, 0x431026, 0x2c450001, 0xa01021, -0x50400014, 0x24c60001, 0x8ec20120, 0x2442ffff, 0xc2102a, 0x1040000b, -0x25050004, 0x94a20006, 0x8ca30008, 0xa4a2fffe, 0xaca30000, 0x8ec20120, -0x24c60001, 0x2442ffff, 0xc2102a, 0x1440fff7, 0x24a50008, 0x8ec20120, -0x2442ffff, 0x10000006, 0xaec20120, 0x8ec20120, 0x24e70008, 0xc2102a, -0x1440ffda, 0x25080008, 0x410c0, 0x2e21021, 0x944271c0, 0x1440001e, -0x3c020800, 0x92c2011c, 0x1040000e, 0x41942, 0x24020003, 0x431023, -0x21080, 0x572821, 0x571021, 0x3084001f, 0x24030001, 0x8c4204ac, -0x831804, 0x31827, 0x431024, 0x1000000d, 0xaca204ac, 0x24020003, -0x431023, 0x21080, 0x5c2821, 0x5c1021, 0x3084001f, 0x24030001, -0x8c420228, 0x831804, 0x31827, 0x431024, 0xaca20228, 0x3c020800, -0x34422000, 0xafa20020, 0x8ec3002c, 0x240200ff, 0x10620004, 0x27a70020, -0x8ec2002c, 0x10000002, 0x24530001, 0x9821, 0x8f420228, 0x1662000f, -0x0, 0x3c040001, 0x24842a58, 0xafa00010, 0xafa00014, 0x8ec6002c, -0x8f470228, 0x3c050009, 0xc00290f, 0x34a5f00f, 0x8ec202a0, 0x24420001, -0xaec202a0, 0x1000006b, 0x8ec202a0, 0x8ec2002c, 0x210c0, 0x571021, -0x8ce30000, 0x8ce40004, 0xac4304c0, 0xac4404c4, 0x8f830054, 0x8f820054, -0x247103e8, 0x2221023, 0x2c4203e9, 0x1040001e, 0xa821, 0x241e000d, -0x8ec8002c, 0x8ee40428, 0x8ee5042c, 0x8ec6002c, 0x24070008, 0xafbe0010, -0xafb30014, 0x840c0, 0x1001821, 0x1021, 0x8ec80008, 0xa32821, -0xa3482b, 0x822021, 0x892021, 0x630c0, 0xafa80018, 0x8ec200a8, -0x24c604c0, 0x40f809, 0x2e63021, 0x54400006, 0x24150001, 0x8f820054, -0x2221023, 0x2c4203e9, 0x1440ffe5, 0x0, 0x32a200ff, 0x54400011, -0xaed3002c, 0x3c040001, 0x24842a64, 0xafa00010, 0xafa00014, 0x8f860120, -0x8f870124, 0x3c050009, 0x1000002e, 0x34a5f010, 0x8ec2026c, 0x24150001, -0x24420001, 0xaec2026c, 0x8ec2026c, 0x1000001d, 0x32a200ff, 0x8f830054, -0x8f820054, 0x247103e8, 0x2221023, 0x2c4203e9, 0x10400015, 0xa821, -0x24130011, 0x8ec30008, 0x8ee40488, 0x8ee5048c, 0x8ec2002c, 0x8f860120, -0xafb30010, 0xafa20014, 0xafa30018, 0x8ec200a8, 0x24070008, 0x40f809, -0x24c6001c, 0x1440ffe4, 0x0, 0x8f820054, 0x2221023, 0x2c4203e9, -0x1440ffee, 0x0, 0x32a200ff, 0x1440000f, 0x0, 0x3c040001, -0x24842a70, 0xafa00010, 0xafa00014, 0x8f860120, 0x8f870124, 0x3c050009, -0x34a5f011, 0xc00290f, 0x0, 0x8ec202d0, 0x24420001, 0xaec202d0, -0x8ec202d0, 0x8ec20220, 0x24420001, 0xaec20220, 0x8ec20220, 0x8ec20258, -0x24420001, 0xaec20258, 0x8ec20258, 0x8fbf0048, 0x8fbe0044, 0x8fb50040, -0x8fb3003c, 0x8fb10038, 0x3e00008, 0x27bd0050, 0x0, 0x0, -0x27bdffe8, 0x27644000, 0xafbf0010, 0xc002990, 0x24051000, 0x24020020, -0xaf82011c, 0xaf800100, 0xaf800104, 0xaf800108, 0xaf800110, 0xaf800114, -0xaf800118, 0xaf800120, 0xaf800124, 0xaf800128, 0xaf800130, 0xaf800134, -0xaf800138, 0xaec000dc, 0xaec000e0, 0xaec000e4, 0xaec000e8, 0x3c020001, -0x571021, 0x904281ec, 0x1440001d, 0x0, 0x8f82011c, 0x34420001, -0xaf82011c, 0x8f830040, 0x3c02f000, 0x621824, 0x3c025000, 0x10620005, -0x3c026000, 0x1062000b, 0x0, 0x10000010, 0x0, 0x8f420218, -0x30420040, 0x14400009, 0x0, 0x8f820050, 0x3c030010, 0x10000003, -0x431024, 0x8f420218, 0x30420040, 0x10400004, 0x0, 0x8f82011c, -0x34420004, 0xaf82011c, 0x8fbf0010, 0x3e00008, 0x27bd0018, 0x8fa90010, -0x8f83012c, 0x8faa0014, 0x8fab0018, 0x1060000a, 0x24680020, 0x8ec20534, -0x51020001, 0x27684800, 0x8f820128, 0x11020004, 0x0, 0x8f820124, -0x15020007, 0x39220011, 0x8ec30298, 0x1021, 0x24630001, 0xaec30298, -0x10000069, 0x8ec30298, 0xac640000, 0xac650004, 0xac660008, 0xa467000e, -0xac690018, 0xac6a001c, 0xac6b0010, 0x2523ffee, 0x2c630002, 0x2c420001, -0x621825, 0x10600025, 0xaf880120, 0x8ec200e4, 0x210c0, 0x24426fc0, -0x2e22021, 0x8c830000, 0x24020012, 0x1462000f, 0x0, 0x8ec300e4, -0x8ec200e8, 0x1062000b, 0x24030040, 0x8c820004, 0x24420001, 0xac820004, -0x8ec200e8, 0x8ec500e4, 0x24420001, 0x1043002b, 0x0, 0x10000023, -0x0, 0x8ec200e4, 0x24030040, 0x24420001, 0x50430003, 0x1021, -0x8ec200e4, 0x24420001, 0xaec200e4, 0x8ec200e4, 0x210c0, 0x24426fc0, -0x2e22021, 0x10000034, 0x24020012, 0x8ec200e4, 0x210c0, 0x24426fc0, -0x2e22021, 0x8c830000, 0x24020007, 0x1462001f, 0x0, 0x8ec300e4, -0x8ec200e8, 0x1062001b, 0x24030040, 0x8c820004, 0x24420001, 0xac820004, -0x8ec200e8, 0x8ec500e4, 0x24420001, 0x10430007, 0x0, 0x8ec200e8, -0x24420001, 0x10a20005, 0x0, 0x10000007, 0x0, 0x14a00005, -0x0, 0x8f820128, 0x24420020, 0xaf820128, 0x8f820128, 0x8c820004, -0x2c420011, 0x50400013, 0xac800000, 0x10000012, 0x24020001, 0x8ec200e4, -0x24030040, 0x24420001, 0x50430003, 0x1021, 0x8ec200e4, 0x24420001, -0xaec200e4, 0x8ec200e4, 0x210c0, 0x24426fc0, 0x2e22021, 0x24020007, -0xac820000, 0x24020001, 0xac820004, 0x24020001, 0x3e00008, 0x0, -0x3e00008, 0x0, 0x8faa0010, 0x8fab0014, 0x8f880120, 0x8ec20534, -0x8fac0018, 0x25030020, 0x14620002, 0x604821, 0x27694800, 0x8f820128, -0x1122000c, 0x25030016, 0xad040000, 0xad050004, 0xad060008, 0xa507000e, -0xad0a0018, 0xad0b001c, 0xad030014, 0xad0c0010, 0xaf890120, 0x10000006, -0x24020001, 0x8ec30298, 0x1021, 0x24630001, 0xaec30298, 0x8ec30298, -0x3e00008, 0x0, 0x3e00008, 0x0, 0x8fa90010, 0x8f83010c, -0x8faa0014, 0x8fab0018, 0x1060000a, 0x24680020, 0x27624800, 0x51020001, -0x27684000, 0x8f820108, 0x11020004, 0x0, 0x8f820104, 0x15020007, -0x2522fffb, 0x8ec3029c, 0x1021, 0x24630001, 0xaec3029c, 0x10000051, -0x8ec3029c, 0x2c420002, 0xac640000, 0xac650004, 0xac660008, 0xa467000e, -0xac690018, 0xac6a001c, 0xac6b0010, 0xaf880100, 0x10400037, 0x24030040, -0x8ec200dc, 0x210c0, 0x24426dc0, 0x2e22021, 0x8c830000, 0x24020005, -0x1462001f, 0x0, 0x8ec300dc, 0x8ec200e0, 0x1062001b, 0x24030040, -0x8c820004, 0x24420001, 0xac820004, 0x8ec200e0, 0x8ec500dc, 0x24420001, -0x10430007, 0x0, 0x8ec200e0, 0x24420001, 0x10a20005, 0x0, -0x10000007, 0x0, 0x14a00005, 0x0, 0x8f820108, 0x24420020, -0xaf820108, 0x8f820108, 0x8c820004, 0x2c420011, 0x50400021, 0xac800000, -0x10000020, 0x24020001, 0x8ec200dc, 0x24030040, 0x24420001, 0x50430003, -0x1021, 0x8ec200dc, 0x24420001, 0xaec200dc, 0x8ec200dc, 0x210c0, -0x24426dc0, 0x2e22021, 0x24020005, 0xac820000, 0x1000000e, 0x24020001, -0x8ec200dc, 0x24420001, 0x50430003, 0x1021, 0x8ec200dc, 0x24420001, -0xaec200dc, 0x8ec200dc, 0x210c0, 0x24426dc0, 0x2e22021, 0x24020001, -0xac890000, 0xac820004, 0x24020001, 0x3e00008, 0x0, 0x3e00008, -0x0, 0x8fab0010, 0x8f880100, 0x8faa0014, 0x8fac0018, 0x27624800, -0x25030020, 0x14620002, 0x604821, 0x27694000, 0x8f820108, 0x1122000c, -0x25030016, 0xad040000, 0xad050004, 0xad060008, 0xa507000e, 0xad0b0018, -0xad0a001c, 0xad030014, 0xad0c0010, 0xaf890100, 0x10000006, 0x24020001, -0x8ec3029c, 0x1021, 0x24630001, 0xaec3029c, 0x8ec3029c, 0x3e00008, -0x0, 0x3e00008, 0x0, 0x27bdffe0, 0xafbf0018, 0x8f820104, -0xafa20010, 0x8f820100, 0x3c040001, 0x24842b5c, 0xafa20014, 0x8f8600b0, -0x8f87011c, 0x3c050002, 0xc00290f, 0x34a5f000, 0x8f420218, 0x30420100, -0x10400017, 0x0, 0x8f8200b0, 0x3c030200, 0x431024, 0x10400012, -0x0, 0x8f82011c, 0x34420002, 0xaf82011c, 0x8f830104, 0x8f8200b0, -0x34420001, 0xaf8200b0, 0xaf830104, 0x8f82011c, 0x2403fffd, 0x431024, -0xaf82011c, 0x8ec20294, 0x24420001, 0xaec20294, 0x10000018, 0x8ec20294, -0x3c040001, 0x24842b68, 0x3405dead, 0x3021, 0x3c070001, 0x24e72b70, -0x24020287, 0xafa20010, 0xc00290f, 0xafa00014, 0x8f82011c, 0x34420002, -0xaf82011c, 0x8f820220, 0x34420004, 0xaf820220, 0x8f820140, 0x3c030001, -0x431025, 0xaf820140, 0x8f8200b0, 0x34420001, 0xaf8200b0, 0x8fbf0018, -0x3e00008, 0x27bd0020, 0x27bdffe0, 0xafbf0018, 0x8f820120, 0xafa20010, -0x8f820124, 0x3c040001, 0x24842b98, 0xafa20014, 0x8f8600a0, 0x8f87011c, -0x3c050001, 0xc00290f, 0x34a5f000, 0x8f420218, 0x30420100, 0x10400017, -0x0, 0x8f8200a0, 0x3c030200, 0x431024, 0x10400012, 0x0, -0x8f82011c, 0x34420002, 0xaf82011c, 0x8f830124, 0x8f8200a0, 0x34420001, -0xaf8200a0, 0xaf830124, 0x8f82011c, 0x2403fffd, 0x431024, 0xaf82011c, -0x8ec20290, 0x24420001, 0xaec20290, 0x10000018, 0x8ec20290, 0x3c040001, -0x24842b68, 0x3405dead, 0x3021, 0x3c070001, 0x24e72b70, 0x240202a3, -0xafa20010, 0xc00290f, 0xafa00014, 0x8f82011c, 0x34420002, 0xaf82011c, -0x8f820220, 0x34420004, 0xaf820220, 0x8f820140, 0x3c030001, 0x431025, -0xaf820140, 0x8f8200a0, 0x34420001, 0xaf8200a0, 0x8fbf0018, 0x3e00008, -0x27bd0020, 0x6021, 0x5021, 0x3021, 0x2821, 0x6821, -0x4821, 0x7821, 0x7021, 0x8f880124, 0x8f870104, 0x1580002e, -0x8f8b011c, 0x11a00014, 0x31620800, 0x8f820120, 0x10460029, 0x0, -0x3c040001, 0x8c8434f0, 0x8cc20000, 0x8cc30004, 0xac820000, 0xac830004, -0x8cc20008, 0xac820008, 0x94c2000e, 0xa482000e, 0x8cc20010, 0x240c0001, -0xac820010, 0x8cc20014, 0x10000012, 0x24c60020, 0x10400017, 0x0, -0x3c040001, 0x8c8434f0, 0x8d020000, 0x8d030004, 0xac820000, 0xac830004, -0x8d020008, 0xac820008, 0x9502000e, 0xa482000e, 0x8d020010, 0x25060020, -0xac820010, 0x8d020014, 0x240c0001, 0xc01821, 0xac820014, 0x27624fe0, -0x43102b, 0x54400001, 0x27634800, 0x603021, 0x1540002f, 0x31620100, -0x11200014, 0x31628000, 0x8f820100, 0x1045002a, 0x31620100, 0x3c040001, -0x8c8434ec, 0x8ca20000, 0x8ca30004, 0xac820000, 0xac830004, 0x8ca20008, -0xac820008, 0x94a2000e, 0xa482000e, 0x8ca20010, 0x240a0001, 0xac820010, -0x8ca20014, 0x10000012, 0x24a50020, 0x10400018, 0x31620100, 0x3c040001, -0x8c8434ec, 0x8ce20000, 0x8ce30004, 0xac820000, 0xac830004, 0x8ce20008, -0xac820008, 0x94e2000e, 0xa482000e, 0x8ce20010, 0x24e50020, 0xac820010, -0x8ce20014, 0x240a0001, 0xa01821, 0xac820014, 0x276247e0, 0x43102b, -0x54400001, 0x27634000, 0x602821, 0x31620100, 0x5440001d, 0x31621000, -0x11a00009, 0x31a20800, 0x10400004, 0x25020020, 0x8f8200a8, 0xa5e20000, -0x25020020, 0xaf820124, 0x8f880124, 0x6821, 0x11800011, 0x31621000, -0x3c040001, 0x8c8434f0, 0x8c820000, 0x8c830004, 0xaf820080, 0xaf830084, -0x8c820008, 0xaf8200a4, 0x9482000e, 0xaf8200ac, 0x8c820010, 0x6021, -0xaf8200a0, 0x8c8d0010, 0x8c8f0014, 0x31621000, 0x1440ff82, 0x0, -0x1120000f, 0x31220800, 0x10400004, 0x3c020002, 0x8f8200b8, 0xa5c20000, -0x3c020002, 0x1221024, 0x10400004, 0x24e20020, 0x8f8200b4, 0xaf8200d4, -0x24e20020, 0xaf820104, 0x8f870104, 0x4821, 0x1140ff70, 0x0, -0x3c040001, 0x8c8434ec, 0x8c820000, 0x8c830004, 0xaf820090, 0xaf830094, -0x8c820008, 0xaf8200b4, 0x9482000e, 0xaf82009c, 0x8c820010, 0x5021, -0xaf8200b0, 0x8c890010, 0x1000ff60, 0x8c8e0014, 0x3e00008, 0x0, -0x6021, 0x5821, 0x3021, 0x2821, 0x6821, 0x5021, -0x7821, 0x7021, 0x8f880124, 0x8f870104, 0x3c180100, 0x1580002e, -0x8f89011c, 0x11a00014, 0x31220800, 0x8f820120, 0x10460029, 0x0, -0x3c040001, 0x8c8434f0, 0x8cc20000, 0x8cc30004, 0xac820000, 0xac830004, -0x8cc20008, 0xac820008, 0x94c2000e, 0xa482000e, 0x8cc20010, 0x240c0001, -0xac820010, 0x8cc20014, 0x10000012, 0x24c60020, 0x10400017, 0x0, -0x3c040001, 0x8c8434f0, 0x8d020000, 0x8d030004, 0xac820000, 0xac830004, -0x8d020008, 0xac820008, 0x9502000e, 0xa482000e, 0x8d020010, 0x25060020, -0xac820010, 0x8d020014, 0x240c0001, 0xc01821, 0xac820014, 0x27624fe0, -0x43102b, 0x54400001, 0x27634800, 0x603021, 0x1560002f, 0x31220100, -0x11400014, 0x31228000, 0x8f820100, 0x1045002a, 0x31220100, 0x3c040001, -0x8c8434ec, 0x8ca20000, 0x8ca30004, 0xac820000, 0xac830004, 0x8ca20008, -0xac820008, 0x94a2000e, 0xa482000e, 0x8ca20010, 0x240b0001, 0xac820010, -0x8ca20014, 0x10000012, 0x24a50020, 0x10400018, 0x31220100, 0x3c040001, -0x8c8434ec, 0x8ce20000, 0x8ce30004, 0xac820000, 0xac830004, 0x8ce20008, -0xac820008, 0x94e2000e, 0xa482000e, 0x8ce20010, 0x24e50020, 0xac820010, -0x8ce20014, 0x240b0001, 0xa01821, 0xac820014, 0x276247e0, 0x43102b, -0x54400001, 0x27634000, 0x602821, 0x31220100, 0x5440001d, 0x31221000, -0x11a00009, 0x31a20800, 0x10400004, 0x25020020, 0x8f8200a8, 0xa5e20000, -0x25020020, 0xaf820124, 0x8f880124, 0x6821, 0x11800011, 0x31221000, -0x3c040001, 0x8c8434f0, 0x8c820000, 0x8c830004, 0xaf820080, 0xaf830084, -0x8c820008, 0xaf8200a4, 0x9482000e, 0xaf8200ac, 0x8c820010, 0x6021, -0xaf8200a0, 0x8c8d0010, 0x8c8f0014, 0x31221000, 0x14400022, 0x0, -0x1140000f, 0x31420800, 0x10400004, 0x3c020002, 0x8f8200b8, 0xa5c20000, -0x3c020002, 0x1421024, 0x10400004, 0x24e20020, 0x8f8200b4, 0xaf8200d4, -0x24e20020, 0xaf820104, 0x8f870104, 0x5021, 0x11600010, 0x0, -0x3c040001, 0x8c8434ec, 0x8c820000, 0x8c830004, 0xaf820090, 0xaf830094, -0x8c820008, 0xaf8200b4, 0x9482000e, 0xaf82009c, 0x8c820010, 0x5821, -0xaf8200b0, 0x8c8a0010, 0x8c8e0014, 0x8f820070, 0x3c031000, 0x431024, -0x1040ff5c, 0x0, 0x8f820054, 0x24420005, 0xaf820078, 0x8f420234, -0x10400017, 0x2021, 0x3c020001, 0x571021, 0x8c4281dc, 0x24420005, -0x3c010001, 0x370821, 0xac2281dc, 0x3c020001, 0x571021, 0x8c4281dc, -0x8f430234, 0x43102b, 0x14400009, 0x24020001, 0x3c040080, 0x3c010001, -0x370821, 0xac2281d4, 0x3c010001, 0x370821, 0x1000000c, 0xac2081dc, -0x3c020001, 0x571021, 0x8c4281d4, 0x14400006, 0x3c020080, 0x3c020001, -0x571021, 0x8c4281d8, 0x10400002, 0x3c020080, 0x822025, 0x8f420230, -0x10400014, 0x0, 0x3c020001, 0x571021, 0x8c4281e4, 0x24420005, -0x3c010001, 0x370821, 0xac2281e4, 0x3c020001, 0x571021, 0x8c4281e4, -0x8f430230, 0x43102b, 0x14400006, 0x0, 0x3c010001, 0x370821, -0xac2081e4, 0x10000006, 0x982025, 0x3c020001, 0x571021, 0x8c4281e0, -0x54400001, 0x982025, 0x3c020001, 0x571021, 0x8c4281e8, 0x10400005, -0x3c022000, 0x822025, 0x3c010001, 0x370821, 0xac2081e8, 0x1080ff0f, -0x0, 0x8ec20000, 0x10400007, 0x0, 0xaf80004c, 0x8f82004c, -0x1040fffd, 0x0, 0x10000005, 0x0, 0xaf800048, 0x8f820048, -0x1040fffd, 0x0, 0x8f820060, 0x441025, 0xaf820060, 0x8ec20000, -0x10400003, 0x0, 0x1000fefa, 0xaf80004c, 0x1000fef8, 0xaf800048, -0x3e00008, 0x0, 0x0, 0x0, 0x3c020001, 0x8c423388, -0x27bdffe8, 0xafbf0014, 0x14400012, 0xafb10010, 0x3c110001, 0x26313590, -0x2202021, 0xc002990, 0x24052000, 0x26221fe0, 0x3c010001, 0xac2234f8, -0x3c010001, 0xac2234f4, 0xaf420250, 0x24022000, 0xaf510254, 0xaf420258, -0x24020001, 0x3c010001, 0xac223388, 0x8fbf0014, 0x8fb10010, 0x3e00008, -0x27bd0018, 0x3c030001, 0x8c6334f8, 0x8c820000, 0x8fa80010, 0x8fa90014, -0xac620000, 0x3c020001, 0x8c4234f8, 0x8c830004, 0xac430004, 0xac450008, -0x8f840054, 0x2443ffe0, 0xac460010, 0xac470014, 0xac480018, 0xac49001c, -0x3c010001, 0xac2334f8, 0xac44000c, 0x3c020001, 0x24423590, 0x62182b, -0x10600005, 0x0, 0x3c020001, 0x8c4234f4, 0x3c010001, 0xac2234f8, -0x3c030001, 0x8c6334f8, 0x3c020001, 0x8c423370, 0xac620000, 0x3c030001, -0x8c6334f8, 0x3c020001, 0x8c423370, 0xac620004, 0x3e00008, 0xaf430250, -0x27bdffd8, 0xafb10010, 0x808821, 0x3c030001, 0x8c6334f8, 0x3c020001, -0x8c423370, 0x8fa40040, 0xafb30014, 0xa09821, 0xafbf0020, 0xafbe001c, -0xafb50018, 0xac620000, 0x3c050001, 0x8ca534f8, 0x3c020001, 0x8c423370, -0xc0a821, 0xe0f021, 0x10800006, 0xaca20004, 0x24a50008, 0xc002998, -0x24060018, 0x10000004, 0x0, 0x24a40008, 0xc002990, 0x24050018, -0x3c020001, 0x8c4234f8, 0x3c050001, 0x24a53590, 0x2442ffe0, 0x3c010001, -0xac2234f8, 0x45102b, 0x10400005, 0x0, 0x3c020001, 0x8c4234f4, -0x3c010001, 0xac2234f8, 0x3c030001, 0x8c6334f8, 0x8e220000, 0xac620000, -0x3c030001, 0x8c6334f8, 0x8e220004, 0xac620004, 0xac730008, 0x8f840054, -0xac750010, 0xac7e0014, 0x8fa80038, 0xac680018, 0x8fa8003c, 0x2462ffe0, -0x3c010001, 0xac2234f8, 0x45102b, 0xac68001c, 0x10400005, 0xac64000c, -0x3c020001, 0x8c4234f4, 0x3c010001, 0xac2234f8, 0x3c030001, 0x8c6334f8, -0x3c020001, 0x8c423370, 0xac620000, 0x3c030001, 0x8c6334f8, 0x3c020001, -0x8c423370, 0xac620004, 0xaf430250, 0x8fbf0020, 0x8fbe001c, 0x8fb50018, -0x8fb30014, 0x8fb10010, 0x3e00008, 0x27bd0028, 0x10a00005, 0x0, -0xac800000, 0x24a5fffc, 0x14a0fffd, 0x24840004, 0x3e00008, 0x0, -0x10c00007, 0x0, 0x8c820000, 0x24840004, 0x24c6fffc, 0xaca20000, -0x14c0fffb, 0x24a50004, 0x3e00008, 0x0, 0x10c00007, 0x0, -0x8ca20000, 0x24a50004, 0x24c6fffc, 0xac820000, 0x14c0fffb, 0x24840004, -0x3e00008, 0x0, 0x63080, 0x861821, 0x83102b, 0x10400006, -0x0, 0xac850000, 0x24840004, 0x83102b, 0x5440fffd, 0xac850000, -0x3e00008, 0x0, 0x27bdffc0, 0xafbf0038, 0xafb30034, 0xafb10030, -0x8ec3001c, 0x8ec20014, 0x10620137, 0x0, 0x8ec2001c, 0x8ee304bc, -0x21100, 0x622021, 0x9493000a, 0x8c880000, 0x8c890004, 0x1312c2, -0x30460001, 0xafa80028, 0xafa9002c, 0x94910008, 0x8ec20078, 0x8ec30088, -0x3225ffff, 0x451021, 0x62182b, 0x10600017, 0x0, 0x8f8200d8, -0x8ec30074, 0x431023, 0x2442fff8, 0xaec20088, 0x8ec20088, 0x4410004, -0x0, 0x8ec3053c, 0x431021, 0xaec20088, 0x8ec20078, 0x8ec30088, -0x451021, 0x62182b, 0x10600006, 0x0, 0x8ec202ac, 0x24420001, -0xaec202ac, 0x1000010e, 0x8ec202ac, 0x8f8200fc, 0x14400006, 0x0, -0x8ec202a8, 0x24420001, 0xaec202a8, 0x10000106, 0x8ec202a8, 0x92c20529, -0x1040000b, 0x32620200, 0x1040000a, 0x32620004, 0x96e20452, 0x30420010, -0x10400005, 0x3c028000, 0xaec2052c, 0x9482000e, 0x21400, 0xaec20530, -0x32620004, 0x104000a8, 0x30c200ff, 0x10400003, 0x3227ffff, 0x10000002, -0x24020017, 0x24020006, 0xafa20010, 0x8ec2001c, 0xafa20014, 0x8ec2000c, -0x8fa40028, 0x8fa5002c, 0x3c030002, 0x431025, 0xafa20018, 0x8ec60080, -0x8ec200a4, 0x40f809, 0x0, 0x5440000b, 0x3225ffff, 0x8fa9002c, -0xafa90010, 0x8ec20080, 0x3c040001, 0x24842e5c, 0x3c050004, 0xafa20014, -0x8ec6001c, 0x100000a5, 0x34a5f004, 0x8ec20078, 0x451021, 0xaec20078, -0x8ec2001c, 0x8ee304bc, 0x8ec40074, 0x21100, 0x431021, 0xac44000c, -0x8ec30074, 0xafa30020, 0x8ec40078, 0xafa40024, 0x8ec2052c, 0x10400006, -0x3c024000, 0x621025, 0xafa20020, 0x8ec20530, 0x821025, 0xafa20024, -0x8ec20080, 0x8ec30078, 0x2406fff8, 0x451021, 0x24420007, 0x461024, -0x24630007, 0xaec20074, 0x8ec20088, 0x8ec40074, 0x8ec50538, 0x661824, -0x431023, 0x85202b, 0x14800005, 0xaec20088, 0x8ec20074, 0x8ec3053c, -0x431023, 0xaec20074, 0x8ec20074, 0xaec20080, 0x8f8600fc, 0x14c00007, -0x0, 0x8ec202a8, 0x1821, 0x24420001, 0xaec202a8, 0x10000008, -0x8ec202a8, 0x8fa20020, 0x8fa30024, 0xacc20000, 0xacc30004, 0x24c20008, -0xaf8200f0, 0x24030001, 0x14600012, 0x131142, 0x8f8200f0, 0xafa20010, -0x8f8200f4, 0x3c040001, 0x24842e68, 0xafa20014, 0x8fa60020, 0x8fa70024, -0x3c050004, 0xc00290f, 0x34a5f005, 0x8ec20180, 0x24420001, 0xaec20180, -0x8ec20180, 0x10000039, 0x24020001, 0x30430003, 0x24020002, 0x10620016, -0x28620003, 0x10400005, 0x24020001, 0x10620008, 0x0, 0x10000023, -0x0, 0x24020003, 0x10620017, 0x0, 0x1000001e, 0x0, -0x8ec201e0, 0x8ec301e4, 0x24630001, 0x2c640001, 0x441021, 0xaec201e0, -0xaec301e4, 0x8ec201e0, 0x10000014, 0x8ec301e4, 0x8ec201e8, 0x8ec301ec, -0x24630001, 0x2c640001, 0x441021, 0xaec201e8, 0xaec301ec, 0x8ec201e8, -0x1000000a, 0x8ec301ec, 0x8ec201f0, 0x8ec301f4, 0x24630001, 0x2c640001, -0x441021, 0xaec201f0, 0xaec301f4, 0x8ec201f0, 0x8ec301f4, 0x8ec20078, -0x8ec401d8, 0x8ec501dc, 0x401821, 0x1021, 0xa32821, 0xa3302b, -0x822021, 0x862021, 0xaec401d8, 0xaec501dc, 0x24020001, 0xaec00078, -0x1000002f, 0xa2c20529, 0x3227ffff, 0x10e0002c, 0x0, 0x14400002, -0x24020016, 0x24020005, 0xafa20010, 0x8ec2001c, 0x8fa40028, 0x8fa5002c, -0xafa20014, 0x8ec2000c, 0xafa20018, 0x8ec60080, 0x8ec200a4, 0x40f809, -0x0, 0x1440000d, 0x3225ffff, 0x3c040001, 0x24842e74, 0x8fa8002c, -0x3c050004, 0xafa00014, 0xafa80010, 0x8ec6001c, 0x34a5f007, 0xc00290f, -0x2203821, 0x10000030, 0x0, 0x8ec20080, 0x8ec40538, 0x451021, -0xaec20080, 0x8ec20078, 0x8ec30080, 0x451021, 0x64182b, 0x14600005, -0xaec20078, 0x8ec20080, 0x8ec3053c, 0x431023, 0xaec20080, 0xa2c00529, -0x8ec3001c, 0x96e20450, 0x24630001, 0x2442ffff, 0x621824, 0xaec3001c, -0x8ec3001c, 0x8ec20014, 0x14620017, 0x0, 0x8ec20000, 0x10400007, -0x2403fff7, 0xaf80004c, 0x8f82004c, 0x1040fffd, 0x0, 0x10000005, -0x0, 0xaf800048, 0x8f820048, 0x1040fffd, 0x0, 0x8f820060, -0x431024, 0xaf820060, 0x8ec20000, 0x10400003, 0x0, 0x10000002, -0xaf80004c, 0xaf800048, 0x8fbf0038, 0x8fb30034, 0x8fb10030, 0x3e00008, -0x27bd0040, 0x3e00008, 0x0, 0x27bdffd0, 0xafbf002c, 0xafb10028, -0x8ec3001c, 0x8ec20014, 0x106200f0, 0x0, 0x8ec2001c, 0x8ee304bc, -0x21100, 0x622821, 0x8caa0000, 0x8cab0004, 0x94a7000a, 0xafaa0020, -0xafab0024, 0x94b10008, 0x71ac2, 0x8ec20088, 0x3224ffff, 0x44102a, -0x10400017, 0x30680001, 0x8f8200d8, 0x8ec30080, 0x431023, 0x2442fff8, -0xaec20088, 0x8ec20088, 0x2842fff9, 0x10400005, 0x0, 0x8ec20088, -0x8ec3053c, 0x431021, 0xaec20088, 0x8ec20088, 0x44102a, 0x10400006, -0x0, 0x8ec202ac, 0x24420001, 0xaec202ac, 0x100000ca, 0x8ec202ac, -0x8f8400fc, 0x1080000c, 0x0, 0x8f8200f4, 0x2403fff8, 0x431024, -0x441023, 0x218c3, 0x50600001, 0x24030100, 0x8ec20070, 0x43102b, -0x14400006, 0x0, 0x8ec202a8, 0x24420001, 0xaec202a8, 0x100000b7, -0x8ec202a8, 0x92c20021, 0x1040000f, 0x0, 0x8ec2000c, 0x34460400, -0x30e20200, 0x1040000b, 0x0, 0x96e20452, 0x30420010, 0x10400007, -0x3c028000, 0xaec2052c, 0x94a2000e, 0x21400, 0x10000002, 0xaec20530, -0x8ec6000c, 0x8ec2001c, 0x8ee304bc, 0x8ec40074, 0x21100, 0x431021, -0xac44000c, 0x30e20004, 0x50400050, 0x3227ffff, 0x8ec2052c, 0x10400013, -0x0, 0x11000003, 0x3227ffff, 0x10000002, 0x24020018, 0x24020015, -0xafa20010, 0x8ec3001c, 0x8ec40530, 0x3c020002, 0xc21025, 0xafa20018, -0x641825, 0xafa30014, 0x8ec60080, 0x8ec200a4, 0x8fa40020, 0x10000010, -0x8fa50024, 0x11000003, 0x3227ffff, 0x10000002, 0x24020017, 0x24020006, -0xafa20010, 0x8ec2001c, 0x8fa40020, 0x8fa50024, 0x3c030002, 0xc31825, -0xafa30018, 0xafa20014, 0x8ec60080, 0x8ec200a4, 0x40f809, 0x0, -0x1440000b, 0x24030001, 0x8fab0024, 0xafab0010, 0x8ec20080, 0x3c040001, -0x24842e5c, 0x3c050004, 0xafa20014, 0x8ec60018, 0x10000037, 0x34a5f004, -0x8ec40070, 0x8ec20080, 0x8ec50538, 0x2406fff8, 0xa2c30021, 0xaec0052c, -0xaec00530, 0x24840001, 0xaec40070, 0x3224ffff, 0x441021, 0x24420007, -0x461024, 0x24840007, 0xaec20074, 0x8ec20088, 0x8ec30074, 0x862024, -0x441023, 0x65182b, 0x14600005, 0xaec20088, 0x8ec20074, 0x8ec3053c, -0x431023, 0xaec20074, 0x8ec20074, 0x1000002d, 0xaec20080, 0x10e0002b, -0x0, 0x15000002, 0x24020016, 0x24020005, 0xafa20010, 0x8ec2001c, -0x8fa40020, 0x8fa50024, 0xafa60018, 0xafa20014, 0x8ec60080, 0x8ec200a4, -0x40f809, 0x0, 0x1440000d, 0x3225ffff, 0x3c040001, 0x24842e74, -0x8faa0024, 0x3c050004, 0xafa00014, 0xafaa0010, 0x8ec60018, 0x34a5f007, -0xc00290f, 0x2203821, 0x10000030, 0x0, 0x8ec20080, 0x8ec40538, -0x451021, 0xaec20080, 0x8ec20088, 0x8ec30080, 0xa2c00021, 0x451023, -0x64182b, 0x14600005, 0xaec20088, 0x8ec20080, 0x8ec3053c, 0x431023, -0xaec20080, 0x8ec3001c, 0x96e20450, 0x24630001, 0x2442ffff, 0x621824, -0xaec3001c, 0x8ec3001c, 0x8ec20014, 0x14620017, 0x0, 0x8ec20000, -0x10400007, 0x2403fff7, 0xaf80004c, 0x8f82004c, 0x1040fffd, 0x0, -0x10000005, 0x0, 0xaf800048, 0x8f820048, 0x1040fffd, 0x0, -0x8f820060, 0x431024, 0xaf820060, 0x8ec20000, 0x10400003, 0x0, -0x10000002, 0xaf80004c, 0xaf800048, 0x8fbf002c, 0x8fb10028, 0x3e00008, -0x27bd0030, 0x3e00008, 0x0, 0x27bdffd8, 0xafbf0024, 0xafb10020, -0x8f820100, 0x8ec300e0, 0x8f820104, 0x8f850108, 0x24020040, 0x24630001, -0x50620003, 0x1021, 0x8ec200e0, 0x24420001, 0xaec200e0, 0x8ec200e0, -0x8ec300e0, 0x210c0, 0x24426dc0, 0x2e22021, 0x8ec200dc, 0x8c870004, -0x14620007, 0xa03021, 0x8f820108, 0x24420020, 0xaf820108, 0x8f820108, -0x10000011, 0xac800000, 0x8ec200e0, 0x24030040, 0x24420001, 0x50430003, -0x1021, 0x8ec200e0, 0x24420001, 0x210c0, 0x24426dc0, 0x2e22021, -0x8c820004, 0x8f830108, 0x21140, 0x621821, 0xaf830108, 0xac800000, -0x8cc50018, 0x24a2fffb, 0x2c420002, 0x1040004c, 0x24a2ffea, 0x8cc2001c, -0x96e30450, 0x8ec40024, 0x24420001, 0x2463ffff, 0x431024, 0x872021, -0xaec20018, 0xaec40024, 0x8ec20024, 0x8f43023c, 0x43102b, 0x144000ec, -0x0, 0x96e20452, 0x8ed10018, 0x30420020, 0x1040001e, 0x24070008, -0x8ee40498, 0x8ee5049c, 0x8ec30008, 0x8f860120, 0x24020019, 0xafa20010, -0xafb10014, 0xafa30018, 0x8ec200a8, 0x40f809, 0x24c6001c, 0x1440000b, -0x24020001, 0x3c040001, 0x24842e00, 0xafb10010, 0xafa00014, 0x8ec6002c, -0x8f470228, 0x3c050009, 0xc00290f, 0x34a5f006, 0x1021, 0x1040004a, -0x24020001, 0x3c010001, 0x370821, 0x1000006f, 0xac2281d0, 0x8ee40498, -0x8ee5049c, 0x8ec30008, 0x8f860120, 0x24020012, 0xafa20010, 0xafb10014, -0xafa30018, 0x8ec200a8, 0x40f809, 0x24c6001c, 0x1440000b, 0x24020001, -0x3c040001, 0x24842e00, 0xafb10010, 0xafa00014, 0x8ec6002c, 0x8f470228, -0x3c050009, 0xc00290f, 0x34a5f006, 0x1021, 0x1040004f, 0x24020001, -0x10000051, 0x0, 0x2c420002, 0x10400062, 0x24a2fffe, 0x8cc2001c, -0x96e30450, 0x8ec40024, 0x24420001, 0x2463ffff, 0x431024, 0x872021, -0xaec20018, 0xaec40024, 0x96e20452, 0x8ed10018, 0x30420020, 0x10400023, -0x24070008, 0x8ee40498, 0x8ee5049c, 0x8ec30008, 0x8f860120, 0x24020019, -0xafa20010, 0xafb10014, 0xafa30018, 0x8ec200a8, 0x40f809, 0x24c6001c, -0x1440000b, 0x24020001, 0x3c040001, 0x24842e00, 0xafb10010, 0xafa00014, -0x8ec6002c, 0x8f470228, 0x3c050009, 0xc00290f, 0x34a5f006, 0x1021, -0x14400006, 0x24020001, 0x24020001, 0x3c010001, 0x370821, 0x10000031, -0xac2281d8, 0x3c010001, 0x370821, 0x10000021, 0xac2281d0, 0x8ee40498, -0x8ee5049c, 0x8ec30008, 0x8f860120, 0x24020012, 0xafa20010, 0xafb10014, -0xafa30018, 0x8ec200a8, 0x40f809, 0x24c6001c, 0x1440000b, 0x24020001, -0x3c040001, 0x24842e00, 0xafb10010, 0xafa00014, 0x8ec6002c, 0x8f470228, -0x3c050009, 0xc00290f, 0x34a5f006, 0x1021, 0x14400005, 0x24020001, -0x3c010001, 0x370821, 0x10000010, 0xac2281d4, 0x3c010001, 0x370821, -0xac2081d0, 0x3c010001, 0x370821, 0xac2081d8, 0x3c010001, 0x370821, -0xac2081d4, 0x8ec20264, 0xaec00024, 0xaed10028, 0x24420001, 0xaec20264, -0x8ec20264, 0x8ec20278, 0x24420001, 0xaec20278, 0x1000004b, 0x8ec20278, -0x2c420002, 0x10400027, 0x24030040, 0x8ec20034, 0x24420001, 0x50430003, -0x1021, 0x8ec20034, 0x24420001, 0xaec20034, 0x8ec20034, 0x21080, -0x571021, 0x8c440cc0, 0x24020003, 0x14a2000d, 0x0, 0x92c20065, -0x50400037, 0x36940040, 0x8ec202c0, 0x8ec3005c, 0x441021, 0xaec202c0, -0x8ec202c4, 0x641821, 0x306300ff, 0x10000009, 0xaec3005c, 0x8ec202bc, -0x8ec3003c, 0x441021, 0xaec202bc, 0x8ec202c4, 0x641821, 0x306301ff, -0xaec3003c, 0x441021, 0xaec202c4, 0x10000022, 0x36940040, 0x24020014, -0x14a20014, 0x24020010, 0x3c020001, 0x8c423334, 0x1040000a, 0x26e50028, -0x26c40128, 0x240300ff, 0x2406ffff, 0x8ca20000, 0x24a50004, 0x2463ffff, -0xac820000, 0x1466fffb, 0x24840004, 0x8ec20240, 0xa2c00528, 0x24420001, -0xaec20240, 0x1000000c, 0x8ec20240, 0x10a2000a, 0x3c050008, 0x94c7000e, -0x8cc2001c, 0x3c040001, 0x24842e80, 0xafa60014, 0xafa20010, 0x8cc60018, -0xc00290f, 0x34a50910, 0x8fbf0024, 0x8fb10020, 0x3e00008, 0x27bd0028, -0x3e00008, 0x0, 0x27bdff80, 0xafbf0078, 0xafbe0074, 0xafb50070, -0xafb3006c, 0xafb10068, 0x8f820104, 0x8f950108, 0xafa00034, 0x12a2039b, -0xafa0003c, 0x8f820108, 0x24420020, 0xaf820108, 0x8ead0018, 0xafad0044, -0x8f820108, 0x39a30015, 0x2c630001, 0x39a20018, 0x2c420001, 0x621825, -0x10600009, 0x3c0d8000, 0x8ea2001c, 0x3c03ffff, 0xafad0034, 0x431824, -0x3042ffff, 0xafa3003c, 0x10000009, 0xaea2001c, 0x8fad0044, 0x39a30006, -0x2c630001, 0x39a20017, 0x2c420001, 0x621825, 0x1060028d, 0x24020005, -0x96a20016, 0x8ead001c, 0xaea20014, 0xafad0054, 0x8ee204bc, 0xd1900, -0x8ee404bc, 0x621021, 0x9442000a, 0xafa2004c, 0x92c20090, 0x641821, -0x14400003, 0x8c71000c, 0xaed1009c, 0xaecd0094, 0x8ec20538, 0x2625000c, -0xa2102b, 0x14400003, 0x0, 0x8ec2053c, 0xa22823, 0x94a30000, -0x24020800, 0x1462014c, 0x0, 0x8fad004c, 0x31a20002, 0x10400045, -0x9821, 0x96e20452, 0x30420002, 0x10400041, 0x2629000e, 0x8ec60538, -0x8ec7053c, 0x126102b, 0x50400001, 0x1274823, 0x25220014, 0x46102b, -0x10400027, 0x24030005, 0x91220000, 0x3042000f, 0x14430024, 0x1202021, -0x952a0000, 0x25290002, 0x95280000, 0x25290002, 0x95270000, 0x25290002, -0x95260000, 0x25290002, 0x95250000, 0x25290002, 0x95230000, 0x25290002, -0x95220000, 0x25290002, 0x95240000, 0x25290002, 0x1485021, 0x1475021, -0x1465021, 0x1455021, 0x1435021, 0x1425021, 0x95220000, 0x95230002, -0x1445021, 0x1425021, 0x1435021, 0xa1c02, 0x3142ffff, 0x625021, -0xa1c02, 0x3142ffff, 0x10000008, 0x625021, 0x1202021, 0x90850000, -0x8ec200ac, 0x30a5000f, 0x40f809, 0x52840, 0x304affff, 0x8ec20538, -0x26250018, 0xa2102b, 0x14400003, 0x3153ffff, 0x8ec2053c, 0xa22823, -0x131027, 0xa4a20000, 0x8fad004c, 0x31a20001, 0x10400101, 0x0, -0x96e20452, 0x30420001, 0x104000fd, 0x31a20080, 0x10400008, 0x0, -0x92c20090, 0x14400005, 0x24020001, 0xa2c20090, 0x8fad0054, 0xaed1009c, -0xaecd0094, 0x8ec3009c, 0x8ec20538, 0x24650017, 0xa2102b, 0x14400003, -0x0, 0x8ec2053c, 0xa22823, 0x90a50000, 0xa3a5005f, 0x93a6005f, -0x38c30006, 0x3182b, 0x38c20011, 0x2102b, 0x621824, 0x1060000c, -0x3c050008, 0x8fad0054, 0xafad0010, 0x8ec2009c, 0x3c040001, 0x24842e8c, -0xafa20014, 0x8ec70094, 0xc00290f, 0x34a5f055, 0x100000d7, 0x0, -0x96e20452, 0x30420008, 0x1040000c, 0x2625000e, 0x8ec20538, 0xa2102b, -0x14400003, 0xf021, 0x8ec2053c, 0xa22823, 0x90a20000, 0x3042000f, -0x21080, 0x10000068, 0xafa20028, 0x8ec20094, 0x8fad0054, 0x11a20013, -0x26240010, 0x8ec30538, 0x8ec5053c, 0x83102b, 0x14400002, 0x2626000e, -0x852023, 0x94870000, 0xc02021, 0x83102b, 0x50400001, 0x852023, -0x90820000, 0x3042000f, 0x21080, 0xe21823, 0x307effff, 0x10000052, -0xafa20028, 0x8ec30538, 0x2625000e, 0x8ec4053c, 0xa3102b, 0x50400001, -0xa42823, 0x24a20014, 0x43102b, 0x10400015, 0xa03821, 0x90a20000, -0x94a30002, 0x3042000f, 0x21080, 0x623023, 0xafa20028, 0x90a30009, -0x24a5000c, 0x94a20000, 0x24a50002, 0x94a40000, 0x24a50002, 0xc33021, -0xc23021, 0x94a20000, 0x94a30002, 0xc43021, 0xc23021, 0x1000002d, -0xc33021, 0x24a50002, 0xa3102b, 0x50400001, 0xa42823, 0x94a60000, -0xe02821, 0xa3102b, 0x50400001, 0xa42823, 0x90a20000, 0x24e50009, -0x3042000f, 0x21080, 0xc23023, 0xafa20028, 0xa3102b, 0x50400001, -0xa42823, 0x90a20000, 0x24e5000c, 0xc23021, 0xa3102b, 0x50400001, -0xa42823, 0x94a20000, 0x24a50002, 0xc23021, 0xa3102b, 0x50400001, -0xa42823, 0x94a20000, 0x24a50002, 0xc23021, 0xa3102b, 0x50400001, -0xa42823, 0x94a20000, 0x24a50002, 0xc23021, 0xa3102b, 0x50400001, -0xa42823, 0x94a20000, 0xc23021, 0x61c02, 0x30c2ffff, 0x623021, -0x61402, 0x30c3ffff, 0x431021, 0x305effff, 0x8ec60538, 0x8ec7053c, -0x226102b, 0x14400002, 0x2204021, 0x2274023, 0x2502000e, 0x46102b, -0x1040001a, 0x1002021, 0x95060000, 0x25080002, 0x95050000, 0x25080002, -0x95030000, 0x25080002, 0x95020000, 0x25080002, 0x95040000, 0x25080002, -0xc53021, 0xc33021, 0xc23021, 0x95020000, 0x95030002, 0xc43021, -0xc23021, 0xc33021, 0x61c02, 0x30c2ffff, 0x623021, 0x61c02, -0x30c2ffff, 0x10000005, 0x623021, 0x8ec200ac, 0x40f809, 0x24050007, -0x3046ffff, 0x30c2ffff, 0x2629821, 0x131c02, 0x3262ffff, 0x629821, -0x131c02, 0x8ea40014, 0x3262ffff, 0x629821, 0x9e2021, 0x41c02, -0x3082ffff, 0x622021, 0x932023, 0x41402, 0x822021, 0x3084ffff, -0x50800001, 0x3404ffff, 0x93a3005f, 0x24020006, 0x14620006, 0x0, -0x8fa20028, 0x8ec3009c, 0x431021, 0x10000005, 0x2445001e, 0x8fa20028, -0x8ec3009c, 0x431021, 0x24450014, 0x8ec20538, 0xa2102b, 0x14400003, -0x0, 0x8ec2053c, 0xa22823, 0x8ec20094, 0x8fad0054, 0x11a20006, -0x0, 0x94a20000, 0x822021, 0x41c02, 0x3082ffff, 0x622021, -0x8fad004c, 0x31a20100, 0x14400005, 0x41027, 0x92c20090, 0x54400004, -0xa4a40000, 0x41027, 0x3044ffff, 0xa4a40000, 0x96a3000e, 0x8ec20078, -0x431021, 0xaec20078, 0xafb10020, 0x8ec30078, 0x8fad0034, 0x11a00007, -0xafa30024, 0x8fad003c, 0x3c024000, 0x2221025, 0xafa20020, 0x6d1025, -0xafa20024, 0x8fad004c, 0x31a20080, 0x1040000c, 0x31a20100, 0x8ee279cc, -0x24430001, 0x210c0, 0x571021, 0xaee379cc, 0x8fa30020, 0x8fa40024, -0xac4379d0, 0xac4479d4, 0x100000ba, 0xaec00078, 0x1040006b, 0x0, -0x8ee279cc, 0x24430001, 0x210c0, 0x571021, 0xaee379cc, 0x8fa30020, -0x8fa40024, 0xac4379d0, 0xac4479d4, 0x8ee279cc, 0x10400058, 0x4821, -0x3c0a001f, 0x354affff, 0x240cffff, 0x340bffff, 0x4021, 0x8f8700fc, -0x1173021, 0x14e00007, 0x24c679d0, 0x8ec202a8, 0x1821, 0x24420001, -0xaec202a8, 0x10000008, 0x8ec202a8, 0x8cc20000, 0x8cc30004, 0xace20000, -0xace30004, 0x24e20008, 0xaf8200f0, 0x24030001, 0x14600006, 0x2e81021, -0x8ec20180, 0x24420001, 0xaec20180, 0x10000036, 0x8ec20180, 0x944279d6, -0x8ec401d8, 0x8ec501dc, 0x401821, 0x1021, 0xa32821, 0xa3302b, -0x822021, 0x862021, 0x2e81021, 0xaec401d8, 0xaec501dc, 0x8c4279d0, -0x4a1824, 0x90620000, 0x30420001, 0x1040001b, 0x0, 0x8c620000, -0x144c000e, 0x0, 0x94620004, 0x144b000b, 0x0, 0x8ec201f0, -0x8ec301f4, 0x24630001, 0x2c640001, 0x441021, 0xaec201f0, 0xaec301f4, -0x8ec201f0, 0x10000014, 0x8ec301f4, 0x8ec201e8, 0x8ec301ec, 0x24630001, -0x2c640001, 0x441021, 0xaec201e8, 0xaec301ec, 0x8ec201e8, 0x1000000a, -0x8ec301ec, 0x8ec201e0, 0x8ec301e4, 0x24630001, 0x2c640001, 0x441021, -0xaec201e0, 0xaec301e4, 0x8ec201e0, 0x8ec301e4, 0x8ee279cc, 0x25290001, -0x122102b, 0x1440ffaf, 0x25080008, 0x8ec20070, 0xa2c00090, 0x8ee379cc, -0x431023, 0xaec20070, 0x1000004d, 0xaee079cc, 0x8f8600fc, 0x14c00007, -0x0, 0x8ec202a8, 0x1821, 0x24420001, 0xaec202a8, 0x10000008, -0x8ec202a8, 0x8fa20020, 0x8fa30024, 0xacc20000, 0xacc30004, 0x24c20008, -0xaf8200f0, 0x24030001, 0x14600006, 0x0, 0x8ec20180, 0x24420001, -0xaec20180, 0x10000033, 0x8ec20180, 0x8ec20078, 0x8ec401d8, 0x8ec501dc, -0x401821, 0x1021, 0xa32821, 0xa3302b, 0x822021, 0x862021, -0xaec401d8, 0xaec501dc, 0x92220000, 0x30420001, 0x1040001b, 0x2402ffff, -0x8e230000, 0x1462000e, 0x3402ffff, 0x96230004, 0x1462000b, 0x0, -0x8ec201f0, 0x8ec301f4, 0x24630001, 0x2c640001, 0x441021, 0xaec201f0, -0xaec301f4, 0x8ec201f0, 0x10000014, 0x8ec301f4, 0x8ec201e8, 0x8ec301ec, -0x24630001, 0x2c640001, 0x441021, 0xaec201e8, 0xaec301ec, 0x8ec201e8, -0x1000000a, 0x8ec301ec, 0x8ec201e0, 0x8ec301e4, 0x24630001, 0x2c640001, -0x441021, 0xaec201e0, 0xaec301e4, 0x8ec201e0, 0x8ec301e4, 0x8ec20070, -0x2442ffff, 0xaec20070, 0xaec00078, 0x8ea2001c, 0x96e30450, 0x8ec40024, -0x24420001, 0x2463ffff, 0x431024, 0x24840001, 0xaec20018, 0xaec40024, -0x8f42023c, 0x82202b, 0x10800006, 0x0, 0x8fad0044, 0x25a2ffe9, -0x2c420002, 0x1040012f, 0x0, 0x96e20452, 0x8ed10018, 0x30420020, -0x1040001e, 0x24070008, 0x8ee40498, 0x8ee5049c, 0x8ec30008, 0x8f860120, -0x24020019, 0xafa20010, 0xafb10014, 0xafa30018, 0x8ec200a8, 0x40f809, -0x24c6001c, 0x1440000b, 0x24020001, 0x3c040001, 0x24842e00, 0xafb10010, -0xafa00014, 0x8ec6002c, 0x8f470228, 0x3c050009, 0xc00290f, 0x34a5f006, -0x1021, 0x1040008f, 0x24020001, 0x3c010001, 0x370821, 0x100000b4, -0xac2281d0, 0x8ee40498, 0x8ee5049c, 0x8ec30008, 0x8f860120, 0x24020012, -0xafa20010, 0xafb10014, 0xafa30018, 0x8ec200a8, 0x40f809, 0x24c6001c, -0x1440000b, 0x24020001, 0x3c040001, 0x24842e00, 0xafb10010, 0xafa00014, -0x8ec6002c, 0x8f470228, 0x3c050009, 0xc00290f, 0x34a5f006, 0x1021, -0x10400094, 0x24020001, 0x10000096, 0x0, 0x15a20043, 0x24020016, -0x96a3000e, 0x8ec20078, 0x8ec40024, 0x431021, 0xaec20078, 0x8ea3001c, -0x96e20450, 0x24840001, 0xaec40024, 0x24630001, 0x2442ffff, 0x621824, -0xaec30018, 0x8f42023c, 0x82202b, 0x148000df, 0x0, 0x96e20452, -0x8ed10018, 0x30420020, 0x1040001e, 0x24070008, 0x8ee40498, 0x8ee5049c, -0x8ec30008, 0x8f860120, 0x24020019, 0xafa20010, 0xafb10014, 0xafa30018, -0x8ec200a8, 0x40f809, 0x24c6001c, 0x1440000b, 0x24020001, 0x3c040001, -0x24842e00, 0xafb10010, 0xafa00014, 0x8ec6002c, 0x8f470228, 0x3c050009, -0xc00290f, 0x34a5f006, 0x1021, 0x1040003f, 0x24020001, 0x3c010001, -0x370821, 0x10000064, 0xac2281d0, 0x8ee40498, 0x8ee5049c, 0x8ec30008, -0x8f860120, 0x24020012, 0xafa20010, 0xafb10014, 0xafa30018, 0x8ec200a8, -0x40f809, 0x24c6001c, 0x1040ffb1, 0x0, 0x1000ffb9, 0x24020001, -0x8fad0044, 0x15a20063, 0x25a2fffe, 0x96a3000e, 0x8ec20078, 0x431021, -0xaec20078, 0x8ea3001c, 0x96e20450, 0x24630001, 0x2442ffff, 0x621824, -0xaec30018, 0x96e20452, 0x8ed10018, 0x30420020, 0x10400023, 0x24070008, -0x8ee40498, 0x8ee5049c, 0x8ec30008, 0x8f860120, 0x24020019, 0xafa20010, -0xafb10014, 0xafa30018, 0x8ec200a8, 0x40f809, 0x24c6001c, 0x1440000b, -0x24020001, 0x3c040001, 0x24842e00, 0xafb10010, 0xafa00014, 0x8ec6002c, -0x8f470228, 0x3c050009, 0xc00290f, 0x34a5f006, 0x1021, 0x14400006, -0x24020001, 0x24020001, 0x3c010001, 0x370821, 0x10000031, 0xac2281d8, -0x3c010001, 0x370821, 0x10000021, 0xac2281d0, 0x8ee40498, 0x8ee5049c, -0x8ec30008, 0x8f860120, 0x24020012, 0xafa20010, 0xafb10014, 0xafa30018, -0x8ec200a8, 0x40f809, 0x24c6001c, 0x1440000b, 0x24020001, 0x3c040001, -0x24842e00, 0xafb10010, 0xafa00014, 0x8ec6002c, 0x8f470228, 0x3c050009, -0xc00290f, 0x34a5f006, 0x1021, 0x14400005, 0x24020001, 0x3c010001, -0x370821, 0x10000010, 0xac2281d4, 0x3c010001, 0x370821, 0xac2081d0, -0x3c010001, 0x370821, 0xac2081d8, 0x3c010001, 0x370821, 0xac2081d4, -0x8ec20264, 0xaec00024, 0xaed10028, 0x24420001, 0xaec20264, 0x8ec20264, -0x8ec20278, 0x24420001, 0xaec20278, 0x10000049, 0x8ec20278, 0x2c420002, -0x10400028, 0x24030040, 0x8ec20034, 0x24420001, 0x50430003, 0x1021, -0x8ec20034, 0x24420001, 0xaec20034, 0x8ec20034, 0x8ea30018, 0x21080, -0x571021, 0x8c440cc0, 0x24020003, 0x1462000d, 0x0, 0x92c20065, -0x50400034, 0x36940040, 0x8ec202c0, 0x8ec3005c, 0x441021, 0xaec202c0, -0x8ec202c4, 0x641821, 0x306300ff, 0x10000009, 0xaec3005c, 0x8ec202bc, -0x8ec3003c, 0x441021, 0xaec202bc, 0x8ec202c4, 0x641821, 0x306301ff, -0xaec3003c, 0x441021, 0xaec202c4, 0x1000001f, 0x36940040, 0x8fad0044, -0x24020014, 0x15a20010, 0x24020010, 0x3c020001, 0x8c423334, 0x10400017, -0x26e50028, 0x26c40128, 0x240300ff, 0x2406ffff, 0x8ca20000, 0x24a50004, -0x2463ffff, 0xac820000, 0x1466fffb, 0x24840004, 0x1000000c, 0x0, -0x11a2000a, 0x3c050008, 0x96a7000e, 0x8ea2001c, 0x3c040001, 0x24842e80, -0xafb50014, 0xafa20010, 0x8ea60018, 0xc00290f, 0x34a50910, 0x8fbf0078, -0x8fbe0074, 0x8fb50070, 0x8fb3006c, 0x8fb10068, 0x3e00008, 0x27bd0080, -0x3e00008, 0x0, 0x803821, 0x8f8600e4, 0x8f8400e0, 0x2402fff8, -0x8cc30004, 0x822024, 0x10c4000d, 0x3c020100, 0x3c050100, 0x651024, -0x1040000c, 0x27623ff8, 0x14c20002, 0x24c20008, 0x27623000, 0x403021, -0x8cc30004, 0x14c4fff8, 0x651024, 0x3c020100, 0x621024, 0x14400007, -0x0, 0x8cc20000, 0x8cc30004, 0xace20000, 0xace30004, 0x10000003, -0x24020001, 0xaf8600e8, 0x1021, 0x3e00008, 0x0, 0x3e00008, -0x0, 0x8f8300e4, 0x8f8500e0, 0x2402fff8, 0x8c640004, 0xa22824, -0x1065000d, 0x3c020100, 0x3c060100, 0x861024, 0x10400008, 0x27623ff8, -0x14620002, 0x24620008, 0x27623000, 0x401821, 0x8c640004, 0x1465fff8, -0x861024, 0x3c020100, 0xac620004, 0xaf8300e8, 0x54650001, 0x24630008, -0xaf8300e4, 0x3e00008, 0x0, 0x3e00008, 0x0, 0x8f8600e4, -0x8f8200e0, 0x2403fff8, 0x431024, 0x14c20003, 0x803821, 0x10000006, -0x1021, 0x8cc20000, 0x8cc30004, 0xace20000, 0xace30004, 0x24020001, -0x3e00008, 0x0, 0x3e00008, 0x0, 0x8f8300e4, 0x27623ff8, -0x14620002, 0x24620008, 0x27623000, 0x401821, 0xaf8300e8, 0xaf8300e4, -0x3e00008, 0x0, 0x3e00008, 0x0, 0x8f8400e0, 0x8f8800c4, -0x8f8300e8, 0x2402fff8, 0x823824, 0xe32023, 0x2c821000, 0x50400001, -0x24841000, 0x420c2, 0x801821, 0x8ec401c0, 0x8ec501c4, 0x1021, -0xa32821, 0xa3302b, 0x822021, 0x862021, 0xaec401c0, 0xaec501c4, -0x8f8300c8, 0x8ec20540, 0x1032023, 0x82102b, 0x14400004, 0x801821, -0x8ec20540, 0x822021, 0x801821, 0x8ec401b8, 0x8ec501bc, 0x1021, -0xa32821, 0xa3302b, 0x822021, 0x862021, 0xaec401b8, 0xaec501bc, -0xaf8800c8, 0xaf8700e4, 0xaf8700e8, 0x3e00008, 0x0, 0x27bdff70, -0xafbf0088, 0xafbe0084, 0xafb50080, 0xafb3007c, 0xafb10078, 0x92c200ed, -0xa3a0004f, 0x1040000b, 0xa3a00067, 0x8ecd00f0, 0xafad0034, 0x8ece00f4, -0xafae002c, 0x8ecd00fc, 0x8ed500f8, 0xafad006c, 0x8ece0100, 0x100000e9, -0xafae003c, 0x3c020001, 0x8c423518, 0x40f809, 0x27a40020, 0x10400295, -0x0, 0x8fa30024, 0x8fb50020, 0x306dffff, 0x25adfffc, 0xafad0034, -0x92a20000, 0xafb5002c, 0x30420001, 0x10400017, 0xafa3006c, 0x8ec2011c, -0x3c03ffff, 0x431024, 0x14400012, 0x2402ffff, 0x8ea30000, 0x14620004, -0x3402ffff, 0x96a30004, 0x1062000c, 0x0, 0xc0022ad, 0x2a02021, -0x304200ff, 0x14400007, 0x0, 0x3c020001, 0x8c423510, 0x40f809, -0x0, 0x10000275, 0x0, 0x8fa20024, 0x3c03ffbf, 0x3463ffff, -0x431024, 0x3c03ffff, 0x432824, 0x14a00003, 0xafa20024, 0x10000053, -0x1821, 0x3c020080, 0xa21024, 0x50400007, 0x3c040040, 0x8ec202e4, -0x24420001, 0xaec202e4, 0x8ec202e4, 0x10000049, 0x24030001, 0x3c070004, -0x3c0c0001, 0x3c0b0002, 0x3c060010, 0x3c0a0008, 0x8ec20178, 0x3c090020, -0x34088000, 0x24420001, 0xaec20178, 0x8ec20178, 0x851824, 0x10670021, -0xe3102b, 0x14400007, 0x0, 0x106c0011, 0x0, 0x106b0015, -0x0, 0x10000030, 0x42042, 0x10660023, 0xc3102b, 0x14400005, -0x0, 0x106a0019, 0x0, 0x10000028, 0x42042, 0x10690021, -0x0, 0x10000024, 0x42042, 0x8ec2012c, 0x24420001, 0xaec2012c, -0x8ec2012c, 0x1000001e, 0x42042, 0x8ec202d4, 0x24420001, 0xaec202d4, -0x8ec202d4, 0x10000018, 0x42042, 0x8ec202d8, 0x24420001, 0xaec202d8, -0x8ec202d8, 0x10000012, 0x42042, 0x8ec202dc, 0x24420001, 0xaec202dc, -0x8ec202dc, 0x1000000c, 0x42042, 0x8ec20128, 0x24420001, 0xaec20128, -0x8ec20128, 0x10000006, 0x42042, 0x8ec202e0, 0x24420001, 0xaec202e0, -0x8ec202e0, 0x42042, 0x1488ffc6, 0x851824, 0x24030001, 0x8f420260, -0x8fae0034, 0x4e102b, 0x10400015, 0x306400ff, 0x8f8200e0, 0xafa20010, -0x8f8200e4, 0x3c040001, 0x24842f5c, 0xafa20014, 0x8fa60020, 0x8fa70024, -0x3c050006, 0xc00290f, 0x34a5f003, 0x8ec30150, 0x8fad006c, 0x3c020100, -0x24040001, 0x1a26825, 0x24630001, 0xafad006c, 0xaec30150, 0x8ec20150, -0x1080000f, 0x0, 0x8f420218, 0x30420800, 0x1440000b, 0x3c020180, -0x8fae006c, 0x1c21024, 0x10400005, 0x0, 0x8ec20174, 0x24420001, -0xaec20174, 0x8ec20174, 0x100001e4, 0x8fa30034, 0x8f420218, 0x30420400, -0x10400004, 0x0, 0x8fad0034, 0x25ad0004, 0xafad0034, 0x8ec20050, -0x5040002d, 0xafa0003c, 0x8fae0034, 0x4e102b, 0x50400029, 0xafa0003c, -0x8ec20050, 0x1c21023, 0xafa2003c, 0x8ecd0050, 0x10000023, 0xafad0034, -0x8ec2005c, 0xafa20010, 0x8ec20060, 0x3c040001, 0x24842f68, 0xafa20014, -0x8ec6003c, 0x8ec70044, 0x3c050006, 0xc00290f, 0x34a5f002, 0x8ec202b4, -0x2403ffbf, 0x283a024, 0x24420001, 0xaec202b4, 0x10000199, 0x8ec202b4, -0x8e220018, 0x8fa70034, 0x3c040001, 0x24842f74, 0xafa20010, 0x8e220000, -0x8e230004, 0x34a5f709, 0x2203021, 0xc00290f, 0xafa30014, 0x8ec20298, -0x24420001, 0xaec20298, 0x10000189, 0x8ec20298, 0x96e20460, 0x8fae0034, -0x4e102b, 0x10400004, 0x0, 0x240d0001, 0xa3ad004f, 0x8fae0034, -0x11c001a0, 0x3c02ffff, 0x8fad006c, 0x1a21024, 0xafa20074, 0x8ec20068, -0x8f430280, 0x24420001, 0x304203ff, 0x10620176, 0x0, 0x93a2004f, -0x10400015, 0x0, 0x8ec3005c, 0x8ec20060, 0x1062000a, 0x26ce0060, -0x8ec60060, 0xafae0054, 0x8ec30060, 0x21140, 0x24424dc0, 0x2e28821, -0x24630001, 0x10000014, 0x306300ff, 0x92c20064, 0x1440ffb9, 0x0, -0x8ec202c8, 0x24420001, 0xaec202c8, 0x8ec202c8, 0x8ec3003c, 0x8ec20044, -0x1062ffb1, 0x26cd0044, 0x8ec60044, 0xafad0054, 0x8ec30044, 0x21140, -0x24420dc0, 0x2e28821, 0x24630001, 0x306301ff, 0xafa3005c, 0x8f83012c, -0x10600011, 0x24040002, 0x8f820124, 0x431023, 0x21143, 0x58400001, -0x24420040, 0x82102a, 0x1040000a, 0x1021, 0x8f820128, 0x431023, -0x21143, 0x58400001, 0x24420040, 0x82102a, 0x14400002, 0x24020001, -0x1021, 0x304200ff, 0x1040ffa3, 0x3c050006, 0x96e20462, 0x30420010, -0x1040001a, 0x340e8100, 0x96a2000c, 0x144e0017, 0x0, 0x92c200ed, -0x14400014, 0x0, 0x96a2000e, 0xa6220016, 0x8ea20008, 0x8ea30004, -0x8fad0034, 0x8ea40000, 0x25adfffc, 0xafad0034, 0xaea2000c, 0xaea30008, -0xaea40004, 0x9622000e, 0x8fae002c, 0x240d0001, 0xa3ad0067, 0x25ce0004, -0x34420200, 0xafae002c, 0xa622000e, 0x9627000a, 0x8fae0034, 0xee102b, -0x14400002, 0x30f3fff8, 0x8fb30034, 0x8e240000, 0x8e250004, 0x8fad002c, -0x24020007, 0xae2d0018, 0xafa20010, 0xafa60014, 0x8ec20004, 0x8fa6002c, -0xafa20018, 0x8ec200a8, 0x40f809, 0x2603821, 0x1440001a, 0x3c050006, -0x3c040001, 0x24842f80, 0x8e220018, 0x34a5f009, 0xafa20010, 0x8e220000, -0x8e230004, 0x2203021, 0x2603821, 0xc00290f, 0xafa30014, 0x93a20067, -0x104000fb, 0x0, 0x8ea20004, 0x8ea30008, 0x8ea4000c, 0x340e8100, -0xa6ae000c, 0xaea20000, 0xaea30004, 0xaea40008, 0x96220016, 0x100000f0, -0xa6a2000e, 0x8fad0034, 0x166d0089, 0x0, 0x962e000a, 0xafae0044, -0x8fae003c, 0x9623000e, 0x1ae1021, 0xa622000a, 0x34620004, 0xa622000e, -0x8fad0074, 0x11a00006, 0x307effff, 0x34620404, 0xa622000e, 0x8fae006c, -0xe1402, 0xa6220014, 0x8ec30068, 0x8ee40478, 0x8ee5047c, 0x24020004, -0xafa20010, 0x8ec20068, 0x2203021, 0x24070020, 0xafa20014, 0x8ec20008, -0x31940, 0x604821, 0xafa20018, 0x8ec200a8, 0x4021, 0xa92821, -0xa9182b, 0x882021, 0x40f809, 0x832021, 0x54400018, 0xa2c000ed, -0x97ad0046, 0xa63e000e, 0xa62d000a, 0x8f820100, 0xafa20010, 0x8f820104, -0x3c040001, 0x24842f8c, 0x3c050006, 0xafa20014, 0x8ec60068, 0x34a5f00b, -0xc00290f, 0x2203821, 0x93a20067, 0x104000b6, 0x0, 0x8ea20004, -0x8ea30008, 0x8ea4000c, 0x340e8100, 0x10000083, 0xa6ae000c, 0x8fae005c, -0x8fad0054, 0xadae0000, 0x8ec202c4, 0x8ec30068, 0x2442ffff, 0xaec202c4, -0x8ec202c4, 0x24630001, 0x306303ff, 0x26c20060, 0x15a20006, 0xaec30068, -0x8ec202c0, 0x2442ffff, 0xaec202c0, 0x10000005, 0x8ec202c0, 0x8ec202bc, -0x2442ffff, 0xaec202bc, 0x8ec202bc, 0x8ec20048, 0x24420001, 0xaec20048, -0x8f430240, 0x43102b, 0x54400090, 0xafa00034, 0x8ed10068, 0x8ee40490, -0x8ee50494, 0x8ec30008, 0x8f860120, 0x24020013, 0xafa20010, 0xafb10014, -0xafa30018, 0x8ec200a8, 0x24070008, 0x40f809, 0x24c6001c, 0x1440000b, -0x24020001, 0x3c040001, 0x24842f0c, 0xafb10010, 0xafa00014, 0x8ec60068, -0x8f470228, 0x3c050009, 0xc00290f, 0x34a5f008, 0x1021, 0x14400005, -0x24020001, 0x3c010001, 0x370821, 0x1000000a, 0xac2281e0, 0x3c010001, -0x370821, 0xac2081e0, 0x8ec20268, 0xaec00048, 0xaed1006c, 0x24420001, -0xaec20268, 0x8ec20268, 0x8ec2027c, 0x24420001, 0xaec2027c, 0x8ec2027c, -0x10000062, 0xafa00034, 0x962d000a, 0xafad0044, 0x9622000e, 0xa633000a, -0x8fae0074, 0x11c00006, 0x305effff, 0x34420400, 0xa622000e, 0x8fad006c, -0xd1402, 0xa6220014, 0x8ec30068, 0x8ee40478, 0x8ee5047c, 0x24020004, -0xafa20010, 0x8ec20068, 0x2203021, 0x24070020, 0xafa20014, 0x8ec20008, -0x31940, 0x604821, 0xafa20018, 0x8ec200a8, 0x4021, 0xa92821, -0xa9182b, 0x882021, 0x40f809, 0x832021, 0x1440001f, 0x3c04001f, -0x97ae0046, 0xa63e000e, 0xa62e000a, 0x8f820100, 0xafa20010, 0x8f820104, -0x3c040001, 0x24842f8c, 0x3c050006, 0xafa20014, 0x8ec60068, 0x34a5f00d, -0xc00290f, 0x2203821, 0x93a20067, 0x10400032, 0x340d8100, 0x8ea20004, -0x8ea30008, 0x8ea4000c, 0xa6ad000c, 0xaea20000, 0xaea30004, 0xaea40008, -0x96220016, 0xa6a2000e, 0x9622000e, 0x3042fdff, 0x10000025, 0xa622000e, -0x8ec202c4, 0x8fae002c, 0x3484ffff, 0x1d37021, 0x2442ffff, 0xafae002c, -0xaec202c4, 0x8ec202c4, 0x8ec302bc, 0x24020001, 0x8e202b, 0xa2c200ed, -0x2463ffff, 0xaec302bc, 0x10800004, 0x8ec202bc, 0x8ec20540, 0x1c27023, -0xafae002c, 0x8fad0034, 0x8fae0054, 0x1b36823, 0xafad0034, 0x8fad005c, -0xadcd0000, 0x8ec20068, 0xa3a0004f, 0x8ec30048, 0x24420001, 0x304203ff, -0x24630001, 0xaec20068, 0xaec30048, 0x8fae0034, 0x15c0fe86, 0x0, -0x8fad0034, 0x11a0001f, 0x0, 0xaecd00f0, 0x8fae002c, 0xaece00f4, -0xaed500f8, 0x93a20067, 0x10400004, 0x0, 0x8ec200f8, 0x24420004, -0xaec200f8, 0x8fad006c, 0x8ec20068, 0xaecd00fc, 0x8fae003c, 0xaece0100, -0x8f430280, 0x24420001, 0x304203ff, 0x14620006, 0x0, 0x8ec202b8, -0x24420001, 0xaec202b8, 0x10000016, 0x8ec202b8, 0x8ec202b0, 0x24420001, -0xaec202b0, 0x10000011, 0x8ec202b0, 0x8fad006c, 0x31a4ffff, 0x2484fffc, -0x801821, 0x8ec401b8, 0x8ec501bc, 0x3c060001, 0x8cc63510, 0x1021, -0xa32821, 0xa3382b, 0x822021, 0x872021, 0xaec401b8, 0xc0f809, -0xaec501bc, 0x8fbf0088, 0x8fbe0084, 0x8fb50080, 0x8fb3007c, 0x8fb10078, -0x3e00008, 0x27bd0090, 0x3e00008, 0x0, 0x27bdff90, 0xafbf0068, -0xafbe0064, 0xafb50060, 0xafb3005c, 0xafb10058, 0x92c200ed, 0xafa0002c, -0x10400007, 0xa3a00037, 0x8ecf00fc, 0x8ec800f0, 0x8ec900f4, 0x8ed500f8, -0x100000d1, 0xafaf003c, 0x3c020001, 0x8c423518, 0x40f809, 0x27a40020, -0x104001ae, 0x0, 0x8fa30024, 0x8fb50020, 0x3068ffff, 0x92a20000, -0x2508fffc, 0x2a04821, 0x30420001, 0x1040001a, 0xafa3003c, 0x8ec2011c, -0x3c03ffff, 0x431024, 0x14400015, 0x2402ffff, 0x8ea30000, 0x14620005, -0x2a02021, 0x96a30004, 0x3402ffff, 0x1062000e, 0x0, 0xafa80048, -0xc0022ad, 0xafa9004c, 0x304200ff, 0x8fa80048, 0x14400007, 0x8fa9004c, -0x3c020001, 0x8c423510, 0x40f809, 0x0, 0x1000018c, 0x0, -0x8fa20024, 0x3c03ffbf, 0x3463ffff, 0x431024, 0x3c03ffff, 0x432824, -0x14a00003, 0xafa20024, 0x10000053, 0x1821, 0x3c020080, 0xa21024, -0x50400007, 0x3c040040, 0x8ec202e4, 0x24420001, 0xaec202e4, 0x8ec202e4, -0x10000049, 0x24030001, 0x3c070004, 0x3c0e0001, 0x3c0d0002, 0x3c060010, -0x3c0c0008, 0x8ec20178, 0x3c0b0020, 0x340a8000, 0x24420001, 0xaec20178, -0x8ec20178, 0x851824, 0x10670021, 0xe3102b, 0x14400007, 0x0, -0x106e0011, 0x0, 0x106d0015, 0x0, 0x10000030, 0x42042, -0x10660023, 0xc3102b, 0x14400005, 0x0, 0x106c0019, 0x0, -0x10000028, 0x42042, 0x106b0021, 0x0, 0x10000024, 0x42042, -0x8ec2012c, 0x24420001, 0xaec2012c, 0x8ec2012c, 0x1000001e, 0x42042, -0x8ec202d4, 0x24420001, 0xaec202d4, 0x8ec202d4, 0x10000018, 0x42042, -0x8ec202d8, 0x24420001, 0xaec202d8, 0x8ec202d8, 0x10000012, 0x42042, -0x8ec202dc, 0x24420001, 0xaec202dc, 0x8ec202dc, 0x1000000c, 0x42042, -0x8ec20128, 0x24420001, 0xaec20128, 0x8ec20128, 0x10000006, 0x42042, -0x8ec202e0, 0x24420001, 0xaec202e0, 0x8ec202e0, 0x42042, 0x148affc6, -0x851824, 0x24030001, 0x8f420260, 0x48102b, 0x10400019, 0x306400ff, -0x8f8200e0, 0xafa20010, 0x8f8200e4, 0x3c040001, 0x24842f5c, 0xafa20014, -0x8fa60020, 0x8fa70024, 0x3c050006, 0x34a5f003, 0xafa80048, 0xc00290f, -0xafa9004c, 0x8ec30150, 0x8faf003c, 0x3c020100, 0x24040001, 0x1e27825, -0x24630001, 0xafaf003c, 0xaec30150, 0x8ec20150, 0x8fa9004c, 0x8fa80048, -0x10800025, 0x0, 0x8f420218, 0x30420800, 0x14400021, 0x3c020180, -0x8faf003c, 0x1e21024, 0x104000fe, 0x1001821, 0x8ec20174, 0x24420001, -0xaec20174, 0x8ec20174, 0x100000f8, 0x1001821, 0x8ec2005c, 0xafa20010, -0x8ec20060, 0x3c040001, 0x24842f68, 0xafa20014, 0x8ec6003c, 0x8ec70044, -0x3c050006, 0x34a5f002, 0xafa80048, 0xc00290f, 0xafa9004c, 0x8ec202b4, -0x2403ffbf, 0x283a024, 0x24420001, 0xaec202b4, 0x8ec202b4, 0x8fa80048, -0x100000c2, 0x8fa9004c, 0x8f420218, 0x30420400, 0x54400001, 0x25080004, -0x96e20460, 0x48102b, 0x10400003, 0x0, 0x3c0f8000, 0xafaf002c, -0x110000d2, 0x3c02ffff, 0x8faf003c, 0x1e21024, 0xafa20044, 0x8ec20068, -0x8f430280, 0x24420001, 0x304203ff, 0x106200ad, 0x0, 0x8faf002c, -0x11e00014, 0x0, 0x8ec3005c, 0x8ec20060, 0x10620009, 0x26cb0060, -0x8ec60060, 0x8ec30060, 0x21140, 0x24424dc0, 0x2e28821, 0x24630001, -0x10000014, 0x306a00ff, 0x92c20064, 0x1440ffc4, 0x0, 0x8ec202c8, -0x24420001, 0xaec202c8, 0x8ec202c8, 0x8ec3003c, 0x8ec20044, 0x1062ffbc, -0x26cb0044, 0x8ec60044, 0xafa0002c, 0x8ec30044, 0x21140, 0x24420dc0, -0x2e28821, 0x24630001, 0x306a01ff, 0x96e20462, 0x30420010, 0x10400017, -0x0, 0x96a2000c, 0x340f8100, 0x144f0013, 0x0, 0x92c200ed, -0x14400010, 0x0, 0x96a2000e, 0xa6220016, 0x8ea20008, 0x8ea30004, -0x8ea40000, 0x2508fffc, 0xaea2000c, 0xaea30008, 0xaea40004, 0x9622000e, -0x25290004, 0x240f0001, 0xa3af0037, 0x34420200, 0xa622000e, 0x9623000a, -0x68102b, 0x14400002, 0x3073fff8, 0x1009821, 0x92c200ed, 0x14400012, -0x260f021, 0x9523000c, 0x24020800, 0x5462000f, 0xae290018, 0x91220017, -0x38430006, 0x2c630001, 0x38420011, 0x2c420001, 0x621825, 0x50600007, -0xae290018, 0x95220010, 0x2443000e, 0x73102b, 0x54400001, 0x60f021, -0xae290018, 0x92c300ed, 0x8e240000, 0x8e250004, 0x8faf002c, 0x2402000b, -0xafa20010, 0x3182b, 0x31ec0, 0xcf1025, 0x431025, 0xafa20014, -0x8ec20004, 0xafa20018, 0x8ec200a8, 0x3c03821, 0x1203021, 0xafa80048, -0xafa9004c, 0xafaa0050, 0x40f809, 0xafab0054, 0x8fa80048, 0x8fa9004c, -0x8faa0050, 0x8fab0054, 0x1440001d, 0x3c050006, 0x3c040001, 0x24842f80, -0x8e220018, 0x34a5f009, 0xafa20010, 0x8e220000, 0x8e230004, 0x2203021, -0x3c03821, 0xafa80048, 0xafa9004c, 0xc00290f, 0xafa30014, 0x93a20037, -0x8fa80048, 0x8fa9004c, 0x1040002a, 0x340f8100, 0x8ea20004, 0x8ea30008, -0x8ea4000c, 0xa6af000c, 0xaea20000, 0xaea30004, 0xaea40008, 0x96220016, -0x10000020, 0xa6a2000e, 0x8faf0044, 0x11e00007, 0x0, 0x8faf003c, -0x9623000e, 0xf1402, 0x34630400, 0xa6220014, 0xa623000e, 0x56680008, -0x1334821, 0x9622000e, 0xa628000a, 0x4021, 0x34420004, 0xa622000e, -0x1000000c, 0xa2c000ed, 0x3c03001f, 0x3463ffff, 0x24020001, 0x69182b, -0xa633000a, 0x10600003, 0xa2c200ed, 0x8ec20540, 0x1224823, 0x1134023, -0xafa0002c, 0x1500ff4f, 0xad6a0000, 0x1100001b, 0x0, 0xaec800f0, -0xaec900f4, 0xaed500f8, 0x93a20037, 0x10400004, 0x0, 0x8ec200f8, -0x24420004, 0xaec200f8, 0x8faf003c, 0x8ec20068, 0xaecf00fc, 0x8f430280, -0x24420001, 0x14620006, 0x0, 0x8ec202b8, 0x24420001, 0xaec202b8, -0x10000016, 0x8ec202b8, 0x8ec202b0, 0x24420001, 0xaec202b0, 0x10000011, -0x8ec202b0, 0x8faf003c, 0x31e4ffff, 0x2484fffc, 0x801821, 0x8ec401b8, -0x8ec501bc, 0x3c060001, 0x8cc63510, 0x1021, 0xa32821, 0xa3382b, -0x822021, 0x872021, 0xaec401b8, 0xc0f809, 0xaec501bc, 0x8fbf0068, -0x8fbe0064, 0x8fb50060, 0x8fb3005c, 0x8fb10058, 0x3e00008, 0x27bd0070, -0x3e00008, 0x0, 0x27bdffd8, 0xafbf0024, 0xafb10020, 0x8ec30040, -0x8ec20038, 0x1062004d, 0x0, 0x8ec30038, 0x8ec20040, 0x623823, -0x4e20001, 0x24e70200, 0x8ec30044, 0x8ec20040, 0x43102b, 0x14400004, -0x24020200, 0x8ec30040, 0x10000005, 0x431823, 0x8ec20044, 0x8ec30040, -0x431023, 0x2443ffff, 0xe08821, 0x71102a, 0x54400001, 0x608821, -0x8ec90040, 0x8ee40458, 0x8ee5045c, 0x8ec60040, 0x113940, 0x24080002, -0xafa80010, 0x8ec80040, 0x94940, 0x1201821, 0x1021, 0xafa80014, -0x8ec80010, 0xa32821, 0xa3482b, 0x822021, 0x892021, 0x63140, -0xafa80018, 0x8ec200a4, 0x24c60dc0, 0x40f809, 0x2e63021, 0x1440000e, -0x24030040, 0x8ec20040, 0xafa20010, 0x8ec20044, 0x3c040001, 0x24842f98, -0xafa20014, 0x8ec60038, 0x8ec7003c, 0x3c050007, 0xc00290f, 0x34a5f001, -0x10000010, 0x0, 0x8ec20030, 0x24420001, 0x50430003, 0x1021, -0x8ec20030, 0x24420001, 0xaec20030, 0x8ec20030, 0x21080, 0x571021, -0xac510cc0, 0x8ec20040, 0x511021, 0x304201ff, 0xaec20040, 0x8ec30040, -0x8ec20038, 0x14620017, 0x0, 0x8ec20000, 0x10400007, 0x2403fdff, -0xaf80004c, 0x8f82004c, 0x1040fffd, 0x0, 0x10000005, 0x0, -0xaf800048, 0x8f820048, 0x1040fffd, 0x0, 0x8f820060, 0x431024, -0xaf820060, 0x8ec20000, 0x10400003, 0x0, 0x10000002, 0xaf80004c, -0xaf800048, 0x8fbf0024, 0x8fb10020, 0x3e00008, 0x27bd0028, 0x3e00008, -0x0, 0x27bdffd8, 0xafbf0024, 0xafb10020, 0x8ec30058, 0x8ec20054, -0x1062004d, 0x0, 0x8ec30054, 0x8ec20058, 0x623823, 0x4e20001, -0x24e70100, 0x8ec30060, 0x8ec20058, 0x43102b, 0x14400004, 0x24020100, -0x8ec30058, 0x10000005, 0x431823, 0x8ec20060, 0x8ec30058, 0x431023, -0x2443ffff, 0xe08821, 0x71102a, 0x54400001, 0x608821, 0x8ec90058, -0x8ee40468, 0x8ee5046c, 0x8ec60058, 0x113940, 0x24080003, 0xafa80010, -0x8ec80058, 0x94940, 0x1201821, 0x1021, 0xafa80014, 0x8ec80010, -0xa32821, 0xa3482b, 0x822021, 0x892021, 0x63140, 0xafa80018, -0x8ec200a4, 0x24c64dc0, 0x40f809, 0x2e63021, 0x1440000e, 0x24030040, -0x8ec20058, 0xafa20010, 0x8ec20060, 0x3c040001, 0x24842fa4, 0xafa20014, -0x8ec60054, 0x8ec7005c, 0x3c050007, 0xc00290f, 0x34a5f010, 0x10000010, -0x0, 0x8ec20030, 0x24420001, 0x50430003, 0x1021, 0x8ec20030, -0x24420001, 0xaec20030, 0x8ec20030, 0x21080, 0x571021, 0xac510cc0, -0x8ec20058, 0x511021, 0x304200ff, 0xaec20058, 0x8ec30058, 0x8ec20054, -0x14620017, 0x0, 0x8ec20000, 0x10400007, 0x2403feff, 0xaf80004c, -0x8f82004c, 0x1040fffd, 0x0, 0x10000005, 0x0, 0xaf800048, -0x8f820048, 0x1040fffd, 0x0, 0x8f820060, 0x431024, 0xaf820060, -0x8ec20000, 0x10400003, 0x0, 0x10000002, 0xaf80004c, 0xaf800048, -0x8fbf0024, 0x8fb10020, 0x3e00008, 0x27bd0028, 0x3e00008, 0x0, -0x8f820120, 0x8ec300e8, 0x8f820124, 0x8f860128, 0x24020040, 0x24630001, -0x50620003, 0x1021, 0x8ec200e8, 0x24420001, 0xaec200e8, 0x8ec200e8, -0x8ec400e8, 0x8ec300e4, 0x210c0, 0x24426fc0, 0x14830007, 0x2e22821, -0x8f820128, 0x24420020, 0xaf820128, 0x8f820128, 0x10000011, 0xaca00000, -0x8ec200e8, 0x24030040, 0x24420001, 0x50430003, 0x1021, 0x8ec200e8, -0x24420001, 0x220c0, 0x2e41021, 0x8c426fc4, 0x8f830128, 0x21140, -0x621821, 0x2e41021, 0xaf830128, 0xac406fc0, 0x8cc20018, 0x2443fffe, -0x2c620018, 0x1040000a, 0x31080, 0x3c010001, 0x220821, 0x8c222fb0, -0x400008, 0x0, 0x24020001, 0x3c010001, 0x370821, 0xac2281e8, -0x3e00008, 0x0, 0x3e00008, 0x0, 0x27bdffa8, 0xafbf0050, -0xafbe004c, 0xafb50048, 0xafb30044, 0xafb10040, 0x8f830128, 0x8f820124, -0x106201e1, 0x0, 0x8f9e0128, 0x8f820128, 0x24420020, 0xaf820128, -0x8fc40018, 0x8f820128, 0x2402000b, 0x1482018f, 0x24020002, 0x8fc3001c, -0x97c20016, 0x3064ffff, 0xafc20014, 0x3c028000, 0x621024, 0xafc4001c, -0xafa2002c, 0x8fab002c, 0x3c020800, 0x11600004, 0x622824, 0x41140, -0x10000003, 0x24424dc0, 0x41140, 0x24420dc0, 0x2e2a821, 0x96a2000e, -0x3043fffc, 0x30420400, 0x10400003, 0xa6a3000e, 0x10000137, 0x8821, -0x10a00004, 0x8821, 0x97d10016, 0x10000132, 0x0, 0x8eab0018, -0xafab0034, 0x9563000c, 0x96eb0462, 0x24020800, 0x1462012b, 0xafab003c, -0x8fab0034, 0x2573000e, 0x8fab003c, 0x31620002, 0x1040003f, 0x3c030020, -0x8ec70540, 0x263102b, 0x14400002, 0x2604821, 0x2674823, 0x25220014, -0x43102b, 0x10400027, 0x24030005, 0x91220000, 0x3042000f, 0x14430024, -0x1202021, 0x952a0000, 0x25290002, 0x95280000, 0x25290002, 0x95270000, -0x25290002, 0x95260000, 0x25290002, 0x95250000, 0x25290002, 0x95230000, -0x25290002, 0x95220000, 0x25290002, 0x95240000, 0x25290002, 0x1485021, -0x1475021, 0x1465021, 0x1455021, 0x1435021, 0x1425021, 0x95220000, -0x95230002, 0x1445021, 0x1425021, 0x1435021, 0xa1c02, 0x3142ffff, -0x625021, 0xa1c02, 0x3142ffff, 0x10000009, 0x625021, 0x1202021, -0x90850000, 0x3c060020, 0x8ec200ac, 0x30a5000f, 0x40f809, 0x52840, -0x304affff, 0x3143ffff, 0x50600001, 0x3403ffff, 0x96a2000e, 0x34420002, -0x10000002, 0xa6a2000e, 0x1821, 0xa6a30010, 0x8fab003c, 0x31620001, -0x104000e1, 0x0, 0x92620009, 0x38430006, 0x2c630001, 0x38420011, -0x2c420001, 0x621825, 0x106000d9, 0x3c030020, 0x8fa60034, 0x8ec70540, -0xc3102b, 0x50400001, 0xc73023, 0x24c2000e, 0x43102b, 0x1040001a, -0xc02021, 0x94c70000, 0x24c60002, 0x94c50000, 0x24c60002, 0x94c30000, -0x24c60002, 0x94c20000, 0x24c60002, 0x94c40000, 0x24c60002, 0xe53821, -0xe33821, 0xe23821, 0x94c20000, 0x94c30002, 0xe43821, 0xe23821, -0xe33821, 0x71c02, 0x30e2ffff, 0x623821, 0x71c02, 0x30e2ffff, -0x10000006, 0x623821, 0x8ec200ac, 0x24050007, 0x40f809, 0x3c060020, -0x3047ffff, 0x8fab003c, 0x31620008, 0x10400003, 0x30e8ffff, 0x1000005b, -0x4821, 0x96620006, 0x30421fff, 0x10400007, 0x2602821, 0x92620000, -0x96630002, 0x3042000f, 0x21080, 0x10000051, 0x624823, 0x3c070020, -0x8ec30540, 0xa7102b, 0x50400001, 0xa32823, 0x24a20014, 0x47102b, -0x10400015, 0xa02021, 0x90a20000, 0x94a30002, 0x3042000f, 0x21080, -0x623023, 0xafa20020, 0x90a30009, 0x24a5000c, 0x94a20000, 0x24a50002, -0x94a40000, 0x24a50002, 0xc33021, 0xc23021, 0x94a20000, 0x94a30002, -0xc43021, 0xc23021, 0x1000002d, 0xc33021, 0x24a50002, 0xa7102b, -0x50400001, 0xa32823, 0x94a60000, 0x802821, 0xa7102b, 0x50400001, -0xa32823, 0x90a20000, 0x24850009, 0x3042000f, 0x21080, 0xc23023, -0xafa20020, 0xa7102b, 0x50400001, 0xa32823, 0x90a20000, 0x2485000c, -0xc23021, 0xa7102b, 0x50400001, 0xa32823, 0x94a20000, 0x24a50002, -0xc23021, 0xa7102b, 0x50400001, 0xa32823, 0x94a20000, 0x24a50002, -0xc23021, 0xa7102b, 0x50400001, 0xa32823, 0x94a20000, 0x24a50002, -0xc23021, 0xa7102b, 0x50400001, 0xa32823, 0x94a20000, 0xc23021, -0x61c02, 0x30c2ffff, 0x623021, 0x61402, 0x30c3ffff, 0x431021, -0x3049ffff, 0x96a2000e, 0x30420004, 0x10400041, 0x0, 0x8f420218, -0x30420400, 0x1040003d, 0x3c070020, 0x97c2000e, 0x8fc30008, 0x8ec60540, -0x621821, 0x2463fffc, 0x67102b, 0x50400001, 0x661823, 0x602821, -0x24a20004, 0x47102b, 0x5040000a, 0xa7102b, 0x90a20000, 0x90a40001, -0x90a30002, 0x21200, 0x441021, 0x90a40003, 0x31a00, 0x10000017, -0x431021, 0x50400001, 0xa62823, 0x90a20000, 0x24a50001, 0x22200, -0xa7102b, 0x50400001, 0xa62823, 0x90a20000, 0x24a50001, 0x822021, -0xa7102b, 0x50400001, 0xa62823, 0x90a20000, 0x24a50001, 0x21200, -0x822021, 0xa7102b, 0x50400001, 0xa62823, 0x90a20000, 0x822021, -0x41c02, 0x3082ffff, 0x622021, 0x41402, 0x3083ffff, 0x431021, -0x3042ffff, 0x1024021, 0x81c02, 0x3102ffff, 0x624021, 0x81c02, -0x3102ffff, 0x624021, 0x3108ffff, 0x8fc20014, 0x488823, 0x111402, -0x2228821, 0x2298821, 0x111402, 0x2228821, 0x3231ffff, 0x52200001, -0x3411ffff, 0x96a2000e, 0x34420001, 0xa6a2000e, 0x96a2000e, 0x24080002, -0x30420004, 0x10400002, 0xa6b10012, 0x24080004, 0x8ec90068, 0x8ee40478, -0x8ee5047c, 0xafa80010, 0x8ec80068, 0x8fab002c, 0x2a03021, 0x24070020, -0x10b4025, 0xafa80014, 0x8ec80008, 0x94940, 0x1201821, 0xafa80018, -0x8ec800a8, 0x1021, 0xa32821, 0xa3482b, 0x822021, 0x100f809, -0x892021, 0x1440000e, 0x0, 0x8f820120, 0xafa20010, 0x8f820128, -0x3c040001, 0x24843010, 0xafa20014, 0x8fc6001c, 0x8f870124, 0x3c050008, -0xc00290f, 0x34a50001, 0x1000005f, 0x0, 0x8ec20068, 0x24420001, -0x304203ff, 0xaec20068, 0x8fab002c, 0x11600006, 0x0, 0x8ec202c0, -0x2442ffff, 0xaec202c0, 0x10000005, 0x8ec202c0, 0x8ec202bc, 0x2442ffff, -0xaec202bc, 0x8ec202bc, 0x8ec202c4, 0x2442ffff, 0xaec202c4, 0x1000004a, -0x8ec202c4, 0x14820005, 0x24020004, 0x8ec20048, 0x24420001, 0x10000044, -0xaec20048, 0x14820036, 0x38830011, 0x97c2001e, 0xafc2001c, 0x8ec20048, -0x24420001, 0xaec20048, 0x8f430240, 0x43102b, 0x14400039, 0x24070008, -0x8ed10068, 0x8ee40490, 0x8ee50494, 0x8ec30008, 0x8f860120, 0x24020013, -0xafa20010, 0xafb10014, 0xafa30018, 0x8ec200a8, 0x40f809, 0x24c6001c, -0x1440000b, 0x24020001, 0x3c040001, 0x24842f0c, 0xafb10010, 0xafa00014, -0x8ec60068, 0x8f470228, 0x3c050009, 0xc00290f, 0x34a5f008, 0x1021, -0x14400005, 0x24020001, 0x3c010001, 0x370821, 0x1000000a, 0xac2281e0, -0x3c010001, 0x370821, 0xac2081e0, 0x8ec20268, 0xaec00048, 0xaed1006c, -0x24420001, 0xaec20268, 0x8ec20268, 0x8ec2027c, 0x24420001, 0xaec2027c, -0x1000000d, 0x8ec2027c, 0x2c630001, 0x38820013, 0x2c420001, 0x621825, -0x14600004, 0x24020001, 0x24020012, 0x14820004, 0x24020001, 0x3c010001, -0x370821, 0xac2281e8, 0x8fbf0050, 0x8fbe004c, 0x8fb50048, 0x8fb30044, -0x8fb10040, 0x3e00008, 0x27bd0058, 0x3e00008, 0x0, 0x0, -0x0, 0x0, 0x8ec20538, 0xaf8200c0, 0x8ec20538, 0xaf8200c4, -0x8ec20538, 0xaf8200c8, 0x8ec20534, 0xaf8200d0, 0x8ec20534, 0xaf8200d4, -0x8ec20534, 0x3e00008, 0xaf8200d8, 0x27bdffe8, 0x27840208, 0x27450200, -0xafbf0010, 0xc0029a2, 0x24060008, 0x8f420204, 0xc003c86, 0xaf820210, -0x24040001, 0x8f460248, 0x24020004, 0x3c010001, 0xac22340c, 0xc0046cc, -0x24050004, 0x3c020001, 0x8c423408, 0x30420001, 0x10400007, 0x24020001, -0x3c010001, 0xac22340c, 0x24040001, 0x24050001, 0xc0046cc, 0x3c06601b, -0x8ec20548, 0x8ec4054c, 0x8ec30550, 0x3c010001, 0xac203404, 0x3c010001, -0xac20341c, 0x21640, 0x42140, 0x34840403, 0x441025, 0x31bc0, -0x431025, 0xaf82021c, 0x8fbf0010, 0x3e00008, 0x27bd0018, 0x27bdffe0, -0x3c050008, 0x34a50400, 0xafbf0018, 0xafa00010, 0xafa00014, 0x8f860200, -0x3c040001, 0x248430dc, 0xc00290f, 0x3821, 0x8ec20368, 0x24420001, -0xaec20368, 0x8ec20368, 0x8f830200, 0x3c023f00, 0x621824, 0x8fbf0018, -0x3c020400, 0x3e00008, 0x27bd0020, 0x27bdffd8, 0xafbf0020, 0xafb3001c, -0xafb10018, 0x8f910220, 0x8ec202fc, 0x24420001, 0xaec202fc, 0x8ec202fc, -0x8ec30310, 0x3c020001, 0x8c42341c, 0x3c040001, 0x248430e8, 0xafa20014, -0xafa30010, 0x8ec70314, 0x3c050008, 0xc00290f, 0x2203021, 0x3c024000, -0x2221024, 0x104000e5, 0x3c040100, 0x8ec20314, 0x24420001, 0xaec20314, -0x8ec20314, 0x8f820220, 0x3c0308ff, 0x3463ffff, 0x431024, 0x34420004, -0xaf820220, 0x8f8200e0, 0x8f8300c4, 0x3c02001f, 0x3442ffff, 0x24690008, -0x49102b, 0x10400003, 0x0, 0x8ec20540, 0x1224823, 0x8f8700c8, -0x8f850120, 0x8f840124, 0x10000005, 0x5821, 0x8ec20534, 0x82102b, -0x50400001, 0x27644800, 0x10a40010, 0x316200ff, 0x8c820018, 0x38430007, -0x2c630001, 0x3842000b, 0x2c420001, 0x621825, 0x5060fff3, 0x24840020, -0x8ec20328, 0x240b0001, 0x24420001, 0xaec20328, 0x8ec20328, 0x8c870008, -0x316200ff, 0x14400078, 0x0, 0x92c200ed, 0x14400075, 0x0, -0x8f8500e4, 0x8f8200e0, 0x2403fff8, 0x433024, 0xc51023, 0x218c3, -0x4620001, 0x24630100, 0x8f8a00c4, 0x10600005, 0x24020001, 0x10620009, -0x0, 0x10000021, 0x0, 0x8ec20318, 0x1403821, 0x24420001, -0xaec20318, 0x10000060, 0x8ec20318, 0x8ec2031c, 0x24420001, 0xaec2031c, -0x8ca70000, 0x8ec20540, 0x8ec3031c, 0x1471823, 0x43102b, 0x10400004, -0x2c62233f, 0x8ec20540, 0x621821, 0x2c62233f, 0x14400051, 0x3c020100, -0xaca20004, 0x8f8200e8, 0x24420008, 0xaf8200e8, 0x8f8200e8, 0x8f8200e4, -0x1403821, 0x24420008, 0xaf8200e4, 0x10000046, 0x8f8200e4, 0x8ec20320, -0x24420001, 0xaec20320, 0x8ca80000, 0x8ec20540, 0x8ec30320, 0x1092023, -0x44102b, 0x10400003, 0x0, 0x8ec20540, 0x822021, 0x8ec20544, -0x44102b, 0x10400003, 0x3c030100, 0x10000034, 0x1003821, 0x8ca20004, -0x431025, 0xaca20004, 0x8f8200e4, 0x24450008, 0xaf8500e4, 0x8f8500e4, -0x10a60025, 0x3c080100, 0x8ec20174, 0x24420001, 0xaec20174, 0x8ca20004, -0x8ec30174, 0x481024, 0x1440000e, 0x0, 0x8ca30000, 0x8ec20540, -0x692023, 0x44102b, 0x10400003, 0x0, 0x8ec20540, 0x822021, -0x8ec20544, 0x44102b, 0x10400006, 0x0, 0x603821, 0x8ec20544, -0x44102b, 0x1440000a, 0x0, 0x8ca20004, 0x481025, 0xaca20004, -0x8f8200e4, 0x24450008, 0xaf8500e4, 0x8f8500e4, 0x14a6ffdf, 0x0, -0x14a60005, 0x0, 0x1403821, 0xaf8600e4, 0x10000003, 0xaf8600e8, -0xaf8500e4, 0xaf8500e8, 0x8f8300c8, 0x8ec20540, 0x692023, 0x44102b, -0x10400003, 0x0, 0x8ec20540, 0x822021, 0x8ec20544, 0x82102b, -0x50400008, 0x5821, 0x8ec20540, 0xe92023, 0x44102b, 0x10400003, -0x0, 0x8ec20540, 0x822021, 0x8ec20544, 0x82102b, 0x10400006, -0x316200ff, 0x1440001c, 0x3c02fdff, 0x92c200ed, 0x14400019, 0x3c02fdff, -0xaf8700c8, 0x8f8400c8, 0x8f8300c4, 0x8ec20540, 0x832023, 0x44102b, -0x10400003, 0x0, 0x8ec20540, 0x822021, 0x8ec20544, 0x2c830001, -0x44102b, 0x431025, 0x10400009, 0x3c02fdff, 0x8f820220, 0x3c0308ff, -0x3463fffb, 0x431024, 0x3c034000, 0x431025, 0x10000075, 0xaf820220, -0x3442ffff, 0x8ec30324, 0x282a024, 0x24020001, 0xa2c200ec, 0x24630001, -0xaec30324, 0x1000006c, 0x8ec20324, 0x2241024, 0x10400013, 0x3c130200, -0x8ec20300, 0x24420001, 0xaec20300, 0x8ec20300, 0x8f820220, 0x3c0308ff, -0x3463ffff, 0x431024, 0x441025, 0xaf820220, 0x3c020004, 0x2221024, -0x14400005, 0x3c130200, 0xc003ab1, 0x0, 0x10000057, 0x0, -0x2331024, 0x50400008, 0x3c130400, 0x8ec20304, 0x24420001, 0xaec20304, -0xc003ab1, 0x8ec20304, 0x10000019, 0x0, 0x2331024, 0x1040001d, -0x3c020800, 0x8f830224, 0x24021402, 0x14620009, 0x3c050008, 0x3c040001, -0x248430f4, 0xafa00010, 0xafa00014, 0x8f860224, 0x34a5ffff, 0xc00290f, -0x3821, 0x8ec20308, 0x24420001, 0xaec20308, 0x8ec20308, 0x8f820220, -0x2202021, 0x34420002, 0xc00447c, 0xaf820220, 0x8f820220, 0x3c0308ff, -0x3463ffff, 0x431024, 0x531025, 0x1000002e, 0xaf820220, 0x2221024, -0x10400009, 0x3c050008, 0x3c040001, 0x248430dc, 0xafa00010, 0xafa00014, -0x8f860220, 0x34a50403, 0xc00290f, 0x3821, 0x3c021000, 0x2221024, -0x10400009, 0x3c050008, 0x3c040001, 0x248430dc, 0xafa00010, 0xafa00014, -0x8f860220, 0x34a50401, 0xc00290f, 0x3821, 0x3c022000, 0x2221024, -0x10400009, 0x3c050008, 0x3c040001, 0x248430dc, 0xafa00010, 0xafa00014, -0x8f860220, 0x34a50402, 0xc00290f, 0x3821, 0x6210009, 0x3c050008, -0x3c040001, 0x248430dc, 0xafa00010, 0xafa00014, 0x8f860220, 0x34a50404, -0xc00290f, 0x3821, 0x8fbf0020, 0x8fb3001c, 0x8fb10018, 0x3e00008, -0x27bd0028, 0x3e00008, 0x0, 0x3c020001, 0x8c42341c, 0x27bdffc0, -0xafbf0038, 0xafbe0034, 0xafb50030, 0xafb3002c, 0x1040000f, 0xafb10028, -0x3c040001, 0x24843100, 0x3c050008, 0xafa00010, 0xafa00014, 0x8f860220, -0x34a50498, 0x24020001, 0x3c010001, 0xac20341c, 0x3c010001, 0xac223410, -0xc00290f, 0x3821, 0x3c037fff, 0x8f420268, 0x3463ffff, 0x3c04fdff, -0x431024, 0xaf420268, 0x8ee204a8, 0x3484ffff, 0x30420002, 0x10400091, -0x284a024, 0x3c040600, 0x8ee204a8, 0x34842000, 0x2403fffd, 0x431024, -0xaee204a8, 0xafa40020, 0x8ec3002c, 0x240200ff, 0x10620004, 0x27a70020, -0x8ec2002c, 0x10000002, 0x24530001, 0x9821, 0x8f420228, 0x1662000f, -0x0, 0x3c040001, 0x248430b8, 0xafa00010, 0xafa00014, 0x8ec6002c, -0x8f470228, 0x3c050009, 0xc00290f, 0x34a5f00f, 0x8ec202a0, 0x24420001, -0xaec202a0, 0x1000006d, 0x8ec202a0, 0x8ec2002c, 0x210c0, 0x571021, -0x8ce30000, 0x8ce40004, 0xac4304c0, 0xac4404c4, 0x8f830054, 0x8f820054, -0x247103e8, 0x2221023, 0x2c4203e9, 0x1040001e, 0xa821, 0x241e000c, -0x8ec8002c, 0x8ee40428, 0x8ee5042c, 0x8ec6002c, 0x24070008, 0xafbe0010, -0xafb30014, 0x840c0, 0x1001821, 0x1021, 0x8ec80008, 0xa32821, -0xa3482b, 0x822021, 0x892021, 0x630c0, 0xafa80018, 0x8ec200a8, -0x24c604c0, 0x40f809, 0x2e63021, 0x54400006, 0x24150001, 0x8f820054, -0x2221023, 0x2c4203e9, 0x1440ffe5, 0x0, 0x32a200ff, 0x54400011, -0xaed3002c, 0x3c040001, 0x248430c4, 0xafa00010, 0xafa00014, 0x8f860120, -0x8f870124, 0x3c050009, 0x10000030, 0x34a5f010, 0x8ec2026c, 0x24150001, -0x24420001, 0xaec2026c, 0x8ec2026c, 0x1000001f, 0x32a200ff, 0x8f830054, -0x8f820054, 0x247103e8, 0x2221023, 0x2c4203e9, 0x10400017, 0xa821, -0x3c1e0020, 0x24130011, 0x8ec20008, 0x8ee40488, 0x8ee5048c, 0x8ec3002c, -0x8f860120, 0xafb30010, 0x5e1025, 0xafa30014, 0xafa20018, 0x8ec200a8, -0x24070008, 0x40f809, 0x24c6001c, 0x1440ffe2, 0x0, 0x8f820054, -0x2221023, 0x2c4203e9, 0x1440ffed, 0x0, 0x32a200ff, 0x1440000f, -0x0, 0x3c040001, 0x248430d0, 0xafa00010, 0xafa00014, 0x8f860120, -0x8f870124, 0x3c050009, 0x34a5f011, 0xc00290f, 0x0, 0x8ec202d0, -0x24420001, 0xaec202d0, 0x8ec202d0, 0x8ec20250, 0x24420001, 0xaec20250, -0x8ec20250, 0x8fbf0038, 0x8fbe0034, 0x8fb50030, 0x8fb3002c, 0x8fb10028, -0x3e00008, 0x27bd0040, 0x3c020001, 0x8c42341c, 0x27bdffe0, 0x1440000d, -0xafbf0018, 0x3c040001, 0x2484310c, 0x3c050008, 0xafa00010, 0xafa00014, -0x8f860220, 0x34a50499, 0x24020001, 0x3c010001, 0xac22341c, 0xc00290f, -0x3821, 0x92c2011d, 0x10400008, 0x24040001, 0x8f820220, 0x3c0308ff, -0x3463ffff, 0x431024, 0x34420008, 0xaf820220, 0x24040001, 0xc0047d1, -0x24050004, 0xaf420268, 0x8fbf0018, 0x3e00008, 0x27bd0020, 0x0, -0x86102b, 0x50400001, 0x872023, 0xc41023, 0x24843, 0x125102b, -0x1040001b, 0x91040, 0x824021, 0x88102b, 0x10400007, 0x1821, -0x94820000, 0x24840002, 0x621821, 0x88102b, 0x1440fffb, 0x0, -0x602021, 0xc73023, 0xa91023, 0x21040, 0xc22821, 0xc5102b, -0x10400007, 0x1821, 0x94c20000, 0x24c60002, 0x621821, 0xc5102b, -0x1440fffb, 0x0, 0x1000000d, 0x832021, 0x51040, 0x822821, -0x85102b, 0x10400007, 0x1821, 0x94820000, 0x24840002, 0x621821, -0x85102b, 0x1440fffb, 0x0, 0x602021, 0x41c02, 0x3082ffff, -0x622021, 0x41c02, 0x3082ffff, 0x622021, 0x3e00008, 0x3082ffff, -0x3e00008, 0x0, 0x8f820220, 0x34420002, 0xaf820220, 0x3c020001, -0x8c425618, 0x30424000, 0x10400054, 0x24040001, 0x8f820200, 0x24067fff, -0x8f830200, 0x30450002, 0x2402fffd, 0x621824, 0xaf830200, 0xaf840204, -0x8f830054, 0x8f820054, 0x10000002, 0x24630001, 0x8f820054, 0x621023, -0x2c420002, 0x1440fffc, 0x0, 0x8f820224, 0x1444004d, 0x42040, -0xc4102b, 0x1040fff1, 0x0, 0x8f820200, 0x451025, 0xaf820200, -0x8f820220, 0x34428000, 0xaf820220, 0x8f830054, 0x8f820054, 0x10000002, -0x24630001, 0x8f820054, 0x621023, 0x2c420002, 0x1440fffc, 0x0, -0x8f820220, 0x3c030004, 0x431024, 0x1440000f, 0x0, 0x8f820220, -0x3c03ffff, 0x34637fff, 0x431024, 0xaf820220, 0x8f830054, 0x8f820054, -0x10000002, 0x24630001, 0x8f820054, 0x621023, 0x2c420002, 0x1440fffc, -0x0, 0x8f820220, 0x3c030004, 0x431024, 0x1440000d, 0x0, -0x8f820220, 0x34428000, 0xaf820220, 0x8f830054, 0x8f820054, 0x10000002, -0x24630001, 0x8f820054, 0x621023, 0x2c420002, 0x1440fffc, 0x0, -0x8f820220, 0x3c030004, 0x431024, 0x1040001b, 0x1021, 0x8f830220, -0x24020001, 0x10000015, 0x3c04f700, 0x8f820220, 0x3c04f700, 0x441025, -0xaf820220, 0x8f820220, 0x2403fffd, 0x431024, 0xaf820220, 0x8f820220, -0x3c030300, 0x431024, 0x14400003, 0x0, 0x10000008, 0x1021, -0x8f820220, 0x34420002, 0xaf820220, 0x8f830220, 0x24020001, 0x641825, -0xaf830220, 0x3e00008, 0x0, 0x2021, 0x3c050100, 0x24020001, -0xaf80021c, 0xaf820200, 0xaf820220, 0x27625000, 0xaf8200c0, 0x27625000, -0xaf8200c4, 0x27625000, 0xaf8200c8, 0x27625000, 0xaf8200d0, 0x27625000, -0xaf8200d4, 0x27625000, 0xaf8200d8, 0x27623000, 0xaf8200e0, 0x27623000, -0xaf8200e4, 0x27623000, 0xaf8200e8, 0x27622800, 0xaf8200f0, 0x27622800, -0xaf8200f4, 0x27622800, 0xaf8200f8, 0x418c0, 0x24840001, 0x3631021, -0xac453004, 0x3631021, 0xac403000, 0x28820200, 0x1440fff9, 0x418c0, -0x2021, 0x418c0, 0x24840001, 0x3631021, 0xac402804, 0x3631021, -0xac402800, 0x28820100, 0x1440fff9, 0x418c0, 0xaf80023c, 0x24030080, -0x24040100, 0xac600000, 0x24630004, 0x64102b, 0x5440fffd, 0xac600000, -0x8f830040, 0x3c02f000, 0x621824, 0x3c025000, 0x1062000c, 0x43102b, -0x14400006, 0x3c026000, 0x3c024000, 0x10620008, 0x24020800, 0x10000008, -0x0, 0x10620004, 0x24020800, 0x10000004, 0x0, 0x24020700, -0x3c010001, 0xac223420, 0x3e00008, 0x0, 0x27bdffc8, 0xafbf0034, -0xafb50030, 0xafb3002c, 0xafb10028, 0x3c010001, 0xc004459, 0xac203408, -0x24040001, 0x2821, 0x27a60020, 0x34028000, 0xc004076, 0xa7a20020, -0x8f830054, 0x8f820054, 0x10000002, 0x24630064, 0x8f820054, 0x621023, -0x2c420065, 0x1440fffc, 0x24040001, 0x24050001, 0xc004034, 0x27a60020, -0x8f830054, 0x8f820054, 0x10000002, 0x24630064, 0x8f820054, 0x621023, -0x2c420065, 0x1440fffc, 0x24040001, 0x24050001, 0xc004034, 0x27a60020, -0x8f830054, 0x8f820054, 0x10000002, 0x24630064, 0x8f820054, 0x621023, -0x2c420065, 0x1440fffc, 0x24040001, 0x24050002, 0xc004034, 0x27a60018, -0x8f830054, 0x8f820054, 0x10000002, 0x24630064, 0x8f820054, 0x621023, -0x2c420065, 0x1440fffc, 0x24040001, 0x24050003, 0xc004034, 0x27a6001a, -0x97a20020, 0x10400024, 0x24020001, 0x3c020001, 0x8c423408, 0x97a30018, -0x34420001, 0x3c010001, 0xac223408, 0x24020015, 0x14620004, 0x3402f423, -0x97a3001a, 0x10620018, 0x24020003, 0x97a30018, 0x24027810, 0x14620014, -0x24020002, 0x97a3001a, 0x24020001, 0x14620010, 0x24020002, 0x1000000e, -0x24020004, 0x3c020001, 0x8c423408, 0x34420008, 0x3c010001, 0xac223408, -0x10000058, 0x24020004, 0x3c020001, 0x8c423408, 0x34420004, 0x3c010001, -0x100000a8, 0xac223408, 0x3c010001, 0xac22353c, 0x24020e00, 0xaf820238, -0x8f840054, 0x8f820054, 0x24030008, 0x3c010001, 0xac23340c, 0x10000002, -0x248401f4, 0x8f820054, 0x821023, 0x2c4201f5, 0x1440fffc, 0x3c0200c8, -0x344201fb, 0xaf820238, 0x8f830054, 0x8f820054, 0x10000002, 0x246301f4, -0x8f820054, 0x621023, 0x2c4201f5, 0x1440fffc, 0x8821, 0x3c1300c8, -0x367301f6, 0x2415fffd, 0xc003f77, 0x0, 0x8f830054, 0x8f820054, -0x10000002, 0x246301f4, 0x8f820054, 0x621023, 0x2c4201f5, 0x1440fffc, -0x0, 0xaf930238, 0x8f830054, 0x8f820054, 0x10000002, 0x2463000a, -0x8f820054, 0x621023, 0x2c42000b, 0x1440fffc, 0x0, 0x8f820220, -0x34420002, 0xaf820220, 0x8f820200, 0x24040001, 0x24057fff, 0x551024, -0xaf820200, 0xaf840204, 0x8f830054, 0x8f820054, 0x10000002, 0x24630001, -0x8f820054, 0x621023, 0x2c420002, 0x1440fffc, 0x0, 0x8f820224, -0x14440005, 0x34028000, 0x42040, 0xa4102b, 0x1040fff0, 0x34028000, -0x1082ffa6, 0x26310001, 0x2e220014, 0x1440ffce, 0x24020004, 0x3c010001, -0xac22340c, 0x8821, 0x3c13ffff, 0x36733f7f, 0xc003f77, 0x0, -0x8f830054, 0x8f820054, 0x10000002, 0x24630001, 0x8f820054, 0x621023, -0x2c420002, 0x1440fffc, 0x0, 0x8f820044, 0x531024, 0x34425080, -0xaf820044, 0x8f830054, 0x8f820054, 0x10000002, 0x2463000a, 0x8f820054, -0x621023, 0x2c42000b, 0x1440fffc, 0x0, 0x8f820044, 0x531024, -0x3442f080, 0xaf820044, 0x8f830054, 0x8f820054, 0x10000002, 0x2463000a, -0x8f820054, 0x621023, 0x2c42000b, 0x1440fffc, 0x0, 0x8f820220, -0x3c03f700, 0x431025, 0xaf820220, 0x8f830054, 0x8f820054, 0x10000002, -0x24630064, 0x8f820054, 0x621023, 0x2c420065, 0x1440fffc, 0x0, -0x8f820220, 0x24040001, 0x34420002, 0xaf820220, 0x8f830200, 0x24057fff, -0x2402fffd, 0x621824, 0xaf830200, 0xaf840204, 0x8f830054, 0x8f820054, -0x10000002, 0x24630001, 0x8f820054, 0x621023, 0x2c420002, 0x1440fffc, -0x0, 0x8f820224, 0x14440005, 0x34028000, 0x42040, 0xa4102b, -0x1040fff0, 0x34028000, 0x1082ff57, 0x26310001, 0x2e220064, 0x1440ffb0, -0x0, 0x3c020001, 0x8c423408, 0x30420004, 0x14400007, 0x3c08fff0, -0x8f820044, 0x3c03ffff, 0x34633f7f, 0x431024, 0xaf820044, 0x3c08fff0, -0x3508bdc0, 0x8f830054, 0x97a60018, 0x3c070001, 0x8ce7353c, 0x3c040001, -0x248431e0, 0x24020001, 0x3c010001, 0xac223410, 0xafa60010, 0x3c060001, -0x8cc63408, 0x97a2001a, 0x3c05000d, 0x34a50100, 0x3c010001, 0xac20340c, -0x681821, 0x3c010001, 0xac233534, 0xc00290f, 0xafa20014, 0x8fbf0034, -0x8fb50030, 0x8fb3002c, 0x8fb10028, 0x3e00008, 0x27bd0038, 0x27bdffe8, -0x24070004, 0x3c040001, 0x8c84340c, 0x3021, 0x24020001, 0x1482000a, -0xafbf0010, 0x3c020001, 0x8c42561c, 0x3c050004, 0x30428000, 0x1040000c, -0x34a593e0, 0x3c05000f, 0x10000009, 0x34a54240, 0x3c020001, 0x8c42561c, -0x3c05000f, 0x30428000, 0x10400003, 0x34a54240, 0x3c05001e, 0x34a58480, -0x3c020001, 0x8c423534, 0x8f830054, 0x451021, 0x431023, 0x45102b, -0x1440002e, 0x0, 0x3c020001, 0x8c423414, 0x1440002a, 0x2cc20001, -0x7182b, 0x431024, 0x1040001d, 0x0, 0x3c090001, 0x8d293408, -0x240b0001, 0x3c054000, 0x3c080001, 0x2508561c, 0x250afffc, 0x42042, -0x14800002, 0x24e7ffff, 0x24040008, 0x891024, 0x5040000b, 0x2cc20001, -0x148b0004, 0x0, 0x8d020000, 0x10000003, 0x451024, 0x8d420000, -0x451024, 0x54400001, 0x24060001, 0x2cc20001, 0x7182b, 0x431024, -0x5440ffed, 0x42042, 0x3c010001, 0x10c00020, 0xac24340c, 0x8f830054, -0x24020001, 0x3c010001, 0xac223410, 0x3c010001, 0xac233534, 0x3c020001, -0x8c423410, 0x10400004, 0x24020001, 0x3c010001, 0xac203410, 0xaee279c8, -0x8ee379c8, 0x24020008, 0x10620005, 0x24020001, 0xc003e23, 0x0, -0x1000000b, 0x0, 0x3c030001, 0x8c63340c, 0x10620007, 0x2402000e, -0x3c030001, 0x8c635590, 0x10620003, 0x0, 0xc00447c, 0x8f840220, -0x8fbf0010, 0x3e00008, 0x27bd0018, 0x27bdffe0, 0x3c03fdff, 0x3c040001, -0x8c84340c, 0x3c020001, 0x8c423424, 0x3463ffff, 0x283a024, 0x14820006, -0xafbf0018, 0x8ee379c8, 0x3c020001, 0x8c423428, 0x10620006, 0x0, -0x8ee279c8, 0x3c010001, 0xac243424, 0x3c010001, 0xac223428, 0x3c030001, -0x8c63340c, 0x24020002, 0x10620139, 0x2c620003, 0x10400005, 0x24020001, -0x1062000a, 0x0, 0x10000131, 0x0, 0x24020004, 0x10620070, -0x24020008, 0x106200ac, 0x24020001, 0x1000012a, 0x0, 0x8ee279c8, -0x2443ffff, 0x2c620008, 0x10400127, 0x31080, 0x3c010001, 0x220821, -0x8c2231f8, 0x400008, 0x0, 0xc003f77, 0x0, 0x3c020001, -0x8c423418, 0x3c010001, 0xac2033a0, 0x104000e8, 0x24020002, 0xaee279c8, -0x3c010001, 0x10000116, 0xac203418, 0xc0040b7, 0x0, 0x3c030001, -0x8c633430, 0x24020011, 0x1462010f, 0x24020003, 0x100000aa, 0x0, -0x3c050001, 0x8ca5340c, 0x3c060001, 0x8cc6561c, 0xc0046cc, 0x24040001, -0x24020005, 0x3c010001, 0xac203418, 0x10000102, 0xaee279c8, 0x3c040001, -0x248431ec, 0x3c05000f, 0x34a50100, 0x3021, 0x3821, 0xafa00010, -0xc00290f, 0xafa00014, 0x100000f7, 0x0, 0x8f820220, 0x3c03f700, -0x431025, 0x100000ae, 0xaf820220, 0x8f820220, 0x3c030004, 0x431024, -0x144000bc, 0x24020007, 0x8f830054, 0x3c020001, 0x8c423530, 0x2463d8f0, -0x431023, 0x2c422710, 0x144000e5, 0x24020001, 0x100000e1, 0x0, -0x3c050001, 0x8ca5340c, 0xc0047d1, 0x24040001, 0xc004899, 0x24040001, -0x3c030001, 0x8c635614, 0x46100d7, 0x24020001, 0x3c020008, 0x621024, -0x10400006, 0x0, 0x8f820214, 0x3c03ffff, 0x431024, 0x10000005, -0x3442251f, 0x8f820214, 0x3c03ffff, 0x431024, 0x3442241f, 0xaf820214, -0x8f820220, 0x3c030200, 0x283a025, 0x34420002, 0xaf820220, 0x24020008, -0xc003b6a, 0xaee279c8, 0x100000c1, 0x0, 0x8ee279c8, 0x2443ffff, -0x2c620008, 0x104000bc, 0x31080, 0x3c010001, 0x220821, 0x8c223218, -0x400008, 0x0, 0xc003ab1, 0x0, 0x3c010001, 0xac203410, -0xaf800204, 0x3c010001, 0xc003f77, 0xac2055e0, 0x8f820044, 0x3c03ffff, -0x34633f7f, 0x431024, 0x34425080, 0xaf820044, 0x8f830054, 0x3c010001, -0xac2033a0, 0x10000062, 0x24020002, 0x3c020001, 0x8c425618, 0x30424000, -0x10400004, 0x0, 0x8f820044, 0x10000006, 0x3442f080, 0x8f820044, -0x3c03ffff, 0x34633f7f, 0x431024, 0x3442a080, 0xaf820044, 0x8f830054, -0x10000051, 0x24020004, 0xc003bc4, 0x0, 0x1040008d, 0x24020001, -0x8f820214, 0x3c03ffff, 0x3c040001, 0x8c843528, 0x431024, 0x3442251f, -0xaf820214, 0x24020008, 0x14800067, 0xaee279c8, 0x1000006c, 0x0, -0x8ee279c8, 0x2443ffff, 0x2c620007, 0x1040007e, 0x31080, 0x3c010001, -0x220821, 0x8c223238, 0x400008, 0x0, 0xc003ab1, 0x0, -0x3c010001, 0xac203410, 0xaf800204, 0x3c010001, 0xc003f77, 0xac2055e0, -0x8f830054, 0x3c010001, 0xac2033a0, 0x1000002a, 0x24020002, 0x8f830054, -0x3c020001, 0x8c423530, 0x2463d8f0, 0x431023, 0x2c422710, 0x14400064, -0x24020003, 0x10000062, 0xaee279c8, 0x3c020001, 0x8c425618, 0x30424000, -0x10400003, 0x3c0200c8, 0x10000002, 0x344201f6, 0x344201fe, 0xaf820238, -0x8f830054, 0x10000014, 0x24020004, 0x8f830054, 0x3c020001, 0x8c423530, -0x2463d8f0, 0x431023, 0x2c422710, 0x1440004e, 0x24020005, 0x1000004c, -0xaee279c8, 0x8f820220, 0x3c03f700, 0x431025, 0xaf820220, 0xaf800204, -0x3c010001, 0xac2055e0, 0x8f830054, 0x24020006, 0xaee279c8, 0x3c010001, -0x1000003f, 0xac233530, 0x3c05fffe, 0x34a57960, 0x3c040001, 0x8f820054, -0x3c030001, 0x8c633530, 0x3484869f, 0x451021, 0x621823, 0x83202b, -0x10800033, 0x0, 0x24020007, 0x10000030, 0xaee279c8, 0xc003bc4, -0x0, 0x1040002a, 0x24020001, 0x8f820214, 0x3c03ffff, 0x3c040001, -0x8c843528, 0x431024, 0x3442251f, 0xaf820214, 0x24020008, 0x1080000b, -0xaee279c8, 0x8f820220, 0x34420002, 0xaf820220, 0x24020001, 0x3c010001, -0xac225590, 0xc00447c, 0x8f840220, 0x10000018, 0x0, 0x8f820220, -0x3c030008, 0x431024, 0x14400013, 0x3c020200, 0x282a025, 0x2402000e, -0x3c010001, 0xac225590, 0xc004899, 0x24040001, 0x8f820220, 0x34420002, -0xc003b6a, 0xaf820220, 0x3c050001, 0x8ca5340c, 0xc0047d1, 0x24040001, -0x10000003, 0x0, 0x3c010001, 0xac223410, 0x8fbf0018, 0x3e00008, -0x27bd0020, 0x8f820200, 0x8f820220, 0x8f820220, 0x34420004, 0xaf820220, -0x8f820200, 0x3c040001, 0x8c84340c, 0x34420004, 0xaf820200, 0x24020002, -0x1082003a, 0x2c820003, 0x10400005, 0x24020001, 0x1082000a, 0x3c03f0ff, -0x100000a8, 0x0, 0x24020004, 0x10820055, 0x24020008, 0x10820074, -0x3c02f0ff, 0x100000a1, 0x0, 0x8f820050, 0x3463ffff, 0x3c05ffff, -0x34a53f7f, 0x431024, 0x3c030700, 0x431025, 0xaf820050, 0x24020e00, -0xaf840200, 0xaf840220, 0xaf820238, 0x8f820044, 0x3c030001, 0x8c6333f8, -0x3c040001, 0x8c84353c, 0x451024, 0x34630022, 0xaf820044, 0x24020004, -0x1082000c, 0xaf830200, 0x3c020001, 0x8c423420, 0x3c030001, 0x8c633404, -0x3c040001, 0x8c8433fc, 0x34428000, 0x621825, 0x641825, 0x1000007e, -0x34620002, 0x3c020001, 0x8c423404, 0x3c030001, 0x8c633420, 0x3c040001, -0x8c8433fc, 0x431025, 0x441025, 0x10000074, 0x34420002, 0x8f830050, -0x3c02f0ff, 0x3442ffff, 0x3c040001, 0x8c843528, 0x621824, 0x3c020d00, -0x621825, 0x24020001, 0xaf830050, 0xaf820200, 0xaf820220, 0x24020e00, -0xaf820238, 0x10800005, 0x3c033f00, 0x3c020001, 0x8c4233f0, 0x10000004, -0x34630070, 0x3c020001, 0x8c4233f0, 0x34630072, 0x431025, 0xaf820200, -0x3c030001, 0x8c6333f4, 0x3c04f700, 0x3c020001, 0x8c423404, 0x3c050001, -0x8ca53420, 0x641825, 0x431025, 0x10000050, 0x451025, 0x3c03f0ff, -0x8f820050, 0x3463ffff, 0x3c04ffff, 0x431024, 0x3c030a00, 0x431025, -0xaf820050, 0x24020001, 0xaf820200, 0xaf820220, 0x24020e01, 0xaf820238, -0x8f820044, 0x34843f7f, 0x3c030001, 0x8c633528, 0x441024, 0x34420080, -0xaf820044, 0x10600005, 0x3c033f00, 0x3c020001, 0x8c4233f0, 0x10000004, -0x346300e0, 0x3c020001, 0x8c4233f0, 0x346300e2, 0x431025, 0xaf820200, -0x10000025, 0x3c05f700, 0x8f830050, 0x3c040001, 0x8c843528, 0x3442ffff, -0x621824, 0xaf830050, 0x10800013, 0x3c0500c8, 0x34a501fb, 0x3c063f00, -0x3c030001, 0x8c633400, 0x3c040001, 0x8c8433f0, 0x34c600e0, 0x24020001, -0xaf820200, 0xaf820220, 0xaf850238, 0x24630001, 0x862025, 0x3c010001, -0xac233400, 0xaf840200, 0x1000000b, 0x3c05f700, 0x3c0200c8, 0x344201fb, -0x3c030001, 0x8c6333f0, 0x3c043f00, 0x348400e2, 0xaf820238, 0x641825, -0xaf830200, 0x3c05f700, 0x34a58000, 0x3c030001, 0x8c6333f4, 0x3c020001, -0x8c423404, 0x3c040001, 0x8c843420, 0x651825, 0x431025, 0x441025, -0xaf820220, 0x3e00008, 0x0, 0x0, 0x27bdffd8, 0xafb50018, -0x80a821, 0xafbe001c, 0xa0f021, 0xafb30014, 0xc09821, 0xafb10010, -0x8821, 0xafbf0020, 0xa6600000, 0xc004433, 0x24040001, 0x26310001, -0x2e220020, 0x1440fffb, 0x0, 0xc004433, 0x2021, 0xc004433, -0x24040001, 0xc004433, 0x24040001, 0xc004433, 0x2021, 0x24110010, -0x2b11024, 0x10400002, 0x2021, 0x24040001, 0xc004433, 0x118842, -0x1620fffa, 0x2b11024, 0x24110010, 0x3d11024, 0x10400002, 0x2021, -0x24040001, 0xc004433, 0x118842, 0x1620fffa, 0x3d11024, 0xc004459, -0x34118000, 0xc004459, 0x0, 0xc004413, 0x0, 0x50400005, -0x118842, 0x96620000, 0x511025, 0xa6620000, 0x118842, 0x1620fff7, -0x0, 0xc004459, 0x0, 0x8fbf0020, 0x8fbe001c, 0x8fb50018, -0x8fb30014, 0x8fb10010, 0x3e00008, 0x27bd0028, 0x27bdffd8, 0xafb30014, -0x809821, 0xafb50018, 0xa0a821, 0xafbe001c, 0xc0f021, 0xafb10010, -0x8821, 0xafbf0020, 0xc004433, 0x24040001, 0x26310001, 0x2e220020, -0x1440fffb, 0x0, 0xc004433, 0x2021, 0xc004433, 0x24040001, -0xc004433, 0x2021, 0xc004433, 0x24040001, 0x24110010, 0x2711024, -0x10400002, 0x2021, 0x24040001, 0xc004433, 0x118842, 0x1620fffa, -0x2711024, 0x24110010, 0x2b11024, 0x10400002, 0x2021, 0x24040001, -0xc004433, 0x118842, 0x1620fffa, 0x2b11024, 0xc004433, 0x24040001, -0xc004433, 0x2021, 0x34118000, 0x97c20000, 0x511024, 0x10400002, -0x2021, 0x24040001, 0xc004433, 0x118842, 0x1620fff8, 0x0, -0xc004459, 0x0, 0x8fbf0020, 0x8fbe001c, 0x8fb50018, 0x8fb30014, -0x8fb10010, 0x3e00008, 0x27bd0028, 0x3c030001, 0x8c633430, 0x3c020001, -0x8c423474, 0x27bdffd8, 0xafbf0020, 0xafb3001c, 0x10620003, 0xafb10018, -0x3c010001, 0xac233474, 0x2463ffff, 0x2c620013, 0x10400349, 0x31080, -0x3c010001, 0x220821, 0x8c223260, 0x400008, 0x0, 0xc004459, -0x8821, 0x34028000, 0xa7a20010, 0x27b30010, 0xc004433, 0x24040001, -0x26310001, 0x2e220020, 0x1440fffb, 0x0, 0xc004433, 0x2021, -0xc004433, 0x24040001, 0xc004433, 0x2021, 0xc004433, 0x24040001, -0x24110010, 0x32220001, 0x10400002, 0x2021, 0x24040001, 0xc004433, -0x118842, 0x1620fffa, 0x32220001, 0x24110010, 0xc004433, 0x2021, -0x118842, 0x1620fffc, 0x0, 0xc004433, 0x24040001, 0xc004433, -0x2021, 0x34118000, 0x96620000, 0x511024, 0x10400002, 0x2021, -0x24040001, 0xc004433, 0x118842, 0x1620fff8, 0x0, 0xc004459, -0x0, 0x1000030e, 0x24020002, 0x27b30010, 0xa7a00010, 0x8821, -0xc004433, 0x24040001, 0x26310001, 0x2e220020, 0x1440fffb, 0x0, -0xc004433, 0x2021, 0xc004433, 0x24040001, 0xc004433, 0x24040001, -0xc004433, 0x2021, 0x24110010, 0x32220001, 0x10400002, 0x2021, -0x24040001, 0xc004433, 0x118842, 0x1620fffa, 0x32220001, 0x24110010, -0xc004433, 0x2021, 0x118842, 0x1620fffc, 0x0, 0xc004459, -0x34118000, 0xc004459, 0x0, 0xc004413, 0x0, 0x50400005, -0x118842, 0x96620000, 0x511025, 0xa6620000, 0x118842, 0x1620fff7, -0x0, 0xc004459, 0x0, 0x97a20010, 0x30428000, 0x144002dc, -0x24020003, 0x100002d8, 0x0, 0x24021200, 0xa7a20010, 0x27b30010, -0x8821, 0xc004433, 0x24040001, 0x26310001, 0x2e220020, 0x1440fffb, -0x0, 0xc004433, 0x2021, 0xc004433, 0x24040001, 0xc004433, -0x2021, 0xc004433, 0x24040001, 0x24110010, 0x32220001, 0x10400002, -0x2021, 0x24040001, 0xc004433, 0x118842, 0x1620fffa, 0x32220001, -0x24110010, 0xc004433, 0x2021, 0x118842, 0x1620fffc, 0x0, -0xc004433, 0x24040001, 0xc004433, 0x2021, 0x34118000, 0x96620000, -0x511024, 0x10400002, 0x2021, 0x24040001, 0xc004433, 0x118842, -0x1620fff8, 0x0, 0xc004459, 0x0, 0x8f830054, 0x10000296, -0x24020004, 0x8f830054, 0x3c020001, 0x8c423538, 0x2463ff9c, 0x431023, -0x2c420064, 0x1440029e, 0x24020002, 0x3c030001, 0x8c63353c, 0x10620297, -0x2c620003, 0x14400296, 0x24020011, 0x24020003, 0x10620005, 0x24020004, -0x10620291, 0x2402000f, 0x1000028f, 0x24020011, 0x1000028d, 0x24020005, -0x24020014, 0xa7a20010, 0x27b30010, 0x8821, 0xc004433, 0x24040001, -0x26310001, 0x2e220020, 0x1440fffb, 0x0, 0xc004433, 0x2021, -0xc004433, 0x24040001, 0xc004433, 0x2021, 0xc004433, 0x24040001, -0x24110010, 0x32220001, 0x10400002, 0x2021, 0x24040001, 0xc004433, -0x118842, 0x1620fffa, 0x32220001, 0x24110010, 0x32220012, 0x10400002, -0x2021, 0x24040001, 0xc004433, 0x118842, 0x1620fffa, 0x32220012, -0xc004433, 0x24040001, 0xc004433, 0x2021, 0x34118000, 0x96620000, -0x511024, 0x10400002, 0x2021, 0x24040001, 0xc004433, 0x118842, -0x1620fff8, 0x0, 0xc004459, 0x0, 0x8f830054, 0x10000248, -0x24020006, 0x8f830054, 0x3c020001, 0x8c423538, 0x2463ff9c, 0x431023, -0x2c420064, 0x14400250, 0x24020007, 0x1000024c, 0x0, 0x24020006, -0xa7a20010, 0x27b30010, 0x8821, 0xc004433, 0x24040001, 0x26310001, -0x2e220020, 0x1440fffb, 0x0, 0xc004433, 0x2021, 0xc004433, -0x24040001, 0xc004433, 0x2021, 0xc004433, 0x24040001, 0x24110010, -0x32220001, 0x10400002, 0x2021, 0x24040001, 0xc004433, 0x118842, -0x1620fffa, 0x32220001, 0x24110010, 0x32220013, 0x10400002, 0x2021, -0x24040001, 0xc004433, 0x118842, 0x1620fffa, 0x32220013, 0xc004433, -0x24040001, 0xc004433, 0x2021, 0x34118000, 0x96620000, 0x511024, -0x10400002, 0x2021, 0x24040001, 0xc004433, 0x118842, 0x1620fff8, -0x0, 0xc004459, 0x0, 0x8f830054, 0x10000207, 0x24020008, -0x8f830054, 0x3c020001, 0x8c423538, 0x2463ff9c, 0x431023, 0x2c420064, -0x1440020f, 0x24020009, 0x1000020b, 0x0, 0x27b30010, 0xa7a00010, -0x8821, 0xc004433, 0x24040001, 0x26310001, 0x2e220020, 0x1440fffb, -0x0, 0xc004433, 0x2021, 0xc004433, 0x24040001, 0xc004433, -0x24040001, 0xc004433, 0x2021, 0x24110010, 0x32220001, 0x10400002, -0x2021, 0x24040001, 0xc004433, 0x118842, 0x1620fffa, 0x32220001, -0x24110010, 0x32220018, 0x10400002, 0x2021, 0x24040001, 0xc004433, -0x118842, 0x1620fffa, 0x32220018, 0xc004459, 0x34118000, 0xc004459, -0x0, 0xc004413, 0x0, 0x50400005, 0x118842, 0x96620000, -0x511025, 0xa6620000, 0x118842, 0x1620fff7, 0x0, 0xc004459, -0x8821, 0x97a20010, 0x27b30010, 0x34420001, 0xa7a20010, 0xc004433, -0x24040001, 0x26310001, 0x2e220020, 0x1440fffb, 0x0, 0xc004433, -0x2021, 0xc004433, 0x24040001, 0xc004433, 0x2021, 0xc004433, -0x24040001, 0x24110010, 0x32220001, 0x10400002, 0x2021, 0x24040001, -0xc004433, 0x118842, 0x1620fffa, 0x32220001, 0x24110010, 0x32220018, -0x10400002, 0x2021, 0x24040001, 0xc004433, 0x118842, 0x1620fffa, -0x32220018, 0xc004433, 0x24040001, 0xc004433, 0x2021, 0x34118000, -0x96620000, 0x511024, 0x10400002, 0x2021, 0x24040001, 0xc004433, -0x118842, 0x1620fff8, 0x0, 0xc004459, 0x0, 0x8f830054, -0x10000193, 0x2402000a, 0x8f830054, 0x3c020001, 0x8c423538, 0x2463ff9c, -0x431023, 0x2c420064, 0x1440019b, 0x2402000b, 0x10000197, 0x0, -0x27b30010, 0xa7a00010, 0x8821, 0xc004433, 0x24040001, 0x26310001, -0x2e220020, 0x1440fffb, 0x0, 0xc004433, 0x2021, 0xc004433, -0x24040001, 0xc004433, 0x24040001, 0xc004433, 0x2021, 0x24110010, -0x32220001, 0x10400002, 0x2021, 0x24040001, 0xc004433, 0x118842, -0x1620fffa, 0x32220001, 0x24110010, 0x32220017, 0x10400002, 0x2021, -0x24040001, 0xc004433, 0x118842, 0x1620fffa, 0x32220017, 0xc004459, -0x34118000, 0xc004459, 0x0, 0xc004413, 0x0, 0x50400005, -0x118842, 0x96620000, 0x511025, 0xa6620000, 0x118842, 0x1620fff7, -0x0, 0xc004459, 0x8821, 0x97a20010, 0x27b30010, 0x34420700, -0xa7a20010, 0xc004433, 0x24040001, 0x26310001, 0x2e220020, 0x1440fffb, -0x0, 0xc004433, 0x2021, 0xc004433, 0x24040001, 0xc004433, -0x2021, 0xc004433, 0x24040001, 0x24110010, 0x32220001, 0x10400002, -0x2021, 0x24040001, 0xc004433, 0x118842, 0x1620fffa, 0x32220001, -0x24110010, 0x32220017, 0x10400002, 0x2021, 0x24040001, 0xc004433, -0x118842, 0x1620fffa, 0x32220017, 0xc004433, 0x24040001, 0xc004433, -0x2021, 0x34118000, 0x96620000, 0x511024, 0x10400002, 0x2021, -0x24040001, 0xc004433, 0x118842, 0x1620fff8, 0x0, 0xc004459, -0x0, 0x8f830054, 0x1000011f, 0x2402000c, 0x8f830054, 0x3c020001, -0x8c423538, 0x2463ff9c, 0x431023, 0x2c420064, 0x14400127, 0x24020012, -0x10000123, 0x0, 0x27b30010, 0xa7a00010, 0x8821, 0xc004433, -0x24040001, 0x26310001, 0x2e220020, 0x1440fffb, 0x0, 0xc004433, -0x2021, 0xc004433, 0x24040001, 0xc004433, 0x24040001, 0xc004433, -0x2021, 0x24110010, 0x32220001, 0x10400002, 0x2021, 0x24040001, -0xc004433, 0x118842, 0x1620fffa, 0x32220001, 0x24110010, 0x32220014, -0x10400002, 0x2021, 0x24040001, 0xc004433, 0x118842, 0x1620fffa, -0x32220014, 0xc004459, 0x34118000, 0xc004459, 0x0, 0xc004413, -0x0, 0x50400005, 0x118842, 0x96620000, 0x511025, 0xa6620000, -0x118842, 0x1620fff7, 0x0, 0xc004459, 0x8821, 0x97a20010, -0x27b30010, 0x34420010, 0xa7a20010, 0xc004433, 0x24040001, 0x26310001, -0x2e220020, 0x1440fffb, 0x0, 0xc004433, 0x2021, 0xc004433, -0x24040001, 0xc004433, 0x2021, 0xc004433, 0x24040001, 0x24110010, -0x32220001, 0x10400002, 0x2021, 0x24040001, 0xc004433, 0x118842, -0x1620fffa, 0x32220001, 0x24110010, 0x32220014, 0x10400002, 0x2021, -0x24040001, 0xc004433, 0x118842, 0x1620fffa, 0x32220014, 0xc004433, -0x24040001, 0xc004433, 0x2021, 0x34118000, 0x96620000, 0x511024, -0x10400002, 0x2021, 0x24040001, 0xc004433, 0x118842, 0x1620fff8, -0x0, 0xc004459, 0x0, 0x8f830054, 0x100000ab, 0x24020013, -0x8f830054, 0x3c020001, 0x8c423538, 0x2463ff9c, 0x431023, 0x2c420064, -0x144000b3, 0x2402000d, 0x100000af, 0x0, 0x27b30010, 0xa7a00010, -0x8821, 0xc004433, 0x24040001, 0x26310001, 0x2e220020, 0x1440fffb, -0x0, 0xc004433, 0x2021, 0xc004433, 0x24040001, 0xc004433, -0x24040001, 0xc004433, 0x2021, 0x24110010, 0x32220001, 0x10400002, -0x2021, 0x24040001, 0xc004433, 0x118842, 0x1620fffa, 0x32220001, -0x24110010, 0x32220018, 0x10400002, 0x2021, 0x24040001, 0xc004433, -0x118842, 0x1620fffa, 0x32220018, 0xc004459, 0x34118000, 0xc004459, -0x0, 0xc004413, 0x0, 0x50400005, 0x118842, 0x96620000, -0x511025, 0xa6620000, 0x118842, 0x1620fff7, 0x0, 0xc004459, -0x8821, 0x97a20010, 0x27b30010, 0x3042fffe, 0xa7a20010, 0xc004433, -0x24040001, 0x26310001, 0x2e220020, 0x1440fffb, 0x0, 0xc004433, -0x2021, 0xc004433, 0x24040001, 0xc004433, 0x2021, 0xc004433, -0x24040001, 0x24110010, 0x32220001, 0x10400002, 0x2021, 0x24040001, -0xc004433, 0x118842, 0x1620fffa, 0x32220001, 0x24110010, 0x32220018, -0x10400002, 0x2021, 0x24040001, 0xc004433, 0x118842, 0x1620fffa, -0x32220018, 0xc004433, 0x24040001, 0xc004433, 0x2021, 0x34118000, -0x96620000, 0x511024, 0x10400002, 0x2021, 0x24040001, 0xc004433, -0x118842, 0x1620fff8, 0x0, 0xc004459, 0x0, 0x8f830054, -0x10000037, 0x2402000e, 0x24020840, 0xa7a20010, 0x27b30010, 0x8821, -0xc004433, 0x24040001, 0x26310001, 0x2e220020, 0x1440fffb, 0x0, -0xc004433, 0x2021, 0xc004433, 0x24040001, 0xc004433, 0x2021, -0xc004433, 0x24040001, 0x24110010, 0x32220001, 0x10400002, 0x2021, -0x24040001, 0xc004433, 0x118842, 0x1620fffa, 0x32220001, 0x24110010, -0x32220013, 0x10400002, 0x2021, 0x24040001, 0xc004433, 0x118842, -0x1620fffa, 0x32220013, 0xc004433, 0x24040001, 0xc004433, 0x2021, -0x34118000, 0x96620000, 0x511024, 0x10400002, 0x2021, 0x24040001, -0xc004433, 0x118842, 0x1620fff8, 0x0, 0xc004459, 0x0, -0x8f830054, 0x24020010, 0x3c010001, 0xac223430, 0x3c010001, 0x1000000c, -0xac233538, 0x8f830054, 0x3c020001, 0x8c423538, 0x2463ff9c, 0x431023, -0x2c420064, 0x14400004, 0x0, 0x24020011, 0x3c010001, 0xac223430, -0x8fbf0020, 0x8fb3001c, 0x8fb10018, 0x3e00008, 0x27bd0028, 0x8f850044, -0x8f820044, 0x3c030001, 0x431025, 0x3c030008, 0xaf820044, 0x8f840054, -0x8f820054, 0xa32824, 0x10000002, 0x24840001, 0x8f820054, 0x821023, -0x2c420002, 0x1440fffc, 0x0, 0x8f820044, 0x3c03fffe, 0x3463ffff, -0x431024, 0xaf820044, 0x8f830054, 0x8f820054, 0x10000002, 0x24630001, -0x8f820054, 0x621023, 0x2c420002, 0x1440fffc, 0x0, 0x3e00008, -0xa01021, 0x8f830044, 0x3c02fff0, 0x3442ffff, 0x42480, 0x621824, -0x3c020002, 0x822025, 0x641825, 0xaf830044, 0x8f820044, 0x3c030001, -0x431025, 0xaf820044, 0x8f830054, 0x8f820054, 0x10000002, 0x24630001, -0x8f820054, 0x621023, 0x2c420002, 0x1440fffc, 0x0, 0x8f820044, -0x3c03fffe, 0x3463ffff, 0x431024, 0xaf820044, 0x8f830054, 0x8f820054, -0x10000002, 0x24630001, 0x8f820054, 0x621023, 0x2c420002, 0x1440fffc, -0x0, 0x3e00008, 0x0, 0x8f820044, 0x3c03fff0, 0x3463ffff, -0x431024, 0xaf820044, 0x8f820044, 0x3c030001, 0x431025, 0xaf820044, -0x8f830054, 0x8f820054, 0x10000002, 0x24630001, 0x8f820054, 0x621023, -0x2c420002, 0x1440fffc, 0x0, 0x8f820044, 0x3c03fffe, 0x3463ffff, -0x431024, 0xaf820044, 0x8f830054, 0x8f820054, 0x10000002, 0x24630001, -0x8f820054, 0x621023, 0x2c420002, 0x1440fffc, 0x0, 0x3e00008, -0x0, 0x0, 0x27bdffe8, 0xafbf0010, 0x8ee379c8, 0x24020008, -0x146201ca, 0x0, 0x3c020001, 0x8c423528, 0x14400005, 0x0, -0xc003ab1, 0x8f840224, 0x100001c2, 0x0, 0x8f820220, 0x3c030008, -0x431024, 0x10400026, 0x24020001, 0x8f840224, 0x8f820220, 0x3c030400, -0x431024, 0x10400006, 0x0, 0x3c010001, 0xac2055a0, 0x3c010001, -0x1000000b, 0xac2055c0, 0x3c030001, 0x246355a0, 0x8c620000, 0x24420001, -0xac620000, 0x2c420002, 0x14400003, 0x24020001, 0x3c010001, 0xac2255c0, -0x3c020001, 0x8c4255c0, 0x10400006, 0x30820040, 0x10400004, 0x24020001, -0x3c010001, 0x10000003, 0xac2255c4, 0x3c010001, 0xac2055c4, 0x3c010001, -0xac24559c, 0x3c010001, 0x1000000b, 0xac2055d0, 0x3c010001, 0xac2255d0, -0x3c010001, 0xac2055c0, 0x3c010001, 0xac2055a0, 0x3c010001, 0xac2055c4, -0x3c010001, 0xac20559c, 0x3c030001, 0x8c635590, 0x3c020001, 0x8c425594, -0x50620004, 0x2463ffff, 0x3c010001, 0xac235594, 0x2463ffff, 0x2c62000e, -0x1040017e, 0x31080, 0x3c010001, 0x220821, 0x8c2232b0, 0x400008, -0x0, 0x3c02fdff, 0x3442ffff, 0x282a024, 0x24020002, 0x3c010001, -0xac2055c0, 0x3c010001, 0xac2055a0, 0x3c010001, 0xac2055d0, 0x3c010001, -0xac20559c, 0x3c010001, 0xac2055c4, 0x3c010001, 0xac2055b8, 0x3c010001, -0xac2055b0, 0xaf800224, 0x3c010001, 0xac225590, 0xc003ab1, 0x0, -0xaf800204, 0x8f820200, 0x2403fffd, 0x431024, 0xaf820200, 0x3c010001, -0xac2055e0, 0x8f830054, 0x3c020001, 0x8c4255b8, 0x24040001, 0x3c010001, -0xac2455cc, 0x24420001, 0x3c010001, 0xac2255b8, 0x2c420004, 0x3c010001, -0xac2355b4, 0x14400006, 0x24020003, 0x3c010001, 0xac243410, 0x3c010001, -0x10000148, 0xac2055b8, 0x3c010001, 0x10000145, 0xac225590, 0x8f830054, -0x3c020001, 0x8c4255b4, 0x2463d8f0, 0x431023, 0x2c422710, 0x1440013d, -0x24020004, 0x3c010001, 0x1000013a, 0xac225590, 0x3c040001, 0x8c84352c, -0x3c010001, 0xc00464e, 0xac2055a8, 0x3c020001, 0x8c4255dc, 0xaf820204, -0x8f820204, 0x30420030, 0x14400125, 0x24020002, 0x3c030001, 0x8c6355dc, -0x24020005, 0x3c010001, 0xac225590, 0x3c010001, 0x10000126, 0xac2355e0, -0x3c020001, 0x8c4255c0, 0x10400122, 0x0, 0x3c020001, 0x8c42559c, -0x1040011e, 0x0, 0x3c010001, 0xac2255c8, 0x24020003, 0x3c010001, -0xac2255a0, 0x100000c1, 0x24020006, 0x3c010001, 0xac2055a8, 0x8f820204, -0x34420040, 0xaf820204, 0x3c020001, 0x8c4255e0, 0x24030007, 0x3c010001, -0xac235590, 0x34420040, 0x3c010001, 0xac2255e0, 0x3c020001, 0x8c4255c0, -0x10400005, 0x0, 0x3c020001, 0x8c42559c, 0x104000f9, 0x24020002, -0x3c050001, 0x24a555a0, 0x8ca20000, 0x2c424e21, 0x104000f3, 0x24020002, -0x3c020001, 0x8c4255c4, 0x104000f8, 0x2404ffbf, 0x3c020001, 0x8c42559c, -0x3c030001, 0x8c6355c8, 0x441024, 0x641824, 0x14430007, 0x24020001, -0x24020003, 0xaca20000, 0x24020008, 0x3c010001, 0x100000ea, 0xac225590, -0x3c010001, 0x100000e7, 0xac225590, 0x3c020001, 0x8c4255cc, 0x1040000c, -0x24020001, 0x3c040001, 0xc00465b, 0x8c84559c, 0x3c020001, 0x8c4255e8, -0x14400005, 0x24020001, 0x3c020001, 0x8c4255e4, 0x10400006, 0x24020001, -0x3c010001, 0xac223410, 0x3c010001, 0x100000d3, 0xac2055b8, 0x8f820204, -0x34420040, 0xaf820204, 0x3c020001, 0x8c4255e0, 0x3c030001, 0x8c6355b0, -0x34420040, 0x3c010001, 0xac2255e0, 0x3c020001, 0x8c42559c, 0x2c630001, -0x318c0, 0x3c010001, 0xac2355b0, 0x30420008, 0x3c010001, 0xac2255ac, -0x8f830054, 0x24020009, 0x3c010001, 0xac225590, 0x3c010001, 0x100000b9, -0xac2355b4, 0x8f830054, 0x3c020001, 0x8c4255b4, 0x2463d8f0, 0x431023, -0x2c422710, 0x1440009f, 0x0, 0x3c020001, 0x8c4255c0, 0x10400005, -0x0, 0x3c020001, 0x8c42559c, 0x104000a0, 0x24020002, 0x3c030001, -0x246355a0, 0x8c620000, 0x2c424e21, 0x1040009a, 0x24020002, 0x3c020001, -0x8c4255cc, 0x1040000e, 0x0, 0x3c020001, 0x8c42559c, 0x3c010001, -0xac2055cc, 0x30420080, 0x1040002f, 0x2402000c, 0x8f820204, 0x30420080, -0x1440000c, 0x24020003, 0x10000029, 0x2402000c, 0x3c020001, 0x8c42559c, -0x30420080, 0x14400005, 0x24020003, 0x8f820204, 0x30420080, 0x1040001f, -0x24020003, 0xac620000, 0x2402000a, 0x3c010001, 0xac225590, 0x3c040001, -0x248455d8, 0x8c820000, 0x3c030001, 0x8c6355b0, 0x431025, 0xaf820204, -0x8c830000, 0x3c040001, 0x8c8455b0, 0x2402000b, 0x3c010001, 0xac225590, -0x641825, 0x3c010001, 0xac2355e0, 0x3c050001, 0x24a555a0, 0x8ca20000, -0x2c424e21, 0x10400066, 0x24020002, 0x3c020001, 0x8c4255d0, 0x10400005, -0x0, 0x2402000c, 0x3c010001, 0x10000067, 0xac225590, 0x3c020001, -0x8c4255c0, 0x10400063, 0x0, 0x3c040001, 0x8c84559c, 0x10800055, -0x30820008, 0x3c030001, 0x8c6355ac, 0x1062005b, 0x24020003, 0x3c010001, -0xac2455c8, 0xaca20000, 0x24020006, 0x3c010001, 0x10000054, 0xac225590, -0x8f820200, 0x34420002, 0xaf820200, 0x8f830054, 0x2402000d, 0x3c010001, -0xac225590, 0x3c010001, 0xac2355b4, 0x8f830054, 0x3c020001, 0x8c4255b4, -0x2463d8f0, 0x431023, 0x2c422710, 0x14400031, 0x0, 0x3c020001, -0x8c4255d0, 0x10400020, 0x2402000e, 0x3c030001, 0x8c6355e4, 0x3c010001, -0x14600015, 0xac225590, 0xc003b6a, 0x0, 0x3c050001, 0x8ca5340c, -0xc0047d1, 0x24040001, 0x3c030001, 0x8c63340c, 0x24020004, 0x14620005, -0x2403fffb, 0x3c020001, 0x8c423408, 0x10000003, 0x2403fff7, 0x3c020001, -0x8c423408, 0x431024, 0x3c010001, 0xac223408, 0x8f830224, 0x3c020200, -0x3c010001, 0xac2355ec, 0x10000020, 0x282a025, 0x3c020001, 0x8c4255c0, -0x10400005, 0x0, 0x3c020001, 0x8c42559c, 0x1040000f, 0x24020002, -0x3c020001, 0x8c4255a0, 0x2c424e21, 0x1040000a, 0x24020002, 0x3c020001, -0x8c4255c0, 0x1040000f, 0x0, 0x3c020001, 0x8c42559c, 0x1440000b, -0x0, 0x24020002, 0x3c010001, 0x10000007, 0xac225590, 0x3c020001, -0x8c4255c0, 0x10400003, 0x0, 0xc003ab1, 0x0, 0x8f820220, -0x3c03f700, 0x431025, 0xaf820220, 0x8fbf0010, 0x3e00008, 0x27bd0018, -0x3c030001, 0x246355e8, 0x8c620000, 0x10400005, 0x34422000, 0x3c010001, -0xac2255dc, 0x10000003, 0xac600000, 0x3c010001, 0xac2455dc, 0x3e00008, -0x0, 0x27bdffe0, 0x30820030, 0xafbf0018, 0x3c010001, 0xac2255e4, -0x14400067, 0x3c02ffff, 0x34421f0e, 0x821024, 0x14400061, 0x24020030, -0x30822000, 0x1040005d, 0x30838000, 0x31a02, 0x30820001, 0x21200, -0x3c040001, 0x8c84352c, 0x621825, 0x331c2, 0x3c030001, 0x2463348c, -0x30828000, 0x21202, 0x30840001, 0x42200, 0x441025, 0x239c2, -0x61080, 0x431021, 0x471021, 0x90430000, 0x24020001, 0x10620025, -0x0, 0x10600007, 0x24020002, 0x10620013, 0x24020003, 0x1062002c, -0x3c05000f, 0x10000037, 0x0, 0x8f820200, 0x2403feff, 0x431024, -0xaf820200, 0x8f820220, 0x3c03fffe, 0x3463ffff, 0x431024, 0xaf820220, -0x3c010001, 0xac205624, 0x3c010001, 0x10000034, 0xac20562c, 0x8f820200, -0x34420100, 0xaf820200, 0x8f820220, 0x3c03fffe, 0x3463ffff, 0x431024, -0xaf820220, 0x24020100, 0x3c010001, 0xac225624, 0x3c010001, 0x10000026, -0xac20562c, 0x8f820200, 0x2403feff, 0x431024, 0xaf820200, 0x8f820220, -0x3c030001, 0x431025, 0xaf820220, 0x3c010001, 0xac205624, 0x3c010001, -0x10000019, 0xac23562c, 0x8f820200, 0x34420100, 0xaf820200, 0x8f820220, -0x3c030001, 0x431025, 0xaf820220, 0x24020100, 0x3c010001, 0xac225624, -0x3c010001, 0x1000000c, 0xac23562c, 0x34a5ffff, 0x3c040001, 0x248432e8, -0xafa30010, 0xc00290f, 0xafa00014, 0x10000004, 0x0, 0x24020030, -0x3c010001, 0xac2255e8, 0x8fbf0018, 0x3e00008, 0x27bd0020, 0x0, -0x27bdffc8, 0xafb30024, 0x809821, 0xafbe002c, 0xa0f021, 0xafb10020, -0xc08821, 0x3c040001, 0x24843300, 0x3c050009, 0x3c020001, 0x8c42340c, -0x34a59001, 0x2603021, 0x3c03821, 0xafbf0030, 0xafb50028, 0xa7a0001a, -0xafb10014, 0xc00290f, 0xafa20010, 0x24020002, 0x13c200e7, 0x2fc20003, -0x10400005, 0x24020001, 0x13c2000a, 0x3c02fffb, 0x100000e1, 0x0, -0x24020004, 0x13c2006d, 0x24020008, 0x13c2006c, 0x3c02ffec, 0x100000da, -0x0, 0x3442ffff, 0x2228824, 0x13a940, 0x3c010001, 0x350821, -0xac3155fc, 0x3c024000, 0x2221024, 0x10400046, 0x1123c2, 0x30840030, -0x111382, 0x3042000c, 0x3c030001, 0x24633434, 0x431021, 0x823821, -0x3c020020, 0x2221024, 0x10400006, 0x24020100, 0x3c010001, 0x350821, -0xac225600, 0x10000005, 0x3c020080, 0x3c010001, 0x350821, 0xac205600, -0x3c020080, 0x2221024, 0x10400006, 0x131940, 0x3c020001, 0x3c010001, -0x230821, 0x10000005, 0xac225608, 0x131140, 0x3c010001, 0x220821, -0xac205608, 0x94e30000, 0x32224000, 0x10400003, 0xa7a30018, 0x34624000, -0xa7a20018, 0x24040001, 0x94e20002, 0x24050004, 0x24e60002, 0x34420001, -0xc004076, 0xa4e20002, 0x24040001, 0x2821, 0xc004076, 0x27a60018, -0x3c020001, 0x8c42340c, 0x24130001, 0x3c010001, 0xac333418, 0x145e0004, -0x32228000, 0xc003ab1, 0x0, 0x32228000, 0x10400093, 0x0, -0xc003ab1, 0x0, 0x24020002, 0x3c010001, 0xac333410, 0x3c010001, -0x1000008b, 0xac22340c, 0x24040001, 0x24050004, 0x27b1001a, 0xc004076, -0x2203021, 0x24040001, 0x2821, 0xc004076, 0x2203021, 0x3c020001, -0x551021, 0x8c4255f4, 0x3c040001, 0x8c84340c, 0x3c03bfff, 0x3463ffff, -0x3c010001, 0xac3e3418, 0x431024, 0x3c010001, 0x350821, 0x109e0072, -0xac2255f4, 0x10000072, 0x0, 0x3c02ffec, 0x3442ffff, 0x2228824, -0x3c020008, 0x2228825, 0x131140, 0x3c010001, 0x220821, 0xac3155f8, -0x3c022000, 0x2221024, 0x10400005, 0x24020001, 0x3c010001, 0xac223528, -0x10000004, 0x3c024000, 0x3c010001, 0xac203528, 0x3c024000, 0x2221024, -0x1440001a, 0x0, 0x3c020001, 0x8c423528, 0x10400005, 0x24022020, -0x3c010001, 0xac22352c, 0x24020001, 0xaee279c8, 0x3c04bfff, 0x131940, -0x3c020001, 0x431021, 0x8c4255f0, 0x3c050001, 0x8ca5340c, 0x3484ffff, -0x441024, 0x3c010001, 0x230821, 0xac2255f0, 0x24020001, 0x10a20044, -0x0, 0x10000040, 0x0, 0x3c020001, 0x8c423528, 0x1040001c, -0x24022000, 0x3c010001, 0xac22352c, 0x3c0300a0, 0x2231024, 0x14430005, -0x131140, 0x3402a000, 0x3c010001, 0x1000002d, 0xac22352c, 0x3c030001, -0x621821, 0x8c6355f8, 0x3c020020, 0x621024, 0x10400004, 0x24022001, -0x3c010001, 0x10000023, 0xac22352c, 0x3c020080, 0x621024, 0x1040001f, -0x3402a001, 0x3c010001, 0x1000001c, 0xac22352c, 0x3c020020, 0x2221024, -0x10400007, 0x131940, 0x24020100, 0x3c010001, 0x230821, 0xac225604, -0x10000006, 0x3c020080, 0x131140, 0x3c010001, 0x220821, 0xac205604, -0x3c020080, 0x2221024, 0x10400006, 0x131940, 0x3c020001, 0x3c010001, -0x230821, 0x10000005, 0xac22560c, 0x131140, 0x3c010001, 0x220821, -0xac20560c, 0x3c030001, 0x8c63340c, 0x24020001, 0x10620003, 0x0, -0xc003ab1, 0x0, 0x8fbf0030, 0x8fbe002c, 0x8fb50028, 0x8fb30024, -0x8fb10020, 0x3e00008, 0x27bd0038, 0x27bdffc8, 0xafb50028, 0xa821, -0xafbe002c, 0xf021, 0xafb30024, 0x9821, 0x24020002, 0xafbf0030, -0xafb10020, 0xafa4001c, 0xa7a00012, 0x10a2006a, 0xa7a00010, 0x2ca20003, -0x10400005, 0x24020001, 0x10a2000a, 0x3c024000, 0x100000ad, 0x2601021, -0x24020004, 0x10a20060, 0x24020008, 0x10a2005e, 0x2601021, 0x100000a6, -0x0, 0x8fa7001c, 0x78940, 0x3c030001, 0x711821, 0x8c6355fc, -0x621024, 0x14400009, 0x24040001, 0x3c027fff, 0x3442ffff, 0x629824, -0x3c010001, 0x310821, 0xac3355f4, 0x10000096, 0x2601021, 0x24050001, -0xc004034, 0x27a60010, 0x24040001, 0x24050001, 0xc004034, 0x27a60010, -0x97a20010, 0x30420004, 0x10400034, 0x3c134000, 0x3c030001, 0x8c63353c, -0x24020003, 0x10620008, 0x2c620004, 0x14400029, 0x3c028000, 0x24020004, -0x10620014, 0x24040001, 0x10000024, 0x3c028000, 0x24040001, 0x24050011, -0x27b10012, 0xc004034, 0x2203021, 0x24040001, 0x24050011, 0xc004034, -0x2203021, 0x97a30012, 0x30624000, 0x10400002, 0x3c1e0010, 0x3c1e0008, -0x3c150001, 0x10000010, 0x30628000, 0x24050014, 0x27b10012, 0xc004034, -0x2203021, 0x24040001, 0x24050014, 0xc004034, 0x2203021, 0x97a30012, -0x30621000, 0x10400002, 0x3c1e0010, 0x3c1e0008, 0x3c150001, 0x30620800, -0x54400001, 0x3c150002, 0x3c028000, 0x2621025, 0x2be1825, 0x10000007, -0x439825, 0x3c130001, 0x2719821, 0x8e7355fc, 0x3c027fff, 0x3442ffff, -0x2629824, 0x8fa7001c, 0x71140, 0x3c010001, 0x220821, 0xac3355f4, -0x1000004b, 0x2601021, 0x8fa7001c, 0x72140, 0x3c030001, 0x641821, -0x8c6355f8, 0x3c024000, 0x621024, 0x14400008, 0x3c027fff, 0x3442ffff, -0x629824, 0x3c010001, 0x240821, 0xac3355f0, 0x1000003b, 0x2601021, -0x3c020001, 0x8c42341c, 0x1040002e, 0x3c13c00c, 0x3c020001, 0x8c423528, -0x3c03e00c, 0x3c010001, 0x240821, 0x8c245604, 0x2102b, 0x21023, -0x431024, 0x10800004, 0x539825, 0x3c020020, 0x10000004, 0x2629825, -0x3c02ffdf, 0x3442ffff, 0x2629824, 0x8fa7001c, 0x71140, 0x3c010001, -0x220821, 0x8c22560c, 0x10400003, 0x3c020080, 0x10000004, 0x2629825, -0x3c02ff7f, 0x3442ffff, 0x2629824, 0x3c020001, 0x8c423480, 0x10400002, -0x3c020800, 0x2629825, 0x3c020001, 0x8c423484, 0x10400002, 0x3c020400, -0x2629825, 0x3c020001, 0x8c423488, 0x10400006, 0x3c020100, 0x10000004, -0x2629825, 0x3c027fff, 0x3442ffff, 0x629824, 0x8fa7001c, 0x71140, -0x3c010001, 0x220821, 0xac3355f0, 0x2601021, 0x8fbf0030, 0x8fbe002c, -0x8fb50028, 0x8fb30024, 0x8fb10020, 0x3e00008, 0x27bd0038, 0x27bdffe0, -0xafb50018, 0x80a821, 0xafbf001c, 0xafb30014, 0xafb10010, 0x8f840200, -0x3c030001, 0x8c63340c, 0x8f860220, 0x24020002, 0x106200a3, 0x2c620003, -0x10400005, 0x24020001, 0x1062000a, 0x151940, 0x1000009d, 0x0, -0x24020004, 0x10620053, 0x24020008, 0x10620052, 0x159940, 0x10000096, -0x0, 0x3c050001, 0xa32821, 0x8ca555fc, 0x3c110001, 0x2238821, -0x8e3155f4, 0x3c024000, 0xa21024, 0x10400038, 0x3c020008, 0x2221024, -0x10400020, 0x34840002, 0x3c020001, 0x431021, 0x8c425600, 0x10400005, -0x34840020, 0x34840100, 0x3c020020, 0x10000006, 0x2228825, 0x2402feff, -0x822024, 0x3c02ffdf, 0x3442ffff, 0x2228824, 0x151140, 0x3c010001, -0x220821, 0x8c225608, 0x10400005, 0x3c020001, 0xc23025, 0x3c020080, -0x10000016, 0x2228825, 0x3c02fffe, 0x3442ffff, 0xc23024, 0x3c02ff7f, -0x3442ffff, 0x1000000f, 0x2228824, 0x2402fedf, 0x822024, 0x3c02fffe, -0x3442ffff, 0xc23024, 0x3c02ff5f, 0x3442ffff, 0x2228824, 0x3c010001, -0x230821, 0xac205600, 0x3c010001, 0x230821, 0xac205608, 0xaf840200, -0xaf860220, 0x8f820220, 0x34420002, 0xaf820220, 0x1000000a, 0x151140, -0x3c02bfff, 0x3442ffff, 0x8f830200, 0x2228824, 0x2402fffd, 0x621824, -0xc003ab1, 0xaf830200, 0x151140, 0x3c010001, 0x220821, 0x10000048, -0xac3155f4, 0x159940, 0x3c050001, 0xb32821, 0x8ca555f8, 0x3c110001, -0x2338821, 0x8e3155f0, 0x3c024000, 0xa21024, 0x14400010, 0x0, -0x3c020001, 0x8c423528, 0x14400005, 0x3c02bfff, 0x8f820200, 0x34420002, -0xaf820200, 0x3c02bfff, 0x3442ffff, 0xc003ab1, 0x2228824, 0x3c010001, -0x330821, 0x1000002e, 0xac3155f0, 0x3c020001, 0x8c423528, 0x14400027, -0x151140, 0x3c020020, 0xa21024, 0x10400007, 0x34840020, 0x24020100, -0x3c010001, 0x330821, 0xac225604, 0x10000006, 0x34840100, 0x3c010001, -0x330821, 0xac205604, 0x2402feff, 0x822024, 0x3c020080, 0xa21024, -0x10400007, 0x151940, 0x3c020001, 0x3c010001, 0x230821, 0xac22560c, -0x10000008, 0xc23025, 0x151140, 0x3c010001, 0x220821, 0xac20560c, -0x3c02fffe, 0x3442ffff, 0xc23024, 0xaf840200, 0xaf860220, 0x8f820220, -0x34420002, 0xaf820220, 0x151140, 0x3c010001, 0x220821, 0xac3155f0, -0x8fbf001c, 0x8fb50018, 0x8fb30014, 0x8fb10010, 0x3e00008, 0x27bd0020, -0x0, 0x0, 0x1821, 0x308400ff, 0x2405ffdf, 0x2406ffbf, -0x641007, 0x30420001, 0x10400004, 0x0, 0x8f820044, 0x10000003, -0x34420040, 0x8f820044, 0x461024, 0xaf820044, 0x8f820044, 0x34420020, -0xaf820044, 0x8f820044, 0x451024, 0xaf820044, 0x24630001, 0x28620008, -0x5440ffee, 0x641007, 0x3e00008, 0x0, 0x0, 0x0, -0x0 }; -u32 tigon2FwData[(MAX_DATA_LEN/4) + 1] __initdata = { -0x1, 0x1, 0x1, 0xc001fc, 0x3ffc, 0xc00000, -0x416c7465, 0x6f6e2041, 0x63654e49, 0x43205600, 0x0, 0x0, -0x416c7465, 0x6f6e2041, 0x63654e49, 0x43205600, 0x42424242, 0x0, -0x0, 0x0, 0x1ffffc, 0x1fff7c, 0x0, 0x0, -0x1, 0x0, 0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x60cf00, 0x60, 0xcf000000, 0x0, -0x0, 0x0, 0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x3, 0x0, 0x1, 0x0, -0x0, 0x0, 0x0, 0x0, 0x1, 0x0, -0x0, 0x0, 0x0, 0x0, 0x1000000, 0x21000000, -0x12000140, 0x0, 0x0, 0x20000000, 0x120000a0, 0x0, -0x12000060, 0x12000180, 0x120001e0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, 0x30001, 0x1, -0x30201, 0x0, 0x0 }; +0x0, +0x10000003, 0x0, 0xd, 0xd, +0x3c1d0001, 0x8fbd3ca0, 0x3a0f021, 0x3c100000, +0x26104000, 0xc0010c0, 0x0, 0xd, +0x3c1d0001, 0x8fbd3ca4, 0x3a0f021, 0x3c100000, +0x26104000, 0xc00178d, 0x0, 0xd, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x2000008, +0x0, 0x80016de, 0x3c0a0001, 0x80016de, +0x3c0a0002, 0x80016de, 0x0, 0x8002acd, +0x0, 0x8002a70, 0x0, 0x80016de, +0x3c0a0004, 0x8003095, 0x0, 0x8001a0e, +0x0, 0x800373f, 0x0, 0x80036e6, +0x0, 0x80016de, 0x3c0a0006, 0x80037ad, +0x3c0a0007, 0x80016de, 0x3c0a0008, 0x80016de, +0x3c0a0009, 0x8003805, 0x0, 0x8002cc0, +0x0, 0x80016de, 0x3c0a000b, 0x80016de, +0x3c0a000c, 0x80016de, 0x3c0a000d, 0x80027ac, +0x0, 0x800275a, 0x0, 0x80016de, +0x3c0a000e, 0x8001f28, 0x0, 0x8001920, +0x0, 0x80019c0, 0x0, 0x8003a70, +0x0, 0x8003a5e, 0x0, 0x80016de, +0x0, 0x80018c6, 0x0, 0x80016de, +0x0, 0x80016de, 0x3c0a0013, 0x80016de, +0x3c0a0014, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x27bdffe0, +0x3c1cc000, 0xafbf001c, 0xafb00018, 0x8f820140, +0x24030003, 0xaf8300ec, 0x34420004, 0xc0029b8, +0xaf820140, 0x3c0100c0, 0xc001712, 0xac203ffc, +0x403021, 0x3c020008, 0x3c010001, 0xac263dd8, +0x50c2000d, 0x3c020003, 0x3c100010, 0x10d00009, +0x24050100, 0x3c040001, 0x24842d34, 0x3821, +0xafa00010, 0xc0029d3, 0xafa00014, 0x3c010001, +0xac303dd8, 0x3c020003, 0x34422000, 0x3c010001, +0xac223de8, 0x24020008, 0x3c010001, 0xac223df0, +0x2402001f, 0x3c010001, 0xac223e00, 0x24020016, +0x3c010001, 0xac223dd4, 0x3c05fffe, 0x34a56f08, +0x3c020001, 0x8c423dd8, 0x3c030001, 0x24635f40, +0x3c040001, 0x8c843c54, 0x431023, 0x14800002, +0x458021, 0x2610fa48, 0x2402f000, 0x2028024, +0xc001734, 0x2002021, 0x2022823, 0x3c040020, +0x821823, 0x651823, 0x247bb000, 0x3c03fffe, +0x3463bf08, 0x363b821, 0x3c0600bf, 0x34c6f000, +0x3c070001, 0x8ce73c50, 0x3c0300bf, 0x3463e000, +0x852023, 0x3c010001, 0xac243de4, 0x822023, +0x3c010001, 0xac223dc0, 0x27620ffc, 0x3c010001, +0xac223ca0, 0x27621ffc, 0xdb3023, 0x7b1823, +0x3c010001, 0xac253dcc, 0x3c010001, 0xac243dc4, +0x3c010001, 0xac223ca4, 0xaf860150, 0x10e00011, +0xaf830250, 0x3c1d0001, 0x8fbd3c5c, 0x3a0f021, +0xc0016f8, 0x0, 0x3c020001, 0x8c423c60, +0x3c030001, 0x8c633c64, 0x2442fe00, 0x24630200, +0x3c010001, 0xac223c60, 0x3c010001, 0x10000004, +0xac233c64, 0x3c1d0001, 0x8fbd3ca0, 0x3a0f021, +0x3c020001, 0x8c423c54, 0x1040000d, 0x26fafa48, +0x3c020001, 0x8c423c60, 0x3c030001, 0x8c633c64, +0x3c1a0001, 0x8f5a3c64, 0x2442fa48, 0x246305b8, +0x3c010001, 0xac223c60, 0x3c010001, 0xac233c64, +0x3c020001, 0x8c423c58, 0x14400003, 0x0, +0x3c010001, 0xac203c60, 0xc00114d, 0x0, +0x8fbf001c, 0x8fb00018, 0x3e00008, 0x27bd0020, +0x3c020001, 0x8c423c60, 0x3c030001, 0x8c633c64, +0x27bdffa0, 0xafb00040, 0x3c100001, 0x8e1036f4, +0x3c040001, 0x24842d40, 0xafbf0058, 0xafbe0054, +0xafb50050, 0xafb3004c, 0xafb20048, 0xafb10044, +0xafa20034, 0xafa30030, 0xafa00010, 0xafa00014, +0x8f860040, 0x24050200, 0xc0029d3, 0x2003821, +0x8f830040, 0x3c02f000, 0x621824, 0x3c026000, +0x1062000b, 0xa3a0003f, 0x240e0001, 0x3c040001, +0x24842d48, 0xa3ae003f, 0xafa00010, 0xafa00014, +0x8f860040, 0x24050300, 0xc0029d3, 0x2003821, +0x8f820240, 0x3c030001, 0x431025, 0xaf820240, +0xaf800048, 0x8f820048, 0x14400005, 0x0, +0xaf800048, 0x8f820048, 0x10400004, 0x0, +0xaf800048, 0x10000003, 0x2e02021, 0xaf80004c, +0x2e02021, 0x3c050001, 0xc002a40, 0x34a540f8, +0x3402021, 0xc002a40, 0x240505b8, 0x3c020001, +0x8c423de4, 0x3c0d0001, 0x8dad3dc4, 0x3c030001, +0x8c633dc0, 0x3c080001, 0x8d083dcc, 0x3c090001, +0x8d293de8, 0x3c0a0001, 0x8d4a3df0, 0x3c0b0001, +0x8d6b3e00, 0x3c0c0001, 0x8d8c3dd4, 0x3c040001, +0x24842d54, 0x24050400, 0xaf420130, 0x8f420130, +0x24060001, 0x24070001, 0xaf400000, 0xaf4d012c, +0xaf430138, 0xaf48013c, 0xaf490140, 0xaf4a0144, +0xaf4b0148, 0xaf4c014c, 0x2442ff80, 0xaf420134, +0x24020001, 0xafa20010, 0xc0029d3, 0xafa00014, +0x8f42012c, 0xafa20010, 0x8f420130, 0xafa20014, +0x8f460138, 0x8f47013c, 0x3c040001, 0x24842d60, +0xc0029d3, 0x24050500, 0xafb70010, 0xafba0014, +0x8f460140, 0x8f470144, 0x3c040001, 0x24842d6c, +0xc0029d3, 0x24050600, 0x3c020001, 0x8c423dd8, +0x3603821, 0x3c060001, 0x24c65f40, 0x2448ffff, +0x1061824, 0xe81024, 0x43102b, 0x10400006, +0x24050900, 0x3c040001, 0x24842d78, 0xafa80010, +0xc0029d3, 0xafa00014, 0x8f82000c, 0xafa20010, +0x8f82003c, 0xafa20014, 0x8f860000, 0x8f870004, +0x3c040001, 0x24842d84, 0xc0029d3, 0x24051000, +0x8c020220, 0x8c030224, 0x8c060218, 0x8c07021c, +0x3c040001, 0x24842d8c, 0x24051100, 0xafa20010, +0xc0029d3, 0xafa30014, 0xaf800054, 0xaf80011c, +0x8c020218, 0x30420002, 0x10400009, 0x0, +0x8c020220, 0x3c030002, 0x34630004, 0x431025, +0xaf42000c, 0x8c02021c, 0x10000008, 0x34420004, +0x8c020220, 0x3c030002, 0x34630006, 0x431025, +0xaf42000c, 0x8c02021c, 0x34420006, 0xaf420014, +0x8c020218, 0x30420010, 0x1040000a, 0x0, +0x8c02021c, 0x34420004, 0xaf420010, 0x8c020220, +0x3c03000a, 0x34630004, 0x431025, 0x10000009, +0xaf420008, 0x8c020220, 0x3c03000a, 0x34630006, +0x431025, 0xaf420008, 0x8c02021c, 0x34420006, +0xaf420010, 0x24020001, 0xaf8200a0, 0xaf8200b0, +0x8f830054, 0x8f820054, 0x10000002, 0x24630064, +0x8f820054, 0x621023, 0x2c420065, 0x1440fffc, +0x0, 0x8c040208, 0x8c05020c, 0x26e20028, +0xaee20020, 0x24020490, 0xaee20010, 0xaee40008, +0xaee5000c, 0x26e40008, 0x8c820000, 0x8c830004, +0xaf820090, 0xaf830094, 0x8c820018, 0xaf8200b4, +0x9482000a, 0xaf82009c, 0x8f8200b0, 0x8f430014, +0x431025, 0xaf8200b0, 0x8f8200b0, 0x30420004, +0x1440fffd, 0x24051200, 0x96e20472, 0x96e60452, +0x96e70462, 0xafa20010, 0x96e20482, 0x3c040001, +0x24842d94, 0xc0029d3, 0xafa20014, 0x96f00452, +0x32020001, 0x10400002, 0xb021, 0x24160001, +0x32020002, 0x54400001, 0x36d60002, 0x32020008, +0x54400001, 0x36d60004, 0x32020010, 0x54400001, +0x36d60008, 0x32020020, 0x54400001, 0x36d60010, +0x32020040, 0x54400001, 0x36d60020, 0x32020080, +0x54400001, 0x36d60040, 0x96e60482, 0x30c20200, +0x54400001, 0x36d64000, 0x96e30472, 0x30620200, +0x10400003, 0x30620100, 0x10000003, 0x36d62000, +0x54400001, 0x36d61000, 0x96f00462, 0x32c24000, +0x14400004, 0x3207009b, 0x30c2009b, 0x14e20007, +0x240e0001, 0x32c22000, 0x1440000d, 0x32020001, +0x3062009b, 0x10e20009, 0x240e0001, 0x3c040001, +0x24842da0, 0x24051300, 0x2003821, 0xa3ae003f, +0xafa30010, 0xc0029d3, 0xafa00014, 0x32020001, +0x54400001, 0x36d60080, 0x32020002, 0x54400001, +0x36d60100, 0x32020008, 0x54400001, 0x36d60200, +0x32020010, 0x54400001, 0x36d60400, 0x32020080, +0x54400001, 0x36d60800, 0x8c020218, 0x30420200, +0x10400002, 0x3c020008, 0x2c2b025, 0x8c020218, +0x30420800, 0x10400002, 0x3c020080, 0x2c2b025, +0x8c020218, 0x30420400, 0x10400002, 0x3c020100, +0x2c2b025, 0x8c020218, 0x30420100, 0x10400002, +0x3c020200, 0x2c2b025, 0x8c020218, 0x30420080, +0x10400002, 0x3c020400, 0x2c2b025, 0x8c020218, +0x30422000, 0x10400002, 0x3c020010, 0x2c2b025, +0x8c020218, 0x30424000, 0x10400002, 0x3c020020, +0x2c2b025, 0x8c020218, 0x30421000, 0x10400002, +0x3c020040, 0x2c2b025, 0x8ee20498, 0x8ee3049c, +0xaf420150, 0xaf430154, 0x8ee204a0, 0x8ee304a4, +0xaf420158, 0xaf43015c, 0x8ee204a8, 0x8ee304ac, +0xaf420160, 0xaf430164, 0x8ee20428, 0x8ee3042c, +0xaf420168, 0xaf43016c, 0x8ee20448, 0x8ee3044c, +0xaf420170, 0xaf430174, 0x8ee20458, 0x8ee3045c, +0xaf420178, 0xaf43017c, 0x8ee20468, 0x8ee3046c, +0xaf420180, 0xaf430184, 0x8ee20478, 0x8ee3047c, +0xaf420188, 0xaf43018c, 0x8ee20488, 0x8ee3048c, +0xaf420190, 0xaf430194, 0x8ee204b0, 0x8ee304b4, +0x24040080, 0xaf420198, 0xaf43019c, 0xc002a40, +0x24050080, 0x8c02025c, 0x27440214, 0xaf4201e0, +0x8c020260, 0x24050200, 0x24060008, 0xc002a57, +0xaf4201e8, 0x3c043b9a, 0x3484ca00, 0x3821, +0x24020006, 0x24030002, 0xaf4201e4, 0x240203e8, +0xaf4301f4, 0xaf4301f0, 0xaf4401ec, 0xaf420284, +0x24020001, 0xaf430280, 0xaf42028c, 0x3c030001, +0x671821, 0x90633c68, 0x3471021, 0x24e70001, +0xa043021c, 0x2ce2000f, 0x1440fff8, 0x3471821, +0x24e70001, 0x3c080001, 0x350840f8, 0x8f820040, +0x3c040001, 0x24842dac, 0x24051400, 0x21702, +0x24420030, 0xa062021c, 0x3471021, 0xa040021c, +0x8c070218, 0x2c03021, 0x240205b8, 0xafa20010, +0xc0029d3, 0xafa80014, 0x3c040001, 0x24842db8, +0x3c050000, 0x24a55b3c, 0x24060010, 0x27b10030, +0x2203821, 0x27b30034, 0xc001750, 0xafb30010, +0x3c030001, 0x8c633c58, 0x1060000a, 0x408021, +0x8fa30030, 0x2405ff00, 0x8fa20034, 0x246400ff, +0x852024, 0x831823, 0x431023, 0xafa20034, +0xafa40030, 0xafb30010, 0x3c040001, 0x24842dc4, +0x3c050000, 0x24a54100, 0x24060108, 0xc001750, +0x2203821, 0x409021, 0x32c20003, 0x50400045, +0x2203821, 0x8f820050, 0x3c030010, 0x431024, +0x10400016, 0x0, 0x8c020218, 0x30420040, +0x1040000f, 0x24020001, 0x8f820050, 0x8c030218, +0x240e0001, 0x3c040001, 0x24842dd0, 0xa3ae003f, +0xafa20010, 0xafa30014, 0x8f870040, 0x24051500, +0xc0029d3, 0x2c03021, 0x10000004, 0x0, +0x3c010001, 0x370821, 0xa02240f4, 0x3c040001, +0x24842ddc, 0x3c050001, 0x24a59ce8, 0x3c060001, +0x24c69d60, 0xc53023, 0x8f420010, 0x27b30030, +0x2603821, 0x27b10034, 0x34420a00, 0xaf420010, +0xc001750, 0xafb10010, 0x3c040001, 0x24842df0, +0x3c050001, 0x24a5af7c, 0x3c060001, 0x24c6b2f8, +0xc53023, 0x2603821, 0xaf420108, 0xc001750, +0xafb10010, 0x3c040001, 0x24842e0c, 0x3c050001, +0x24a5b714, 0x3c060001, 0x24c6c1d4, 0xc53023, +0x2603821, 0x3c010001, 0xac223e30, 0xc001750, +0xafb10010, 0x3c040001, 0x24842e24, 0x10000024, +0x24051600, 0x3c040001, 0x24842e2c, 0x3c050001, +0x24a59bb4, 0x3c060001, 0x24c69ce0, 0xc53023, +0xc001750, 0xafb30010, 0x3c040001, 0x24842e3c, +0x3c050001, 0x24a5ab34, 0x3c060001, 0x24c6af74, +0xc53023, 0x2203821, 0xaf420108, 0xc001750, +0xafb30010, 0x3c040001, 0x24842e50, 0x3c050001, +0x24a5b300, 0x3c060001, 0x24c6b70c, 0xc53023, +0x2203821, 0x3c010001, 0xac223e30, 0xc001750, +0xafb30010, 0x3c040001, 0x24842e64, 0x24051650, +0x2c03021, 0x3821, 0x3c010001, 0xac223e34, +0xafa00010, 0xc0029d3, 0xafa00014, 0x32c20020, +0x10400021, 0x27a70030, 0x3c040001, 0x24842e70, +0x3c050001, 0x24a5a9c0, 0x3c060001, 0x24c6ab2c, +0xc53023, 0x24022000, 0xaf42001c, 0x27a20034, +0xc001750, 0xafa20010, 0x21900, 0x31982, +0x3c040800, 0x641825, 0xae430028, 0x24030010, +0xaf43003c, 0x96e30450, 0xaf430040, 0x8f430040, +0x3c040001, 0x24842e84, 0xafa00014, 0xafa30010, +0x8f47001c, 0x24051660, 0x3c010001, 0xac223e2c, +0x10000025, 0x32c60020, 0x8ee20448, 0x8ee3044c, +0xaf43001c, 0x8f42001c, 0x2442e000, 0x2c422001, +0x1440000a, 0x240e0001, 0x3c040001, 0x24842e90, +0xa3ae003f, 0xafa00010, 0xafa00014, 0x8f46001c, +0x24051700, 0xc0029d3, 0x3821, 0x3c020000, +0x24425b78, 0x21100, 0x21182, 0x3c030800, +0x431025, 0xae420028, 0x24020008, 0xaf42003c, +0x96e20450, 0xaf420040, 0x8f420040, 0x3c040001, +0x24842e9c, 0xafa00014, 0xafa20010, 0x8f47001c, +0x24051800, 0x32c60020, 0xc0029d3, 0x0, +0x3c030001, 0x8c633e30, 0x3c050fff, 0x34a5ffff, +0x3c020001, 0x8c423e34, 0x3c040800, 0x651824, +0x31882, 0x641825, 0x451024, 0x21082, +0x441025, 0xae420080, 0x32c20180, 0x10400056, +0xae430020, 0x8f82005c, 0x3c030080, 0x431024, +0x1040000d, 0x0, 0x8f820050, 0xafa20010, +0x8f82005c, 0x240e0001, 0x3c040001, 0x24842ea8, +0xa3ae003f, 0xafa20014, 0x8f870040, 0x24051900, +0xc0029d3, 0x2c03021, 0x8f820050, 0x3c030010, +0x431024, 0x10400016, 0x0, 0x8c020218, +0x30420040, 0x1040000f, 0x24020001, 0x8f820050, +0x8c030218, 0x240e0001, 0x3c040001, 0x24842dd0, +0xa3ae003f, 0xafa20010, 0xafa30014, 0x8f870040, +0x24052000, 0xc0029d3, 0x2c03021, 0x10000004, +0x0, 0x3c010001, 0x370821, 0xa02240f4, +0x3c040001, 0x24842eb4, 0x3c050001, 0x24a59b2c, +0x3c060001, 0x24c69bac, 0xc53023, 0x8f420008, +0x27b30030, 0x2603821, 0x27b10034, 0x34420e00, +0xaf420008, 0xc001750, 0xafb10010, 0x3c040001, +0x24842ecc, 0x3c050001, 0x24a5d090, 0x3c060001, +0x24c6db90, 0xc53023, 0x2603821, 0xaf42010c, +0xc001750, 0xafb10010, 0x3c040001, 0x24842ee4, +0x3c050001, 0x24a5e174, 0x3c060001, 0x24c6e860, +0xc53023, 0x2603821, 0x3c010001, 0xac223e40, +0xc001750, 0xafb10010, 0x3c040001, 0x24842efc, +0x10000027, 0x24052100, 0x3c040001, 0x24842f04, +0x3c050001, 0x24a599e8, 0x3c060001, 0x24c69b24, +0xc53023, 0x27b10030, 0x2203821, 0x27b30034, +0xc001750, 0xafb30010, 0x3c040001, 0x24842f14, +0x3c050001, 0x24a5c300, 0x3c060001, 0x24c6d088, +0xc53023, 0x2203821, 0xaf42010c, 0xc001750, +0xafb30010, 0x3c040001, 0x24842f24, 0x3c050001, +0x24a5e014, 0x3c060001, 0x24c6e16c, 0xc53023, +0x2203821, 0x3c010001, 0xac223e40, 0xc001750, +0xafb30010, 0x3c040001, 0x24842f38, 0x24052150, +0x2c03021, 0x3821, 0x3c010001, 0xac223e4c, +0xafa00010, 0xc0029d3, 0xafa00014, 0x3c030001, +0x8c633e40, 0x3c110fff, 0x3631ffff, 0x3c020001, +0x8c423e4c, 0x3c1e0800, 0x711824, 0x31882, +0x7e1825, 0x511024, 0x21082, 0x5e1025, +0xae430038, 0xae420078, 0x8c020218, 0x30420040, +0x14400004, 0x24020001, 0x3c010001, 0x370821, +0xa02240f4, 0x3c040001, 0x24842f44, 0x3c050001, +0x24a5db98, 0x3c060001, 0x24c6dcf4, 0xc53023, +0x27b50030, 0x2a03821, 0x27b30034, 0xc001750, +0xafb30010, 0x3c010001, 0xac223e38, 0x511024, +0x21082, 0x5e1025, 0xae420050, 0x32c22000, +0x10400005, 0x2a03821, 0x3c020000, 0x24425b78, +0x1000000d, 0x511024, 0x3c040001, 0x24842f58, +0x3c050001, 0x24a5dcfc, 0x3c060001, 0x24c6deac, +0xc53023, 0xc001750, 0xafb30010, 0x3c010001, +0xac223e50, 0x511024, 0x21082, 0x5e1025, +0xae420048, 0x32c24000, 0x10400005, 0x27a70030, +0x3c020000, 0x24425b78, 0x1000000e, 0x21100, +0x3c040001, 0x24842f70, 0x3c050001, 0x24a5deb4, +0x3c060001, 0x24c6e00c, 0xc53023, 0x27a20034, +0xc001750, 0xafa20010, 0x3c010001, 0xac223e44, +0x21100, 0x21182, 0x3c030800, 0x431025, +0xae420060, 0x3c040001, 0x24842f88, 0x3c050000, +0x24a57ca0, 0x3c060001, 0x24c680c4, 0xc53023, +0x27b10030, 0x2203821, 0x27b30034, 0xc001750, +0xafb30010, 0x3c1e0fff, 0x37deffff, 0x3c040001, +0x24842f94, 0x3c050000, 0x24a56318, 0x3c060000, +0x24c66478, 0xc53023, 0x2203821, 0x3c010001, +0xac223e18, 0x5e1024, 0x21082, 0x3c150800, +0x551025, 0xae4200b8, 0xc001750, 0xafb30010, +0x3c040001, 0x24842fa0, 0x3c050000, 0x24a56480, +0x3c060000, 0x24c666f8, 0xc53023, 0x2203821, +0x3c010001, 0xac223e0c, 0x5e1024, 0x21082, +0x551025, 0xae4200e8, 0xc001750, 0xafb30010, +0x3c040001, 0x24842fb8, 0x3c050000, 0x24a56700, +0x3c060000, 0x24c66830, 0xc53023, 0x2203821, +0x3c010001, 0xac223e04, 0x5e1024, 0x21082, +0x551025, 0xae4200c0, 0xc001750, 0xafb30010, +0x3c040001, 0x24842fd0, 0x3c050001, 0x24a5f240, +0x3c060001, 0x24c6f318, 0xc53023, 0x2203821, +0x3c010001, 0xac223e10, 0x5e1024, 0x21082, +0x551025, 0xae4200c8, 0xc001750, 0xafb30010, +0x3c040001, 0x24842fdc, 0x3c050001, 0x24a5c1e0, +0x3c060001, 0x24c6c21c, 0xc53023, 0x2203821, +0xaf420110, 0xc001750, 0xafb30010, 0x3c040001, +0x24842fec, 0x3c050001, 0x24a5c224, 0x3c060001, +0x24c6c24c, 0xc53023, 0x2203821, 0xaf420114, +0xc001750, 0xafb30010, 0x3c040001, 0x24842ff8, +0x3c050001, 0x24a5e9c0, 0x3c060001, 0x24c6eeac, +0xc53023, 0x2203821, 0xaf420118, 0xc001750, +0xafb30010, 0x3c010001, 0xac223e54, 0x5e1024, +0x21082, 0x551025, 0xc003d9f, 0xae4200d0, +0xc003a1c, 0x0, 0xc002630, 0x0, +0xac000228, 0xac00022c, 0x96e20450, 0x2442ffff, +0xaf420038, 0x96e20460, 0xaf420080, 0x32c24000, +0x14400003, 0x0, 0x96e20480, 0xaf420084, +0x96e70490, 0x50e00001, 0x24070800, 0x24e2ffff, +0xaf420088, 0xaf42007c, 0x24020800, 0x10e2000f, +0x32c24000, 0x10400003, 0x24020400, 0x10e2000b, +0x0, 0x240e0001, 0x3c040001, 0x24843008, +0xa3ae003f, 0x96e60490, 0x24052170, 0x2c03821, +0xafa00010, 0xc0029d3, 0xafa00014, 0x8f43012c, +0x8f44012c, 0x24020001, 0xa34205b3, 0xaf430094, +0xaf440098, 0xafa00010, 0xafa00014, 0x8f460080, +0x8f470084, 0x3c040001, 0x24843014, 0xc0029d3, +0x24052200, 0xc00232c, 0x3c110800, 0x3c1433d8, +0x3694cb58, 0x3c020800, 0x34420080, 0x3c040001, +0x24843020, 0x3c050000, 0x24a55bbc, 0x3c060000, +0x24c65bd8, 0xc53023, 0x27a70030, 0xaf820060, +0x2402ffff, 0xaf820064, 0x27a20034, 0xc001750, +0xafa20010, 0x3c010001, 0xac223df4, 0x21100, +0x21182, 0x511025, 0xc0018a8, 0xae420000, +0x8f820240, 0x3c030001, 0x431025, 0xaf820240, +0x3c020000, 0x24424034, 0xaf820244, 0xaf800240, +0x8f820060, 0x511024, 0x14400005, 0x3c030800, +0x8f820060, 0x431024, 0x1040fffd, 0x0, +0xc003a29, 0x8821, 0x3c020100, 0xafa20020, +0x8f530018, 0x240200ff, 0x56620001, 0x26710001, +0x8c020228, 0x1622000e, 0x1330c0, 0x8f42032c, +0x24420001, 0xaf42032c, 0x8f42032c, 0x8c020228, +0x3c040001, 0x24842ce4, 0x3c050009, 0xafa00014, +0xafa20010, 0x8fa60020, 0x1000003f, 0x34a50100, +0xd71021, 0x8fa30020, 0x8fa40024, 0xac4304c0, +0xac4404c4, 0xc01821, 0x8f440168, 0x8f45016c, +0x1021, 0x24070004, 0xafa70010, 0xafb10014, +0x8f48000c, 0x24c604c0, 0x2e63021, 0xafa80018, +0x8f48010c, 0x24070008, 0xa32821, 0xa3482b, +0x822021, 0x100f809, 0x892021, 0x1440000b, +0x24070008, 0x8f820120, 0xafa20010, 0x8f820124, +0x3c040001, 0x24842cec, 0x3c050009, 0xafa20014, +0x8fa60020, 0x1000001c, 0x34a50200, 0x8f440150, +0x8f450154, 0x8f43000c, 0xaf510018, 0x8f860120, +0x24020010, 0xafa20010, 0xafb10014, 0xafa30018, +0x8f42010c, 0x40f809, 0x24c6001c, 0x14400010, +0x0, 0x8f420330, 0x24420001, 0xaf420330, +0x8f420330, 0x8f820120, 0xafa20010, 0x8f820124, +0x3c040001, 0x24842cf4, 0x3c050009, 0xafa20014, +0x8fa60020, 0x34a50300, 0xc0029d3, 0x2603821, +0x8f4202d4, 0x24420001, 0xaf4202d4, 0x8f4202d4, +0x93a2003f, 0x10400069, 0x3c020700, 0x34423000, +0xafa20028, 0x8f530018, 0x240200ff, 0x12620002, +0x8821, 0x26710001, 0x8c020228, 0x1622000e, +0x1330c0, 0x8f42032c, 0x24420001, 0xaf42032c, +0x8f42032c, 0x8c020228, 0x3c040001, 0x24842ce4, +0x3c050009, 0xafa00014, 0xafa20010, 0x8fa60028, +0x1000003f, 0x34a50100, 0xd71021, 0x8fa30028, +0x8fa4002c, 0xac4304c0, 0xac4404c4, 0xc01821, +0x8f440168, 0x8f45016c, 0x1021, 0x24070004, +0xafa70010, 0xafb10014, 0x8f48000c, 0x24c604c0, +0x2e63021, 0xafa80018, 0x8f48010c, 0x24070008, +0xa32821, 0xa3482b, 0x822021, 0x100f809, +0x892021, 0x1440000b, 0x24070008, 0x8f820120, +0xafa20010, 0x8f820124, 0x3c040001, 0x24842cec, +0x3c050009, 0xafa20014, 0x8fa60028, 0x1000001c, +0x34a50200, 0x8f440150, 0x8f450154, 0x8f43000c, +0xaf510018, 0x8f860120, 0x24020010, 0xafa20010, +0xafb10014, 0xafa30018, 0x8f42010c, 0x40f809, +0x24c6001c, 0x14400010, 0x0, 0x8f420330, +0x24420001, 0xaf420330, 0x8f420330, 0x8f820120, +0xafa20010, 0x8f820124, 0x3c040001, 0x24842cf4, +0x3c050009, 0xafa20014, 0x8fa60028, 0x34a50300, +0xc0029d3, 0x2603821, 0x8f4202e0, 0x24420001, +0xaf4202e0, 0x8f4202e0, 0x3c040001, 0x24843030, +0xafa00010, 0xafa00014, 0x8fa60028, 0x24052300, +0xc0029d3, 0x3821, 0x10000004, 0x0, +0x8c020264, 0x10400005, 0x0, 0x8f8200a0, +0x30420004, 0x1440fffa, 0x0, 0x8f820044, +0x34420004, 0xaf820044, 0x8f4202f8, 0x24420001, +0xaf4202f8, 0x8f4202f8, 0x8f8200d8, 0x8f8300d4, +0x431023, 0x2442ff80, 0xaf420090, 0x8f420090, +0x2842ff81, 0x10400006, 0x24020001, 0x8f420090, +0x8f430138, 0x431021, 0xaf420090, 0x24020001, +0xaf42008c, 0x32c20008, 0x10400006, 0x0, +0x8f820214, 0x3c038100, 0x3042ffff, 0x431025, +0xaf820214, 0x3c020001, 0x8c423d14, 0x30420001, +0x10400009, 0x0, 0x3c040001, 0x2484303c, +0x3c050000, 0x24a56c40, 0x3c060000, 0x24c670e8, +0x10000008, 0xc53023, 0x3c040001, 0x2484304c, +0x3c050000, 0x24a56838, 0x3c060000, 0x24c66c38, +0xc53023, 0x27a70030, 0x27a20034, 0xc001750, +0xafa20010, 0x3c010001, 0xac223e08, 0x3c020001, +0x8c423e08, 0x3c030800, 0x21100, 0x21182, +0x431025, 0xae420040, 0x8f8200a0, 0xafa20010, +0x8f8200b0, 0xafa20014, 0x8f86005c, 0x8f87011c, +0x3c040001, 0x2484305c, 0x3c010001, 0xac363de0, +0x3c010001, 0xac203dd0, 0x3c010001, 0xac3c3dc8, +0x3c010001, 0xac3b3df8, 0x3c010001, 0xac373dfc, +0x3c010001, 0xac3a3ddc, 0xc0029d3, 0x24052400, +0x8f820200, 0xafa20010, 0x8f820220, 0xafa20014, +0x8f860044, 0x8f870050, 0x3c040001, 0x24843068, +0xc0029d3, 0x24052500, 0x8f830060, 0x74100b, +0x242000a, 0x200f821, 0x0, 0xd, +0x8fbf0058, 0x8fbe0054, 0x8fb50050, 0x8fb3004c, +0x8fb20048, 0x8fb10044, 0x8fb00040, 0x3e00008, +0x27bd0060, 0x27bdffe0, 0x3c040001, 0x24843074, +0x24052600, 0x3021, 0x3821, 0xafbf0018, +0xafa00010, 0xc0029d3, 0xafa00014, 0x8fbf0018, +0x3e00008, 0x27bd0020, 0x3e00008, 0x0, +0x3e00008, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x3e00008, +0x0, 0x3e00008, 0x0, 0x27bdfde0, +0x27a50018, 0x3c04dead, 0x3484beef, 0xafbf0218, +0x8f820150, 0x3c03001f, 0x3463ffff, 0xafa40018, +0xa22823, 0xa32824, 0x8ca20000, 0x1044000a, +0x0, 0xafa50010, 0x8ca20000, 0xafa20014, +0x8f860150, 0x8f870250, 0x3c040001, 0x2484307c, +0xc0029d3, 0x24052700, 0x8fbf0218, 0x3e00008, +0x27bd0220, 0x27bdffe0, 0x3c06abba, 0x34c6babe, +0xafb00018, 0x3c100004, 0x3c07007f, 0x34e7ffff, +0xafbf001c, 0x102840, 0x8e040000, 0x8ca30000, +0xaca00000, 0xae060000, 0x8ca20000, 0xaca30000, +0x10460005, 0xae040000, 0xa08021, 0xf0102b, +0x1040fff5, 0x102840, 0x3c040001, 0x24843088, +0x24052800, 0x2003021, 0x3821, 0xafa00010, +0xc0029d3, 0xafa00014, 0x2001021, 0x8fbf001c, +0x8fb00018, 0x3e00008, 0x27bd0020, 0x8c020224, +0x3047003f, 0x10e00010, 0x803021, 0x2821, +0x24030020, 0xe31024, 0x10400002, 0x63042, +0xa62821, 0x31842, 0x1460fffb, 0xe31024, +0x2402f000, 0xa22824, 0x3403ffff, 0x65102b, +0x14400003, 0x851023, 0x10000006, 0x3c020001, +0x62102b, 0x14400003, 0xa01021, 0x3c02ffff, +0x821021, 0x3e00008, 0x0, 0x27bdffd0, +0xafb50028, 0x8fb50040, 0xafb20020, 0xa09021, +0xafb1001c, 0x24c60003, 0xafbf002c, 0xafb30024, +0xafb00018, 0x8ea20000, 0x2403fffc, 0xc38024, +0x50102b, 0x1440001b, 0xe08821, 0x8e330000, +0xafb00010, 0x8ea20000, 0xafa20014, 0x8e270000, +0x24053000, 0xc0029d3, 0x2403021, 0x8e230000, +0x702021, 0x64102b, 0x10400007, 0x2402821, +0x8ca20000, 0xac620000, 0x24630004, 0x64102b, +0x1440fffb, 0x24a50004, 0x8ea20000, 0x501023, +0xaea20000, 0x8e220000, 0x501021, 0x1000000b, +0xae220000, 0x2402002d, 0xa0820000, 0xafb00010, +0x8ea20000, 0x2409821, 0xafa20014, 0x8e270000, +0x24053100, 0xc0029d3, 0x2603021, 0x2601021, +0x8fbf002c, 0x8fb50028, 0x8fb30024, 0x8fb20020, +0x8fb1001c, 0x8fb00018, 0x3e00008, 0x27bd0030, +0x27bdffe8, 0x3c1cc000, 0x3c05fffe, 0x3c030001, +0x8c633dc0, 0x3c040001, 0x8c843dcc, 0x34a5bf08, +0x24021ffc, 0x3c010001, 0xac223c60, 0x3c0200c0, +0x3c010001, 0xac223c64, 0x3c020020, 0xafbf0010, +0x3c0100c0, 0xac201ffc, 0x431023, 0x441023, +0x245bb000, 0x365b821, 0x3c1d0001, 0x8fbd3c5c, +0x3a0f021, 0x3c0400c0, 0x34840200, 0x3c1a00c0, +0x3c0300c0, 0x346307b8, 0x24021dfc, 0x3c010001, +0xac223c60, 0x24021844, 0x3c010001, 0xac243c64, +0x3c010001, 0xac223c60, 0x3c010001, 0xac233c64, +0xc0017ba, 0x375a0200, 0x8fbf0010, 0x3e00008, +0x27bd0018, 0x27bdffc8, 0x3c040001, 0x24843094, +0x24053200, 0x3c020001, 0x8c423c60, 0x3c030001, +0x8c633c64, 0x3021, 0x3603821, 0xafbf0030, +0xafb3002c, 0xafb20028, 0xafb10024, 0xafb00020, +0xafa2001c, 0xafa30018, 0xafb70010, 0xc0029d3, +0xafba0014, 0xc0018c2, 0x0, 0x8f820240, +0x34420004, 0xaf820240, 0x24020001, 0xaf420000, +0x3c020001, 0x571021, 0x904240f4, 0x10400092, +0x2403fffc, 0x3c100001, 0x2610a6d3, 0x3c120001, +0x2652a2ac, 0x2121023, 0x438024, 0x8fa3001c, +0x3c040001, 0x248430a0, 0x70102b, 0x1440001a, +0x27b30018, 0x8fb10018, 0x24053000, 0x2403021, +0xafb00010, 0xafa30014, 0xc0029d3, 0x2203821, +0x8fa30018, 0x702021, 0x64102b, 0x10400007, +0x2403021, 0x8cc20000, 0xac620000, 0x24630004, +0x64102b, 0x1440fffb, 0x24c60004, 0x8fa2001c, +0x501023, 0xafa2001c, 0x8e620000, 0x501021, +0x1000000a, 0xae620000, 0x2408821, 0x24053100, +0xafb00010, 0xafa30014, 0x8fa70018, 0x2203021, +0x2402002d, 0xc0029d3, 0xa0820000, 0x24070020, +0x8fa3001c, 0x3c040001, 0x248430bc, 0x24120020, +0x3c010001, 0xac313dec, 0x2c620020, 0x1440001d, +0x27b10018, 0x8fb00018, 0x24053000, 0x3c060001, +0x24c63e80, 0xafa70010, 0xafa30014, 0xc0029d3, +0x2003821, 0x8fa30018, 0x3c040001, 0x24843e80, +0x24650020, 0x65102b, 0x10400007, 0x0, +0x8c820000, 0xac620000, 0x24630004, 0x65102b, +0x1440fffb, 0x24840004, 0x8fa2001c, 0x521023, +0xafa2001c, 0x8e220000, 0x521021, 0x1000000b, +0xae220000, 0x3c100001, 0x26103e80, 0x24053100, +0xafa70010, 0xafa30014, 0x8fa70018, 0x2003021, +0x2402002d, 0xc0029d3, 0xa0820000, 0x24070020, +0x3c040001, 0x248430d0, 0x8fa3001c, 0x24120020, +0x3c010001, 0xac303e20, 0x2c620020, 0x1440001d, +0x27b10018, 0x8fb00018, 0x24053000, 0x3c060001, +0x24c63ea0, 0xafa70010, 0xafa30014, 0xc0029d3, +0x2003821, 0x8fa30018, 0x3c040001, 0x24843ea0, +0x24650020, 0x65102b, 0x10400007, 0x0, +0x8c820000, 0xac620000, 0x24630004, 0x65102b, +0x1440fffb, 0x24840004, 0x8fa2001c, 0x521023, +0xafa2001c, 0x8e220000, 0x521021, 0x1000000b, +0xae220000, 0x3c100001, 0x26103ea0, 0x24053100, +0xafa70010, 0xafa30014, 0x8fa70018, 0x2003021, +0x2402002d, 0xc0029d3, 0xa0820000, 0x3c010001, +0x10000031, 0xac303e1c, 0x3c100000, 0x26107c8f, +0x3c120000, 0x26527b0c, 0x2121023, 0x438024, +0x8fa3001c, 0x3c040001, 0x248430e4, 0x70102b, +0x1440001a, 0x27b30018, 0x8fb10018, 0x24053000, +0x2403021, 0xafb00010, 0xafa30014, 0xc0029d3, +0x2203821, 0x8fa30018, 0x702021, 0x64102b, +0x10400007, 0x2403021, 0x8cc20000, 0xac620000, +0x24630004, 0x64102b, 0x1440fffb, 0x24c60004, +0x8fa2001c, 0x501023, 0xafa2001c, 0x8e620000, +0x501021, 0x1000000a, 0xae620000, 0x2408821, +0x24053100, 0xafb00010, 0xafa30014, 0x8fa70018, +0x2203021, 0x2402002d, 0xc0029d3, 0xa0820000, +0x3c010001, 0xac313dec, 0x3c030001, 0x8c633dec, +0x24020400, 0x60f809, 0xaf820070, 0x8fbf0030, +0x8fb3002c, 0x8fb20028, 0x8fb10024, 0x8fb00020, +0x3e00008, 0x27bd0038, 0x0, 0x8f820040, +0x3c03f000, 0x431024, 0x3c036000, 0x14430006, +0x0, 0x8f820050, 0x2403ff80, 0x431024, +0x34420055, 0xaf820050, 0x8f820054, 0x244203e8, +0xaf820058, 0x240201f4, 0xaf4200e0, 0x24020004, +0xaf4200e8, 0x24020002, 0xaf4001a0, 0xaf4000e4, +0xaf4200dc, 0xaf4000d8, 0xaf4000d4, 0x3e00008, +0xaf4000d0, 0x8f820054, 0x24420005, 0x3e00008, +0xaf820078, 0x27bdffe8, 0xafbf0010, 0x8f820054, +0x244203e8, 0xaf820058, 0x3c020800, 0x2c21024, +0x10400004, 0x3c02f7ff, 0x3442ffff, 0x2c2b024, +0x36940040, 0x3c020001, 0x8c423d28, 0x10400027, +0x0, 0x3c020001, 0x8c423d14, 0x30420001, +0x14400010, 0x0, 0x3c020001, 0x8c423e58, +0x1040000c, 0x0, 0x3c020001, 0x8c423da4, +0x14400008, 0x0, 0x8f830224, 0x3c020001, +0x8c425f1c, 0x10620003, 0x0, 0xc003bad, +0x0, 0x934205b1, 0x10400012, 0x24020001, +0x934305b1, 0x14620004, 0x3c0208ff, 0x24020002, +0x1000000c, 0xa34205b1, 0x3442fffb, 0xa34005b1, +0x8f830220, 0x3c040200, 0x284a025, 0x621824, +0xaf830220, 0x10000004, 0x3c020200, 0xc003f27, +0x0, 0x3c020200, 0x2c21024, 0x10400003, +0x0, 0xc001de7, 0x0, 0x8f4200d8, +0x8f4300dc, 0x24420001, 0xaf4200d8, 0x43102b, +0x14400003, 0x0, 0xaf4000d8, 0x36940080, +0x8c030238, 0x1060000c, 0x0, 0x8f4201a0, +0x244203e8, 0xaf4201a0, 0x43102b, 0x14400006, +0x0, 0x934205b6, 0x14400003, 0x0, +0xc001c3c, 0x0, 0x8fbf0010, 0x3e00008, +0x27bd0018, 0x3e00008, 0x0, 0x27bdffd8, +0xafbf0020, 0x8f43002c, 0x8f420038, 0x10620059, +0x0, 0x3c020001, 0x571021, 0x904240f0, +0x10400026, 0x24070008, 0x8f440160, 0x8f450164, +0x8f48000c, 0x8f860120, 0x24020020, 0xafa20010, +0xafa30014, 0xafa80018, 0x8f42010c, 0x40f809, +0x24c6001c, 0x14400011, 0x24020001, 0x3c010001, +0x370821, 0xa02240f0, 0x8f820124, 0xafa20010, +0x8f820128, 0x3c040001, 0x24843184, 0xafa20014, +0x8f46002c, 0x8f870120, 0x3c050009, 0xc0029d3, +0x34a50900, 0x1000005c, 0x0, 0x8f4202f0, +0x24420001, 0xaf4202f0, 0x8f4202f0, 0x8f42002c, +0xa34005b2, 0x10000027, 0xaf420038, 0x8f440160, +0x8f450164, 0x8f43002c, 0x8f48000c, 0x8f860120, +0x24020080, 0xafa20010, 0xafa30014, 0xafa80018, +0x8f42010c, 0x40f809, 0x24c6001c, 0x14400011, +0x24020001, 0x3c010001, 0x370821, 0xa02240f1, +0x8f820124, 0xafa20010, 0x8f820128, 0x3c040001, +0x24843190, 0xafa20014, 0x8f46002c, 0x8f870120, +0x3c050009, 0xc0029d3, 0x34a51100, 0x10000036, +0x0, 0x8f4202f0, 0x8f43002c, 0x24420001, +0xaf4202f0, 0x8f4202f0, 0x24020001, 0xa34205b2, +0xaf430038, 0x3c010001, 0x370821, 0xa02040f1, +0x3c010001, 0x370821, 0xa02040f0, 0x10000026, +0xaf400034, 0x934205b2, 0x1040001d, 0x0, +0xa34005b2, 0x8f820040, 0x30420001, 0x14400008, +0x2021, 0x8c030104, 0x24020001, 0x50620005, +0x24040001, 0x8c020264, 0x10400003, 0x801021, +0x24040001, 0x801021, 0x10400006, 0x0, +0x8f4202fc, 0x24420001, 0xaf4202fc, 0x10000008, +0x8f4202fc, 0x8f820044, 0x34420004, 0xaf820044, +0x8f4202f8, 0x24420001, 0xaf4202f8, 0x8f4202f8, +0x3c010001, 0x370821, 0xa02040f0, 0x3c010001, +0x370821, 0xa02040f1, 0x8f420000, 0x10400007, +0x0, 0xaf80004c, 0x8f82004c, 0x1040fffd, +0x0, 0x10000005, 0x0, 0xaf800048, +0x8f820048, 0x1040fffd, 0x0, 0x8f820060, +0x3c03ff7f, 0x3463ffff, 0x431024, 0xaf820060, +0x8f420000, 0x10400003, 0x0, 0x10000002, +0xaf80004c, 0xaf800048, 0x8fbf0020, 0x3e00008, +0x27bd0028, 0x3e00008, 0x0, 0x27bdffd8, +0xafbf0020, 0x8f430044, 0x8f42007c, 0x10620029, +0x24070008, 0x8f440158, 0x8f45015c, 0x8f48000c, +0x8f860120, 0x24020040, 0xafa20010, 0xafa30014, +0xafa80018, 0x8f42010c, 0x40f809, 0x24c6001c, +0x14400011, 0x24020001, 0x3c010001, 0x370821, +0xa02240f2, 0x8f820124, 0xafa20010, 0x8f820128, +0x3c040001, 0x24843198, 0xafa20014, 0x8f460044, +0x8f870120, 0x3c050009, 0xc0029d3, 0x34a51300, +0x1000000f, 0x0, 0x8f4202f4, 0x24420001, +0xaf4202f4, 0x8f4202f4, 0x8f420044, 0xaf42007c, +0x3c010001, 0x370821, 0xa02040f2, 0x10000004, +0xaf400078, 0x3c010001, 0x370821, 0xa02040f2, +0x8f420000, 0x10400007, 0x0, 0xaf80004c, +0x8f82004c, 0x1040fffd, 0x0, 0x10000005, +0x0, 0xaf800048, 0x8f820048, 0x1040fffd, +0x0, 0x8f820060, 0x3c03feff, 0x3463ffff, +0x431024, 0xaf820060, 0x8f420000, 0x10400003, +0x0, 0x10000002, 0xaf80004c, 0xaf800048, +0x8fbf0020, 0x3e00008, 0x27bd0028, 0x3e00008, +0x0, 0x3c020001, 0x8c423d28, 0x27bdffa8, +0xafbf0050, 0xafbe004c, 0xafb50048, 0xafb30044, +0xafb20040, 0xafb1003c, 0xafb00038, 0x104000d5, +0x8f900044, 0x8f4200d0, 0x24430001, 0x2842000b, +0x144000e4, 0xaf4300d0, 0x8f420004, 0x30420002, +0x1440009c, 0xaf4000d0, 0x8f420004, 0x3c030001, +0x8c633d18, 0x34420002, 0xaf420004, 0x24020001, +0x14620003, 0x3c020600, 0x10000002, 0x34423000, +0x34421000, 0xafa20020, 0x8f4a0018, 0xafaa0034, +0x27aa0020, 0xafaa002c, 0x8faa0034, 0x240200ff, +0x11420002, 0x1821, 0x25430001, 0x8c020228, +0x609821, 0x1662000e, 0x3c050009, 0x8f42032c, +0x24420001, 0xaf42032c, 0x8f42032c, 0x8c020228, +0x8fa70034, 0x3c040001, 0x24843168, 0xafa00014, +0xafa20010, 0x8fa60020, 0x10000070, 0x34a50500, +0x8faa0034, 0xa38c0, 0xf71021, 0x8fa30020, +0x8fa40024, 0xac4304c0, 0xac4404c4, 0x8f830054, +0x8f820054, 0x247103e8, 0x2221023, 0x2c4203e9, +0x1040001b, 0xa821, 0xe09021, 0x265e04c0, +0x8f440168, 0x8f45016c, 0x2401821, 0x240a0004, +0xafaa0010, 0xafb30014, 0x8f48000c, 0x1021, +0x2fe3021, 0xafa80018, 0x8f48010c, 0x24070008, +0xa32821, 0xa3482b, 0x822021, 0x100f809, +0x892021, 0x54400006, 0x24150001, 0x8f820054, +0x2221023, 0x2c4203e9, 0x1440ffe9, 0x0, +0x32a200ff, 0x54400018, 0xaf530018, 0x8f420368, +0x24420001, 0xaf420368, 0x8f420368, 0x8f820120, +0x8faa002c, 0x8fa70034, 0xafa20010, 0x8f820124, +0x3c040001, 0x24843174, 0xafa20014, 0x8d460000, +0x3c050009, 0x10000035, 0x34a50600, 0x8f4202f8, +0x24150001, 0x24420001, 0xaf4202f8, 0x8f4202f8, +0x1000001e, 0x32a200ff, 0x8f830054, 0x8f820054, +0x247103e8, 0x2221023, 0x2c4203e9, 0x10400016, +0xa821, 0x3c1e0020, 0x24120010, 0x8f42000c, +0x8f440150, 0x8f450154, 0x8f860120, 0xafb20010, +0xafb30014, 0x5e1025, 0xafa20018, 0x8f42010c, +0x24070008, 0x40f809, 0x24c6001c, 0x1440ffe3, +0x0, 0x8f820054, 0x2221023, 0x2c4203e9, +0x1440ffee, 0x0, 0x32a200ff, 0x14400011, +0x3c050009, 0x8f420368, 0x24420001, 0xaf420368, +0x8f420368, 0x8f820120, 0x8faa002c, 0x8fa70034, +0xafa20010, 0x8f820124, 0x3c040001, 0x2484317c, +0xafa20014, 0x8d460000, 0x34a50700, 0xc0029d3, +0x0, 0x8f4202dc, 0x24420001, 0xaf4202dc, +0x8f4202dc, 0x8f420004, 0x30420001, 0x50400029, +0x36100040, 0x3c020400, 0x2c21024, 0x10400013, +0x2404ffdf, 0x8f420240, 0x8f430244, 0x8f4401a4, +0x14640006, 0x36100040, 0x8f420260, 0x8f430264, +0x8f4401a8, 0x10640007, 0x2402ffdf, 0x8f420240, +0x8f430244, 0x8f440260, 0x8f450264, 0x10000012, +0x3a100020, 0x1000002b, 0x2028024, 0x8f420240, +0x8f430244, 0x8f4501a4, 0x14650006, 0x2048024, +0x8f420260, 0x8f430264, 0x8f4401a8, 0x50640021, +0x36100040, 0x8f420240, 0x8f430244, 0x8f440260, +0x8f450264, 0x3a100040, 0xaf4301a4, 0x10000019, +0xaf4501a8, 0x8f4200d4, 0x24430001, 0x10000011, +0x28420033, 0x8f420004, 0x30420001, 0x10400009, +0x3c020400, 0x2c21024, 0x10400004, 0x2402ffdf, +0x2028024, 0x1000000b, 0x36100040, 0x10000009, +0x36100060, 0x8f4200d4, 0x36100040, 0x24430001, +0x284201f5, 0x14400003, 0xaf4300d4, 0xaf4000d4, +0x3a100020, 0xaf900044, 0x2402ff7f, 0x282a024, +0x8fbf0050, 0x8fbe004c, 0x8fb50048, 0x8fb30044, +0x8fb20040, 0x8fb1003c, 0x8fb00038, 0x3e00008, +0x27bd0058, 0x3e00008, 0x0, 0x3c020001, +0x8c423d28, 0x27bdffb0, 0xafbf0048, 0xafbe0044, +0xafb50040, 0xafb3003c, 0xafb20038, 0xafb10034, +0x104000de, 0xafb00030, 0x8f4200d0, 0x3c040001, +0x8c843d18, 0x24430001, 0x2842000b, 0xaf4400e8, +0x144000fe, 0xaf4300d0, 0x8f420004, 0x30420002, +0x14400095, 0xaf4000d0, 0x8f420004, 0x34420002, +0xaf420004, 0x24020001, 0x14820003, 0x3c020600, +0x10000002, 0x34423000, 0x34421000, 0xafa20020, +0x1821, 0x8f5e0018, 0x27aa0020, 0x240200ff, +0x13c20002, 0xafaa002c, 0x27c30001, 0x8c020228, +0x609021, 0x1642000e, 0x1e38c0, 0x8f42032c, +0x24420001, 0xaf42032c, 0x8f42032c, 0x8c020228, +0x3c040001, 0x24843168, 0x3c050009, 0xafa00014, +0xafa20010, 0x8fa60020, 0x1000006d, 0x34a50500, +0xf71021, 0x8fa30020, 0x8fa40024, 0xac4304c0, +0xac4404c4, 0x8f830054, 0x8f820054, 0x247003e8, +0x2021023, 0x2c4203e9, 0x1040001b, 0x9821, +0xe08821, 0x263504c0, 0x8f440168, 0x8f45016c, +0x2201821, 0x240a0004, 0xafaa0010, 0xafb20014, +0x8f48000c, 0x1021, 0x2f53021, 0xafa80018, +0x8f48010c, 0x24070008, 0xa32821, 0xa3482b, +0x822021, 0x100f809, 0x892021, 0x54400006, +0x24130001, 0x8f820054, 0x2021023, 0x2c4203e9, +0x1440ffe9, 0x0, 0x326200ff, 0x54400017, +0xaf520018, 0x8f420368, 0x24420001, 0xaf420368, +0x8f420368, 0x8f820120, 0x8faa002c, 0xafa20010, +0x8f820124, 0x3c040001, 0x24843174, 0x3c050009, +0xafa20014, 0x8d460000, 0x10000035, 0x34a50600, +0x8f4202f8, 0x24130001, 0x24420001, 0xaf4202f8, +0x8f4202f8, 0x1000001e, 0x326200ff, 0x8f830054, +0x8f820054, 0x247003e8, 0x2021023, 0x2c4203e9, +0x10400016, 0x9821, 0x3c150020, 0x24110010, +0x8f42000c, 0x8f440150, 0x8f450154, 0x8f860120, +0xafb10010, 0xafb20014, 0x551025, 0xafa20018, +0x8f42010c, 0x24070008, 0x40f809, 0x24c6001c, +0x1440ffe3, 0x0, 0x8f820054, 0x2021023, +0x2c4203e9, 0x1440ffee, 0x0, 0x326200ff, +0x14400011, 0x0, 0x8f420368, 0x24420001, +0xaf420368, 0x8f420368, 0x8f820120, 0x8faa002c, +0xafa20010, 0x8f820124, 0x3c040001, 0x2484317c, +0x3c050009, 0xafa20014, 0x8d460000, 0x34a50700, +0xc0029d3, 0x3c03821, 0x8f4202dc, 0x24420001, +0xaf4202dc, 0x8f4202dc, 0x8f420004, 0x30420001, +0x10400033, 0x3c020400, 0x2c21024, 0x10400017, +0x0, 0x934205b0, 0x8f440240, 0x8f450244, +0x8f4301a4, 0x34420020, 0x14a30006, 0xa34205b0, +0x8f420260, 0x8f430264, 0x8f4401a8, 0x10640008, +0x0, 0x8f420240, 0x8f430244, 0x934405b0, +0x8f460260, 0x8f470264, 0x10000016, 0x38840040, +0x934205b0, 0x10000048, 0x304200bf, 0x934205b0, +0x8f440240, 0x8f450244, 0x8f4301a4, 0x304200bf, +0x14a30006, 0xa34205b0, 0x8f420260, 0x8f430264, +0x8f4401a8, 0x1064000b, 0x0, 0x8f420240, +0x8f430244, 0x934405b0, 0x8f460260, 0x8f470264, +0x38840020, 0xaf4301a4, 0xaf4701a8, 0x10000033, +0xa34405b0, 0x934205b0, 0x1000002f, 0x34420020, +0x934205b0, 0x8f4300d4, 0x34420020, 0xa34205b0, +0x24620001, 0x10000023, 0x28630033, 0x8f4200e4, +0x8f4300e0, 0x24420001, 0xaf4200e4, 0x43102a, +0x14400006, 0x24030001, 0x8f4200e8, 0x14430002, +0xaf4000e4, 0x24030004, 0xaf4300e8, 0x8f420004, +0x30420001, 0x1040000d, 0x3c020400, 0x2c21024, +0x10400007, 0x0, 0x934205b0, 0x34420040, +0xa34205b0, 0x934205b0, 0x1000000f, 0x304200df, +0x934205b0, 0x1000000c, 0x34420060, 0x934205b0, +0x8f4300d4, 0x34420020, 0xa34205b0, 0x24620001, +0x286300fb, 0x14600005, 0xaf4200d4, 0x934205b0, +0xaf4000d4, 0x38420040, 0xa34205b0, 0x934205b0, +0x8f4300e8, 0x3042007f, 0xa34205b0, 0x24020001, +0x14620005, 0x0, 0x934405b0, 0x42102, +0x10000003, 0x348400f0, 0x934405b0, 0x3484000f, +0xc004b04, 0x0, 0x2402ff7f, 0x282a024, +0x8fbf0048, 0x8fbe0044, 0x8fb50040, 0x8fb3003c, +0x8fb20038, 0x8fb10034, 0x8fb00030, 0x3e00008, +0x27bd0050, 0x3e00008, 0x0, 0x27bdffb0, +0x274401b0, 0x26e30028, 0x24650400, 0x65102b, +0xafbf0048, 0xafbe0044, 0xafb50040, 0xafb3003c, +0xafb20038, 0xafb10034, 0x10400007, 0xafb00030, +0x8c820000, 0xac620000, 0x24630004, 0x65102b, +0x1440fffb, 0x24840004, 0x8c020080, 0xaee20044, +0x8c0200c0, 0xaee20040, 0x8c020084, 0xaee20030, +0x8c020084, 0xaee2023c, 0x8c020088, 0xaee20240, +0x8c02008c, 0xaee20244, 0x8c020090, 0xaee20248, +0x8c020094, 0xaee2024c, 0x8c020098, 0xaee20250, +0x8c02009c, 0xaee20254, 0x8c0200a0, 0xaee20258, +0x8c0200a4, 0xaee2025c, 0x8c0200a8, 0xaee20260, +0x8c0200ac, 0xaee20264, 0x8c0200b0, 0xaee20268, +0x8c0200b4, 0xaee2026c, 0x8c0200b8, 0xaee20270, +0x8c0200bc, 0x24040001, 0xaee20274, 0xaee00034, +0x41080, 0x571021, 0x8ee30034, 0x8c42023c, +0x24840001, 0x621821, 0x2c82000f, 0xaee30034, +0x1440fff8, 0x41080, 0x8c0200cc, 0xaee20048, +0x8c0200d0, 0xaee2004c, 0x8c0200e0, 0xaee201f8, +0x8c0200e4, 0xaee201fc, 0x8c0200e8, 0xaee20200, +0x8c0200ec, 0xaee20204, 0x8c0200f0, 0xaee20208, +0x8ee400c0, 0x8ee500c4, 0x8c0200fc, 0x45102b, +0x1040000b, 0x0, 0x8ee200c0, 0x8ee300c4, +0x24040001, 0x24050000, 0x651821, 0x65302b, +0x441021, 0x461021, 0xaee200c0, 0xaee300c4, +0x8c0200fc, 0x8ee400c0, 0x8ee500c4, 0x2408ffff, +0x24090000, 0x401821, 0x1021, 0x882024, +0xa92824, 0x822025, 0xa32825, 0xaee400c0, +0xaee500c4, 0x8ee400d0, 0x8ee500d4, 0x8c0200f4, +0x45102b, 0x1040000b, 0x0, 0x8ee200d0, +0x8ee300d4, 0x24040001, 0x24050000, 0x651821, +0x65302b, 0x441021, 0x461021, 0xaee200d0, +0xaee300d4, 0x8c0200f4, 0x8ee400d0, 0x8ee500d4, +0x401821, 0x1021, 0x882024, 0xa92824, +0x822025, 0xa32825, 0xaee400d0, 0xaee500d4, +0x8ee400c8, 0x8ee500cc, 0x8c0200f8, 0x45102b, +0x1040000b, 0x0, 0x8ee200c8, 0x8ee300cc, +0x24040001, 0x24050000, 0x651821, 0x65302b, +0x441021, 0x461021, 0xaee200c8, 0xaee300cc, +0x8c0200f8, 0x8ee400c8, 0x8ee500cc, 0x401821, +0x1021, 0x882024, 0xa92824, 0x822025, +0xa32825, 0x24020008, 0xaee400c8, 0xaee500cc, +0xafa20010, 0xafa00014, 0x8f42000c, 0x8c040208, +0x8c05020c, 0xafa20018, 0x8f42010c, 0x26e60028, +0x40f809, 0x24070400, 0x104000f0, 0x3c020400, +0xafa20020, 0x934205b7, 0x10400089, 0x1821, +0x8f5e0018, 0x27aa0020, 0x240200ff, 0x13c20002, +0xafaa002c, 0x27c30001, 0x8c020228, 0x609021, +0x1642000e, 0x1e38c0, 0x8f42032c, 0x24420001, +0xaf42032c, 0x8f42032c, 0x8c020228, 0x3c040001, +0x24843168, 0x3c050009, 0xafa00014, 0xafa20010, +0x8fa60020, 0x1000006b, 0x34a50500, 0xf71021, +0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4, +0x8f830054, 0x8f820054, 0x247003e8, 0x2021023, +0x2c4203e9, 0x1040001b, 0x9821, 0xe08821, +0x263504c0, 0x8f440168, 0x8f45016c, 0x2201821, +0x240a0004, 0xafaa0010, 0xafb20014, 0x8f48000c, +0x1021, 0x2f53021, 0xafa80018, 0x8f48010c, +0x24070008, 0xa32821, 0xa3482b, 0x822021, +0x100f809, 0x892021, 0x54400006, 0x24130001, +0x8f820054, 0x2021023, 0x2c4203e9, 0x1440ffe9, +0x0, 0x326200ff, 0x54400017, 0xaf520018, +0x8f420368, 0x24420001, 0xaf420368, 0x8f420368, +0x8f820120, 0x8faa002c, 0xafa20010, 0x8f820124, +0x3c040001, 0x24843174, 0x3c050009, 0xafa20014, +0x8d460000, 0x10000033, 0x34a50600, 0x8f4202f8, +0x24130001, 0x24420001, 0xaf4202f8, 0x8f4202f8, +0x1000001c, 0x326200ff, 0x8f830054, 0x8f820054, +0x247003e8, 0x2021023, 0x2c4203e9, 0x10400014, +0x9821, 0x24110010, 0x8f42000c, 0x8f440150, +0x8f450154, 0x8f860120, 0xafb10010, 0xafb20014, +0xafa20018, 0x8f42010c, 0x24070008, 0x40f809, +0x24c6001c, 0x1440ffe5, 0x0, 0x8f820054, +0x2021023, 0x2c4203e9, 0x1440ffef, 0x0, +0x326200ff, 0x54400012, 0x24020001, 0x8f420368, +0x24420001, 0xaf420368, 0x8f420368, 0x8f820120, +0x8faa002c, 0xafa20010, 0x8f820124, 0x3c040001, +0x2484317c, 0x3c050009, 0xafa20014, 0x8d460000, +0x34a50700, 0xc0029d3, 0x3c03821, 0x1021, +0x1440005b, 0x24020001, 0x10000065, 0x0, +0x8f510018, 0x240200ff, 0x12220002, 0x8021, +0x26300001, 0x8c020228, 0x1602000e, 0x1130c0, +0x8f42032c, 0x24420001, 0xaf42032c, 0x8f42032c, +0x8c020228, 0x3c040001, 0x24843150, 0x3c050009, +0xafa00014, 0xafa20010, 0x8fa60020, 0x1000003f, +0x34a50100, 0xd71021, 0x8fa30020, 0x8fa40024, +0xac4304c0, 0xac4404c4, 0xc01821, 0x8f440168, +0x8f45016c, 0x1021, 0x24070004, 0xafa70010, +0xafb00014, 0x8f48000c, 0x24c604c0, 0x2e63021, +0xafa80018, 0x8f48010c, 0x24070008, 0xa32821, +0xa3482b, 0x822021, 0x100f809, 0x892021, +0x1440000b, 0x24070008, 0x8f820120, 0xafa20010, +0x8f820124, 0x3c040001, 0x24843158, 0x3c050009, +0xafa20014, 0x8fa60020, 0x1000001c, 0x34a50200, +0x8f440150, 0x8f450154, 0x8f43000c, 0xaf500018, +0x8f860120, 0x24020010, 0xafa20010, 0xafb00014, +0xafa30018, 0x8f42010c, 0x40f809, 0x24c6001c, +0x54400011, 0x24020001, 0x8f420330, 0x24420001, +0xaf420330, 0x8f420330, 0x8f820120, 0xafa20010, +0x8f820124, 0x3c040001, 0x24843160, 0x3c050009, +0xafa20014, 0x8fa60020, 0x34a50300, 0xc0029d3, +0x2203821, 0x1021, 0x1040000d, 0x24020001, +0x8f4202d8, 0xa34005b7, 0xaf4001a0, 0x24420001, +0xaf4202d8, 0x8f4202d8, 0x8ee20150, 0x24420001, +0xaee20150, 0x10000003, 0x8ee20150, 0x24020001, +0xa34205b7, 0x8fbf0048, 0x8fbe0044, 0x8fb50040, +0x8fb3003c, 0x8fb20038, 0x8fb10034, 0x8fb00030, +0x3e00008, 0x27bd0050, 0x27bdffd8, 0xafbf0020, +0x8f8200b0, 0x30420004, 0x10400068, 0x0, +0x8f43011c, 0x8f820104, 0x14620005, 0x0, +0x8f430124, 0x8f8200b4, 0x10620006, 0x0, +0x8f820104, 0xaf42011c, 0x8f8200b4, 0x1000005b, +0xaf420124, 0x8f8200b0, 0x3c030080, 0x431024, +0x1040000d, 0x0, 0x8f82011c, 0x34420002, +0xaf82011c, 0x8f8200b0, 0x2403fffb, 0x431024, +0xaf8200b0, 0x8f82011c, 0x2403fffd, 0x431024, +0x1000004a, 0xaf82011c, 0x8f43011c, 0x8f820104, +0x14620005, 0x0, 0x8f430124, 0x8f8200b4, +0x10620010, 0x0, 0x8f820104, 0xaf42011c, +0x8f8200b4, 0x8f43011c, 0xaf420124, 0xafa30010, +0x8f420124, 0x3c040001, 0x248431a0, 0xafa20014, +0x8f86011c, 0x8f8700b0, 0x3c050005, 0x10000031, +0x34a50900, 0x8f42011c, 0xafa20010, 0x8f420124, +0x3c040001, 0x248431ac, 0xafa20014, 0x8f86011c, +0x8f8700b0, 0x3c050005, 0xc0029d3, 0x34a51000, +0x8f82011c, 0x34420002, 0xaf82011c, 0x8f830104, +0x8f8200b0, 0x34420001, 0xaf8200b0, 0x24020008, +0xaf830104, 0xafa20010, 0xafa00014, 0x8f42000c, +0x8c040208, 0x8c05020c, 0xafa20018, 0x8f42010c, +0x26e60028, 0x40f809, 0x24070400, 0x8f82011c, +0x2403fffd, 0x431024, 0xaf82011c, 0x8ee201dc, +0x24420001, 0xaee201dc, 0x8ee201dc, 0x8f42011c, +0xafa20010, 0x8f420124, 0x3c040001, 0x248431b8, +0xafa20014, 0x8f86011c, 0x8f8700b0, 0x3c050005, +0x34a51100, 0xc0029d3, 0x0, 0x8f8200a0, +0x30420004, 0x10400069, 0x0, 0x8f430120, +0x8f820124, 0x14620005, 0x0, 0x8f430128, +0x8f8200a4, 0x10620006, 0x0, 0x8f820124, +0xaf420120, 0x8f8200a4, 0x1000005c, 0xaf420128, +0x8f8200a0, 0x3c030080, 0x431024, 0x1040000d, +0x0, 0x8f82011c, 0x34420002, 0xaf82011c, +0x8f8200a0, 0x2403fffb, 0x431024, 0xaf8200a0, +0x8f82011c, 0x2403fffd, 0x431024, 0x1000004b, +0xaf82011c, 0x8f430120, 0x8f820124, 0x14620005, +0x0, 0x8f430128, 0x8f8200a4, 0x10620010, +0x0, 0x8f820124, 0xaf420120, 0x8f8200a4, +0x8f430120, 0xaf420128, 0xafa30010, 0x8f420128, +0x3c040001, 0x248431c4, 0xafa20014, 0x8f86011c, +0x8f8700a0, 0x3c050005, 0x10000032, 0x34a51200, +0x8f420120, 0xafa20010, 0x8f420128, 0x3c040001, +0x248431d0, 0xafa20014, 0x8f86011c, 0x8f8700a0, +0x3c050005, 0xc0029d3, 0x34a51300, 0x8f82011c, +0x34420002, 0xaf82011c, 0x8f830124, 0x8f8200a0, +0x34420001, 0xaf8200a0, 0x24020080, 0xaf830124, +0xafa20010, 0xafa00014, 0x8f420014, 0x8c040208, +0x8c05020c, 0xafa20018, 0x8f420108, 0x3c060001, +0x24c63e14, 0x40f809, 0x24070004, 0x8f82011c, +0x2403fffd, 0x431024, 0xaf82011c, 0x8ee201dc, +0x24420001, 0xaee201dc, 0x8ee201dc, 0x8f420120, +0xafa20010, 0x8f420128, 0x3c040001, 0x248431dc, +0xafa20014, 0x8f86011c, 0x8f8700a0, 0x3c050005, +0x34a51400, 0xc0029d3, 0x0, 0x8fbf0020, +0x3e00008, 0x27bd0028, 0x3c081000, 0x24070001, +0x3c060080, 0x3c050100, 0x8f820070, 0x481024, +0x1040fffd, 0x0, 0x8f820054, 0x24420005, +0xaf820078, 0x8c040234, 0x10800016, 0x1821, +0x3c020001, 0x571021, 0x8c4240e8, 0x24420005, +0x3c010001, 0x370821, 0xac2240e8, 0x3c020001, +0x571021, 0x8c4240e8, 0x44102b, 0x14400009, +0x0, 0x3c030080, 0x3c010001, 0x370821, +0xac2040e8, 0x3c010001, 0x370821, 0x1000000b, +0xa02740f0, 0x3c020001, 0x571021, 0x904240f0, +0x54400006, 0x661825, 0x3c020001, 0x571021, +0x904240f1, 0x54400001, 0x661825, 0x8c040230, +0x10800013, 0x0, 0x3c020001, 0x571021, +0x8c4240ec, 0x24420005, 0x3c010001, 0x370821, +0xac2240ec, 0x3c020001, 0x571021, 0x8c4240ec, +0x44102b, 0x14400006, 0x0, 0x3c010001, +0x370821, 0xac2040ec, 0x10000006, 0x651825, +0x3c020001, 0x571021, 0x904240f2, 0x54400001, +0x651825, 0x1060ffbc, 0x0, 0x8f420000, +0x10400007, 0x0, 0xaf80004c, 0x8f82004c, +0x1040fffd, 0x0, 0x10000005, 0x0, +0xaf800048, 0x8f820048, 0x1040fffd, 0x0, +0x8f820060, 0x431025, 0xaf820060, 0x8f420000, +0x10400003, 0x0, 0x1000ffa7, 0xaf80004c, +0x1000ffa5, 0xaf800048, 0x3e00008, 0x0, +0x0, 0x0, 0x0, 0x27bdffe0, +0xafbf001c, 0xafb00018, 0x8f860064, 0x30c20004, +0x10400025, 0x24040004, 0x8c020114, 0xaf420020, +0xaf840064, 0x8f4202ec, 0x24420001, 0xaf4202ec, +0x8f4202ec, 0x8f820064, 0x30420004, 0x14400005, +0x0, 0x8c030114, 0x8f420020, 0x1462fff2, +0x0, 0x8f420000, 0x10400007, 0x8f43003c, +0xaf80004c, 0x8f82004c, 0x1040fffd, 0x0, +0x10000005, 0x0, 0xaf800048, 0x8f820048, +0x1040fffd, 0x0, 0x8f820060, 0x431025, +0xaf820060, 0x8f420000, 0x10400073, 0x0, +0x1000006f, 0x0, 0x30c20008, 0x10400020, +0x24040008, 0x8c02011c, 0xaf420048, 0xaf840064, +0x8f420298, 0x24420001, 0xaf420298, 0x8f420298, +0x8f820064, 0x30420008, 0x14400005, 0x0, +0x8c03011c, 0x8f420048, 0x1462fff2, 0x0, +0x8f420000, 0x10400007, 0x0, 0xaf80004c, +0x8f82004c, 0x1040fffd, 0x0, 0x10000005, +0x0, 0xaf800048, 0x8f820048, 0x1040fffd, +0x0, 0x8f820060, 0x1000ffd9, 0x34420200, +0x30c20020, 0x10400023, 0x24040020, 0x8c02012c, +0xaf420068, 0xaf840064, 0x8f4202c8, 0x24420001, +0xaf4202c8, 0x8f4202c8, 0x8f820064, 0x30420020, +0x14400005, 0x32c24000, 0x8c03012c, 0x8f420068, +0x1462fff2, 0x32c24000, 0x14400002, 0x3c020001, +0x2c2b025, 0x8f420000, 0x10400007, 0x0, +0xaf80004c, 0x8f82004c, 0x1040fffd, 0x0, +0x10000005, 0x0, 0xaf800048, 0x8f820048, +0x1040fffd, 0x0, 0x8f820060, 0x1000ffb4, +0x34420800, 0x30c20010, 0x10400029, 0x24040010, +0x8c020124, 0xaf420058, 0xaf840064, 0x8f4202c4, +0x24420001, 0xaf4202c4, 0x8f4202c4, 0x8f820064, +0x30420010, 0x14400005, 0x32c22000, 0x8c030124, +0x8f420058, 0x1462fff2, 0x32c22000, 0x50400001, +0x36d68000, 0x8f420000, 0x10400007, 0x0, +0xaf80004c, 0x8f82004c, 0x1040fffd, 0x0, +0x10000005, 0x0, 0xaf800048, 0x8f820048, +0x1040fffd, 0x0, 0x8f820060, 0x34420100, +0xaf820060, 0x8f420000, 0x10400003, 0x0, +0x1000006b, 0xaf80004c, 0x10000069, 0xaf800048, +0x30c20001, 0x10400004, 0x24020001, 0xaf820064, +0x10000063, 0x0, 0x30c20002, 0x1440000b, +0x3c050003, 0x3c040001, 0x248432a4, 0x34a50500, +0x3821, 0xafa00010, 0xc0029d3, 0xafa00014, +0x2402ffc0, 0x10000056, 0xaf820064, 0x8c10022c, +0x8c02010c, 0x12020047, 0x101080, 0x8c450300, +0x26020001, 0x3050003f, 0x24020003, 0xac10022c, +0x51e02, 0x10620005, 0x24020010, 0x1062001d, +0x30a20fff, 0x10000039, 0x0, 0x8f430298, +0x8f440000, 0x30a20fff, 0xaf420048, 0x24630001, +0xaf430298, 0x10800007, 0x8f420298, 0xaf80004c, +0x8f82004c, 0x1040fffd, 0x0, 0x10000005, +0x0, 0xaf800048, 0x8f820048, 0x1040fffd, +0x0, 0x8f820060, 0x34420200, 0xaf820060, +0x8f420000, 0x1040001f, 0x0, 0x1000001b, +0x0, 0xaf420058, 0x32c22000, 0x50400001, +0x36d68000, 0x8f4202c4, 0x8f430000, 0x24420001, +0xaf4202c4, 0x10600007, 0x8f4202c4, 0xaf80004c, +0x8f82004c, 0x1040fffd, 0x0, 0x10000005, +0x0, 0xaf800048, 0x8f820048, 0x1040fffd, +0x0, 0x8f820060, 0x34420100, 0xaf820060, +0x8f420000, 0x10400003, 0x0, 0x10000005, +0xaf80004c, 0x10000003, 0xaf800048, 0xc002033, +0xa02021, 0x8c02010c, 0x16020002, 0x24020002, +0xaf820064, 0x8f820064, 0x30420002, 0x14400004, +0x0, 0x8c02010c, 0x1602ffad, 0x0, +0x8fbf001c, 0x8fb00018, 0x3e00008, 0x27bd0020, +0x3e00008, 0x0, 0x27bdffa8, 0xafb00038, +0x808021, 0x101602, 0x2442ffff, 0x304300ff, +0x2c620013, 0xafbf0050, 0xafbe004c, 0xafb50048, +0xafb30044, 0xafb20040, 0x104001e6, 0xafb1003c, +0x31080, 0x3c010001, 0x220821, 0x8c2232e8, +0x400008, 0x0, 0x101302, 0x30440fff, +0x24020001, 0x10820005, 0x24020002, 0x1082000a, +0x2402fffe, 0x10000021, 0x3c050003, 0x8f430004, +0x3c020001, 0x8c423e40, 0xaf4401f0, 0xaf4401f4, +0x10000007, 0x34630001, 0x8f430004, 0xaf4401f0, +0xaf4401f4, 0x621824, 0x3c020001, 0x2442c254, +0x21100, 0x21182, 0xaf430004, 0x3c030800, +0x431025, 0x3c010000, 0xac224138, 0x8f840054, +0x41442, 0x41c82, 0x431021, 0x41cc2, +0x431023, 0x41d02, 0x431021, 0x41d42, +0x431023, 0x10000009, 0xaf4201f8, 0x3c040001, +0x248432b0, 0x34a51000, 0x2003021, 0x3821, +0xafa00010, 0xc0029d3, 0xafa00014, 0x8f420290, +0x24420001, 0xaf420290, 0x10000215, 0x8f420290, +0x27b00028, 0x2002021, 0x24050210, 0xc002a57, +0x24060008, 0xc0023a0, 0x2002021, 0x1000020c, +0x0, 0x8c06022c, 0x27a40028, 0x61880, +0x24c20001, 0x3046003f, 0x8c650300, 0x61080, +0x8c430300, 0x24c20001, 0x3042003f, 0xac02022c, +0xafa50028, 0xc0023a0, 0xafa3002c, 0x100001fc, +0x0, 0x27b00028, 0x2002021, 0x24050210, +0xc002a57, 0x24060008, 0xc0024df, 0x2002021, +0x100001f3, 0x0, 0x8c06022c, 0x27a40028, +0x61880, 0x24c20001, 0x3046003f, 0x8c650300, +0x61080, 0x8c430300, 0x24c20001, 0x3042003f, +0xac02022c, 0xafa50028, 0xc0024df, 0xafa3002c, +0x100001e3, 0x0, 0x101302, 0x30430fff, +0x24020001, 0x10620005, 0x24020002, 0x1062001e, +0x3c020002, 0x10000033, 0x3c050003, 0x3c030002, +0x2c31024, 0x54400037, 0x2c3b025, 0x8f820228, +0x3c010001, 0x370821, 0xac2238d8, 0x8f82022c, +0x3c010001, 0x370821, 0xac2238dc, 0x8f820230, +0x3c010001, 0x370821, 0xac2238e0, 0x8f820234, +0x3c010001, 0x370821, 0xac2238e4, 0x2402ffff, +0xaf820228, 0xaf82022c, 0xaf820230, 0xaf820234, +0x10000020, 0x2c3b025, 0x2c21024, 0x10400012, +0x3c02fffd, 0x3c020001, 0x571021, 0x8c4238d8, +0xaf820228, 0x3c020001, 0x571021, 0x8c4238dc, +0xaf82022c, 0x3c020001, 0x571021, 0x8c4238e0, +0xaf820230, 0x3c020001, 0x571021, 0x8c4238e4, +0xaf820234, 0x3c02fffd, 0x3442ffff, 0x10000009, +0x2c2b024, 0x3c040001, 0x248432bc, 0x34a51100, +0x2003021, 0x3821, 0xafa00010, 0xc0029d3, +0xafa00014, 0x8f4202bc, 0x24420001, 0xaf4202bc, +0x1000019b, 0x8f4202bc, 0x101302, 0x30450fff, +0x24020001, 0x10a20005, 0x24020002, 0x10a2000d, +0x3c0408ff, 0x10000014, 0x3c050003, 0x3c0208ff, +0x3442ffff, 0x8f830220, 0x3c040004, 0x2c4b025, +0x621824, 0x34630008, 0xaf830220, 0x10000012, +0xaf450288, 0x3484fff7, 0x3c03fffb, 0x8f820220, +0x3463ffff, 0x2c3b024, 0x441024, 0xaf820220, +0x10000009, 0xaf450288, 0x3c040001, 0x248432c8, +0x34a51200, 0x2003021, 0x3821, 0xafa00010, +0xc0029d3, 0xafa00014, 0x8f4202ac, 0x24420001, +0xaf4202ac, 0x10000172, 0x8f4202ac, 0x27840208, +0x24050200, 0xc002a57, 0x24060008, 0x27440214, +0x24050200, 0xc002a57, 0x24060008, 0x8f4202b4, +0x24420001, 0xaf4202b4, 0x10000165, 0x8f4202b4, +0x101302, 0x30430fff, 0x24020001, 0x10620011, +0x28620002, 0x50400005, 0x24020002, 0x10600007, +0x0, 0x10000017, 0x0, 0x1062000f, +0x0, 0x10000013, 0x0, 0x8c060248, +0x2021, 0xc004878, 0x24050004, 0x10000007, +0x0, 0x8c060248, 0x2021, 0xc004878, +0x24050004, 0x10000010, 0x0, 0x8c06024c, +0x2021, 0xc004878, 0x24050001, 0x1000000a, +0x0, 0x3c040001, 0x248432d4, 0x3c050003, +0x34a51300, 0x2003021, 0x3821, 0xafa00010, +0xc0029d3, 0xafa00014, 0x8f4202b0, 0x24420001, +0xaf4202b0, 0x10000136, 0x8f4202b0, 0xc0022b4, +0x0, 0x10000132, 0x0, 0x24020001, +0xa34205b6, 0x24100100, 0x8f440198, 0x8f45019c, +0xafb00010, 0xafa00014, 0x8f420014, 0xafa20018, +0x8f420108, 0x26e60028, 0x40f809, 0x24070400, +0x1040fff5, 0x0, 0x10000121, 0x0, +0x3c02ffff, 0x34427fff, 0x2c2b024, 0x1821, +0x3c020900, 0xaf400058, 0xaf40005c, 0xaf400060, +0xaf400064, 0xaf400350, 0xafa20020, 0x8f5e0018, +0x27aa0020, 0x240200ff, 0x13c20002, 0xafaa0034, +0x27c30001, 0x8c020228, 0x609021, 0x1642000e, +0x1e38c0, 0x8f42032c, 0x24420001, 0xaf42032c, +0x8f42032c, 0x8c020228, 0x3c040001, 0x2484326c, +0x3c050009, 0xafa00014, 0xafa20010, 0x8fa60020, +0x1000006b, 0x34a50500, 0xf71021, 0x8fa30020, +0x8fa40024, 0xac4304c0, 0xac4404c4, 0x8f830054, +0x8f820054, 0x247003e8, 0x2021023, 0x2c4203e9, +0x1040001b, 0x9821, 0xe08821, 0x263504c0, +0x8f440168, 0x8f45016c, 0x2201821, 0x240a0004, +0xafaa0010, 0xafb20014, 0x8f48000c, 0x1021, +0x2f53021, 0xafa80018, 0x8f48010c, 0x24070008, +0xa32821, 0xa3482b, 0x822021, 0x100f809, +0x892021, 0x54400006, 0x24130001, 0x8f820054, +0x2021023, 0x2c4203e9, 0x1440ffe9, 0x0, +0x326200ff, 0x54400017, 0xaf520018, 0x8f420368, +0x24420001, 0xaf420368, 0x8f420368, 0x8f820120, +0x8faa0034, 0xafa20010, 0x8f820124, 0x3c040001, +0x24843278, 0x3c050009, 0xafa20014, 0x8d460000, +0x10000033, 0x34a50600, 0x8f4202f8, 0x24130001, +0x24420001, 0xaf4202f8, 0x8f4202f8, 0x1000001c, +0x326200ff, 0x8f830054, 0x8f820054, 0x247003e8, +0x2021023, 0x2c4203e9, 0x10400014, 0x9821, +0x24110010, 0x8f42000c, 0x8f440150, 0x8f450154, +0x8f860120, 0xafb10010, 0xafb20014, 0xafa20018, +0x8f42010c, 0x24070008, 0x40f809, 0x24c6001c, +0x1440ffe5, 0x0, 0x8f820054, 0x2021023, +0x2c4203e9, 0x1440ffef, 0x0, 0x326200ff, +0x14400011, 0x0, 0x8f420368, 0x24420001, +0xaf420368, 0x8f420368, 0x8f820120, 0x8faa0034, +0xafa20010, 0x8f820124, 0x3c040001, 0x24843280, +0x3c050009, 0xafa20014, 0x8d460000, 0x34a50700, +0xc0029d3, 0x3c03821, 0x8f4202a0, 0x24420001, +0xaf4202a0, 0x8f4202a0, 0x8f4202e8, 0x24420001, +0xaf4202e8, 0x1000008a, 0x8f4202e8, 0x8c02025c, +0x27440214, 0xaf4201e0, 0x8c020260, 0x24050200, +0x24060008, 0xc002a57, 0xaf4201e8, 0x8f820220, +0x30420008, 0x14400002, 0x24020001, 0x24020002, +0xaf420288, 0x8f42029c, 0x24420001, 0xaf42029c, +0x10000077, 0x8f42029c, 0x3c0200ff, 0x3442ffff, +0x2021824, 0x32c20180, 0x14400006, 0x3402fffb, +0x43102b, 0x14400003, 0x0, 0x1000006c, +0xaf4300bc, 0x3c040001, 0x248432e0, 0x3c050003, +0x34a51500, 0x2003021, 0x3821, 0xafa00010, +0xc0029d3, 0xafa00014, 0x3c020700, 0x34421000, +0x101e02, 0x621825, 0xafa30020, 0x8f510018, +0x240200ff, 0x12220002, 0x8021, 0x26300001, +0x8c020228, 0x1602000e, 0x1130c0, 0x8f42032c, +0x24420001, 0xaf42032c, 0x8f42032c, 0x8c020228, +0x3c040001, 0x24843254, 0x3c050009, 0xafa00014, +0xafa20010, 0x8fa60020, 0x1000003f, 0x34a50100, +0xd71021, 0x8fa30020, 0x8fa40024, 0xac4304c0, +0xac4404c4, 0xc01821, 0x8f440168, 0x8f45016c, +0x1021, 0x24070004, 0xafa70010, 0xafb00014, +0x8f48000c, 0x24c604c0, 0x2e63021, 0xafa80018, +0x8f48010c, 0x24070008, 0xa32821, 0xa3482b, +0x822021, 0x100f809, 0x892021, 0x1440000b, +0x24070008, 0x8f820120, 0xafa20010, 0x8f820124, +0x3c040001, 0x2484325c, 0x3c050009, 0xafa20014, +0x8fa60020, 0x1000001c, 0x34a50200, 0x8f440150, +0x8f450154, 0x8f43000c, 0xaf500018, 0x8f860120, +0x24020010, 0xafa20010, 0xafb00014, 0xafa30018, +0x8f42010c, 0x40f809, 0x24c6001c, 0x14400010, +0x0, 0x8f420330, 0x24420001, 0xaf420330, +0x8f420330, 0x8f820120, 0xafa20010, 0x8f820124, +0x3c040001, 0x24843264, 0x3c050009, 0xafa20014, +0x8fa60020, 0x34a50300, 0xc0029d3, 0x2203821, +0x8f4202d0, 0x24420001, 0xaf4202d0, 0x8f4202d0, +0x8f4202e0, 0x24420001, 0xaf4202e0, 0x8f4202e0, +0x8fbf0050, 0x8fbe004c, 0x8fb50048, 0x8fb30044, +0x8fb20040, 0x8fb1003c, 0x8fb00038, 0x3e00008, +0x27bd0058, 0x27bdfff8, 0x2408ffff, 0x10a00014, +0x4821, 0x3c0aedb8, 0x354a8320, 0x90870000, +0x24840001, 0x3021, 0x1071026, 0x30420001, +0x10400002, 0x81842, 0x6a1826, 0x604021, +0x24c60001, 0x2cc20008, 0x1440fff7, 0x73842, +0x25290001, 0x125102b, 0x1440fff0, 0x0, +0x1001021, 0x3e00008, 0x27bd0008, 0x27bdffb8, +0xafbf0040, 0xafbe003c, 0xafb50038, 0xafb30034, +0xafb20030, 0xafb1002c, 0xafb00028, 0x8f870220, +0xafa7001c, 0x8f870200, 0xafa70024, 0x8f820220, +0x3c0308ff, 0x3463ffff, 0x431024, 0x34420004, +0xaf820220, 0x8f820200, 0x3c03c0ff, 0x3463ffff, +0x431024, 0x34420004, 0xaf820200, 0x8f53034c, +0x8f550350, 0x8f5e0354, 0x8f470358, 0xafa70014, +0x8f4202c0, 0x274401b0, 0x24420001, 0xaf4202c0, +0x8f5002c0, 0x8f5101f4, 0x8f5201f0, 0xc002a40, +0x24050400, 0xaf53034c, 0xaf550350, 0xaf5e0354, +0x8fa70014, 0xaf470358, 0xaf5002c0, 0xaf5101f4, +0xaf5201f0, 0x8c02025c, 0x27440214, 0xaf4201e0, +0x8c020260, 0x24050200, 0x24060008, 0xaf4201e8, +0x24020006, 0xc002a57, 0xaf4201e4, 0x3c023b9a, +0x3442ca00, 0xaf4201ec, 0x240203e8, 0x24040002, +0x24030001, 0xaf420284, 0xaf440280, 0xaf43028c, +0x8f820220, 0x30420008, 0x10400004, 0x0, +0xaf430288, 0x10000003, 0x3021, 0xaf440288, +0x3021, 0x3c030001, 0x661821, 0x90633c80, +0x3461021, 0x24c60001, 0xa043021c, 0x2cc2000f, +0x1440fff8, 0x3461821, 0x24c60001, 0x8f820040, +0x24040080, 0x24050080, 0x21702, 0x24420030, +0xa062021c, 0x3461021, 0xc002a40, 0xa040021c, +0x8fa7001c, 0x30e20004, 0x14400006, 0x0, +0x8f820220, 0x3c0308ff, 0x3463fffb, 0x431024, +0xaf820220, 0x8fa70024, 0x30e20004, 0x14400006, +0x0, 0x8f820200, 0x3c03c0ff, 0x3463fffb, +0x431024, 0xaf820200, 0x8fbf0040, 0x8fbe003c, +0x8fb50038, 0x8fb30034, 0x8fb20030, 0x8fb1002c, +0x8fb00028, 0x3e00008, 0x27bd0048, 0xaf400104, +0x24040001, 0x410c0, 0x2e21821, 0x24820001, +0x3c010001, 0x230821, 0xa42234d0, 0x402021, +0x2c820080, 0x1440fff8, 0x410c0, 0x24020001, +0x3c010001, 0x370821, 0xa42038d0, 0xaf420100, +0xaf800228, 0xaf80022c, 0xaf800230, 0xaf800234, +0x3e00008, 0x0, 0x27bdffe8, 0xafbf0014, +0xafb00010, 0x8f420104, 0x28420005, 0x10400026, +0x808021, 0x3c020001, 0x8f430104, 0x344230d0, +0x2e22021, 0x318c0, 0x621821, 0x2e31821, +0x83102b, 0x10400015, 0x1021, 0x96070000, +0x24840006, 0x24660006, 0x9482fffc, 0x14470009, +0x2821, 0x9483fffe, 0x96020002, 0x14620006, +0xa01021, 0x94820000, 0x96030004, 0x431026, +0x2c450001, 0xa01021, 0x14400009, 0x24840008, +0x86102b, 0x1440fff0, 0x1021, 0x304200ff, +0x14400030, 0x24020001, 0x1000002e, 0x1021, +0x1000fffa, 0x24020001, 0x2002021, 0xc00229a, +0x24050006, 0x3042007f, 0x218c0, 0x2e31021, +0x3c010001, 0x220821, 0x942230d0, 0x1040fff2, +0x2e31021, 0x3c060001, 0xc23021, 0x94c630d0, +0x10c0ffed, 0x3c080001, 0x350834d2, 0x96070000, +0x610c0, 0x572021, 0x882021, 0x94820000, +0x14470009, 0x2821, 0x94830002, 0x96020002, +0x14620006, 0xa01021, 0x94820004, 0x96030004, +0x431026, 0x2c450001, 0xa01021, 0x14400007, +0x610c0, 0x2e21021, 0x3c060001, 0xc23021, +0x94c634d0, 0x14c0ffeb, 0x610c0, 0x10c0ffd2, +0x24020001, 0x8fbf0014, 0x8fb00010, 0x3e00008, +0x27bd0018, 0x3e00008, 0x0, 0x27bdffb0, +0x801021, 0xafb00030, 0x24500002, 0x2002021, +0x24050006, 0xafb10034, 0x408821, 0xafbf0048, +0xafbe0044, 0xafb50040, 0xafb3003c, 0xc00229a, +0xafb20038, 0x3047007f, 0x710c0, 0x2e21021, +0x3c050001, 0xa22821, 0x94a530d0, 0x50a0001c, +0xa03021, 0x3c090001, 0x352934d2, 0x96280002, +0x510c0, 0x572021, 0x892021, 0x94820000, +0x14480009, 0x3021, 0x94830002, 0x96020002, +0x14620006, 0xc01021, 0x94820004, 0x96030004, +0x431026, 0x2c460001, 0xc01021, 0x14400007, +0x510c0, 0x2e21021, 0x3c050001, 0xa22821, +0x94a534d0, 0x14a0ffeb, 0x510c0, 0xa03021, +0x10c00014, 0x610c0, 0x571821, 0x3c010001, +0x230821, 0x8c2334d0, 0x571021, 0xafa30010, +0x3c010001, 0x220821, 0x8c2234d4, 0x3c040001, +0x248433f0, 0xafa20014, 0x8e260000, 0x8e270004, +0x3c050004, 0xc0029d3, 0x34a50400, 0x10000063, +0x3c020800, 0x8f450100, 0x10a00006, 0x510c0, +0x2e21021, 0x3c010001, 0x220821, 0x942234d0, +0xaf420100, 0xa03021, 0x14c00011, 0x628c0, +0x710c0, 0x2e21021, 0xafa70010, 0x3c010001, +0x220821, 0x942230d0, 0x3c040001, 0x248433fc, +0xafa20014, 0x8e260000, 0x8e270004, 0x3c050004, +0xc0029d3, 0x34a50500, 0x10000048, 0x3c020800, +0xb71821, 0x3c020001, 0x96040000, 0x344234d2, +0x621821, 0xa4640000, 0x8e020002, 0x720c0, +0xac620002, 0x2e41021, 0x3c030001, 0x621821, +0x946330d0, 0x2e51021, 0x3c010001, 0x220821, +0xa42334d0, 0x2e41021, 0x3c010001, 0x220821, +0xa42630d0, 0x8f420104, 0x24420001, 0x28420080, +0x1040000f, 0x3c020002, 0x8f420104, 0x3c040001, +0x348430d2, 0x96030000, 0x210c0, 0x571021, +0x441021, 0xa4430000, 0x8e030002, 0xac430002, +0x8f420104, 0x24420001, 0xaf420104, 0x3c020002, +0x2c21024, 0x10400011, 0x72142, 0x3c030001, +0x346338d8, 0x24020003, 0x441023, 0x21080, +0x572021, 0x832021, 0x571021, 0x431021, +0x30e5001f, 0x8c430000, 0x24020001, 0xa21004, +0x621825, 0x1000000c, 0xac830000, 0x24020003, +0x441023, 0x21080, 0x5c2821, 0x5c1021, +0x30e4001f, 0x8c430228, 0x24020001, 0x821004, +0x621825, 0xaca30228, 0x3c020800, 0x34421000, +0x1821, 0xafa20020, 0x8f5e0018, 0x27aa0020, +0x240200ff, 0x13c20002, 0xafaa002c, 0x27c30001, +0x8c020228, 0x609021, 0x1642000e, 0x1e38c0, +0x8f42032c, 0x24420001, 0xaf42032c, 0x8f42032c, +0x8c020228, 0x3c040001, 0x248433b8, 0x3c050009, +0xafa00014, 0xafa20010, 0x8fa60020, 0x1000006b, +0x34a50500, 0xf71021, 0x8fa30020, 0x8fa40024, +0xac4304c0, 0xac4404c4, 0x8f830054, 0x8f820054, +0x247003e8, 0x2021023, 0x2c4203e9, 0x1040001b, +0x9821, 0xe08821, 0x263504c0, 0x8f440168, +0x8f45016c, 0x2201821, 0x240a0004, 0xafaa0010, +0xafb20014, 0x8f48000c, 0x1021, 0x2f53021, +0xafa80018, 0x8f48010c, 0x24070008, 0xa32821, +0xa3482b, 0x822021, 0x100f809, 0x892021, +0x54400006, 0x24130001, 0x8f820054, 0x2021023, +0x2c4203e9, 0x1440ffe9, 0x0, 0x326200ff, +0x54400017, 0xaf520018, 0x8f420368, 0x24420001, +0xaf420368, 0x8f420368, 0x8f820120, 0x8faa002c, +0xafa20010, 0x8f820124, 0x3c040001, 0x248433c4, +0x3c050009, 0xafa20014, 0x8d460000, 0x10000033, +0x34a50600, 0x8f4202f8, 0x24130001, 0x24420001, +0xaf4202f8, 0x8f4202f8, 0x1000001c, 0x326200ff, +0x8f830054, 0x8f820054, 0x247003e8, 0x2021023, +0x2c4203e9, 0x10400014, 0x9821, 0x24110010, +0x8f42000c, 0x8f440150, 0x8f450154, 0x8f860120, +0xafb10010, 0xafb20014, 0xafa20018, 0x8f42010c, +0x24070008, 0x40f809, 0x24c6001c, 0x1440ffe5, +0x0, 0x8f820054, 0x2021023, 0x2c4203e9, +0x1440ffef, 0x0, 0x326200ff, 0x14400011, +0x0, 0x8f420368, 0x24420001, 0xaf420368, +0x8f420368, 0x8f820120, 0x8faa002c, 0xafa20010, +0x8f820124, 0x3c040001, 0x248433cc, 0x3c050009, +0xafa20014, 0x8d460000, 0x34a50700, 0xc0029d3, +0x3c03821, 0x8f4202a4, 0x24420001, 0xaf4202a4, +0x8f4202a4, 0x8f4202e4, 0x24420001, 0xaf4202e4, +0x8f4202e4, 0x8fbf0048, 0x8fbe0044, 0x8fb50040, +0x8fb3003c, 0x8fb20038, 0x8fb10034, 0x8fb00030, +0x3e00008, 0x27bd0050, 0x27bdffa0, 0x801021, +0xafb00040, 0x24500002, 0x2002021, 0x24050006, +0xafb10044, 0x408821, 0xafbf0058, 0xafbe0054, +0xafb50050, 0xafb3004c, 0xc00229a, 0xafb20048, +0x3048007f, 0x810c0, 0x2e21021, 0x3c060001, +0xc23021, 0x94c630d0, 0x10c0001c, 0x3821, +0x3c0a0001, 0x354a34d2, 0x96290002, 0x610c0, +0x572021, 0x8a2021, 0x94820000, 0x14490009, +0x2821, 0x94830002, 0x96020002, 0x14620006, +0xa01021, 0x94820004, 0x96030004, 0x431026, +0x2c450001, 0xa01021, 0x14400008, 0x610c0, +0xc03821, 0x2e21021, 0x3c060001, 0xc23021, +0x94c634d0, 0x14c0ffea, 0x610c0, 0x14c00011, +0xafa70028, 0x810c0, 0x2e21021, 0xafa80010, +0x3c010001, 0x220821, 0x942230d0, 0x3c040001, +0x24843408, 0xafa20014, 0x8e260000, 0x8e270004, +0x3c050004, 0xc0029d3, 0x34a50900, 0x10000075, +0x3c020800, 0x10e0000c, 0x610c0, 0x2e21021, +0x3c030001, 0x621821, 0x946334d0, 0x710c0, +0x2e21021, 0x3c010001, 0x220821, 0xa42334d0, +0x1000000b, 0x3c040001, 0x2e21021, 0x3c030001, +0x621821, 0x946334d0, 0x810c0, 0x2e21021, +0x3c010001, 0x220821, 0xa42330d0, 0x3c040001, +0x348430d0, 0x8f430100, 0x610c0, 0x2e21021, +0x3c010001, 0x220821, 0xa42334d0, 0x8f420104, +0x2e43821, 0x2821, 0x18400029, 0xaf460100, +0x24e60006, 0x94c3fffc, 0x96020000, 0x14620009, +0x2021, 0x94c3fffe, 0x96020002, 0x14620006, +0x801021, 0x94c20000, 0x96030004, 0x431026, +0x2c440001, 0x801021, 0x50400014, 0x24a50001, +0x8f420104, 0x2442ffff, 0xa2102a, 0x1040000b, +0x24e40004, 0x94820006, 0x8c830008, 0xa482fffe, +0xac830000, 0x8f420104, 0x24a50001, 0x2442ffff, +0xa2102a, 0x1440fff7, 0x24840008, 0x8f420104, +0x2442ffff, 0x10000006, 0xaf420104, 0x8f420104, +0x24c60008, 0xa2102a, 0x1440ffda, 0x24e70008, +0x810c0, 0x2e21021, 0x3c010001, 0x220821, +0x942230d0, 0x14400023, 0x3c020800, 0x3c020002, +0x2c21024, 0x10400012, 0x82142, 0x3c030001, +0x346338d8, 0x24020003, 0x441023, 0x21080, +0x572021, 0x832021, 0x571021, 0x431021, +0x3105001f, 0x24030001, 0x8c420000, 0xa31804, +0x31827, 0x431024, 0x1000000d, 0xac820000, +0x24020003, 0x441023, 0x21080, 0x5c2821, +0x5c1021, 0x3104001f, 0x24030001, 0x8c420228, +0x831804, 0x31827, 0x431024, 0xaca20228, +0x3c020800, 0x34422000, 0x1821, 0xafa20020, +0x8f5e0018, 0x27ab0020, 0x240200ff, 0x13c20002, +0xafab0034, 0x27c30001, 0x8c020228, 0x609021, +0x1642000e, 0x1e38c0, 0x8f42032c, 0x24420001, +0xaf42032c, 0x8f42032c, 0x8c020228, 0x3c040001, +0x248433b8, 0x3c050009, 0xafa00014, 0xafa20010, +0x8fa60020, 0x1000006b, 0x34a50500, 0xf71021, +0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4, +0x8f830054, 0x8f820054, 0x247003e8, 0x2021023, +0x2c4203e9, 0x1040001b, 0x9821, 0xe08821, +0x263504c0, 0x8f440168, 0x8f45016c, 0x2201821, +0x240b0004, 0xafab0010, 0xafb20014, 0x8f48000c, +0x1021, 0x2f53021, 0xafa80018, 0x8f48010c, +0x24070008, 0xa32821, 0xa3482b, 0x822021, +0x100f809, 0x892021, 0x54400006, 0x24130001, +0x8f820054, 0x2021023, 0x2c4203e9, 0x1440ffe9, +0x0, 0x326200ff, 0x54400017, 0xaf520018, +0x8f420368, 0x24420001, 0xaf420368, 0x8f420368, +0x8f820120, 0x8fab0034, 0xafa20010, 0x8f820124, +0x3c040001, 0x248433c4, 0x3c050009, 0xafa20014, +0x8d660000, 0x10000033, 0x34a50600, 0x8f4202f8, +0x24130001, 0x24420001, 0xaf4202f8, 0x8f4202f8, +0x1000001c, 0x326200ff, 0x8f830054, 0x8f820054, +0x247003e8, 0x2021023, 0x2c4203e9, 0x10400014, +0x9821, 0x24110010, 0x8f42000c, 0x8f440150, +0x8f450154, 0x8f860120, 0xafb10010, 0xafb20014, +0xafa20018, 0x8f42010c, 0x24070008, 0x40f809, +0x24c6001c, 0x1440ffe5, 0x0, 0x8f820054, +0x2021023, 0x2c4203e9, 0x1440ffef, 0x0, +0x326200ff, 0x14400011, 0x0, 0x8f420368, +0x24420001, 0xaf420368, 0x8f420368, 0x8f820120, +0x8fab0034, 0xafa20010, 0x8f820124, 0x3c040001, +0x248433cc, 0x3c050009, 0xafa20014, 0x8d660000, +0x34a50700, 0xc0029d3, 0x3c03821, 0x8f4202a8, +0x24420001, 0xaf4202a8, 0x8f4202a8, 0x8f4202e4, +0x24420001, 0xaf4202e4, 0x8f4202e4, 0x8fbf0058, +0x8fbe0054, 0x8fb50050, 0x8fb3004c, 0x8fb20048, +0x8fb10044, 0x8fb00040, 0x3e00008, 0x27bd0060, +0x0, 0x0, 0x0, 0x27bdffe0, +0x27644000, 0xafbf0018, 0xc002a40, 0x24051000, +0x3c030001, 0x34632cc0, 0x3c040001, 0x34842ec8, +0x24020020, 0xaf82011c, 0x2e31021, 0xaf800100, +0xaf800104, 0xaf800108, 0xaf800110, 0xaf800114, +0xaf800118, 0xaf800120, 0xaf800124, 0xaf800128, +0xaf800130, 0xaf800134, 0xaf800138, 0xaf4200ec, +0x2e31021, 0xaf4200f0, 0x2e41021, 0xaf4200f4, +0x2e41021, 0xaf4200f8, 0x3c020001, 0x571021, +0x904240f4, 0x1440001c, 0x3c050001, 0x8f82011c, +0x3c040001, 0x248434d0, 0x3c050001, 0x34420001, +0xaf82011c, 0xafa00010, 0xafa00014, 0x8f86011c, +0x34a50100, 0xc0029d3, 0x3821, 0x8c020218, +0x30420040, 0x10400014, 0x0, 0x8f82011c, +0x3c040001, 0x248434dc, 0x3c050001, 0x34420004, +0xaf82011c, 0xafa00010, 0xafa00014, 0x8f86011c, +0x10000007, 0x34a50200, 0x3c040001, 0x248434e4, +0xafa00010, 0xafa00014, 0x8f86011c, 0x34a50300, +0xc0029d3, 0x3821, 0x8fbf0018, 0x3e00008, +0x27bd0020, 0x8fa90010, 0x8f83012c, 0x8faa0014, +0x8fab0018, 0x1060000a, 0x27624fe0, 0x14620002, +0x24680020, 0x27684800, 0x8f820128, 0x11020004, +0x0, 0x8f820124, 0x15020007, 0x0, +0x8f430324, 0x1021, 0x24630001, 0xaf430324, +0x10000039, 0x8f430324, 0xac640000, 0xac650004, +0xac660008, 0xa467000e, 0xac690018, 0xac6a001c, +0xac6b0010, 0xac620014, 0xaf880120, 0x8f4200fc, +0x8f4400f4, 0x2442ffff, 0xaf4200fc, 0x8c820000, +0x10490005, 0x3042ff8f, 0x10400019, 0x3122ff8f, +0x10400018, 0x3c020001, 0x8c830004, 0x2c620010, +0x10400013, 0x3c020001, 0x24630001, 0xac830004, +0x8f4300f8, 0x344230c8, 0x2e21021, 0x54620004, +0x24620008, 0x3c020001, 0x34422ec8, 0x2e21021, +0x14440015, 0x24020001, 0x8f820128, 0x24420020, +0xaf820128, 0x8f820128, 0x1000000f, 0x24020001, +0x3c020001, 0x344230c8, 0x2e21021, 0x54820004, +0x24820008, 0x3c020001, 0x34422ec8, 0x2e21021, +0x402021, 0x24020001, 0xaf4400f4, 0xac890000, +0xac820004, 0x24020001, 0x3e00008, 0x0, +0x3e00008, 0x0, 0x8fa90010, 0x8faa0014, +0x8f830120, 0x8fab0018, 0x27624fe0, 0x14620002, +0x24680020, 0x27684800, 0x8f820128, 0x1102000f, +0x24620016, 0xac640000, 0xac650004, 0xac660008, +0xa467000e, 0xac690018, 0xac6a001c, 0xac620014, +0xac6b0010, 0xaf880120, 0x8f4300fc, 0x24020001, +0x2463ffff, 0x10000006, 0xaf4300fc, 0x8f430324, +0x1021, 0x24630001, 0xaf430324, 0x8f430324, +0x3e00008, 0x0, 0x3e00008, 0x0, +0x8fa90010, 0x8f83010c, 0x8faa0014, 0x8fab0018, +0x1060000a, 0x276247e0, 0x14620002, 0x24680020, +0x27684000, 0x8f820108, 0x11020004, 0x0, +0x8f820104, 0x15020007, 0x0, 0x8f430328, +0x1021, 0x24630001, 0xaf430328, 0x10000035, +0x8f430328, 0xac640000, 0xac650004, 0xac660008, +0xa467000e, 0xac690018, 0xac6a001c, 0xac6b0010, +0xac620014, 0xaf880100, 0x8f4400ec, 0x8c820000, +0x30420006, 0x10400019, 0x31220006, 0x10400018, +0x3c020001, 0x8c830004, 0x2c620010, 0x10400013, +0x3c020001, 0x24630001, 0xac830004, 0x8f4300f0, +0x34422ec0, 0x2e21021, 0x54620004, 0x24620008, +0x3c020001, 0x34422cc0, 0x2e21021, 0x14440015, +0x24020001, 0x8f820108, 0x24420020, 0xaf820108, +0x8f820108, 0x1000000f, 0x24020001, 0x3c020001, +0x34422ec0, 0x2e21021, 0x54820004, 0x24820008, +0x3c020001, 0x34422cc0, 0x2e21021, 0x402021, +0x24020001, 0xaf4400ec, 0xac890000, 0xac820004, +0x24020001, 0x3e00008, 0x0, 0x3e00008, +0x0, 0x8fa30010, 0x8faa0014, 0x8f880100, +0x8fab0018, 0x276247e0, 0x15020002, 0x25090020, +0x27694000, 0x8f820108, 0x1122000d, 0x0, +0xad030018, 0x25030016, 0xad040000, 0xad050004, +0xad060008, 0xa507000e, 0xad0a001c, 0xad030014, +0xad0b0010, 0xaf890100, 0x10000006, 0x24020001, +0x8f430328, 0x1021, 0x24630001, 0xaf430328, +0x8f430328, 0x3e00008, 0x0, 0x3e00008, +0x0, 0x27bdffd8, 0x3c040001, 0x248434ec, +0x3c050001, 0xafbf0024, 0xafb20020, 0xafb1001c, +0xafb00018, 0x8f900104, 0x8f9100b0, 0x8f92011c, +0x34a52500, 0x8f820100, 0x2403021, 0x2203821, +0xafa20010, 0xc0029d3, 0xafb00014, 0x8e020008, +0xafa20010, 0x8e02000c, 0x3c040001, 0x248434f8, +0xafa20014, 0x8e060000, 0x8e070004, 0x3c050001, +0xc0029d3, 0x34a52510, 0x8e020018, 0xafa20010, +0x8e02001c, 0x3c040001, 0x24843504, 0xafa20014, +0x8e060010, 0x8e070014, 0x3c050001, 0xc0029d3, +0x34a52520, 0x3c030200, 0x2c31024, 0x1040000d, +0x2231024, 0x1040000b, 0x36420002, 0xaf82011c, +0x36220001, 0xaf8200b0, 0xaf900104, 0xaf92011c, +0x8f420320, 0x24420001, 0xaf420320, 0x10000015, +0x8f420320, 0x3c040001, 0x24843510, 0x24020290, +0xafa20010, 0xafa00014, 0x8f860144, 0x3c070001, +0x24e73518, 0xc0029d3, 0x3405dead, 0x8f82011c, +0x34420002, 0xaf82011c, 0x8f820220, 0x34420004, +0xaf820220, 0x8f820140, 0x3c030001, 0x431025, +0xaf820140, 0x8fbf0024, 0x8fb20020, 0x8fb1001c, +0x8fb00018, 0x3e00008, 0x27bd0028, 0x27bdffd8, +0x3c040001, 0x24843540, 0x3c050001, 0xafbf0024, +0xafb20020, 0xafb1001c, 0xafb00018, 0x8f900124, +0x8f9100a0, 0x8f92011c, 0x34a52600, 0x8f820120, +0x2403021, 0x2203821, 0xafa20010, 0xc0029d3, +0xafb00014, 0x8e020008, 0xafa20010, 0x8e02000c, +0x3c040001, 0x2484354c, 0xafa20014, 0x8e060000, +0x8e070004, 0x3c050001, 0xc0029d3, 0x34a52610, +0x8e020018, 0xafa20010, 0x8e02001c, 0x3c040001, +0x24843558, 0xafa20014, 0x8e060010, 0x8e070014, +0x3c050001, 0xc0029d3, 0x34a52620, 0x3c030200, +0x2c31024, 0x1040000d, 0x2231024, 0x1040000b, +0x36420002, 0xaf82011c, 0x36220001, 0xaf8200a0, +0xaf900124, 0xaf92011c, 0x8f42031c, 0x24420001, +0xaf42031c, 0x10000015, 0x8f42031c, 0x3c040001, +0x24843510, 0x240202bc, 0xafa20010, 0xafa00014, +0x8f860144, 0x3c070001, 0x24e73518, 0xc0029d3, +0x3405dead, 0x8f82011c, 0x34420002, 0xaf82011c, +0x8f820220, 0x34420004, 0xaf820220, 0x8f820140, +0x3c030001, 0x431025, 0xaf820140, 0x8fbf0024, +0x8fb20020, 0x8fb1001c, 0x8fb00018, 0x3e00008, +0x27bd0028, 0x6021, 0x5021, 0x3021, +0x2821, 0x6821, 0x4821, 0x7821, +0x7021, 0x8f880124, 0x8f870104, 0x1580002e, +0x8f8b011c, 0x11a00014, 0x31620800, 0x8f820120, +0x10460029, 0x0, 0x3c040001, 0x8c843e20, +0x8cc20000, 0x8cc30004, 0xac820000, 0xac830004, +0x8cc20008, 0xac820008, 0x94c2000e, 0xa482000e, +0x8cc20010, 0x240c0001, 0xac820010, 0x8cc20014, +0x10000012, 0x24c60020, 0x10400017, 0x0, +0x3c040001, 0x8c843e20, 0x8d020000, 0x8d030004, +0xac820000, 0xac830004, 0x8d020008, 0xac820008, +0x9502000e, 0xa482000e, 0x8d020010, 0x25060020, +0xac820010, 0x8d020014, 0x240c0001, 0xc01821, +0xac820014, 0x27624fe0, 0x43102b, 0x54400001, +0x27634800, 0x603021, 0x1540002f, 0x31620100, +0x11200014, 0x31628000, 0x8f820100, 0x1045002a, +0x31620100, 0x3c040001, 0x8c843e1c, 0x8ca20000, +0x8ca30004, 0xac820000, 0xac830004, 0x8ca20008, +0xac820008, 0x94a2000e, 0xa482000e, 0x8ca20010, +0x240a0001, 0xac820010, 0x8ca20014, 0x10000012, +0x24a50020, 0x10400018, 0x31620100, 0x3c040001, +0x8c843e1c, 0x8ce20000, 0x8ce30004, 0xac820000, +0xac830004, 0x8ce20008, 0xac820008, 0x94e2000e, +0xa482000e, 0x8ce20010, 0x24e50020, 0xac820010, +0x8ce20014, 0x240a0001, 0xa01821, 0xac820014, +0x276247e0, 0x43102b, 0x54400001, 0x27634000, +0x602821, 0x31620100, 0x5440001d, 0x31621000, +0x11a00009, 0x31a20800, 0x10400004, 0x25020020, +0x8f8200a8, 0xa5e20000, 0x25020020, 0xaf820124, +0x8f880124, 0x6821, 0x11800011, 0x31621000, +0x3c040001, 0x8c843e20, 0x8c820000, 0x8c830004, +0xaf820080, 0xaf830084, 0x8c820008, 0xaf8200a4, +0x9482000e, 0xaf8200ac, 0x8c820010, 0x6021, +0xaf8200a0, 0x8c8d0010, 0x8c8f0014, 0x31621000, +0x1440ff82, 0x0, 0x1120000f, 0x31220800, +0x10400004, 0x3c020002, 0x8f8200b8, 0xa5c20000, +0x3c020002, 0x1221024, 0x10400004, 0x24e20020, +0x8f8200b4, 0xaf8200d4, 0x24e20020, 0xaf820104, +0x8f870104, 0x4821, 0x1140ff70, 0x0, +0x3c040001, 0x8c843e1c, 0x8c820000, 0x8c830004, +0xaf820090, 0xaf830094, 0x8c820008, 0xaf8200b4, +0x9482000e, 0xaf82009c, 0x8c820010, 0x5021, +0xaf8200b0, 0x8c890010, 0x1000ff60, 0x8c8e0014, +0x3e00008, 0x0, 0x6021, 0x5821, +0x3021, 0x2821, 0x6821, 0x5021, +0x7821, 0x7021, 0x8f880124, 0x8f870104, +0x3c180100, 0x1580002e, 0x8f89011c, 0x11a00014, +0x31220800, 0x8f820120, 0x10460029, 0x0, +0x3c040001, 0x8c843e20, 0x8cc20000, 0x8cc30004, +0xac820000, 0xac830004, 0x8cc20008, 0xac820008, +0x94c2000e, 0xa482000e, 0x8cc20010, 0x240c0001, +0xac820010, 0x8cc20014, 0x10000012, 0x24c60020, +0x10400017, 0x0, 0x3c040001, 0x8c843e20, +0x8d020000, 0x8d030004, 0xac820000, 0xac830004, +0x8d020008, 0xac820008, 0x9502000e, 0xa482000e, +0x8d020010, 0x25060020, 0xac820010, 0x8d020014, +0x240c0001, 0xc01821, 0xac820014, 0x27624fe0, +0x43102b, 0x54400001, 0x27634800, 0x603021, +0x1560002f, 0x31220100, 0x11400014, 0x31228000, +0x8f820100, 0x1045002a, 0x31220100, 0x3c040001, +0x8c843e1c, 0x8ca20000, 0x8ca30004, 0xac820000, +0xac830004, 0x8ca20008, 0xac820008, 0x94a2000e, +0xa482000e, 0x8ca20010, 0x240b0001, 0xac820010, +0x8ca20014, 0x10000012, 0x24a50020, 0x10400018, +0x31220100, 0x3c040001, 0x8c843e1c, 0x8ce20000, +0x8ce30004, 0xac820000, 0xac830004, 0x8ce20008, +0xac820008, 0x94e2000e, 0xa482000e, 0x8ce20010, +0x24e50020, 0xac820010, 0x8ce20014, 0x240b0001, +0xa01821, 0xac820014, 0x276247e0, 0x43102b, +0x54400001, 0x27634000, 0x602821, 0x31220100, +0x5440001d, 0x31221000, 0x11a00009, 0x31a20800, +0x10400004, 0x25020020, 0x8f8200a8, 0xa5e20000, +0x25020020, 0xaf820124, 0x8f880124, 0x6821, +0x11800011, 0x31221000, 0x3c040001, 0x8c843e20, +0x8c820000, 0x8c830004, 0xaf820080, 0xaf830084, +0x8c820008, 0xaf8200a4, 0x9482000e, 0xaf8200ac, +0x8c820010, 0x6021, 0xaf8200a0, 0x8c8d0010, +0x8c8f0014, 0x31221000, 0x14400022, 0x0, +0x1140000f, 0x31420800, 0x10400004, 0x3c020002, +0x8f8200b8, 0xa5c20000, 0x3c020002, 0x1421024, +0x10400004, 0x24e20020, 0x8f8200b4, 0xaf8200d4, +0x24e20020, 0xaf820104, 0x8f870104, 0x5021, +0x11600010, 0x0, 0x3c040001, 0x8c843e1c, +0x8c820000, 0x8c830004, 0xaf820090, 0xaf830094, +0x8c820008, 0xaf8200b4, 0x9482000e, 0xaf82009c, +0x8c820010, 0x5821, 0xaf8200b0, 0x8c8a0010, +0x8c8e0014, 0x8f820070, 0x3c031000, 0x431024, +0x1040ff5c, 0x0, 0x8f820054, 0x24420005, +0xaf820078, 0x8c040234, 0x10800016, 0x1821, +0x3c020001, 0x571021, 0x8c4240e8, 0x24420005, +0x3c010001, 0x370821, 0xac2240e8, 0x3c020001, +0x571021, 0x8c4240e8, 0x44102b, 0x14400009, +0x24020001, 0x3c030080, 0x3c010001, 0x370821, +0xac2040e8, 0x3c010001, 0x370821, 0x1000000c, +0xa02240f0, 0x3c020001, 0x571021, 0x904240f0, +0x14400006, 0x3c020080, 0x3c020001, 0x571021, +0x904240f1, 0x10400002, 0x3c020080, 0x621825, +0x8c040230, 0x10800013, 0x0, 0x3c020001, +0x571021, 0x8c4240ec, 0x24420005, 0x3c010001, +0x370821, 0xac2240ec, 0x3c020001, 0x571021, +0x8c4240ec, 0x44102b, 0x14400006, 0x0, +0x3c010001, 0x370821, 0xac2040ec, 0x10000006, +0x781825, 0x3c020001, 0x571021, 0x904240f2, +0x54400001, 0x781825, 0x1060ff1a, 0x0, +0x8f420000, 0x10400007, 0x0, 0xaf80004c, +0x8f82004c, 0x1040fffd, 0x0, 0x10000005, +0x0, 0xaf800048, 0x8f820048, 0x1040fffd, +0x0, 0x8f820060, 0x431025, 0xaf820060, +0x8f420000, 0x10400003, 0x0, 0x1000ff05, +0xaf80004c, 0x1000ff03, 0xaf800048, 0x3e00008, +0x0, 0x0, 0x0, 0x3c020001, +0x8c423ca8, 0x27bdffe8, 0xafbf0014, 0x14400012, +0xafb00010, 0x3c100001, 0x26103ec0, 0x2002021, +0xc002a40, 0x24052000, 0x26021fe0, 0x3c010001, +0xac223e28, 0x3c010001, 0xac223e24, 0xac020250, +0x24022000, 0xac100254, 0xac020258, 0x24020001, +0x3c010001, 0xac223ca8, 0x8fbf0014, 0x8fb00010, +0x3e00008, 0x27bd0018, 0x3c090001, 0x8d293e28, +0x8c820000, 0x8fa30010, 0x8fa80014, 0xad220000, +0x8c820004, 0xad250008, 0xad220004, 0x8f820054, +0xad260010, 0xad270014, 0xad230018, 0xad28001c, +0xad22000c, 0x2529ffe0, 0x3c020001, 0x24423ec0, +0x122102b, 0x10400003, 0x0, 0x3c090001, +0x8d293e24, 0x3c020001, 0x8c423c90, 0xad220000, +0x3c020001, 0x8c423c90, 0x3c010001, 0xac293e28, +0xad220004, 0xac090250, 0x3e00008, 0x0, +0x27bdffd0, 0xafb00010, 0x3c100001, 0x8e103e28, +0x3c020001, 0x8c423c90, 0xafb10014, 0x808821, +0xafbe0024, 0x8fbe0040, 0x8fa40048, 0xafb20018, +0xa09021, 0xafbf0028, 0xafb50020, 0xafb3001c, +0xae020000, 0x3c020001, 0x8c423c90, 0xc09821, +0xe0a821, 0x10800006, 0xae020004, 0x26050008, +0xc002a4b, 0x24060018, 0x10000005, 0x2610ffe0, +0x26040008, 0xc002a40, 0x24050018, 0x2610ffe0, +0x3c030001, 0x24633ec0, 0x203102b, 0x10400003, +0x0, 0x3c100001, 0x8e103e24, 0x8e220000, +0xae020000, 0x8e220004, 0xae120008, 0xae020004, +0x8f820054, 0xae130010, 0xae150014, 0xae1e0018, +0x8fa80044, 0xae08001c, 0xae02000c, 0x2610ffe0, +0x203102b, 0x10400003, 0x0, 0x3c100001, +0x8e103e24, 0x3c020001, 0x8c423c90, 0xae020000, +0x3c020001, 0x8c423c90, 0x3c010001, 0xac303e28, +0xae020004, 0xac100250, 0x8fbf0028, 0x8fbe0024, +0x8fb50020, 0x8fb3001c, 0x8fb20018, 0x8fb10014, +0x8fb00010, 0x3e00008, 0x27bd0030, 0x851821, +0x83102b, 0x10400006, 0x0, 0xac800000, +0x24840004, 0x83102b, 0x5440fffd, 0xac800000, +0x3e00008, 0x0, 0xa61821, 0xa3102b, +0x10400007, 0x0, 0x8c820000, 0xaca20000, +0x24a50004, 0xa3102b, 0x1440fffb, 0x24840004, +0x3e00008, 0x0, 0x861821, 0x83102b, +0x10400007, 0x0, 0x8ca20000, 0xac820000, +0x24840004, 0x83102b, 0x1440fffb, 0x24a50004, +0x3e00008, 0x0, 0x63080, 0x861821, +0x83102b, 0x10400006, 0x0, 0xac850000, +0x24840004, 0x83102b, 0x5440fffd, 0xac850000, +0x3e00008, 0x0, 0x0, 0x27bdffd8, +0xafbf0024, 0xafb00020, 0x8f430024, 0x8f420020, +0x10620038, 0x0, 0x8f430020, 0x8f420024, +0x622023, 0x4810003, 0x0, 0x8f420040, +0x822021, 0x8f430030, 0x8f420024, 0x43102b, +0x14400005, 0x0, 0x8f430040, 0x8f420024, +0x10000005, 0x621023, 0x8f420030, 0x8f430024, +0x431023, 0x2442ffff, 0x406021, 0x8c102a, +0x54400001, 0x806021, 0x8f4a0024, 0x8f490040, +0x8f480024, 0x8f440170, 0x8f450174, 0x8f460024, +0x8f4b001c, 0x24070001, 0xafa70010, 0x84100, +0x1001821, 0x14c5021, 0x2529ffff, 0x1498024, +0xafb00014, 0x8f470014, 0x1021, 0x63100, +0xafa70018, 0xa32821, 0xa3382b, 0x822021, +0x872021, 0x8f420108, 0x1663021, 0x40f809, +0xc3900, 0x54400001, 0xaf500024, 0x8f430024, +0x8f420020, 0x14620018, 0x0, 0x8f420000, +0x10400007, 0x0, 0xaf80004c, 0x8f82004c, +0x1040fffd, 0x0, 0x10000005, 0x0, +0xaf800048, 0x8f820048, 0x1040fffd, 0x0, +0x8f820060, 0x2403ffef, 0x431024, 0xaf820060, +0x8f420000, 0x10400003, 0x0, 0x10000002, +0xaf80004c, 0xaf800048, 0x8fbf0024, 0x8fb00020, +0x3e00008, 0x27bd0028, 0x3e00008, 0x0, +0x27bdffc0, 0x32c20020, 0xafbf0038, 0xafb30034, +0xafb20030, 0xafb1002c, 0x10400004, 0xafb00028, +0x8f530028, 0x10000002, 0x0, 0x8f530020, +0x8f420030, 0x105300e4, 0x21100, 0x8f43001c, +0x628021, 0x8e040000, 0x8e050004, 0x96120008, +0x8f420090, 0x9611000a, 0x3246ffff, 0x46102a, +0x10400017, 0x0, 0x8f8200d8, 0x8f430098, +0x431023, 0x2442fff8, 0xaf420090, 0x8f420090, +0x2842fff9, 0x10400005, 0x0, 0x8f420090, +0x8f430138, 0x431021, 0xaf420090, 0x8f420090, +0x46102a, 0x10400006, 0x0, 0x8f420338, +0x24420001, 0xaf420338, 0x100000da, 0x8f420338, +0x8f8200fc, 0x14400006, 0x32c20008, 0x8f420334, +0x24420001, 0xaf420334, 0x100000d2, 0x8f420334, +0x5040000c, 0xaf4000ac, 0x934205b3, 0x10400008, +0x32220200, 0x10400006, 0x3c034000, 0x9602000e, +0xaf4300ac, 0x21400, 0x10000002, 0xaf4200b0, +0xaf4000ac, 0x32220004, 0x1040007f, 0x32220800, +0x10400003, 0x3247ffff, 0x10000002, 0x24020020, +0x24020004, 0xafa20010, 0x8f420030, 0xafa20014, +0x8f420010, 0x3c030002, 0x431025, 0xafa20018, +0x8f460098, 0x8f420108, 0x40f809, 0x0, +0x104000b0, 0x0, 0x8f42009c, 0x8f430094, +0x2421021, 0xaf42009c, 0xae03000c, 0x8f4200ac, +0x10400008, 0x3c034000, 0x8f420094, 0x431025, +0xafa20020, 0x8f42009c, 0x8f4300b0, 0x10000004, +0x431025, 0x8f420094, 0xafa20020, 0x8f42009c, +0xafa20024, 0x8f8200fc, 0x8fa30020, 0x8fa40024, +0xac430000, 0xac440004, 0x24420008, 0xaf8200f0, +0x8f42009c, 0x8f440260, 0x8f450264, 0x401821, +0x1021, 0xa32821, 0xa3302b, 0x822021, +0x862021, 0x32230060, 0x24020040, 0xaf440260, +0xaf450264, 0x10620017, 0x2c620041, 0x10400005, +0x24020020, 0x10620008, 0x24020001, 0x10000026, +0x0, 0x24020060, 0x10620019, 0x24020001, +0x10000021, 0x0, 0x8f420268, 0x8f43026c, +0x24630001, 0x2c640001, 0x441021, 0xaf420268, +0xaf43026c, 0x8f420268, 0x8f43026c, 0x10000016, +0x24020001, 0x8f420270, 0x8f430274, 0x24630001, +0x2c640001, 0x441021, 0xaf420270, 0xaf430274, +0x8f420270, 0x8f430274, 0x1000000b, 0x24020001, +0x8f420278, 0x8f43027c, 0x24630001, 0x2c640001, +0x441021, 0xaf420278, 0xaf43027c, 0x8f420278, +0x8f43027c, 0x24020001, 0xa34205b3, 0x8f420098, +0x3244ffff, 0x2406fff8, 0x8f450130, 0x441021, +0x24420007, 0x461024, 0x24840007, 0xaf420094, +0x8f420090, 0x8f430094, 0x862024, 0x441023, +0x65182b, 0x14600005, 0xaf420090, 0x8f420094, +0x8f430138, 0x431023, 0xaf420094, 0x8f420094, +0x10000023, 0xaf40009c, 0x3247ffff, 0x10e00021, +0x0, 0x14400002, 0x24020010, 0x24020002, +0xafa20010, 0x8f420030, 0xafa20014, 0x8f420010, +0xafa20018, 0x8f460098, 0x8f420108, 0x40f809, +0x0, 0x10400033, 0x3245ffff, 0x8f420098, +0x8f430090, 0x8f460130, 0x451021, 0xaf420098, +0x8f42009c, 0x8f440098, 0xa34005b3, 0x651823, +0xaf430090, 0x451021, 0x86202b, 0x14800005, +0xaf42009c, 0x8f420098, 0x8f430138, 0x431023, +0xaf420098, 0x8f420030, 0x8f430040, 0x24420001, +0x2463ffff, 0x431024, 0xaf420030, 0x8f420030, +0x14530018, 0x0, 0x8f420000, 0x10400007, +0x0, 0xaf80004c, 0x8f82004c, 0x1040fffd, +0x0, 0x10000005, 0x0, 0xaf800048, +0x8f820048, 0x1040fffd, 0x0, 0x8f820060, +0x2403fff7, 0x431024, 0xaf820060, 0x8f420000, +0x10400003, 0x0, 0x10000002, 0xaf80004c, +0xaf800048, 0x8fbf0038, 0x8fb30034, 0x8fb20030, +0x8fb1002c, 0x8fb00028, 0x3e00008, 0x27bd0040, +0x3e00008, 0x0, 0x27bdffd0, 0x32c20020, +0xafbf002c, 0xafb20028, 0xafb10024, 0x10400004, +0xafb00020, 0x8f520028, 0x10000002, 0x0, +0x8f520020, 0x8f420030, 0x105200b5, 0x21100, +0x8f43001c, 0x628021, 0x8e040000, 0x8e050004, +0x96110008, 0x8f420090, 0x9607000a, 0x3226ffff, +0x46102a, 0x10400017, 0x0, 0x8f8200d8, +0x8f430098, 0x431023, 0x2442ff80, 0xaf420090, +0x8f420090, 0x2842ff81, 0x10400005, 0x0, +0x8f420090, 0x8f430138, 0x431021, 0xaf420090, +0x8f420090, 0x46102a, 0x10400006, 0x0, +0x8f420338, 0x24420001, 0xaf420338, 0x100000ab, +0x8f420338, 0x8f8600fc, 0x10c0000c, 0x0, +0x8f8200f4, 0x2403fff8, 0x431024, 0x461023, +0x218c3, 0x50600001, 0x24030100, 0x8f42008c, +0x43102b, 0x14400006, 0x712c2, 0x8f420334, +0x24420001, 0xaf420334, 0x10000098, 0x8f420334, +0x934305b3, 0x1060000f, 0x30460001, 0x8f420010, +0x34480400, 0x32c20008, 0x10400008, 0x30e20200, +0x10400006, 0x3c034000, 0x9602000e, 0xaf4300ac, +0x21400, 0x10000004, 0xaf4200b0, 0x10000002, +0xaf4000ac, 0x8f480010, 0x30e20004, 0x10400045, +0x3227ffff, 0x8f4900ac, 0x11200005, 0x30c200ff, +0x14400006, 0x24020040, 0x10000004, 0x24020008, +0x14400002, 0x24020020, 0x24020004, 0xafa20010, +0x8f430030, 0x11200004, 0xafa30014, 0x8f4200b0, +0x621025, 0xafa20014, 0x3c020002, 0x1021025, +0xafa20018, 0x8f460098, 0x8f420108, 0x40f809, +0x0, 0x10400069, 0x3224ffff, 0x8f42008c, +0x8f430094, 0x24420001, 0xaf42008c, 0x24020001, +0xae03000c, 0xa34205b3, 0x8f420098, 0x2406fff8, +0x8f450130, 0x441021, 0x24420007, 0x461024, +0x24840007, 0xaf420094, 0x8f420090, 0x8f430094, +0x862024, 0x441023, 0x65182b, 0x14600005, +0xaf420090, 0x8f420094, 0x8f430138, 0x431023, +0xaf420094, 0x8f430094, 0x8f420134, 0x43102b, +0x10400009, 0x0, 0x8f430130, 0x8f440094, +0x8f420090, 0x8f45012c, 0x641823, 0x431023, +0xaf420090, 0xaf450094, 0x8f420094, 0x1000001f, +0xaf420098, 0x10e0001d, 0x30c200ff, 0x14400002, +0x24020010, 0x24020002, 0xafa20010, 0x8f420030, +0xafa80018, 0xafa20014, 0x8f460098, 0x8f420108, +0x40f809, 0x0, 0x10400030, 0x3225ffff, +0x8f420098, 0x8f440130, 0x451021, 0xaf420098, +0x8f420090, 0x8f430098, 0xa34005b3, 0x451023, +0x64182b, 0x14600005, 0xaf420090, 0x8f420098, +0x8f430138, 0x431023, 0xaf420098, 0x8f420030, +0x8f430040, 0x24420001, 0x2463ffff, 0x431024, +0xaf420030, 0x8f420030, 0x14520018, 0x0, +0x8f420000, 0x10400007, 0x0, 0xaf80004c, +0x8f82004c, 0x1040fffd, 0x0, 0x10000005, +0x0, 0xaf800048, 0x8f820048, 0x1040fffd, +0x0, 0x8f820060, 0x2403fff7, 0x431024, +0xaf820060, 0x8f420000, 0x10400003, 0x0, +0x10000002, 0xaf80004c, 0xaf800048, 0x8fbf002c, +0x8fb20028, 0x8fb10024, 0x8fb00020, 0x3e00008, +0x27bd0030, 0x3e00008, 0x0, 0x27bdffd8, +0x3c020001, 0x34422ec0, 0xafbf0020, 0x8f4300f0, +0x8f840108, 0x2e21021, 0x54620004, 0x24620008, +0x3c020001, 0x34422cc0, 0x2e21021, 0x401821, +0xaf4300f0, 0xac600000, 0x8f4200ec, 0x8c660004, +0x14620004, 0x3c020001, 0x24820020, 0x1000000f, +0xaf820108, 0x8f4300f0, 0x34422ec0, 0x2e21021, +0x54620004, 0x24620008, 0x3c020001, 0x34422cc0, +0x2e21021, 0x401821, 0x8c620004, 0x21140, +0x821021, 0xaf820108, 0xac600000, 0x8c850018, +0x30a20036, 0x1040006c, 0x30a20001, 0x8c82001c, +0x8f430040, 0x8f440034, 0x24420001, 0x2463ffff, +0x431024, 0x862021, 0xaf42002c, 0x30a20030, +0x14400006, 0xaf440034, 0x8f420034, 0x8c03023c, +0x43102b, 0x144000c9, 0x0, 0x32c20010, +0x10400028, 0x24070008, 0x8f440160, 0x8f450164, +0x8f43002c, 0x8f48000c, 0x8f860120, 0x24020080, +0xafa20010, 0xafa30014, 0xafa80018, 0x8f42010c, +0x40f809, 0x24c6001c, 0x14400011, 0x24020001, +0x3c010001, 0x370821, 0xa02240f1, 0x8f820124, +0xafa20010, 0x8f820128, 0x3c040001, 0x24843800, +0xafa20014, 0x8f46002c, 0x8f870120, 0x3c050009, +0xc0029d3, 0x34a51100, 0x10000036, 0x0, +0x8f4202f0, 0x8f43002c, 0x24420001, 0xaf4202f0, +0x8f4202f0, 0x24020001, 0xa34205b2, 0x10000026, +0xaf430038, 0x8f440160, 0x8f450164, 0x8f43002c, +0x8f48000c, 0x8f860120, 0x24020020, 0xafa20010, +0xafa30014, 0xafa80018, 0x8f42010c, 0x40f809, +0x24c6001c, 0x14400011, 0x24020001, 0x3c010001, +0x370821, 0xa02240f0, 0x8f820124, 0xafa20010, +0x8f820128, 0x3c040001, 0x248437f4, 0xafa20014, +0x8f46002c, 0x8f870120, 0x3c050009, 0xc0029d3, +0x34a50900, 0x1000000f, 0x0, 0x8f4202f0, +0x24420001, 0xaf4202f0, 0x8f4202f0, 0x8f42002c, +0xa34005b2, 0xaf420038, 0x3c010001, 0x370821, +0xa02040f1, 0x3c010001, 0x370821, 0xa02040f0, +0xaf400034, 0x8f420304, 0x24420001, 0xaf420304, +0x1000006e, 0x8f420304, 0x10400025, 0x30a27000, +0x8c85001c, 0x8f420028, 0xa22023, 0x4810003, +0x0, 0x8f420040, 0x822021, 0x8f420348, +0x8f430000, 0x441021, 0xaf420348, 0x8f42035c, +0xaf450028, 0x441021, 0x10600007, 0xaf42035c, +0xaf80004c, 0x8f82004c, 0x1040fffd, 0x0, +0x10000005, 0x0, 0xaf800048, 0x8f820048, +0x1040fffd, 0x0, 0x8f820060, 0x34420008, +0xaf820060, 0x8f420000, 0x10400003, 0x0, +0x1000004a, 0xaf80004c, 0x10000048, 0xaf800048, +0x1040002f, 0x30a21000, 0x1040000c, 0x30a24000, +0x8c83001c, 0x8f420050, 0x622023, 0x4820001, +0x24840200, 0x8f42034c, 0x441021, 0xaf42034c, +0x8f420358, 0x1000001a, 0xaf430050, 0x1040000c, +0x32c28000, 0x8c83001c, 0x8f420070, 0x622023, +0x4820001, 0x24840400, 0x8f420354, 0x441021, +0xaf420354, 0x8f420358, 0x1000000d, 0xaf430070, +0x1040000e, 0x3c020800, 0x8c83001c, 0x8f420060, +0x622023, 0x4820001, 0x24840100, 0x8f420350, +0x441021, 0xaf420350, 0x8f420358, 0xaf430060, +0x441021, 0xaf420358, 0x3c020800, 0x2c21024, +0x5040001a, 0x36940040, 0x10000018, 0x0, +0x30a20100, 0x10400015, 0x0, 0x3c020001, +0x8c423c54, 0x1040000c, 0x0, 0x274301b0, +0x24650400, 0x65102b, 0x10400007, 0x26e40028, +0x8c820000, 0xac620000, 0x24630004, 0x65102b, +0x1440fffb, 0x24840004, 0x8f4202cc, 0xa34005b6, +0x24420001, 0xaf4202cc, 0x8f4202cc, 0x8fbf0020, +0x3e00008, 0x27bd0028, 0x3e00008, 0x0, +0x27bdffa8, 0xafbf0050, 0xafbe004c, 0xafb50048, +0xafb30044, 0xafb20040, 0xafb1003c, 0xafb00038, +0x8f910108, 0x26220020, 0xaf820108, 0x8e320018, +0xa821, 0x32420024, 0x104001b1, 0xf021, +0x8e26001c, 0x8f42001c, 0x61900, 0x431021, +0x8c50000c, 0x9603000c, 0x962d0016, 0x9453000a, +0x2c6205dd, 0x10400015, 0x2821, 0x32c20040, +0x10400015, 0x24020800, 0x96030014, 0x14620012, +0x3402aaaa, 0x9603000e, 0x14620007, 0x2021, +0x96030010, 0x24020300, 0x14620004, 0x801021, +0x96020012, 0x2c440001, 0x801021, 0x54400006, +0x24050016, 0x10000004, 0x0, 0x24020800, +0x50620001, 0x2405000e, 0x934205b4, 0x14400008, +0x5821, 0x240b0001, 0x32620180, 0xaf4500a8, +0xaf5000a0, 0x10400002, 0xaf4600a4, 0xa34b05b4, +0x10a00085, 0x2054021, 0x91020000, 0x3821, +0x3042000f, 0x25080, 0x32c20002, 0x10400012, +0x10a1821, 0x32620002, 0x10400010, 0x32c20001, +0x1002021, 0x94820000, 0x24840002, 0xe23821, +0x83102b, 0x1440fffb, 0x30e2ffff, 0x71c02, +0x623821, 0x71c02, 0x30e2ffff, 0x623821, +0x71027, 0xa502000a, 0x32c20001, 0x1040006a, +0x32620001, 0x10400068, 0x0, 0x8f4200a8, +0x10400065, 0x0, 0x8f4200a0, 0x8f4300a8, +0x431021, 0x904c0009, 0x318900ff, 0x39230006, +0x3182b, 0x39220011, 0x2102b, 0x621824, +0x1060000c, 0x3c050006, 0x8f4200a4, 0x3c040001, +0x24843810, 0xafa20010, 0x8f4200a0, 0x34a54600, +0x1203821, 0xc0029d3, 0xafa20014, 0x1000004e, +0x0, 0x32c20004, 0x14400013, 0x2821, +0x316200ff, 0x14400004, 0x0, 0x95020002, +0x1000000d, 0x4a2823, 0x9505000c, 0x9502000e, +0x95030010, 0xa22821, 0xa32821, 0x95030012, +0x91040009, 0x95020002, 0xa32821, 0xa42821, +0x4a1023, 0xa22821, 0x2002021, 0x94820000, +0x24840002, 0xe23821, 0x88102b, 0x1440fffb, +0x71c02, 0x30e2ffff, 0x623821, 0x71c02, +0x30e2ffff, 0x623821, 0x1a52821, 0x51c02, +0x30a2ffff, 0x622821, 0x51c02, 0x30a2ffff, +0x622821, 0xa72823, 0x51402, 0xa22821, +0x30a5ffff, 0x50a00001, 0x3405ffff, 0x316200ff, +0x14400008, 0x318300ff, 0x8f4300a0, 0x8f4200a8, +0x624021, 0x91020000, 0x3042000f, 0x25080, +0x318300ff, 0x24020006, 0x14620003, 0x10a1021, +0x10000002, 0x24440010, 0x24440006, 0x316200ff, +0x14400006, 0x0, 0x94820000, 0xa22821, +0x51c02, 0x30a2ffff, 0x622821, 0x934205b4, +0x10400003, 0x32620100, 0x50400003, 0xa4850000, +0x52827, 0xa4850000, 0x9622000e, 0x8f43009c, +0x621821, 0x32a200ff, 0x10400007, 0xaf43009c, +0x3c024000, 0x2021025, 0xafa20020, 0x8f42009c, +0x10000003, 0x5e1025, 0xafb00020, 0x8f42009c, +0xafa20024, 0x32620080, 0x10400010, 0x32620100, +0x8f4200b4, 0x24430001, 0x210c0, 0x571021, +0xaf4300b4, 0x8fa30020, 0x8fa40024, 0x3c010001, +0x220821, 0xac2338e8, 0x3c010001, 0x220821, +0xac2438ec, 0x100000a5, 0xaf40009c, 0x10400064, +0x0, 0x8f4200b4, 0x24430001, 0x210c0, +0x571021, 0xaf4300b4, 0x8fa30020, 0x8fa40024, +0x3c010001, 0x220821, 0xac2338e8, 0x3c010001, +0x220821, 0xac2438ec, 0x8f4200b4, 0x10400051, +0x3821, 0x3c090001, 0x352938e8, 0x3c08001f, +0x3508ffff, 0x240bffff, 0x340affff, 0x710c0, +0x571021, 0x491021, 0x8c430000, 0x8c440004, +0xafa30028, 0xafa4002c, 0x8f8200fc, 0x8fa30028, +0x8fa4002c, 0xac430000, 0xac440004, 0x24420008, +0xaf8200f0, 0x8f42008c, 0x2442ffff, 0xaf42008c, +0x97a2002e, 0x8f440260, 0x8f450264, 0x401821, +0x1021, 0xa32821, 0xa3302b, 0x822021, +0x862021, 0xaf440260, 0xaf450264, 0x8fa20028, +0x481024, 0x90430000, 0x30630001, 0x1460000b, +0x402021, 0x8f420268, 0x8f43026c, 0x24630001, +0x2c640001, 0x441021, 0xaf420268, 0xaf43026c, +0x8f420268, 0x1000001a, 0x8f43026c, 0x8c820000, +0x144b000e, 0x0, 0x94820004, 0x144a000b, +0x0, 0x8f420278, 0x8f43027c, 0x24630001, +0x2c640001, 0x441021, 0xaf420278, 0xaf43027c, +0x8f420278, 0x1000000a, 0x8f43027c, 0x8f420270, +0x8f430274, 0x24630001, 0x2c640001, 0x441021, +0xaf420270, 0xaf430274, 0x8f420270, 0x8f430274, +0x8f4200b4, 0x24e70001, 0xe2102b, 0x1440ffb8, +0x710c0, 0xa34005b4, 0x1000003f, 0xaf4000b4, +0x8f8200fc, 0x8fa30020, 0x8fa40024, 0xac430000, +0xac440004, 0x24420008, 0xaf8200f0, 0x8f42009c, +0x8f46008c, 0x8f440260, 0x8f450264, 0x401821, +0x1021, 0x24c6ffff, 0xaf46008c, 0xa32821, +0xa3302b, 0x822021, 0x862021, 0xaf440260, +0xaf450264, 0x92020000, 0x30420001, 0x1440000c, +0x2402ffff, 0x8f420268, 0x8f43026c, 0x24630001, +0x2c640001, 0x441021, 0xaf420268, 0xaf43026c, +0x8f420268, 0x8f43026c, 0x1000001c, 0xaf40009c, +0x8e030000, 0x1462000f, 0x3402ffff, 0x96030004, +0x1462000c, 0x0, 0x8f420278, 0x8f43027c, +0x24630001, 0x2c640001, 0x441021, 0xaf420278, +0xaf43027c, 0x8f420278, 0x8f43027c, 0x1000000b, +0xaf40009c, 0x8f420270, 0x8f430274, 0x24630001, +0x2c640001, 0x441021, 0xaf420270, 0xaf430274, +0x8f420270, 0x8f430274, 0xaf40009c, 0x8e22001c, +0x8f430040, 0x24420001, 0x2463ffff, 0x431024, +0xaf42002c, 0x32420060, 0x14400008, 0x32c20010, +0x8f420034, 0x24420001, 0xaf420034, 0x8c03023c, +0x43102b, 0x14400111, 0x32c20010, 0x10400018, +0x24070008, 0x8f440160, 0x8f450164, 0x8f43002c, +0x8f48000c, 0x8f860120, 0x24020080, 0xafa20010, +0xafa30014, 0xafa80018, 0x8f42010c, 0x40f809, +0x24c6001c, 0x10400041, 0x24020001, 0x8f4202f0, +0x8f43002c, 0x24420001, 0xaf4202f0, 0x8f4202f0, +0x24020001, 0xa34205b2, 0x10000076, 0xaf430038, +0x8f440160, 0x8f450164, 0x8f43002c, 0x8f48000c, +0x8f860120, 0x24020020, 0xafa20010, 0xafa30014, +0xafa80018, 0x8f42010c, 0x40f809, 0x24c6001c, +0x10400051, 0x24020001, 0x1000005f, 0x0, +0x32420012, 0x1040006f, 0x32420001, 0x9623000e, +0x8f42009c, 0x431021, 0xaf42009c, 0x8e23001c, +0x8f420040, 0x24630001, 0x2442ffff, 0x621824, +0x32420010, 0x14400008, 0xaf43002c, 0x8f420034, +0x24420001, 0xaf420034, 0x8c03023c, 0x43102b, +0x144000d2, 0x0, 0x32c20010, 0x10400028, +0x24070008, 0x8f440160, 0x8f450164, 0x8f43002c, +0x8f48000c, 0x8f860120, 0x24020080, 0xafa20010, +0xafa30014, 0xafa80018, 0x8f42010c, 0x40f809, +0x24c6001c, 0x14400011, 0x24020001, 0x3c010001, +0x370821, 0xa02240f1, 0x8f820124, 0xafa20010, +0x8f820128, 0x3c040001, 0x24843800, 0xafa20014, +0x8f46002c, 0x8f870120, 0x3c050009, 0xc0029d3, +0x34a51100, 0x10000036, 0x0, 0x8f4202f0, +0x8f43002c, 0x24420001, 0xaf4202f0, 0x8f4202f0, +0x24020001, 0xa34205b2, 0x10000026, 0xaf430038, +0x8f440160, 0x8f450164, 0x8f43002c, 0x8f48000c, +0x8f860120, 0x24020020, 0xafa20010, 0xafa30014, +0xafa80018, 0x8f42010c, 0x40f809, 0x24c6001c, +0x14400011, 0x24020001, 0x3c010001, 0x370821, +0xa02240f0, 0x8f820124, 0xafa20010, 0x8f820128, +0x3c040001, 0x248437f4, 0xafa20014, 0x8f46002c, +0x8f870120, 0x3c050009, 0xc0029d3, 0x34a50900, +0x1000000f, 0x0, 0x8f4202f0, 0x24420001, +0xaf4202f0, 0x8f4202f0, 0x8f42002c, 0xa34005b2, +0xaf420038, 0x3c010001, 0x370821, 0xa02040f1, +0x3c010001, 0x370821, 0xa02040f0, 0xaf400034, +0x8f420304, 0x24420001, 0xaf420304, 0x10000077, +0x8f420304, 0x10400025, 0x32427000, 0x8e25001c, +0x8f420028, 0xa22023, 0x4810003, 0x0, +0x8f420040, 0x822021, 0x8f420348, 0x8f430000, +0x441021, 0xaf420348, 0x8f42035c, 0xaf450028, +0x441021, 0x10600007, 0xaf42035c, 0xaf80004c, +0x8f82004c, 0x1040fffd, 0x0, 0x10000005, +0x0, 0xaf800048, 0x8f820048, 0x1040fffd, +0x0, 0x8f820060, 0x34420008, 0xaf820060, +0x8f420000, 0x10400003, 0x0, 0x10000053, +0xaf80004c, 0x10000051, 0xaf800048, 0x1040002f, +0x32421000, 0x1040000c, 0x32424000, 0x8e23001c, +0x8f420050, 0x622023, 0x4820001, 0x24840200, +0x8f42034c, 0x441021, 0xaf42034c, 0x8f420358, +0x1000001a, 0xaf430050, 0x1040000c, 0x32c28000, +0x8e23001c, 0x8f420070, 0x622023, 0x4820001, +0x24840400, 0x8f420354, 0x441021, 0xaf420354, +0x8f420358, 0x1000000d, 0xaf430070, 0x1040000e, +0x3c020800, 0x8e23001c, 0x8f420060, 0x622023, +0x4820001, 0x24840100, 0x8f420350, 0x441021, +0xaf420350, 0x8f420358, 0xaf430060, 0x441021, +0xaf420358, 0x3c020800, 0x2c21024, 0x50400023, +0x36940040, 0x10000021, 0x0, 0x32420048, +0x10400007, 0x24150001, 0x8e22001c, 0x3c03ffff, +0x43f024, 0x3042ffff, 0x1000fd81, 0xae22001c, +0x32420100, 0x10400015, 0x0, 0x3c020001, +0x8c423c54, 0x1040000c, 0x0, 0x274301b0, +0x24650400, 0x65102b, 0x10400007, 0x26e40028, +0x8c820000, 0xac620000, 0x24630004, 0x65102b, +0x1440fffb, 0x24840004, 0x8f4202cc, 0xa34005b6, +0x24420001, 0xaf4202cc, 0x8f4202cc, 0x8fbf0050, +0x8fbe004c, 0x8fb50048, 0x8fb30044, 0x8fb20040, +0x8fb1003c, 0x8fb00038, 0x3e00008, 0x27bd0058, +0x3e00008, 0x0, 0x0, 0x8f8600e4, +0x8f8200e0, 0x2403fff8, 0x431024, 0x10c20007, +0x803821, 0x8cc20000, 0x8cc30004, 0xace20000, +0xace30004, 0x10000002, 0x24020001, 0x1021, +0x3e00008, 0x0, 0x3e00008, 0x0, +0x8f8300e4, 0x27623ff8, 0x14620002, 0x24620008, +0x27623000, 0x401821, 0xaf8300e8, 0xaf8300e4, +0x3e00008, 0x0, 0x3e00008, 0x0, +0x8f8400e0, 0x8f8800c4, 0x8f8300e8, 0x2402fff8, +0x823824, 0xe32023, 0x2c821000, 0x50400001, +0x24841000, 0x420c2, 0x801821, 0x8f440248, +0x8f45024c, 0x1021, 0xa32821, 0xa3302b, +0x822021, 0x862021, 0xaf440248, 0xaf45024c, +0x8f8300c8, 0x8f42013c, 0x1032023, 0x82102b, +0x14400004, 0x801821, 0x8f42013c, 0x822021, +0x801821, 0x8f440240, 0x8f450244, 0x1021, +0xa32821, 0xa3302b, 0x822021, 0x862021, +0xaf440240, 0xaf450244, 0xaf8800c8, 0xaf8700e4, +0xaf8700e8, 0x3e00008, 0x0, 0x27bdff30, +0x240a0001, 0xafbf00c8, 0xafbe00c4, 0xafb500c0, +0xafb300bc, 0xafb200b8, 0xafb100b4, 0xafb000b0, +0xa3a00097, 0xafa00044, 0xafaa005c, 0x934205b5, +0xa7a0008e, 0x1040000a, 0xa7a00086, 0x8f4b00c4, +0xafab0064, 0x8f4a00c0, 0xafaa006c, 0x8f4b00cc, +0xafab0074, 0x8f4a00c8, 0x10000125, 0xafaa007c, +0x8f420114, 0x40f809, 0x27a40020, 0x304200ff, +0x1040033b, 0x0, 0x8fab0024, 0x8faa0020, +0x3162ffff, 0x2442fffc, 0xafa2006c, 0x3c020006, +0x2c21024, 0xafab007c, 0x14400015, 0xafaa0064, +0x91420000, 0x30420001, 0x10400011, 0x2402ffff, +0x8d430000, 0x14620004, 0x3402ffff, 0x95430004, +0x1062000b, 0x0, 0xc002343, 0x8fa40064, +0x304200ff, 0x14400006, 0x0, 0x8f420118, +0x40f809, 0x0, 0x1000031d, 0x0, +0x8fa20024, 0x3c03ffbf, 0x3463ffff, 0x431024, +0x3c03ffff, 0x431824, 0x14600003, 0xafa20024, +0x10000040, 0x1821, 0x3c020080, 0x621024, +0x10400007, 0x0, 0x8f42037c, 0x24420001, +0xaf42037c, 0x8f42037c, 0x10000036, 0x24030001, +0x8f420200, 0x24420001, 0xaf420200, 0x8f420200, +0x3c020001, 0x621024, 0x10400006, 0x3c020002, +0x8f4201b4, 0x24420001, 0xaf4201b4, 0x8f4201b4, +0x3c020002, 0x621024, 0x10400006, 0x3c020004, +0x8f42036c, 0x24420001, 0xaf42036c, 0x8f42036c, +0x3c020004, 0x621024, 0x10400006, 0x3c020008, +0x8f420370, 0x24420001, 0xaf420370, 0x8f420370, +0x3c020008, 0x621024, 0x10400006, 0x3c020010, +0x8f420374, 0x24420001, 0xaf420374, 0x8f420374, +0x3c020010, 0x621024, 0x10400006, 0x3c020020, +0x8f4201b0, 0x24420001, 0xaf4201b0, 0x8f4201b0, +0x3c020020, 0x621024, 0x10400006, 0x24030001, +0x8f420378, 0x24420001, 0xaf420378, 0x8f420378, +0x24030001, 0x8c020260, 0x8fab006c, 0x4b102b, +0x10400014, 0x307000ff, 0x8f4201d8, 0x24420001, +0xaf4201d8, 0x8f4201d8, 0x8faa007c, 0x8f8200e0, +0x354a0100, 0xafaa007c, 0xafa20010, 0x8f8200e4, +0x24100001, 0x3c040001, 0x248438d0, 0xafa20014, +0x8fa60020, 0x8fa70024, 0x3c050007, 0xc0029d3, +0x34a50800, 0x12000010, 0x3c020080, 0x2c21024, +0x1440000e, 0x32c20400, 0x8fab007c, 0x3c020080, +0x34420100, 0x1621024, 0x10400005, 0x0, +0x8f4201fc, 0x24420001, 0xaf4201fc, 0x8f4201fc, +0x100002a0, 0x8fa3006c, 0x32c20400, 0x10400015, +0x34028100, 0x8faa0064, 0x9543000c, 0x14620012, +0x3c020100, 0x240b0200, 0xa7ab008e, 0x9542000e, +0x8d430008, 0x8d440004, 0x8d450000, 0x8faa006c, +0x8fab0064, 0x254afffc, 0xafaa006c, 0xa7a20086, +0xad63000c, 0xad640008, 0xad650004, 0x256b0004, +0xafab0064, 0x3c020100, 0x2c21024, 0x10400004, +0x0, 0x8faa006c, 0x254a0004, 0xafaa006c, +0x8f4200bc, 0x5040000a, 0xafa00074, 0x8fab006c, +0x4b102b, 0x50400006, 0xafa00074, 0x8f4200bc, +0x1621023, 0xafa20074, 0x8f4a00bc, 0xafaa006c, +0x8f420080, 0x8fab006c, 0x4b102b, 0x10400056, +0x32c28000, 0x1040005e, 0x240a0003, 0x32c21000, +0x1040005b, 0xafaa005c, 0x10000058, 0x240b0004, +0x8f420340, 0x2403ffbf, 0x283a024, 0x24420001, +0xaf420340, 0x1000023f, 0x8f420340, 0x2c2b025, +0x2402ffbf, 0x282a024, 0x8f830128, 0x3c040001, +0x24843900, 0x26620001, 0xafa20014, 0xafa30010, +0x8f860120, 0x8f870124, 0x3c050007, 0xc0029d3, +0x34a52250, 0x1000022f, 0x0, 0x2c2b025, +0x2402ffbf, 0x282a024, 0x8f830128, 0x3c040001, +0x24843900, 0x24020002, 0xafa20014, 0xafa30010, +0x8f860120, 0x8f870124, 0x3c050007, 0xc0029d3, +0x34a52450, 0x1000021f, 0x0, 0x8ea20000, +0x8ea30004, 0x3c040001, 0x24843918, 0xafb00010, +0xafbe0014, 0x8ea70018, 0x34a52800, 0xc0029d3, +0x603021, 0x10000213, 0x0, 0xa6b1000a, +0x8f820124, 0x3c040001, 0x24843920, 0xafbe0014, +0xafa20010, 0x8f460044, 0x8f870120, 0x3c050007, +0xc0029d3, 0x34a53000, 0x10000206, 0x0, +0xa6b1000a, 0xa6b2000e, 0x8f820124, 0x3c040001, +0x2484392c, 0xafbe0014, 0xafa20010, 0x8f460044, +0x8f870120, 0x3c050007, 0xc0029d3, 0x34a53200, +0x100001f8, 0x0, 0x8f420084, 0x8faa006c, +0x4a102b, 0x14400007, 0x3c020001, 0x2c21024, +0x10400004, 0x0, 0x240b0002, 0xafab005c, +0x8faa006c, 0x1140020b, 0x27ab0020, 0xafab00a4, +0x3c0a001f, 0x354affff, 0xafaa009c, 0x8fab005c, +0x240a0001, 0x156a0021, 0x24020002, 0x8f430054, +0x8f420050, 0x1062000b, 0x274b0054, 0x8f5e0054, +0x3403ecc0, 0xafab004c, 0x27c20001, 0x304201ff, +0xafa20054, 0x1e1140, 0x431021, 0x1000006b, +0x2e2a821, 0x8f420044, 0x8faa006c, 0x3c040001, +0x248438dc, 0xafaa0014, 0xafa20010, 0x8f460054, +0x8f470050, 0x3c050007, 0xc0029d3, 0x34a51300, +0x8f430340, 0x2402ffbf, 0x282a024, 0x24630001, +0xaf430340, 0x100001c3, 0x8f420340, 0x1562001d, +0x0, 0x8f430074, 0x8f420070, 0x1062000a, +0x274a0074, 0x8f5e0074, 0xafaa004c, 0x27c20001, +0x304203ff, 0xafa20054, 0x1e1140, 0x24426cc0, +0x1000004a, 0x2e2a821, 0x8f420044, 0x8fab006c, +0x3c040001, 0x248438e8, 0x3c050007, 0xafab0014, +0xafa20010, 0x8f460074, 0x8f470070, 0x34a51500, +0x240a0001, 0xc0029d3, 0xafaa005c, 0x1000ffc3, +0x0, 0x8f430064, 0x8f420060, 0x1062001a, +0x274b0064, 0x8f5e0064, 0x8faa005c, 0xafab004c, +0x27c20001, 0x304200ff, 0xafa20054, 0x24020004, +0x1542000e, 0x1e1140, 0x1e1180, 0x24420cc0, +0x2e21021, 0xafa20044, 0x9442002a, 0x8fab0044, +0x8faa006c, 0x4a102b, 0x10400024, 0x25750020, +0x240b0001, 0x10000021, 0xa3ab0097, 0x24424cc0, +0x1000001e, 0x2e2a821, 0x8f420044, 0x8faa006c, +0x3c040001, 0x248438f4, 0xafaa0014, 0xafa20010, +0x8f460064, 0x8f470060, 0x3c050007, 0xc0029d3, +0x34a51800, 0x3c020008, 0x2c21024, 0x1440ff34, +0x0, 0x8f420360, 0x240b0001, 0xafab005c, +0x24420001, 0xaf420360, 0x1000ff90, 0x8f420360, +0x27a30036, 0x131040, 0x621821, 0x94620000, +0x441021, 0x10000020, 0xa4620000, 0x8faa0064, +0xaeaa0018, 0x93a20097, 0x10400072, 0x9821, +0x8fab0044, 0x8fa4006c, 0x8fa300a4, 0x25620020, +0xafa20028, 0x25620008, 0xafa20030, 0x25620010, +0xafab002c, 0xafa20034, 0x9562002a, 0xa7a20038, +0x95620018, 0xa7a2003a, 0x9562001a, 0xa7a2003c, +0x9562001c, 0xa7a2003e, 0x94620018, 0x24630002, +0x822023, 0x1880ffde, 0x26730001, 0x2e620004, +0x1440fff9, 0x0, 0x8f4200fc, 0x26650001, +0xa2102a, 0x1440002b, 0x24030001, 0x8f83012c, +0x10600023, 0x0, 0x8f820124, 0x431023, +0x22143, 0x58800001, 0x24840040, 0x8f820128, +0x431023, 0x21943, 0x58600001, 0x24630040, +0x64102a, 0x54400001, 0x602021, 0xaf4400fc, +0x8f4200fc, 0xa2102a, 0x10400011, 0x24030001, +0x10000015, 0x306200ff, 0x8faa0064, 0x96070018, +0xafaa0010, 0x8e220008, 0x3c040001, 0x2484390c, +0x8c430004, 0x8c420000, 0x34a52400, 0x2403021, +0xc0029d3, 0xafa30014, 0x1000002b, 0x0, +0x8f420324, 0x1821, 0x24420001, 0xaf420324, +0x8f420324, 0x306200ff, 0x5040fedc, 0x3c020800, +0x12600021, 0x9021, 0x8fb100a4, 0x2208021, +0x8e220008, 0x96070018, 0x8fa60064, 0x8c440000, +0x8c450004, 0x240b0001, 0xafab0010, 0xafbe0014, +0x8f420008, 0xafa20018, 0x8f42010c, 0x40f809, +0x0, 0x1040ffd8, 0x3c050007, 0x96020018, +0x8faa0064, 0x8fab009c, 0x1425021, 0x16a102b, +0x10400004, 0xafaa0064, 0x8f42013c, 0x1425023, +0xafaa0064, 0x26100002, 0x26520001, 0x253102b, +0x1440ffe3, 0x26310004, 0x8fb0006c, 0x10000036, +0x97b10038, 0x8f4200fc, 0x24050002, 0xa2102a, +0x1440001b, 0x24030001, 0x8f83012c, 0x10600013, +0x0, 0x8f820124, 0x431023, 0x22143, +0x58800001, 0x24840040, 0x8f820128, 0x431023, +0x21943, 0x58600001, 0x24630040, 0x64102a, +0x54400001, 0x602021, 0xaf4400fc, 0x8f4200fc, +0xa2102a, 0x14400006, 0x24030001, 0x8f420324, +0x1821, 0x24420001, 0xaf420324, 0x8f420324, +0x306200ff, 0x1040fea5, 0x3c020800, 0x96b1000a, +0x8fb0006c, 0x3223ffff, 0x70102b, 0x54400001, +0x608021, 0x8ea40000, 0x8ea50004, 0x240a0001, +0xafaa0010, 0xafbe0014, 0x8f420008, 0x8fa60064, +0xafa20018, 0x8f42010c, 0x40f809, 0x2003821, +0x1040fea2, 0x3c050007, 0x96a3000e, 0x97ab008e, +0x11600007, 0x609021, 0x934205b5, 0x14400004, +0x0, 0x97aa0086, 0x6b1825, 0xa6aa0016, +0x8fab007c, 0x3c02ffff, 0x1621024, 0x10400003, +0xb1402, 0x34630400, 0xa6a20014, 0x8faa006c, +0x560a0072, 0xa6a3000e, 0x34620004, 0xa6a2000e, +0x8fab0074, 0x14b1021, 0xa6a2000a, 0x8f430044, +0x8f440190, 0x8f450194, 0x34028000, 0xafa20010, +0x8f420044, 0x2a03021, 0x24070020, 0xafa20014, +0x8f42000c, 0x31940, 0x604821, 0xafa20018, +0x8f42010c, 0x4021, 0xa92821, 0xa9182b, +0x882021, 0x40f809, 0x832021, 0x5040fe7f, +0xa6b2000e, 0x8f420358, 0xafa0006c, 0xa34005b5, +0x2442ffff, 0xaf420358, 0x8faa005c, 0x240b0001, +0x8f420358, 0x154b0006, 0x24020002, 0x8f42034c, +0x2442ffff, 0xaf42034c, 0x1000000c, 0x8f42034c, +0x15420006, 0x0, 0x8f420354, 0x2442ffff, +0xaf420354, 0x10000005, 0x8f420354, 0x8f420350, +0x2442ffff, 0xaf420350, 0x8f420350, 0x8faa0054, +0x8fab004c, 0xad6a0000, 0x8f420044, 0x8f440088, +0x8f430078, 0x24420001, 0x441024, 0x24630001, +0xaf420044, 0xaf430078, 0x8c020240, 0x62182b, +0x14600065, 0x24070008, 0x8f440158, 0x8f45015c, +0x8f430044, 0x8f48000c, 0x8f860120, 0x24020040, +0xafa20010, 0xafa30014, 0xafa80018, 0x8f42010c, +0x40f809, 0x24c6001c, 0x14400011, 0x240b0001, +0x3c010001, 0x370821, 0xa02b40f2, 0x8f820124, +0xafa20010, 0x8f820128, 0x3c040001, 0x248438c8, +0xafa20014, 0x8f460044, 0x8f870120, 0x3c050009, +0xc0029d3, 0x34a51300, 0x1000000b, 0x0, +0x8f4202f4, 0x24420001, 0xaf4202f4, 0x8f4202f4, +0x8f420044, 0xaf42007c, 0x3c010001, 0x370821, +0xa02040f2, 0xaf400078, 0x8f420308, 0x24420001, +0xaf420308, 0x10000038, 0x8f420308, 0xa6b0000a, +0x8f430044, 0x8f440190, 0x8f450194, 0x34028000, +0xafa20010, 0x8f420044, 0x2a03021, 0x24070020, +0xafa20014, 0x8f42000c, 0x31940, 0x604821, +0xafa20018, 0x8f42010c, 0x4021, 0xa92821, +0xa9182b, 0x882021, 0x40f809, 0x832021, +0x1040fe1f, 0x240a0001, 0xa34a05b5, 0x8fab006c, +0x8faa0064, 0x1705823, 0xafab006c, 0x8fab009c, +0x1505021, 0x16a102b, 0x10400004, 0xafaa0064, +0x8f42013c, 0x1425023, 0xafaa0064, 0x8f420358, +0x2442ffff, 0xaf420358, 0x8f420358, 0x8f42034c, +0x2442ffff, 0xaf42034c, 0x8fab0054, 0x8faa004c, +0x8f42034c, 0xad4b0000, 0x8f420044, 0x8f440088, +0x8f430078, 0x24420001, 0x441024, 0x24630001, +0xaf420044, 0xaf430078, 0x8faa006c, 0x1540fe1b, +0x0, 0x8fab006c, 0x1160001e, 0x0, +0x934205b5, 0x10400009, 0x0, 0x8faa0064, +0xaf4a00c4, 0xaf4b00c0, 0x8fab007c, 0xaf4b00c8, +0x8faa0074, 0x1000000e, 0xaf4a00cc, 0x97ab008e, +0x1160000b, 0x34038100, 0x8fa20020, 0x8c46000c, +0xa443000c, 0x97aa0086, 0x8c440004, 0x8c450008, +0xa44a000e, 0xac440000, 0xac450004, 0xac460008, +0x8f42033c, 0x24420001, 0xaf42033c, 0x10000010, +0x8f42033c, 0x8fab007c, 0x3164ffff, 0x2484fffc, +0x801821, 0x8f440240, 0x8f450244, 0x8f460118, +0x1021, 0xa32821, 0xa3382b, 0x822021, +0x872021, 0xaf440240, 0xc0f809, 0xaf450244, +0x8fbf00c8, 0x8fbe00c4, 0x8fb500c0, 0x8fb300bc, +0x8fb200b8, 0x8fb100b4, 0x8fb000b0, 0x3e00008, +0x27bd00d0, 0x3e00008, 0x0, 0x27bdff38, +0x240b0001, 0xafbf00c0, 0xafbe00bc, 0xafb500b8, +0xafb300b4, 0xafb200b0, 0xafb100ac, 0xafb000a8, +0xa3a00087, 0xafa00044, 0xafab005c, 0x934205b5, +0xa7a00076, 0x10400007, 0xa7a0007e, 0x8f4c00c0, +0xafac0064, 0x8f4b00c8, 0x8f5e00c4, 0x10000129, +0xafab006c, 0x8f420114, 0x40f809, 0x27a40020, +0x304200ff, 0x1040029c, 0x0, 0x8fac0024, +0x8fbe0020, 0x3182ffff, 0x2442fffc, 0xafa20064, +0x3c020006, 0x2c21024, 0x14400015, 0xafac006c, +0x93c20000, 0x30420001, 0x10400011, 0x2402ffff, +0x8fc30000, 0x14620004, 0x3402ffff, 0x97c30004, +0x1062000b, 0x0, 0xc002343, 0x3c02021, +0x304200ff, 0x14400006, 0x0, 0x8f420118, +0x40f809, 0x0, 0x1000027f, 0x0, +0x8fa20024, 0x3c03ffbf, 0x3463ffff, 0x431024, +0x3c03ffff, 0x431824, 0x14600003, 0xafa20024, +0x10000040, 0x8021, 0x3c020080, 0x621024, +0x10400007, 0x0, 0x8f42037c, 0x24420001, +0xaf42037c, 0x8f42037c, 0x10000036, 0x24100001, +0x8f420200, 0x24420001, 0xaf420200, 0x8f420200, +0x3c020001, 0x621024, 0x10400006, 0x3c020002, +0x8f4201b4, 0x24420001, 0xaf4201b4, 0x8f4201b4, +0x3c020002, 0x621024, 0x10400006, 0x3c020004, +0x8f42036c, 0x24420001, 0xaf42036c, 0x8f42036c, +0x3c020004, 0x621024, 0x10400006, 0x3c020008, +0x8f420370, 0x24420001, 0xaf420370, 0x8f420370, +0x3c020008, 0x621024, 0x10400006, 0x3c020010, +0x8f420374, 0x24420001, 0xaf420374, 0x8f420374, +0x3c020010, 0x621024, 0x10400006, 0x3c020020, +0x8f4201b0, 0x24420001, 0xaf4201b0, 0x8f4201b0, +0x3c020020, 0x621024, 0x10400006, 0x24100001, +0x8f420378, 0x24420001, 0xaf420378, 0x8f420378, +0x24100001, 0x8c020260, 0x8fab0064, 0x4b102b, +0x10400015, 0x320200ff, 0x8f4201d8, 0x24420001, +0xaf4201d8, 0x8f4201d8, 0x8fac006c, 0x8f8200e0, +0x358c0100, 0xafac006c, 0xafa20010, 0x8f8200e4, +0x24100001, 0x3c040001, 0x248438d0, 0xafa20014, +0x8fa60020, 0x8fa70024, 0x3c050007, 0xc0029d3, +0x34a53600, 0x320200ff, 0x10400010, 0x3c020080, +0x2c21024, 0x1440000e, 0x32c20400, 0x8fab006c, +0x3c020080, 0x34420100, 0x1621024, 0x10400005, +0x0, 0x8f4201fc, 0x24420001, 0xaf4201fc, +0x8f4201fc, 0x10000201, 0x8fa30064, 0x32c20400, +0x10400012, 0x34028100, 0x97c3000c, 0x1462000f, +0x0, 0x240c0200, 0xa7ac0076, 0x97c2000e, +0x8fc30008, 0x8fc40004, 0x8fab0064, 0x8fc50000, +0x256bfffc, 0xafab0064, 0xa7a2007e, 0xafc3000c, +0xafc40008, 0xafc50004, 0x27de0004, 0x8fa70064, +0x320200ff, 0x14400031, 0x3c020100, 0x97c3000c, +0x2c6205dd, 0x10400015, 0x2821, 0x32c20800, +0x10400015, 0x24020800, 0x97c30014, 0x14620012, +0x3402aaaa, 0x97c3000e, 0x14620007, 0x2021, +0x97c30010, 0x24020300, 0x14620004, 0x801021, +0x97c20012, 0x2c440001, 0x801021, 0x54400006, +0x24050016, 0x10000004, 0x0, 0x24020800, +0x50620001, 0x2405000e, 0x10a00013, 0x3c52021, +0x24830009, 0x3c02001f, 0x3442ffff, 0x43102b, +0x10400003, 0x0, 0x8f42013c, 0x621823, +0x90620000, 0x38430006, 0x2c630001, 0x38420011, +0x2c420001, 0x621825, 0x10600004, 0x3c020100, +0x94820002, 0x453821, 0x3c020100, 0x2c21024, +0x5040000e, 0xafa70064, 0x8fac0064, 0x10ec0008, +0x3c050007, 0x3c040001, 0x24843938, 0x8fa60064, +0x34a54000, 0xafa00010, 0xc0029d3, 0xafa00014, +0x8fab0064, 0x256b0004, 0xafab0064, 0x8f420080, +0x8fac0064, 0x4c102b, 0x1040002c, 0x32c28000, +0x10400034, 0x240b0003, 0x32c21000, 0x10400031, +0xafab005c, 0x1000002e, 0x240c0004, 0x8f420340, +0x2403ffbf, 0x283a024, 0x24420001, 0xaf420340, +0x10000175, 0x8f420340, 0x3c020800, 0x2c2b025, +0x2402ffbf, 0x282a024, 0x8f830128, 0x3c040001, +0x24843900, 0x26620001, 0xafa20014, 0xafa30010, +0x8f860120, 0x8f870124, 0x3c050007, 0xc0029d3, +0x34a55300, 0x10000164, 0x0, 0x8ea20000, +0x8ea30004, 0x3c040001, 0x24843918, 0xafb00010, +0xafb20014, 0x8ea70018, 0x34a55900, 0xc0029d3, +0x603021, 0x10000158, 0x0, 0x8f420084, +0x8fab0064, 0x4b102b, 0x14400007, 0x3c020001, +0x2c21024, 0x10400004, 0x0, 0x240c0002, +0xafac005c, 0x8fab0064, 0x11600168, 0x27ac0020, +0xafac008c, 0x8fab005c, 0x240c0001, 0x556c0021, +0x240c0002, 0x8f430054, 0x8f420050, 0x1062000b, +0x274b0054, 0x8f520054, 0x3403ecc0, 0xafab004c, +0x26420001, 0x304201ff, 0xafa20054, 0x121140, +0x431021, 0x1000006b, 0x2e2a821, 0x8f420044, +0x8fac0064, 0x3c040001, 0x248438dc, 0xafac0014, +0xafa20010, 0x8f460054, 0x8f470050, 0x3c050007, +0xc0029d3, 0x34a54300, 0x8f430340, 0x2402ffbf, +0x282a024, 0x24630001, 0xaf430340, 0x10000126, +0x8f420340, 0x156c001d, 0x0, 0x8f430074, +0x8f420070, 0x1062000a, 0x274b0074, 0x8f520074, +0xafab004c, 0x26420001, 0x304203ff, 0xafa20054, +0x121140, 0x24426cc0, 0x1000004a, 0x2e2a821, +0x8f420044, 0x8fac0064, 0x3c040001, 0x248438e8, +0x3c050007, 0xafac0014, 0xafa20010, 0x8f460074, +0x8f470070, 0x34a54500, 0x240b0001, 0xc0029d3, +0xafab005c, 0x1000ffc3, 0x0, 0x8f430064, +0x8f420060, 0x1062001a, 0x274c0064, 0x8f520064, +0x8fab005c, 0xafac004c, 0x26420001, 0x304200ff, +0xafa20054, 0x24020004, 0x1562000e, 0x121140, +0x121180, 0x24420cc0, 0x2e21021, 0xafa20044, +0x9442002a, 0x8fac0044, 0x8fab0064, 0x4b102b, +0x10400024, 0x25950020, 0x240c0001, 0x10000021, +0xa3ac0087, 0x24424cc0, 0x1000001e, 0x2e2a821, +0x8f420044, 0x8fab0064, 0x3c040001, 0x248438f4, +0xafab0014, 0xafa20010, 0x8f460064, 0x8f470060, +0x3c050007, 0xc0029d3, 0x34a54800, 0x3c020008, +0x2c21024, 0x1440ff61, 0x0, 0x8f420360, +0x240c0001, 0xafac005c, 0x24420001, 0xaf420360, +0x1000ff90, 0x8f420360, 0x27a30036, 0x131040, +0x621821, 0x94620000, 0x441021, 0x1000001f, +0xa4620000, 0xaebe0018, 0x93a20087, 0x10400086, +0x9821, 0x8fab0044, 0x8fa40064, 0x8fa3008c, +0x25620020, 0xafa20028, 0x25620008, 0xafa20030, +0x25620010, 0xafab002c, 0xafa20034, 0x9562002a, +0xa7a20038, 0x95620018, 0xa7a2003a, 0x9562001a, +0xa7a2003c, 0x9562001c, 0xa7a2003e, 0x94620018, +0x24630002, 0x822023, 0x1880ffdf, 0x26730001, +0x2e620004, 0x1440fff9, 0x0, 0x8f4200fc, +0x262102a, 0x14400030, 0x24030001, 0x8f83012c, +0x10600028, 0x0, 0x8f820124, 0x431023, +0x22143, 0x58800001, 0x24840040, 0x8f820128, +0x431023, 0x21943, 0x58600001, 0x24630040, +0x64102a, 0x54400001, 0x602021, 0xaf4400fc, +0x8f4200fc, 0x262102a, 0x10400016, 0x24030001, +0x1000001a, 0x306200ff, 0x8fac008c, 0x111040, +0x4c1021, 0x94470018, 0x111080, 0x4c1021, +0xafbe0010, 0x8c420008, 0x3c040001, 0x2484390c, +0x3c050007, 0x8c430004, 0x8c420000, 0x34a55500, +0x2203021, 0xc0029d3, 0xafa30014, 0x1000003b, +0x0, 0x8f420324, 0x1821, 0x24420001, +0xaf420324, 0x8f420324, 0x306200ff, 0x1040ff06, +0x8821, 0x8f430008, 0x2402fbff, 0x621824, +0x605021, 0x1260002d, 0xaf430008, 0x2669ffff, +0x8fb0008c, 0x3c0b4000, 0x24b4025, 0x2009021, +0x8e420008, 0x96070018, 0x8c440000, 0x8c450004, +0x56290004, 0x240b0001, 0x240c0002, 0x10000002, +0xafac0010, 0xafab0010, 0x16200004, 0xafa80014, +0x8f420008, 0x10000002, 0xafa20018, 0xafaa0018, +0x8f42010c, 0x3c03021, 0xafa80098, 0xafa9009c, +0x40f809, 0xafaa00a0, 0x8fa80098, 0x8fa9009c, +0x8faa00a0, 0x1040ffc0, 0x3c02001f, 0x96030018, +0x3442ffff, 0x3c3f021, 0x5e102b, 0x10400003, +0x26100002, 0x8f42013c, 0x3c2f023, 0x26310001, +0x233102b, 0x1440ffda, 0x26520004, 0x8fb00064, +0x1000001a, 0x0, 0x96a3000a, 0x8fb00064, +0x70102b, 0x54400001, 0x608021, 0x8ea40000, +0x8ea50004, 0x8fab005c, 0x240c0002, 0xafac0010, +0x934305b5, 0xb1700, 0x10600003, 0x2423025, +0x3c020800, 0xc23025, 0xafa60014, 0x8f420008, +0xafa20018, 0x8f42010c, 0x3c03021, 0x40f809, +0x2003821, 0x1040fec9, 0x3c050007, 0x97ac0076, +0x11800007, 0x96a3000e, 0x934205b5, 0x14400004, +0x0, 0x97ab007e, 0x6c1825, 0xa6ab0016, +0x8fac006c, 0x3c02ffff, 0x1821024, 0x10400003, +0xc1402, 0x34630400, 0xa6a20014, 0xa6b0000a, +0x8fab0064, 0x560b0006, 0x3d0f021, 0x34620004, +0xafa00064, 0xa6a2000e, 0x1000000d, 0xa34005b5, +0x8fac0064, 0x3c02001f, 0x3442ffff, 0x5e102b, +0x1906023, 0xafac0064, 0xa6a3000e, 0x240b0001, +0x10400003, 0xa34b05b5, 0x8f42013c, 0x3c2f023, +0x8fab0054, 0x8fac004c, 0xad8b0000, 0x8fac0064, +0x1580feb8, 0x0, 0x8fab0064, 0x1160001b, +0x0, 0x934205b5, 0x10400006, 0x0, +0xaf5e00c4, 0xaf4b00c0, 0x8fac006c, 0x1000000e, +0xaf4c00c8, 0x97ab0076, 0x1160000b, 0x34038100, +0x8fa20020, 0x8c46000c, 0xa443000c, 0x97ac007e, +0x8c440004, 0x8c450008, 0xa44c000e, 0xac440000, +0xac450004, 0xac460008, 0x8f42033c, 0x24420001, +0xaf42033c, 0x10000010, 0x8f42033c, 0x8fab006c, +0x3164ffff, 0x2484fffc, 0x801821, 0x8f440240, +0x8f450244, 0x8f460118, 0x1021, 0xa32821, +0xa3382b, 0x822021, 0x872021, 0xaf440240, +0xc0f809, 0xaf450244, 0x8fbf00c0, 0x8fbe00bc, +0x8fb500b8, 0x8fb300b4, 0x8fb200b0, 0x8fb100ac, +0x8fb000a8, 0x3e00008, 0x27bd00c8, 0x3e00008, +0x0, 0x27bdffd8, 0xafbf0024, 0xafb00020, +0x8f43004c, 0x8f420048, 0x10620034, 0x0, +0x8f430048, 0x8f42004c, 0x622023, 0x4820001, +0x24840200, 0x8f430054, 0x8f42004c, 0x43102b, +0x14400004, 0x24020200, 0x8f43004c, 0x10000005, +0x431023, 0x8f420054, 0x8f43004c, 0x431023, +0x2442ffff, 0x405021, 0x8a102a, 0x54400001, +0x805021, 0x8f49004c, 0x8f48004c, 0x8f440178, +0x8f45017c, 0x8f46004c, 0x24071000, 0xafa70010, +0x84140, 0x1001821, 0x12a4821, 0x313001ff, +0xafb00014, 0x8f470014, 0x1021, 0x63140, +0xafa70018, 0xa32821, 0xa3382b, 0x822021, +0x872021, 0x3402ecc0, 0xc23021, 0x8f420108, +0x2e63021, 0x40f809, 0xa3940, 0x54400001, +0xaf50004c, 0x8f43004c, 0x8f420048, 0x14620018, +0x0, 0x8f420000, 0x10400007, 0x0, +0xaf80004c, 0x8f82004c, 0x1040fffd, 0x0, +0x10000005, 0x0, 0xaf800048, 0x8f820048, +0x1040fffd, 0x0, 0x8f820060, 0x2403fdff, +0x431024, 0xaf820060, 0x8f420000, 0x10400003, +0x0, 0x10000002, 0xaf80004c, 0xaf800048, +0x8fbf0024, 0x8fb00020, 0x3e00008, 0x27bd0028, +0x3e00008, 0x0, 0x27bdffd8, 0xafbf0024, +0xafb00020, 0x8f43005c, 0x8f420058, 0x10620049, +0x0, 0x8f430058, 0x8f42005c, 0x622023, +0x4820001, 0x24840100, 0x8f430064, 0x8f42005c, +0x43102b, 0x14400004, 0x24020100, 0x8f43005c, +0x10000005, 0x431023, 0x8f420064, 0x8f43005c, +0x431023, 0x2442ffff, 0x403821, 0x87102a, +0x54400001, 0x803821, 0x8f42005c, 0x471021, +0x305000ff, 0x32c21000, 0x10400015, 0x24082000, +0x8f49005c, 0x8f440180, 0x8f450184, 0x8f46005c, +0x73980, 0xafa80010, 0xafb00014, 0x8f480014, +0x94980, 0x1201821, 0x1021, 0xa32821, +0xa3482b, 0x822021, 0x892021, 0x63180, +0xafa80018, 0x8f420108, 0x10000014, 0x24c60cc0, +0x8f49005c, 0x8f440180, 0x8f450184, 0x8f46005c, +0x73940, 0xafa80010, 0xafb00014, 0x8f480014, +0x94940, 0x1201821, 0x1021, 0xa32821, +0xa3482b, 0x822021, 0x892021, 0x63140, +0xafa80018, 0x8f420108, 0x24c64cc0, 0x40f809, +0x2e63021, 0x54400001, 0xaf50005c, 0x8f43005c, +0x8f420058, 0x14620018, 0x0, 0x8f420000, +0x10400007, 0x0, 0xaf80004c, 0x8f82004c, +0x1040fffd, 0x0, 0x10000005, 0x0, +0xaf800048, 0x8f820048, 0x1040fffd, 0x0, +0x8f820060, 0x2403feff, 0x431024, 0xaf820060, +0x8f420000, 0x10400003, 0x0, 0x10000002, +0xaf80004c, 0xaf800048, 0x8fbf0024, 0x8fb00020, +0x3e00008, 0x27bd0028, 0x3e00008, 0x0, +0x27bdffd8, 0xafbf0024, 0xafb00020, 0x8f43006c, +0x8f420068, 0x10620033, 0x0, 0x8f430068, +0x8f42006c, 0x622023, 0x4820001, 0x24840400, +0x8f430074, 0x8f42006c, 0x43102b, 0x14400004, +0x24020400, 0x8f43006c, 0x10000005, 0x431023, +0x8f420074, 0x8f43006c, 0x431023, 0x2442ffff, +0x405021, 0x8a102a, 0x54400001, 0x805021, +0x8f49006c, 0x8f48006c, 0x8f440188, 0x8f45018c, +0x8f46006c, 0x24074000, 0xafa70010, 0x84140, +0x1001821, 0x12a4821, 0x313003ff, 0xafb00014, +0x8f470014, 0x1021, 0x63140, 0x24c66cc0, +0xafa70018, 0xa32821, 0xa3382b, 0x822021, +0x872021, 0x8f420108, 0x2e63021, 0x40f809, +0xa3940, 0x54400001, 0xaf50006c, 0x8f43006c, +0x8f420068, 0x14620018, 0x0, 0x8f420000, +0x10400007, 0x0, 0xaf80004c, 0x8f82004c, +0x1040fffd, 0x0, 0x10000005, 0x0, +0xaf800048, 0x8f820048, 0x1040fffd, 0x0, +0x8f820060, 0x2403f7ff, 0x431024, 0xaf820060, +0x8f420000, 0x10400003, 0x0, 0x10000002, +0xaf80004c, 0xaf800048, 0x8fbf0024, 0x8fb00020, +0x3e00008, 0x27bd0028, 0x3e00008, 0x0, +0x8f4200fc, 0x3c030001, 0x8f4400f8, 0x346330c8, +0x24420001, 0xaf4200fc, 0x8f850128, 0x2e31021, +0x54820004, 0x24820008, 0x3c020001, 0x34422ec8, +0x2e21021, 0x401821, 0xaf4300f8, 0xac600000, +0x8f4200f4, 0x14620004, 0x3c020001, 0x24a20020, +0x1000000f, 0xaf820128, 0x8f4300f8, 0x344230c8, +0x2e21021, 0x54620004, 0x24620008, 0x3c020001, +0x34422ec8, 0x2e21021, 0x401821, 0x8c620004, +0x21140, 0xa21021, 0xaf820128, 0xac600000, +0x8ca30018, 0x30620070, 0x1040002d, 0x30620020, +0x10400004, 0x3c020010, 0x2c21024, 0x1040000d, +0x0, 0x30620040, 0x10400004, 0x3c020020, +0x2c21024, 0x10400007, 0x0, 0x30620010, +0x1040001f, 0x3c020040, 0x2c21024, 0x1440001c, +0x0, 0x8f820040, 0x30420001, 0x14400008, +0x2021, 0x8c030104, 0x24020001, 0x50620005, +0x24040001, 0x8c020264, 0x10400003, 0x801021, +0x24040001, 0x801021, 0x10400006, 0x0, +0x8f4202fc, 0x24420001, 0xaf4202fc, 0x10000008, +0x8f4202fc, 0x8f820044, 0x34420004, 0xaf820044, +0x8f4202f8, 0x24420001, 0xaf4202f8, 0x8f4202f8, +0x3e00008, 0x0, 0x3e00008, 0x0, +0x27bdffa0, 0xafbf0058, 0xafbe0054, 0xafb50050, +0xafb3004c, 0xafb20048, 0xafb10044, 0xafb00040, +0x8f4200fc, 0x24420001, 0xaf4200fc, 0x8f880128, +0x25020020, 0xaf820128, 0x8d030018, 0x30620070, +0x1040002e, 0x30620020, 0x10400004, 0x3c020010, +0x2c21024, 0x1040000d, 0x0, 0x30620040, +0x10400004, 0x3c020020, 0x2c21024, 0x10400007, +0x0, 0x30620010, 0x10400193, 0x3c020040, +0x2c21024, 0x14400190, 0x0, 0x8f820040, +0x30420001, 0x14400008, 0x2021, 0x8c030104, +0x24020001, 0x50620005, 0x24040001, 0x8c020264, +0x10400003, 0x801021, 0x24040001, 0x801021, +0x10400006, 0x0, 0x8f4202fc, 0x24420001, +0xaf4202fc, 0x1000017c, 0x8f4202fc, 0x8f820044, +0x34420004, 0xaf820044, 0x8f4202f8, 0x24420001, +0xaf4202f8, 0x10000174, 0x8f4202f8, 0x30620002, +0x10400135, 0x3c020800, 0x8d0a001c, 0x1422024, +0xafaa0024, 0xa5702, 0xafaa0034, 0x8faa0024, +0x314affff, 0xafaa0024, 0x950a0016, 0xafaa002c, +0x8faa0034, 0x24020001, 0x15420007, 0x24020002, +0x8faa0024, 0xa1140, 0x3403ecc0, 0x431021, +0x10000014, 0x2e2a821, 0x15420006, 0x24020003, +0x8faa0024, 0xa1140, 0x24426cc0, 0x1000000d, +0x2e2a821, 0x8faa0034, 0x15420006, 0x0, +0x8faa0024, 0xa1140, 0x24424cc0, 0x10000005, +0x2e2a821, 0x8faa0024, 0xa1180, 0x571021, +0x24550ce0, 0x96a2000e, 0x305efffc, 0x30420400, +0x144000c5, 0x8821, 0x10800004, 0x24091000, +0x97b1002e, 0x100000c1, 0x0, 0x8eb30018, +0x9663000c, 0x2c6205dd, 0x10400015, 0x2021, +0x32c20800, 0x10400015, 0x24020800, 0x96630014, +0x14620012, 0x3402aaaa, 0x9663000e, 0x14620007, +0x2821, 0x96630010, 0x24020300, 0x14620004, +0xa01021, 0x96620012, 0x2c450001, 0xa01021, +0x54400006, 0x24040016, 0x10000004, 0x0, +0x24020800, 0x50620001, 0x2404000e, 0x108000a2, +0x2649021, 0x92420000, 0x3042000f, 0x28080, +0x32c20100, 0x1040001e, 0x2501821, 0x3c020020, +0x43102b, 0x1440000e, 0x2402021, 0x2821, +0x94820000, 0x24840002, 0xa22821, 0x83102b, +0x1440fffb, 0x30a2ffff, 0x51c02, 0x622821, +0x51c02, 0x30a2ffff, 0x10000009, 0x622821, +0x8f47013c, 0x8f420110, 0x102842, 0x3c060020, +0x40f809, 0xafa80038, 0x3045ffff, 0x8fa80038, +0x50a00001, 0x3405ffff, 0x10000002, 0x37de0002, +0x2821, 0x32c20080, 0x1040007b, 0xa6a50010, +0x26430009, 0x3c02001f, 0x3442ffff, 0x43102b, +0x10400003, 0x0, 0x8f42013c, 0x621823, +0x90660000, 0x30c200ff, 0x38430006, 0x2c630001, +0x38420011, 0x2c420001, 0x621825, 0x1060006b, +0x24091000, 0x8821, 0x2602021, 0x94820000, +0x24840002, 0x2228821, 0x92102b, 0x1440fffb, +0x111c02, 0x3222ffff, 0x628821, 0x111c02, +0x3222ffff, 0x628821, 0x32c20200, 0x10400003, +0x26440006, 0x1000003e, 0x8021, 0x3c05001f, +0x34a5ffff, 0xa4102b, 0x10400003, 0x0, +0x8f42013c, 0x822023, 0x94820000, 0x30421fff, +0x10400004, 0x2644000c, 0x96420002, 0x10000030, +0x508023, 0x96420002, 0x26430014, 0x508023, +0x3c020020, 0x43102b, 0x1440000a, 0xd08021, +0x9642000c, 0x2028021, 0x9642000e, 0x96430010, +0x96440012, 0x2028021, 0x2038021, 0x10000020, +0x2048021, 0xa4102b, 0x10400003, 0x0, +0x8f42013c, 0x822023, 0x94820000, 0x24840002, +0x2028021, 0xa4102b, 0x10400003, 0x0, +0x8f42013c, 0x822023, 0x94820000, 0x24840002, +0x2028021, 0xa4102b, 0x10400003, 0x0, +0x8f42013c, 0x822023, 0x94820000, 0x24840002, +0x2028021, 0xa4102b, 0x10400003, 0x0, +0x8f42013c, 0x822023, 0x94820000, 0x2028021, +0x3c020100, 0x2c21024, 0x1040000c, 0x33c20004, +0x1040000a, 0x0, 0x9504000e, 0x2642021, +0xc003cc8, 0x2484fffc, 0x3042ffff, 0x2228821, +0x111c02, 0x3222ffff, 0x628821, 0x8faa002c, +0x1518823, 0x111402, 0x2228821, 0x2308821, +0x111402, 0x2228821, 0x3231ffff, 0x52200001, +0x3411ffff, 0x37de0001, 0x24091000, 0x33c20004, +0xa6b10012, 0x10400002, 0xa6be000e, 0x34098000, +0x8f480044, 0x8f440190, 0x8f450194, 0xafa90010, +0x8f490044, 0x84140, 0x1001821, 0xafa90014, +0x8f48000c, 0x2a03021, 0x24070020, 0xafa80018, +0x8f48010c, 0x1021, 0xa32821, 0xa3482b, +0x822021, 0x100f809, 0x892021, 0x1440000c, +0x0, 0x8f820128, 0x8faa0024, 0x3c040001, +0x24843944, 0xafaa0014, 0xafa20010, 0x8f860124, +0x8f870120, 0x3c050007, 0xc0029d3, 0x34a59920, +0x8f420358, 0x2442ffff, 0xaf420358, 0x8f420044, +0x8f430088, 0x24420001, 0x431024, 0xaf420044, +0x8faa0034, 0x8f440358, 0x24020001, 0x15420006, +0x24020002, 0x8f42034c, 0x2442ffff, 0xaf42034c, +0x10000049, 0x8f42034c, 0x15420006, 0x0, +0x8f420354, 0x2442ffff, 0xaf420354, 0x10000042, +0x8f420354, 0x8f420350, 0x2442ffff, 0xaf420350, +0x1000003d, 0x8f420350, 0x30621000, 0x10400005, +0x30628000, 0x8f420078, 0x24420001, 0x10000036, +0xaf420078, 0x10400034, 0x0, 0x8f420078, +0x24420001, 0xaf420078, 0x8c030240, 0x43102b, +0x1440002d, 0x24070008, 0x8f440158, 0x8f45015c, +0x8f430044, 0x8f48000c, 0x8f860120, 0x24020040, +0xafa20010, 0xafa30014, 0xafa80018, 0x8f42010c, +0x40f809, 0x24c6001c, 0x14400011, 0x24020001, +0x3c010001, 0x370821, 0xa02240f2, 0x8f820124, +0xafa20010, 0x8f820128, 0x3c040001, 0x248438c8, +0xafa20014, 0x8f460044, 0x8f870120, 0x3c050009, +0xc0029d3, 0x34a51300, 0x1000000b, 0x0, +0x8f4202f4, 0x24420001, 0xaf4202f4, 0x8f4202f4, +0x8f420044, 0xaf42007c, 0x3c010001, 0x370821, +0xa02040f2, 0xaf400078, 0x8f420308, 0x24420001, +0xaf420308, 0x8f420308, 0x8fbf0058, 0x8fbe0054, +0x8fb50050, 0x8fb3004c, 0x8fb20048, 0x8fb10044, +0x8fb00040, 0x3e00008, 0x27bd0060, 0x3e00008, +0x0, 0x0, 0x0, 0x8f420130, +0xaf8200c0, 0x8f420130, 0xaf8200c4, 0x8f420130, +0xaf8200c8, 0x8f42012c, 0xaf8200d0, 0x8f42012c, +0xaf8200d4, 0x8f42012c, 0x3e00008, 0xaf8200d8, +0x27bdffe0, 0x27840208, 0x24050200, 0xafbf0018, +0xc002a57, 0x24060008, 0x8c020204, 0xc003dee, +0xaf820210, 0x2021, 0x8c060248, 0x24020004, +0x3c010001, 0xac223d18, 0xc004878, 0x24050004, +0x3c020001, 0x8c423d14, 0x30420001, 0x10400007, +0x24020001, 0x3c010001, 0xac223d18, 0x2021, +0x24050001, 0xc004878, 0x3c06601b, 0x3c040001, +0x24843a00, 0x8f420144, 0x8f430148, 0x3c050008, +0x8f46014c, 0x21640, 0x31940, 0x34630403, +0x431025, 0x633c0, 0x461025, 0xaf82021c, +0xafa00010, 0xafa00014, 0x8f86021c, 0x34a50200, +0xc0029d3, 0x3821, 0x3c010001, 0xac203d10, +0x3c010001, 0xac203d28, 0x8fbf0018, 0x3e00008, +0x27bd0020, 0x27bdffe0, 0x3c050008, 0x34a50300, +0xafbf0018, 0xafa00010, 0xafa00014, 0x8f860200, +0x3c040001, 0x24843a0c, 0xc0029d3, 0x3821, +0x8f420400, 0x24420001, 0xaf420400, 0x8f420400, +0x8fbf0018, 0x3e00008, 0x27bd0020, 0x27bdffd8, +0xafbf0020, 0xafb1001c, 0xafb00018, 0x8f420394, +0x24420001, 0xaf420394, 0x8f420394, 0x8f900220, +0x8f4303a8, 0x3c020001, 0x8c423d28, 0x3c040001, +0x24843a18, 0x3c050008, 0xafa20014, 0xafa30010, +0x8f4703ac, 0x34a50400, 0xc0029d3, 0x2003021, +0x3c024000, 0x2021024, 0x104000e1, 0x3c040100, +0x8f4203ac, 0x24420001, 0xaf4203ac, 0x8f4203ac, +0x8f820220, 0x3c0308ff, 0x3463ffff, 0x431024, +0x34420004, 0xaf820220, 0x8f8200e0, 0x8f8300c4, +0x3c02001f, 0x3442ffff, 0x24690008, 0x49102b, +0x10400003, 0x0, 0x8f42013c, 0x1224823, +0x8f8700c8, 0x8f840120, 0x8f830124, 0x10000005, +0x5821, 0x8f42012c, 0x62102b, 0x50400001, +0x27634800, 0x1083000d, 0x316200ff, 0x8c620018, +0x2442ffff, 0x2c420002, 0x5040fff6, 0x24630020, +0x8f4203c0, 0x240b0001, 0x24420001, 0xaf4203c0, +0x8f4203c0, 0x8c670008, 0x316200ff, 0x14400078, +0x0, 0x934205b5, 0x14400075, 0x0, +0x8f8500e4, 0x8f8200e0, 0x2403fff8, 0x433024, +0xc51023, 0x218c3, 0x4620001, 0x24630100, +0x8f8a00c4, 0x10600005, 0x24020001, 0x10620009, +0x0, 0x10000021, 0x0, 0x8f4203b0, +0x1403821, 0x24420001, 0xaf4203b0, 0x10000060, +0x8f4203b0, 0x8f4203b4, 0x24420001, 0xaf4203b4, +0x8ca70000, 0x8f42013c, 0x8f4303b4, 0x1471823, +0x43102b, 0x10400004, 0x2c62233f, 0x8f42013c, +0x621821, 0x2c62233f, 0x14400051, 0x3c020100, +0xaca20004, 0x8f8200e8, 0x24420008, 0xaf8200e8, +0x8f8200e8, 0x8f8200e4, 0x1403821, 0x24420008, +0xaf8200e4, 0x10000046, 0x8f8200e4, 0x8f4203b8, +0x24420001, 0xaf4203b8, 0x8ca80000, 0x8f42013c, +0x8f4303b8, 0x1092023, 0x44102b, 0x10400003, +0x0, 0x8f42013c, 0x822021, 0x8f420140, +0x44102b, 0x10400003, 0x3c030100, 0x10000034, +0x1003821, 0x8ca20004, 0x431025, 0xaca20004, +0x8f8200e4, 0x24450008, 0xaf8500e4, 0x8f8500e4, +0x10a60025, 0x3c080100, 0x8f4201fc, 0x24420001, +0xaf4201fc, 0x8ca20004, 0x8f4301fc, 0x481024, +0x1440000e, 0x0, 0x8ca30000, 0x8f42013c, +0x692023, 0x44102b, 0x10400003, 0x0, +0x8f42013c, 0x822021, 0x8f420140, 0x44102b, +0x10400006, 0x0, 0x603821, 0x8f420140, +0x44102b, 0x1440000a, 0x0, 0x8ca20004, +0x481025, 0xaca20004, 0x8f8200e4, 0x24450008, +0xaf8500e4, 0x8f8500e4, 0x14a6ffdf, 0x0, +0x14a60005, 0x0, 0x1403821, 0xaf8600e4, +0x10000003, 0xaf8600e8, 0xaf8500e4, 0xaf8500e8, +0x8f8300c8, 0x8f42013c, 0x692023, 0x44102b, +0x10400003, 0x0, 0x8f42013c, 0x822021, +0x8f420140, 0x82102b, 0x50400008, 0x5821, +0x8f42013c, 0xe92023, 0x44102b, 0x10400003, +0x0, 0x8f42013c, 0x822021, 0x8f420140, +0x82102b, 0x10400006, 0x316200ff, 0x1440001b, +0x3c02fdff, 0x934205b5, 0x14400018, 0x3c02fdff, +0xaf8700c8, 0x8f8400c8, 0x8f8300c4, 0x8f42013c, +0x832023, 0x44102b, 0x10400003, 0x0, +0x8f42013c, 0x822021, 0x8f420140, 0x2c830001, +0x44102b, 0x431025, 0x50400008, 0x3c02fdff, +0x8f820220, 0x3c0308ff, 0x3463fffb, 0x431024, +0x3c034000, 0x10000046, 0x431025, 0x3442ffff, +0x8f4303bc, 0x282a024, 0x24020001, 0xa34205b1, +0x24630001, 0xaf4303bc, 0x1000003e, 0x8f4203bc, +0x2041024, 0x10400013, 0x3c110200, 0x8f420398, +0x24420001, 0xaf420398, 0x8f420398, 0x8f820220, +0x3c0308ff, 0x3463ffff, 0x431024, 0x441025, +0xaf820220, 0x3c020004, 0x2021024, 0x14400005, +0x3c110200, 0xc003bad, 0x0, 0x10000029, +0x0, 0x2111024, 0x50400008, 0x3c110400, +0x8f42039c, 0x24420001, 0xaf42039c, 0xc003bad, +0x8f42039c, 0x10000019, 0x0, 0x2111024, +0x1040001c, 0x0, 0x8f830224, 0x24021402, +0x14620009, 0x3c050008, 0x3c040001, 0x24843a24, +0xafa00010, 0xafa00014, 0x8f860224, 0x34a50500, +0xc0029d3, 0x3821, 0x8f4203a0, 0x24420001, +0xaf4203a0, 0x8f4203a0, 0x8f820220, 0x2002021, +0x34420002, 0xc004610, 0xaf820220, 0x8f820220, +0x3c0308ff, 0x3463ffff, 0x431024, 0x511025, +0xaf820220, 0x8fbf0020, 0x8fb1001c, 0x8fb00018, +0x3e00008, 0x27bd0028, 0x3e00008, 0x0, +0x3c020001, 0x8c423d28, 0x27bdffb0, 0xafbf0048, +0xafbe0044, 0xafb50040, 0xafb3003c, 0xafb20038, +0xafb10034, 0x1040000f, 0xafb00030, 0x3c040001, +0x24843a30, 0x3c050008, 0xafa00010, 0xafa00014, +0x8f860220, 0x34a50600, 0x24020001, 0x3c010001, +0xac203d28, 0x3c010001, 0xac223d1c, 0xc0029d3, +0x3821, 0x3c037fff, 0x8c020268, 0x3463ffff, +0x3c04fdff, 0x431024, 0xac020268, 0x8f420004, +0x3484ffff, 0x30420002, 0x10400092, 0x284a024, +0x3c040600, 0x34842000, 0x8f420004, 0x2821, +0x2403fffd, 0x431024, 0xaf420004, 0xafa40020, +0x8f5e0018, 0x27aa0020, 0x240200ff, 0x13c20002, +0xafaa002c, 0x27c50001, 0x8c020228, 0xa09021, +0x1642000e, 0x1e38c0, 0x8f42032c, 0x24420001, +0xaf42032c, 0x8f42032c, 0x8c020228, 0x3c040001, +0x248439c8, 0x3c050009, 0xafa00014, 0xafa20010, +0x8fa60020, 0x1000006d, 0x34a50500, 0xf71021, +0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4, +0x8f830054, 0x8f820054, 0x247003e8, 0x2021023, +0x2c4203e9, 0x1040001b, 0x9821, 0xe08821, +0x263504c0, 0x8f440168, 0x8f45016c, 0x2201821, +0x240a0004, 0xafaa0010, 0xafb20014, 0x8f48000c, +0x1021, 0x2f53021, 0xafa80018, 0x8f48010c, +0x24070008, 0xa32821, 0xa3482b, 0x822021, +0x100f809, 0x892021, 0x54400006, 0x24130001, +0x8f820054, 0x2021023, 0x2c4203e9, 0x1440ffe9, +0x0, 0x326200ff, 0x54400017, 0xaf520018, +0x8f420368, 0x24420001, 0xaf420368, 0x8f420368, +0x8f820120, 0x8faa002c, 0xafa20010, 0x8f820124, +0x3c040001, 0x248439d4, 0x3c050009, 0xafa20014, +0x8d460000, 0x10000035, 0x34a50600, 0x8f4202f8, +0x24130001, 0x24420001, 0xaf4202f8, 0x8f4202f8, +0x1000001e, 0x326200ff, 0x8f830054, 0x8f820054, +0x247003e8, 0x2021023, 0x2c4203e9, 0x10400016, +0x9821, 0x3c150020, 0x24110010, 0x8f42000c, +0x8f440150, 0x8f450154, 0x8f860120, 0xafb10010, +0xafb20014, 0x551025, 0xafa20018, 0x8f42010c, +0x24070008, 0x40f809, 0x24c6001c, 0x1440ffe3, +0x0, 0x8f820054, 0x2021023, 0x2c4203e9, +0x1440ffee, 0x0, 0x326200ff, 0x14400011, +0x0, 0x8f420368, 0x24420001, 0xaf420368, +0x8f420368, 0x8f820120, 0x8faa002c, 0xafa20010, +0x8f820124, 0x3c040001, 0x248439dc, 0x3c050009, +0xafa20014, 0x8d460000, 0x34a50700, 0xc0029d3, +0x3c03821, 0x8f4202dc, 0x24420001, 0xaf4202dc, +0x8f4202dc, 0x8fbf0048, 0x8fbe0044, 0x8fb50040, +0x8fb3003c, 0x8fb20038, 0x8fb10034, 0x8fb00030, +0x3e00008, 0x27bd0050, 0x3c020001, 0x8c423d28, +0x27bdffe0, 0x1440000d, 0xafbf0018, 0x3c040001, +0x24843a3c, 0x3c050008, 0xafa00010, 0xafa00014, +0x8f860220, 0x34a50700, 0x24020001, 0x3c010001, +0xac223d28, 0xc0029d3, 0x3821, 0x3c020004, +0x2c21024, 0x10400008, 0x2021, 0x8f820220, +0x3c0308ff, 0x3463ffff, 0x431024, 0x34420008, +0xaf820220, 0x2021, 0xc004981, 0x24050004, +0xac020268, 0x8fbf0018, 0x3e00008, 0x27bd0020, +0x0, 0x0, 0x0, 0x86102b, +0x50400001, 0x872023, 0xc41023, 0x24843, +0x125102b, 0x1040001b, 0x91040, 0x824021, +0x88102b, 0x10400007, 0x1821, 0x94820000, +0x24840002, 0x621821, 0x88102b, 0x1440fffb, +0x0, 0x602021, 0xc73023, 0xa91023, +0x21040, 0xc22821, 0xc5102b, 0x10400007, +0x1821, 0x94c20000, 0x24c60002, 0x621821, +0xc5102b, 0x1440fffb, 0x0, 0x1000000d, +0x832021, 0x51040, 0x822821, 0x85102b, +0x10400007, 0x1821, 0x94820000, 0x24840002, +0x621821, 0x85102b, 0x1440fffb, 0x0, +0x602021, 0x41c02, 0x3082ffff, 0x622021, +0x41c02, 0x3082ffff, 0x622021, 0x3e00008, +0x3082ffff, 0x3e00008, 0x0, 0x802821, +0x30a20001, 0x1040002b, 0x3c03001f, 0x3463ffff, +0x24a20004, 0x62102b, 0x54400007, 0x65102b, +0x90a20001, 0x90a40003, 0x90a30000, 0x90a50002, +0x1000002a, 0x441021, 0x10400003, 0x0, +0x8f42013c, 0xa22823, 0x90a40000, 0x24a50001, +0x65102b, 0x10400003, 0x0, 0x8f42013c, +0xa22823, 0x90a20000, 0x24a50001, 0x21200, +0x822021, 0x65102b, 0x10400003, 0x0, +0x8f42013c, 0xa22823, 0x90a20000, 0x24a50001, +0x822021, 0x65102b, 0x10400003, 0x0, +0x8f42013c, 0xa22823, 0x90a20000, 0x1000002d, +0x21200, 0x3463ffff, 0x24a20004, 0x62102b, +0x5440000a, 0x65102b, 0x90a20000, 0x90a40002, +0x90a30001, 0x90a50003, 0x441021, 0x21200, +0x651821, 0x10000020, 0x432021, 0x10400003, +0x0, 0x8f42013c, 0xa22823, 0x90a20000, +0x24a50001, 0x22200, 0x65102b, 0x10400003, +0x0, 0x8f42013c, 0xa22823, 0x90a20000, +0x24a50001, 0x822021, 0x65102b, 0x10400003, +0x0, 0x8f42013c, 0xa22823, 0x90a20000, +0x24a50001, 0x21200, 0x822021, 0x65102b, +0x10400003, 0x0, 0x8f42013c, 0xa22823, +0x90a20000, 0x822021, 0x41c02, 0x3082ffff, +0x622021, 0x41c02, 0x3082ffff, 0x622021, +0x3e00008, 0x3082ffff, 0x0, 0x8f820220, +0x34420002, 0xaf820220, 0x3c020001, 0x8c425f28, +0x30424000, 0x10400054, 0x24040001, 0x8f820200, +0x24067fff, 0x8f830200, 0x30450002, 0x2402fffd, +0x621824, 0xaf830200, 0xaf840204, 0x8f830054, +0x8f820054, 0x10000002, 0x24630001, 0x8f820054, +0x621023, 0x2c420002, 0x1440fffc, 0x0, +0x8f820224, 0x1444004d, 0x42040, 0xc4102b, +0x1040fff1, 0x0, 0x8f820200, 0x451025, +0xaf820200, 0x8f820220, 0x34428000, 0xaf820220, +0x8f830054, 0x8f820054, 0x10000002, 0x24630001, +0x8f820054, 0x621023, 0x2c420002, 0x1440fffc, +0x0, 0x8f820220, 0x3c030004, 0x431024, +0x1440000f, 0x0, 0x8f820220, 0x3c03ffff, +0x34637fff, 0x431024, 0xaf820220, 0x8f830054, +0x8f820054, 0x10000002, 0x24630001, 0x8f820054, +0x621023, 0x2c420002, 0x1440fffc, 0x0, +0x8f820220, 0x3c030004, 0x431024, 0x1440000d, +0x0, 0x8f820220, 0x34428000, 0xaf820220, +0x8f830054, 0x8f820054, 0x10000002, 0x24630001, +0x8f820054, 0x621023, 0x2c420002, 0x1440fffc, +0x0, 0x8f820220, 0x3c030004, 0x431024, +0x1040001b, 0x1021, 0x8f830220, 0x24020001, +0x10000015, 0x3c04f700, 0x8f820220, 0x3c04f700, +0x441025, 0xaf820220, 0x8f820220, 0x2403fffd, +0x431024, 0xaf820220, 0x8f820220, 0x3c030300, +0x431024, 0x14400003, 0x0, 0x10000008, +0x1021, 0x8f820220, 0x34420002, 0xaf820220, +0x8f830220, 0x24020001, 0x641825, 0xaf830220, +0x3e00008, 0x0, 0x2021, 0x3c050100, +0x24020001, 0xaf80021c, 0xaf820200, 0xaf820220, +0x27625000, 0xaf8200c0, 0x27625000, 0xaf8200c4, +0x27625000, 0xaf8200c8, 0x27625000, 0xaf8200d0, +0x27625000, 0xaf8200d4, 0x27625000, 0xaf8200d8, +0x27623000, 0xaf8200e0, 0x27623000, 0xaf8200e4, +0x27623000, 0xaf8200e8, 0x27622800, 0xaf8200f0, +0x27622800, 0xaf8200f4, 0x27622800, 0xaf8200f8, +0x418c0, 0x24840001, 0x3631021, 0xac453004, +0x3631021, 0xac403000, 0x28820200, 0x1440fff9, +0x418c0, 0x2021, 0x418c0, 0x24840001, +0x3631021, 0xac402804, 0x3631021, 0xac402800, +0x28820100, 0x1440fff9, 0x418c0, 0xaf80023c, +0x24030080, 0x24040100, 0xac600000, 0x24630004, +0x64102b, 0x5440fffd, 0xac600000, 0x8f830040, +0x3c02f000, 0x621824, 0x3c025000, 0x1062000c, +0x43102b, 0x14400006, 0x3c026000, 0x3c024000, +0x10620008, 0x24020800, 0x10000008, 0x0, +0x10620004, 0x24020800, 0x10000004, 0x0, +0x24020700, 0x3c010001, 0xac223d2c, 0x3e00008, +0x0, 0x27bdffc8, 0xafbf0034, 0xafb20030, +0xafb1002c, 0xafb00028, 0x3c010001, 0xc0045ed, +0xac203d14, 0x24040001, 0x2821, 0x27a60020, +0x34028000, 0xc00420a, 0xa7a20020, 0x8f830054, +0x8f820054, 0x10000002, 0x24630064, 0x8f820054, +0x621023, 0x2c420065, 0x1440fffc, 0x24040001, +0x24050001, 0xc0041c8, 0x27a60020, 0x8f830054, +0x8f820054, 0x10000002, 0x24630064, 0x8f820054, +0x621023, 0x2c420065, 0x1440fffc, 0x24040001, +0x24050001, 0xc0041c8, 0x27a60020, 0x8f830054, +0x8f820054, 0x10000002, 0x24630064, 0x8f820054, +0x621023, 0x2c420065, 0x1440fffc, 0x24040001, +0x24050002, 0xc0041c8, 0x27a60018, 0x8f830054, +0x8f820054, 0x10000002, 0x24630064, 0x8f820054, +0x621023, 0x2c420065, 0x1440fffc, 0x24040001, +0x24050003, 0xc0041c8, 0x27a6001a, 0x97a20020, +0x10400029, 0x24020001, 0x3c020001, 0x8c423d14, +0x97a30018, 0x34420001, 0x3c010001, 0xac223d14, +0x24020015, 0x14620009, 0x0, 0x97a2001a, +0x3843f423, 0x2c630001, 0x3842f430, 0x2c420001, +0x621825, 0x14600018, 0x24020003, 0x97a30018, +0x24027810, 0x14620014, 0x24020002, 0x97a3001a, +0x24020001, 0x14620010, 0x24020002, 0x1000000e, +0x24020004, 0x3c020001, 0x8c423d14, 0x34420008, +0x3c010001, 0xac223d14, 0x10000058, 0x24020004, +0x3c020001, 0x8c423d14, 0x34420004, 0x3c010001, +0x100000a9, 0xac223d14, 0x3c010001, 0xac223e70, +0x24020e00, 0xaf820238, 0x8f840054, 0x8f820054, +0x24030008, 0x3c010001, 0xac233d18, 0x10000002, +0x248401f4, 0x8f820054, 0x821023, 0x2c4201f5, +0x1440fffc, 0x3c0200c8, 0x344201fb, 0xaf820238, +0x8f830054, 0x8f820054, 0x10000002, 0x246301f4, +0x8f820054, 0x621023, 0x2c4201f5, 0x1440fffc, +0x8021, 0x24120001, 0x24110009, 0xc0040e8, +0x0, 0x3c010001, 0xac323d30, 0xc004194, +0x0, 0x3c020001, 0x8c423d30, 0x1451fffb, +0x3c0200c8, 0x344201f6, 0xaf820238, 0x8f830054, +0x8f820054, 0x10000002, 0x2463000a, 0x8f820054, +0x621023, 0x2c42000b, 0x1440fffc, 0x0, +0x8f820220, 0x24040001, 0x34420002, 0xaf820220, +0x8f830200, 0x24057fff, 0x2402fffd, 0x621824, +0xaf830200, 0xaf840204, 0x8f830054, 0x8f820054, +0x10000002, 0x24630001, 0x8f820054, 0x621023, +0x2c420002, 0x1440fffc, 0x0, 0x8f820224, +0x14440005, 0x34028000, 0x42040, 0xa4102b, +0x1040fff0, 0x34028000, 0x1082ffa6, 0x26100001, +0x2e020014, 0x1440ffcd, 0x24020004, 0x3c010001, +0xac223d18, 0x8021, 0x24120009, 0x3c11ffff, +0x36313f7f, 0xc0040e8, 0x0, 0x24020001, +0x3c010001, 0xac223d30, 0xc004194, 0x0, +0x3c020001, 0x8c423d30, 0x1452fffb, 0x0, +0x8f820044, 0x511024, 0x34425080, 0xaf820044, +0x8f830054, 0x8f820054, 0x10000002, 0x2463000a, +0x8f820054, 0x621023, 0x2c42000b, 0x1440fffc, +0x0, 0x8f820044, 0x511024, 0x3442f080, +0xaf820044, 0x8f830054, 0x8f820054, 0x10000002, +0x2463000a, 0x8f820054, 0x621023, 0x2c42000b, +0x1440fffc, 0x0, 0x8f820220, 0x3c03f700, +0x431025, 0xaf820220, 0x8f830054, 0x8f820054, +0x10000002, 0x24630064, 0x8f820054, 0x621023, +0x2c420065, 0x1440fffc, 0x0, 0x8f820220, +0x24040001, 0x34420002, 0xaf820220, 0x8f830200, +0x24057fff, 0x2402fffd, 0x621824, 0xaf830200, +0xaf840204, 0x8f830054, 0x8f820054, 0x10000002, +0x24630001, 0x8f820054, 0x621023, 0x2c420002, +0x1440fffc, 0x0, 0x8f820224, 0x14440005, +0x34028000, 0x42040, 0xa4102b, 0x1040fff0, +0x34028000, 0x1082ff56, 0x26100001, 0x2e020064, +0x1440ffb0, 0x0, 0x3c020001, 0x8c423d14, +0x30420004, 0x14400007, 0x3c08fff0, 0x8f820044, +0x3c03ffff, 0x34633f7f, 0x431024, 0xaf820044, +0x3c08fff0, 0x3508bdc0, 0x8f830054, 0x97a60018, +0x3c070001, 0x8ce73e70, 0x3c040001, 0x24843b00, +0x24020001, 0x3c010001, 0xac223d1c, 0xafa60010, +0x3c060001, 0x8cc63d14, 0x97a2001a, 0x3c05000d, +0x34a50100, 0x3c010001, 0xac203d18, 0x681821, +0x3c010001, 0xac233e68, 0xc0029d3, 0xafa20014, +0x8fbf0034, 0x8fb20030, 0x8fb1002c, 0x8fb00028, +0x3e00008, 0x27bd0038, 0x27bdffe8, 0x24070004, +0x3c040001, 0x8c843d18, 0x3021, 0x24020001, +0x1482000a, 0xafbf0010, 0x3c020001, 0x8c425f2c, +0x3c050004, 0x30428000, 0x1040000c, 0x34a593e0, +0x3c05000f, 0x10000009, 0x34a54240, 0x3c020001, +0x8c425f2c, 0x3c05000f, 0x30428000, 0x10400003, +0x34a54240, 0x3c05001e, 0x34a58480, 0x3c020001, +0x8c423e68, 0x8f830054, 0x451021, 0x431023, +0x45102b, 0x1440002e, 0x0, 0x3c020001, +0x8c423d20, 0x1440002a, 0x2cc20001, 0x7182b, +0x431024, 0x1040001d, 0x0, 0x3c090001, +0x8d293d14, 0x240b0001, 0x3c054000, 0x3c080001, +0x25085f2c, 0x250afffc, 0x42042, 0x14800002, +0x24e7ffff, 0x24040008, 0x891024, 0x5040000b, +0x2cc20001, 0x148b0004, 0x0, 0x8d020000, +0x10000003, 0x451024, 0x8d420000, 0x451024, +0x54400001, 0x24060001, 0x2cc20001, 0x7182b, +0x431024, 0x5440ffed, 0x42042, 0x3c010001, +0x10c00020, 0xac243d18, 0x8f830054, 0x24020001, +0x3c010001, 0xac223d1c, 0x3c010001, 0xac233e68, +0x3c020001, 0x8c423d1c, 0x10400004, 0x24020001, +0x3c010001, 0xac203d1c, 0xaee204b8, 0x8ee304b8, +0x24020008, 0x10620005, 0x24020001, 0xc003f91, +0x0, 0x1000000b, 0x0, 0x3c030001, +0x8c633d18, 0x10620007, 0x2402000e, 0x3c030001, +0x8c635ec0, 0x10620003, 0x0, 0xc004610, +0x8f840220, 0x8fbf0010, 0x3e00008, 0x27bd0018, +0x27bdffe0, 0x3c03fdff, 0x3c040001, 0x8c843d18, +0x3c020001, 0x8c423d38, 0x3463ffff, 0x283a024, +0x14820006, 0xafbf0018, 0x8ee304b8, 0x3c020001, +0x8c423d3c, 0x10620006, 0x0, 0x8ee204b8, +0x3c010001, 0xac243d38, 0x3c010001, 0xac223d3c, +0x3c030001, 0x8c633d18, 0x24020002, 0x1062013c, +0x2c620003, 0x10400005, 0x24020001, 0x1062000a, +0x0, 0x10000134, 0x0, 0x24020004, +0x1062006d, 0x24020008, 0x1062009f, 0x24020001, +0x1000012d, 0x0, 0x8ee204b8, 0x2443ffff, +0x2c620008, 0x1040012a, 0x31080, 0x3c010001, +0x220821, 0x8c223b18, 0x400008, 0x0, +0xc0040e8, 0x0, 0x3c020001, 0x8c423d24, +0x3c010001, 0xac203cb0, 0x104000d7, 0x24020002, +0xaee204b8, 0x3c010001, 0x10000119, 0xac203d24, +0xc00424b, 0x0, 0x3c030001, 0x8c633d40, +0x1000009e, 0x24020011, 0x3c050001, 0x8ca53d18, +0x3c060001, 0x8cc65f2c, 0xc004878, 0x2021, +0x24020005, 0x3c010001, 0xac203d24, 0x10000108, +0xaee204b8, 0x3c040001, 0x24843b0c, 0x3c05000f, +0x34a50100, 0x3021, 0x3821, 0xafa00010, +0xc0029d3, 0xafa00014, 0x100000fd, 0x0, +0x8f820220, 0x3c03f700, 0x431025, 0x100000a4, +0xaf820220, 0x8f820220, 0x3c030004, 0x431024, +0x144000ae, 0x24020007, 0x8f830054, 0x3c020001, +0x8c423e60, 0x2463d8f0, 0x431023, 0x2c422710, +0x144000eb, 0x24020001, 0x100000e7, 0x0, +0x3c050001, 0x8ca53d18, 0xc004981, 0x2021, +0xc004a4c, 0x2021, 0x3c030001, 0x8c635f24, +0x46100dd, 0x24020001, 0x3c020008, 0x621024, +0x10400006, 0x0, 0x8f820214, 0x3c03ffff, +0x431024, 0x10000005, 0x3442251f, 0x8f820214, +0x3c03ffff, 0x431024, 0x3442241f, 0xaf820214, +0x8f820220, 0x3c030200, 0x283a025, 0x34420002, +0xaf820220, 0x24020008, 0xc003c6b, 0xaee204b8, +0x100000c7, 0x0, 0x8ee204b8, 0x2443ffff, +0x2c620008, 0x104000c2, 0x31080, 0x3c010001, +0x220821, 0x8c223b38, 0x400008, 0x0, +0x3c020001, 0x8c425f28, 0x30424000, 0x10400004, +0x0, 0x8f820044, 0x10000006, 0x3442f080, +0x8f820044, 0x3c03ffff, 0x34633f7f, 0x431024, +0x3442a080, 0xaf820044, 0x8f830054, 0x1000005a, +0x24020004, 0xc003d2c, 0x0, 0x104000a6, +0x24020001, 0x8f820214, 0x3c03ffff, 0x3c040001, +0x8c843e58, 0x431024, 0x3442251f, 0xaf820214, +0x24020008, 0x10800005, 0xaee204b8, 0x3c020001, +0x8c423da4, 0x1040006d, 0x24020001, 0x8f820220, +0x3c030008, 0x431024, 0x10400073, 0x3c020200, +0x10000081, 0x0, 0x8ee204b8, 0x2443ffff, +0x2c620007, 0x1040008e, 0x31080, 0x3c010001, +0x220821, 0x8c223b58, 0x400008, 0x0, +0xc003bad, 0x0, 0x3c010001, 0xac203d1c, +0xaf800204, 0x3c010001, 0xc0040e8, 0xac205f10, +0x24020001, 0x3c010001, 0xac223d30, 0x24020002, +0x1000007b, 0xaee204b8, 0xc004194, 0x0, +0x3c030001, 0x8c633d30, 0x24020009, 0x14620074, +0x24020003, 0x10000072, 0xaee204b8, 0x3c020001, +0x8c425f28, 0x30424000, 0x10400003, 0x3c0200c8, +0x10000002, 0x344201f6, 0x344201fe, 0xaf820238, +0x8f830054, 0x10000014, 0x24020004, 0x8f830054, +0x3c020001, 0x8c423e60, 0x2463d8f0, 0x431023, +0x2c422710, 0x1440005e, 0x24020005, 0x1000005c, +0xaee204b8, 0x8f820220, 0x3c03f700, 0x431025, +0xaf820220, 0xaf800204, 0x3c010001, 0xac205f10, +0x8f830054, 0x24020006, 0xaee204b8, 0x3c010001, +0x1000004f, 0xac233e60, 0x8f830054, 0x3c020001, +0x8c423e60, 0x2463fff6, 0x431023, 0x2c42000a, +0x14400047, 0x0, 0x24020007, 0x10000044, +0xaee204b8, 0xc003d2c, 0x0, 0x1040003e, +0x24020001, 0x8f820214, 0x3c03ffff, 0x3c040001, +0x8c843e58, 0x431024, 0x3442251f, 0xaf820214, +0x24020008, 0x1080000f, 0xaee204b8, 0x3c020001, +0x8c423da4, 0x1440000b, 0x0, 0x8f820220, +0x34420002, 0xaf820220, 0x24020001, 0x3c010001, +0xac225ec0, 0xc004610, 0x8f840220, 0x10000016, +0x0, 0x8f820220, 0x3c030008, 0x431024, +0x14400011, 0x3c020200, 0x282a025, 0x2402000e, +0x3c010001, 0xac225ec0, 0xc004a4c, 0x2021, +0x8f820220, 0x34420002, 0xc003c6b, 0xaf820220, +0x3c050001, 0x8ca53d18, 0xc004981, 0x2021, +0x10000013, 0x0, 0x3c020001, 0x8c423da4, +0x1040000f, 0x0, 0x3c020001, 0x8c423da0, +0x2442ffff, 0x3c010001, 0xac223da0, 0x14400008, +0x24020002, 0x3c010001, 0xac203da4, 0x3c010001, +0x10000003, 0xac223da0, 0x3c010001, 0xac223d1c, +0x8fbf0018, 0x3e00008, 0x27bd0020, 0x8f820200, +0x8f820220, 0x8f820220, 0x34420004, 0xaf820220, +0x8f820200, 0x3c040001, 0x8c843d18, 0x34420004, +0xaf820200, 0x24020002, 0x1082003a, 0x2c820003, +0x10400005, 0x24020001, 0x1082000a, 0x3c03f0ff, +0x10000098, 0x0, 0x24020004, 0x10820059, +0x24020008, 0x1082006c, 0x3c02f0ff, 0x10000091, +0x0, 0x8f820050, 0x3463ffff, 0x3c05ffff, +0x34a53f7f, 0x431024, 0x3c030700, 0x431025, +0xaf820050, 0x24020e00, 0xaf840200, 0xaf840220, +0xaf820238, 0x8f820044, 0x3c030001, 0x8c633d08, +0x3c040001, 0x8c843e70, 0x451024, 0x34630022, +0xaf820044, 0x24020004, 0x1082000c, 0xaf830200, +0x3c020001, 0x8c423d2c, 0x3c030001, 0x8c633d10, +0x3c040001, 0x8c843d0c, 0x34428000, 0x621825, +0x641825, 0x1000006e, 0x34620002, 0x3c020001, +0x8c423d10, 0x3c030001, 0x8c633d2c, 0x3c040001, +0x8c843d0c, 0x431025, 0x441025, 0x10000064, +0x34420002, 0x8f830050, 0x3c02f0ff, 0x3442ffff, +0x3c040001, 0x8c843e58, 0x621824, 0x3c020d00, +0x621825, 0x24020001, 0xaf830050, 0xaf820200, +0xaf820220, 0x24020e00, 0x10800009, 0xaf820238, +0x3c020001, 0x8c423da4, 0x14400005, 0x3c033f00, +0x3c020001, 0x8c423d00, 0x10000005, 0x34630070, +0x3c020001, 0x8c423d00, 0x3c033f00, 0x34630072, +0x431025, 0xaf820200, 0x3c030001, 0x8c633d04, +0x3c04f700, 0x3c020001, 0x8c423d10, 0x3c050001, +0x8ca53d2c, 0x641825, 0x431025, 0x1000003c, +0x451025, 0x8f830050, 0x3c02f0ff, 0x3442ffff, +0x3c040001, 0x8c843e58, 0x621824, 0x3c020a00, +0x621825, 0x24020001, 0xaf830050, 0xaf820200, +0x1080001e, 0xaf820220, 0x3c020001, 0x8c423da4, +0x1440001a, 0x3c033f00, 0x3c020001, 0x8c423d00, +0x1000001a, 0x346300e0, 0x8f830050, 0x3c040001, +0x8c843e58, 0x3442ffff, 0x621824, 0x1080000f, +0xaf830050, 0x3c020001, 0x8c423da4, 0x1440000b, +0x3c043f00, 0x3c030001, 0x8c633d00, 0x348400e0, +0x24020001, 0xaf820200, 0xaf820220, 0x641825, +0xaf830200, 0x10000008, 0x3c05f700, 0x3c020001, +0x8c423d00, 0x3c033f00, 0x346300e2, 0x431025, +0xaf820200, 0x3c05f700, 0x34a58000, 0x3c030001, +0x8c633d04, 0x3c020001, 0x8c423d10, 0x3c040001, +0x8c843d2c, 0x651825, 0x431025, 0x441025, +0xaf820220, 0x3e00008, 0x0, 0x3c030001, +0x8c633d30, 0x3c020001, 0x8c423d34, 0x10620003, +0x24020002, 0x3c010001, 0xac233d34, 0x1062001d, +0x2c620003, 0x10400025, 0x24020001, 0x14620023, +0x24020004, 0x3c030001, 0x8c633d18, 0x10620006, +0x24020008, 0x1462000c, 0x3c0200c8, 0x344201fb, +0x10000009, 0xaf820238, 0x24020e01, 0xaf820238, +0x8f820044, 0x3c03ffff, 0x34633f7f, 0x431024, +0x34420080, 0xaf820044, 0x8f830054, 0x24020002, +0x3c010001, 0xac223d30, 0x3c010001, 0x1000000b, +0xac233e64, 0x8f830054, 0x3c020001, 0x8c423e64, +0x2463d8f0, 0x431023, 0x2c422710, 0x14400003, +0x24020009, 0x3c010001, 0xac223d30, 0x3e00008, +0x0, 0x0, 0x0, 0x27bdffd8, +0xafb20018, 0x809021, 0xafb3001c, 0xa09821, +0xafb10014, 0xc08821, 0xafb00010, 0x8021, +0xafbf0020, 0xa6200000, 0xc0045c7, 0x24040001, +0x26100001, 0x2e020020, 0x1440fffb, 0x0, +0xc0045c7, 0x2021, 0xc0045c7, 0x24040001, +0xc0045c7, 0x24040001, 0xc0045c7, 0x2021, +0x24100010, 0x2501024, 0x10400002, 0x2021, +0x24040001, 0xc0045c7, 0x108042, 0x1600fffa, +0x2501024, 0x24100010, 0x2701024, 0x10400002, +0x2021, 0x24040001, 0xc0045c7, 0x108042, +0x1600fffa, 0x2701024, 0xc0045ed, 0x34108000, +0xc0045ed, 0x0, 0xc0045a7, 0x0, +0x50400005, 0x108042, 0x96220000, 0x501025, +0xa6220000, 0x108042, 0x1600fff7, 0x0, +0xc0045ed, 0x0, 0x8fbf0020, 0x8fb3001c, +0x8fb20018, 0x8fb10014, 0x8fb00010, 0x3e00008, +0x27bd0028, 0x27bdffd8, 0xafb10014, 0x808821, +0xafb20018, 0xa09021, 0xafb3001c, 0xc09821, +0xafb00010, 0x8021, 0xafbf0020, 0xc0045c7, +0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, +0x0, 0xc0045c7, 0x2021, 0xc0045c7, +0x24040001, 0xc0045c7, 0x2021, 0xc0045c7, +0x24040001, 0x24100010, 0x2301024, 0x10400002, +0x2021, 0x24040001, 0xc0045c7, 0x108042, +0x1600fffa, 0x2301024, 0x24100010, 0x2501024, +0x10400002, 0x2021, 0x24040001, 0xc0045c7, +0x108042, 0x1600fffa, 0x2501024, 0xc0045c7, +0x24040001, 0xc0045c7, 0x2021, 0x34108000, +0x96620000, 0x501024, 0x10400002, 0x2021, +0x24040001, 0xc0045c7, 0x108042, 0x1600fff8, +0x0, 0xc0045ed, 0x0, 0x8fbf0020, +0x8fb3001c, 0x8fb20018, 0x8fb10014, 0x8fb00010, +0x3e00008, 0x27bd0028, 0x3c030001, 0x8c633d40, +0x3c020001, 0x8c423d84, 0x27bdffd8, 0xafbf0020, +0xafb1001c, 0x10620003, 0xafb00018, 0x3c010001, +0xac233d84, 0x2463ffff, 0x2c620013, 0x10400349, +0x31080, 0x3c010001, 0x220821, 0x8c223b80, +0x400008, 0x0, 0xc0045ed, 0x8021, +0x34028000, 0xa7a20010, 0x27b10010, 0xc0045c7, +0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, +0x0, 0xc0045c7, 0x2021, 0xc0045c7, +0x24040001, 0xc0045c7, 0x2021, 0xc0045c7, +0x24040001, 0x24100010, 0x32020001, 0x10400002, +0x2021, 0x24040001, 0xc0045c7, 0x108042, +0x1600fffa, 0x32020001, 0x24100010, 0xc0045c7, +0x2021, 0x108042, 0x1600fffc, 0x0, +0xc0045c7, 0x24040001, 0xc0045c7, 0x2021, +0x34108000, 0x96220000, 0x501024, 0x10400002, +0x2021, 0x24040001, 0xc0045c7, 0x108042, +0x1600fff8, 0x0, 0xc0045ed, 0x0, +0x1000030e, 0x24020002, 0x27b10010, 0xa7a00010, +0x8021, 0xc0045c7, 0x24040001, 0x26100001, +0x2e020020, 0x1440fffb, 0x0, 0xc0045c7, +0x2021, 0xc0045c7, 0x24040001, 0xc0045c7, +0x24040001, 0xc0045c7, 0x2021, 0x24100010, +0x32020001, 0x10400002, 0x2021, 0x24040001, +0xc0045c7, 0x108042, 0x1600fffa, 0x32020001, +0x24100010, 0xc0045c7, 0x2021, 0x108042, +0x1600fffc, 0x0, 0xc0045ed, 0x34108000, +0xc0045ed, 0x0, 0xc0045a7, 0x0, +0x50400005, 0x108042, 0x96220000, 0x501025, +0xa6220000, 0x108042, 0x1600fff7, 0x0, +0xc0045ed, 0x0, 0x97a20010, 0x30428000, +0x144002dc, 0x24020003, 0x100002d8, 0x0, +0x24021200, 0xa7a20010, 0x27b10010, 0x8021, +0xc0045c7, 0x24040001, 0x26100001, 0x2e020020, +0x1440fffb, 0x0, 0xc0045c7, 0x2021, +0xc0045c7, 0x24040001, 0xc0045c7, 0x2021, +0xc0045c7, 0x24040001, 0x24100010, 0x32020001, +0x10400002, 0x2021, 0x24040001, 0xc0045c7, +0x108042, 0x1600fffa, 0x32020001, 0x24100010, +0xc0045c7, 0x2021, 0x108042, 0x1600fffc, +0x0, 0xc0045c7, 0x24040001, 0xc0045c7, +0x2021, 0x34108000, 0x96220000, 0x501024, +0x10400002, 0x2021, 0x24040001, 0xc0045c7, +0x108042, 0x1600fff8, 0x0, 0xc0045ed, +0x0, 0x8f830054, 0x10000296, 0x24020004, +0x8f830054, 0x3c020001, 0x8c423e6c, 0x2463ff9c, +0x431023, 0x2c420064, 0x1440029e, 0x24020002, +0x3c030001, 0x8c633e70, 0x10620297, 0x2c620003, +0x14400296, 0x24020011, 0x24020003, 0x10620005, +0x24020004, 0x10620291, 0x2402000f, 0x1000028f, +0x24020011, 0x1000028d, 0x24020005, 0x24020014, +0xa7a20010, 0x27b10010, 0x8021, 0xc0045c7, +0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, +0x0, 0xc0045c7, 0x2021, 0xc0045c7, +0x24040001, 0xc0045c7, 0x2021, 0xc0045c7, +0x24040001, 0x24100010, 0x32020001, 0x10400002, +0x2021, 0x24040001, 0xc0045c7, 0x108042, +0x1600fffa, 0x32020001, 0x24100010, 0x32020012, +0x10400002, 0x2021, 0x24040001, 0xc0045c7, +0x108042, 0x1600fffa, 0x32020012, 0xc0045c7, +0x24040001, 0xc0045c7, 0x2021, 0x34108000, +0x96220000, 0x501024, 0x10400002, 0x2021, +0x24040001, 0xc0045c7, 0x108042, 0x1600fff8, +0x0, 0xc0045ed, 0x0, 0x8f830054, +0x10000248, 0x24020006, 0x8f830054, 0x3c020001, +0x8c423e6c, 0x2463ff9c, 0x431023, 0x2c420064, +0x14400250, 0x24020007, 0x1000024c, 0x0, +0x24020006, 0xa7a20010, 0x27b10010, 0x8021, +0xc0045c7, 0x24040001, 0x26100001, 0x2e020020, +0x1440fffb, 0x0, 0xc0045c7, 0x2021, +0xc0045c7, 0x24040001, 0xc0045c7, 0x2021, +0xc0045c7, 0x24040001, 0x24100010, 0x32020001, +0x10400002, 0x2021, 0x24040001, 0xc0045c7, +0x108042, 0x1600fffa, 0x32020001, 0x24100010, +0x32020013, 0x10400002, 0x2021, 0x24040001, +0xc0045c7, 0x108042, 0x1600fffa, 0x32020013, +0xc0045c7, 0x24040001, 0xc0045c7, 0x2021, +0x34108000, 0x96220000, 0x501024, 0x10400002, +0x2021, 0x24040001, 0xc0045c7, 0x108042, +0x1600fff8, 0x0, 0xc0045ed, 0x0, +0x8f830054, 0x10000207, 0x24020008, 0x8f830054, +0x3c020001, 0x8c423e6c, 0x2463ff9c, 0x431023, +0x2c420064, 0x1440020f, 0x24020009, 0x1000020b, +0x0, 0x27b10010, 0xa7a00010, 0x8021, +0xc0045c7, 0x24040001, 0x26100001, 0x2e020020, +0x1440fffb, 0x0, 0xc0045c7, 0x2021, +0xc0045c7, 0x24040001, 0xc0045c7, 0x24040001, +0xc0045c7, 0x2021, 0x24100010, 0x32020001, +0x10400002, 0x2021, 0x24040001, 0xc0045c7, +0x108042, 0x1600fffa, 0x32020001, 0x24100010, +0x32020018, 0x10400002, 0x2021, 0x24040001, +0xc0045c7, 0x108042, 0x1600fffa, 0x32020018, +0xc0045ed, 0x34108000, 0xc0045ed, 0x0, +0xc0045a7, 0x0, 0x50400005, 0x108042, +0x96220000, 0x501025, 0xa6220000, 0x108042, +0x1600fff7, 0x0, 0xc0045ed, 0x8021, +0x97a20010, 0x27b10010, 0x34420001, 0xa7a20010, +0xc0045c7, 0x24040001, 0x26100001, 0x2e020020, +0x1440fffb, 0x0, 0xc0045c7, 0x2021, +0xc0045c7, 0x24040001, 0xc0045c7, 0x2021, +0xc0045c7, 0x24040001, 0x24100010, 0x32020001, +0x10400002, 0x2021, 0x24040001, 0xc0045c7, +0x108042, 0x1600fffa, 0x32020001, 0x24100010, +0x32020018, 0x10400002, 0x2021, 0x24040001, +0xc0045c7, 0x108042, 0x1600fffa, 0x32020018, +0xc0045c7, 0x24040001, 0xc0045c7, 0x2021, +0x34108000, 0x96220000, 0x501024, 0x10400002, +0x2021, 0x24040001, 0xc0045c7, 0x108042, +0x1600fff8, 0x0, 0xc0045ed, 0x0, +0x8f830054, 0x10000193, 0x2402000a, 0x8f830054, +0x3c020001, 0x8c423e6c, 0x2463ff9c, 0x431023, +0x2c420064, 0x1440019b, 0x2402000b, 0x10000197, +0x0, 0x27b10010, 0xa7a00010, 0x8021, +0xc0045c7, 0x24040001, 0x26100001, 0x2e020020, +0x1440fffb, 0x0, 0xc0045c7, 0x2021, +0xc0045c7, 0x24040001, 0xc0045c7, 0x24040001, +0xc0045c7, 0x2021, 0x24100010, 0x32020001, +0x10400002, 0x2021, 0x24040001, 0xc0045c7, +0x108042, 0x1600fffa, 0x32020001, 0x24100010, +0x32020017, 0x10400002, 0x2021, 0x24040001, +0xc0045c7, 0x108042, 0x1600fffa, 0x32020017, +0xc0045ed, 0x34108000, 0xc0045ed, 0x0, +0xc0045a7, 0x0, 0x50400005, 0x108042, +0x96220000, 0x501025, 0xa6220000, 0x108042, +0x1600fff7, 0x0, 0xc0045ed, 0x8021, +0x97a20010, 0x27b10010, 0x34420700, 0xa7a20010, +0xc0045c7, 0x24040001, 0x26100001, 0x2e020020, +0x1440fffb, 0x0, 0xc0045c7, 0x2021, +0xc0045c7, 0x24040001, 0xc0045c7, 0x2021, +0xc0045c7, 0x24040001, 0x24100010, 0x32020001, +0x10400002, 0x2021, 0x24040001, 0xc0045c7, +0x108042, 0x1600fffa, 0x32020001, 0x24100010, +0x32020017, 0x10400002, 0x2021, 0x24040001, +0xc0045c7, 0x108042, 0x1600fffa, 0x32020017, +0xc0045c7, 0x24040001, 0xc0045c7, 0x2021, +0x34108000, 0x96220000, 0x501024, 0x10400002, +0x2021, 0x24040001, 0xc0045c7, 0x108042, +0x1600fff8, 0x0, 0xc0045ed, 0x0, +0x8f830054, 0x1000011f, 0x2402000c, 0x8f830054, +0x3c020001, 0x8c423e6c, 0x2463ff9c, 0x431023, +0x2c420064, 0x14400127, 0x24020012, 0x10000123, +0x0, 0x27b10010, 0xa7a00010, 0x8021, +0xc0045c7, 0x24040001, 0x26100001, 0x2e020020, +0x1440fffb, 0x0, 0xc0045c7, 0x2021, +0xc0045c7, 0x24040001, 0xc0045c7, 0x24040001, +0xc0045c7, 0x2021, 0x24100010, 0x32020001, +0x10400002, 0x2021, 0x24040001, 0xc0045c7, +0x108042, 0x1600fffa, 0x32020001, 0x24100010, +0x32020014, 0x10400002, 0x2021, 0x24040001, +0xc0045c7, 0x108042, 0x1600fffa, 0x32020014, +0xc0045ed, 0x34108000, 0xc0045ed, 0x0, +0xc0045a7, 0x0, 0x50400005, 0x108042, +0x96220000, 0x501025, 0xa6220000, 0x108042, +0x1600fff7, 0x0, 0xc0045ed, 0x8021, +0x97a20010, 0x27b10010, 0x34420010, 0xa7a20010, +0xc0045c7, 0x24040001, 0x26100001, 0x2e020020, +0x1440fffb, 0x0, 0xc0045c7, 0x2021, +0xc0045c7, 0x24040001, 0xc0045c7, 0x2021, +0xc0045c7, 0x24040001, 0x24100010, 0x32020001, +0x10400002, 0x2021, 0x24040001, 0xc0045c7, +0x108042, 0x1600fffa, 0x32020001, 0x24100010, +0x32020014, 0x10400002, 0x2021, 0x24040001, +0xc0045c7, 0x108042, 0x1600fffa, 0x32020014, +0xc0045c7, 0x24040001, 0xc0045c7, 0x2021, +0x34108000, 0x96220000, 0x501024, 0x10400002, +0x2021, 0x24040001, 0xc0045c7, 0x108042, +0x1600fff8, 0x0, 0xc0045ed, 0x0, +0x8f830054, 0x100000ab, 0x24020013, 0x8f830054, +0x3c020001, 0x8c423e6c, 0x2463ff9c, 0x431023, +0x2c420064, 0x144000b3, 0x2402000d, 0x100000af, +0x0, 0x27b10010, 0xa7a00010, 0x8021, +0xc0045c7, 0x24040001, 0x26100001, 0x2e020020, +0x1440fffb, 0x0, 0xc0045c7, 0x2021, +0xc0045c7, 0x24040001, 0xc0045c7, 0x24040001, +0xc0045c7, 0x2021, 0x24100010, 0x32020001, +0x10400002, 0x2021, 0x24040001, 0xc0045c7, +0x108042, 0x1600fffa, 0x32020001, 0x24100010, +0x32020018, 0x10400002, 0x2021, 0x24040001, +0xc0045c7, 0x108042, 0x1600fffa, 0x32020018, +0xc0045ed, 0x34108000, 0xc0045ed, 0x0, +0xc0045a7, 0x0, 0x50400005, 0x108042, +0x96220000, 0x501025, 0xa6220000, 0x108042, +0x1600fff7, 0x0, 0xc0045ed, 0x8021, +0x97a20010, 0x27b10010, 0x3042fffe, 0xa7a20010, +0xc0045c7, 0x24040001, 0x26100001, 0x2e020020, +0x1440fffb, 0x0, 0xc0045c7, 0x2021, +0xc0045c7, 0x24040001, 0xc0045c7, 0x2021, +0xc0045c7, 0x24040001, 0x24100010, 0x32020001, +0x10400002, 0x2021, 0x24040001, 0xc0045c7, +0x108042, 0x1600fffa, 0x32020001, 0x24100010, +0x32020018, 0x10400002, 0x2021, 0x24040001, +0xc0045c7, 0x108042, 0x1600fffa, 0x32020018, +0xc0045c7, 0x24040001, 0xc0045c7, 0x2021, +0x34108000, 0x96220000, 0x501024, 0x10400002, +0x2021, 0x24040001, 0xc0045c7, 0x108042, +0x1600fff8, 0x0, 0xc0045ed, 0x0, +0x8f830054, 0x10000037, 0x2402000e, 0x24020840, +0xa7a20010, 0x27b10010, 0x8021, 0xc0045c7, +0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, +0x0, 0xc0045c7, 0x2021, 0xc0045c7, +0x24040001, 0xc0045c7, 0x2021, 0xc0045c7, +0x24040001, 0x24100010, 0x32020001, 0x10400002, +0x2021, 0x24040001, 0xc0045c7, 0x108042, +0x1600fffa, 0x32020001, 0x24100010, 0x32020013, +0x10400002, 0x2021, 0x24040001, 0xc0045c7, +0x108042, 0x1600fffa, 0x32020013, 0xc0045c7, +0x24040001, 0xc0045c7, 0x2021, 0x34108000, +0x96220000, 0x501024, 0x10400002, 0x2021, +0x24040001, 0xc0045c7, 0x108042, 0x1600fff8, +0x0, 0xc0045ed, 0x0, 0x8f830054, +0x24020010, 0x3c010001, 0xac223d40, 0x3c010001, +0x1000000c, 0xac233e6c, 0x8f830054, 0x3c020001, +0x8c423e6c, 0x2463ff9c, 0x431023, 0x2c420064, +0x14400004, 0x0, 0x24020011, 0x3c010001, +0xac223d40, 0x8fbf0020, 0x8fb1001c, 0x8fb00018, +0x3e00008, 0x27bd0028, 0x8f850044, 0x8f820044, +0x3c030001, 0x431025, 0x3c030008, 0xaf820044, +0x8f840054, 0x8f820054, 0xa32824, 0x10000002, +0x24840001, 0x8f820054, 0x821023, 0x2c420002, +0x1440fffc, 0x0, 0x8f820044, 0x3c03fffe, +0x3463ffff, 0x431024, 0xaf820044, 0x8f830054, +0x8f820054, 0x10000002, 0x24630001, 0x8f820054, +0x621023, 0x2c420002, 0x1440fffc, 0x0, +0x3e00008, 0xa01021, 0x8f830044, 0x3c02fff0, +0x3442ffff, 0x42480, 0x621824, 0x3c020002, +0x822025, 0x641825, 0xaf830044, 0x8f820044, +0x3c030001, 0x431025, 0xaf820044, 0x8f830054, +0x8f820054, 0x10000002, 0x24630001, 0x8f820054, +0x621023, 0x2c420002, 0x1440fffc, 0x0, +0x8f820044, 0x3c03fffe, 0x3463ffff, 0x431024, +0xaf820044, 0x8f830054, 0x8f820054, 0x10000002, +0x24630001, 0x8f820054, 0x621023, 0x2c420002, +0x1440fffc, 0x0, 0x3e00008, 0x0, +0x8f820044, 0x3c03fff0, 0x3463ffff, 0x431024, +0xaf820044, 0x8f820044, 0x3c030001, 0x431025, +0xaf820044, 0x8f830054, 0x8f820054, 0x10000002, +0x24630001, 0x8f820054, 0x621023, 0x2c420002, +0x1440fffc, 0x0, 0x8f820044, 0x3c03fffe, +0x3463ffff, 0x431024, 0xaf820044, 0x8f830054, +0x8f820054, 0x10000002, 0x24630001, 0x8f820054, +0x621023, 0x2c420002, 0x1440fffc, 0x0, +0x3e00008, 0x0, 0x0, 0x27bdffe8, +0xafbf0010, 0x8ee304b8, 0x24020008, 0x146201e0, +0x0, 0x3c020001, 0x8c423e58, 0x14400005, +0x0, 0xc003bad, 0x8f840224, 0x100001d8, +0x0, 0x8f820220, 0x3c030008, 0x431024, +0x10400026, 0x24020001, 0x8f840224, 0x8f820220, +0x3c030400, 0x431024, 0x10400006, 0x0, +0x3c010001, 0xac205ed0, 0x3c010001, 0x1000000b, +0xac205ef0, 0x3c030001, 0x24635ed0, 0x8c620000, +0x24420001, 0xac620000, 0x2c420002, 0x14400003, +0x24020001, 0x3c010001, 0xac225ef0, 0x3c020001, +0x8c425ef0, 0x10400006, 0x30820040, 0x10400004, +0x24020001, 0x3c010001, 0x10000003, 0xac225ef4, +0x3c010001, 0xac205ef4, 0x3c010001, 0xac245ecc, +0x3c010001, 0x1000000b, 0xac205f00, 0x3c010001, +0xac225f00, 0x3c010001, 0xac205ef0, 0x3c010001, +0xac205ed0, 0x3c010001, 0xac205ef4, 0x3c010001, +0xac205ecc, 0x3c030001, 0x8c635ec0, 0x3c020001, +0x8c425ec4, 0x50620004, 0x2463ffff, 0x3c010001, +0xac235ec4, 0x2463ffff, 0x2c62000e, 0x10400194, +0x31080, 0x3c010001, 0x220821, 0x8c223bd0, +0x400008, 0x0, 0x24020002, 0x3c010001, +0xac205ef0, 0x3c010001, 0xac205ed0, 0x3c010001, +0xac205ecc, 0x3c010001, 0xac205ef4, 0x3c010001, +0xac205ee8, 0x3c010001, 0xac205ee0, 0xaf800224, +0x3c010001, 0xac225ec0, 0x3c020001, 0x8c425f00, +0x1440004f, 0x3c02fdff, 0x3442ffff, 0xc003bad, +0x282a024, 0xaf800204, 0x8f820200, 0x2403fffd, +0x431024, 0xaf820200, 0x3c010001, 0xac205f10, +0x8f830054, 0x3c020001, 0x8c425ee8, 0x24040001, +0x3c010001, 0xac245efc, 0x24420001, 0x3c010001, +0xac225ee8, 0x2c420004, 0x3c010001, 0xac235ee4, +0x14400006, 0x24020003, 0x3c010001, 0xac243d1c, +0x3c010001, 0x1000015e, 0xac205ee8, 0x3c010001, +0x1000015b, 0xac225ec0, 0x8f830054, 0x3c020001, +0x8c425ee4, 0x2463d8f0, 0x431023, 0x2c422710, +0x14400003, 0x24020004, 0x3c010001, 0xac225ec0, +0x3c020001, 0x8c425f00, 0x14400021, 0x3c02fdff, +0x3442ffff, 0x1000014a, 0x282a024, 0x3c040001, +0x8c843e5c, 0x3c010001, 0xc0047f8, 0xac205ed8, +0x3c020001, 0x8c425f0c, 0xaf820204, 0x3c020001, +0x8c425f00, 0x14400012, 0x3c03fdff, 0x8f820204, +0x3463ffff, 0x30420030, 0x1440012f, 0x283a024, +0x3c030001, 0x8c635f0c, 0x24020005, 0x3c010001, +0xac225ec0, 0x3c010001, 0x10000131, 0xac235f10, +0x3c020001, 0x8c425f00, 0x10400010, 0x3c02fdff, +0x3c020001, 0x8c423d9c, 0x24420001, 0x3c010001, +0xac223d9c, 0x2c420002, 0x14400125, 0x24020001, +0x3c010001, 0xac223da4, 0x3c010001, 0xac203d9c, +0x3c010001, 0x1000011e, 0xac223d1c, 0x3c030001, +0x8c635ef0, 0x3442ffff, 0x10600119, 0x282a024, +0x3c020001, 0x8c425ecc, 0x10400115, 0x0, +0x3c010001, 0xac225ef8, 0x24020003, 0x3c010001, +0xac225ed0, 0x100000b8, 0x24020006, 0x3c010001, +0xac205ed8, 0x8f820204, 0x34420040, 0xaf820204, +0x3c020001, 0x8c425f10, 0x24030007, 0x3c010001, +0xac235ec0, 0x34420040, 0x3c010001, 0xac225f10, +0x3c020001, 0x8c425ef0, 0x10400005, 0x0, +0x3c020001, 0x8c425ecc, 0x104000f0, 0x24020002, +0x3c050001, 0x24a55ed0, 0x8ca20000, 0x2c424e21, +0x104000ea, 0x24020002, 0x3c020001, 0x8c425ef4, +0x104000ef, 0x2404ffbf, 0x3c020001, 0x8c425ecc, +0x3c030001, 0x8c635ef8, 0x441024, 0x641824, +0x10430004, 0x24020001, 0x3c010001, 0x100000e4, +0xac225ec0, 0x24020003, 0xaca20000, 0x24020008, +0x3c010001, 0xac225ec0, 0x3c020001, 0x8c425efc, +0x1040000c, 0x24020001, 0x3c040001, 0xc004805, +0x8c845ecc, 0x3c020001, 0x8c425f18, 0x14400005, +0x24020001, 0x3c020001, 0x8c425f14, 0x10400006, +0x24020001, 0x3c010001, 0xac223d1c, 0x3c010001, +0x100000cb, 0xac205ee8, 0x3c020001, 0x8c425ee0, +0x3c030001, 0x8c635ecc, 0x2c420001, 0x210c0, +0x30630008, 0x3c010001, 0xac225ee0, 0x3c010001, +0xac235edc, 0x8f830054, 0x24020009, 0x3c010001, +0xac225ec0, 0x3c010001, 0x100000b9, 0xac235ee4, +0x8f830054, 0x3c020001, 0x8c425ee4, 0x2463d8f0, +0x431023, 0x2c422710, 0x1440009f, 0x0, +0x3c020001, 0x8c425ef0, 0x10400005, 0x0, +0x3c020001, 0x8c425ecc, 0x104000a0, 0x24020002, +0x3c030001, 0x24635ed0, 0x8c620000, 0x2c424e21, +0x1040009a, 0x24020002, 0x3c020001, 0x8c425efc, +0x1040000e, 0x0, 0x3c020001, 0x8c425ecc, +0x3c010001, 0xac205efc, 0x30420080, 0x1040002f, +0x2402000c, 0x8f820204, 0x30420080, 0x1440000c, +0x24020003, 0x10000029, 0x2402000c, 0x3c020001, +0x8c425ecc, 0x30420080, 0x14400005, 0x24020003, +0x8f820204, 0x30420080, 0x1040001f, 0x24020003, +0xac620000, 0x2402000a, 0x3c010001, 0xac225ec0, +0x3c040001, 0x24845f08, 0x8c820000, 0x3c030001, +0x8c635ee0, 0x431025, 0xaf820204, 0x8c830000, +0x3c040001, 0x8c845ee0, 0x2402000b, 0x3c010001, +0xac225ec0, 0x641825, 0x3c010001, 0xac235f10, +0x3c050001, 0x24a55ed0, 0x8ca20000, 0x2c424e21, +0x10400066, 0x24020002, 0x3c020001, 0x8c425f00, +0x10400005, 0x0, 0x2402000c, 0x3c010001, +0x10000067, 0xac225ec0, 0x3c020001, 0x8c425ef0, +0x10400063, 0x0, 0x3c040001, 0x8c845ecc, +0x10800055, 0x30820008, 0x3c030001, 0x8c635edc, +0x1062005b, 0x24020003, 0x3c010001, 0xac245ef8, +0xaca20000, 0x24020006, 0x3c010001, 0x10000054, +0xac225ec0, 0x8f820200, 0x34420002, 0xaf820200, +0x8f830054, 0x2402000d, 0x3c010001, 0xac225ec0, +0x3c010001, 0xac235ee4, 0x8f830054, 0x3c020001, +0x8c425ee4, 0x2463d8f0, 0x431023, 0x2c422710, +0x14400031, 0x0, 0x3c020001, 0x8c425f00, +0x10400020, 0x2402000e, 0x3c030001, 0x8c635f14, +0x3c010001, 0x14600015, 0xac225ec0, 0xc003c6b, +0x0, 0x3c050001, 0x8ca53d18, 0xc004981, +0x2021, 0x3c030001, 0x8c633d18, 0x24020004, +0x14620005, 0x2403fffb, 0x3c020001, 0x8c423d14, +0x10000003, 0x2403fff7, 0x3c020001, 0x8c423d14, +0x431024, 0x3c010001, 0xac223d14, 0x8f830224, +0x3c020200, 0x3c010001, 0xac235f1c, 0x10000020, +0x282a025, 0x3c020001, 0x8c425ef0, 0x10400005, +0x0, 0x3c020001, 0x8c425ecc, 0x1040000f, +0x24020002, 0x3c020001, 0x8c425ed0, 0x2c424e21, +0x1040000a, 0x24020002, 0x3c020001, 0x8c425ef0, +0x1040000f, 0x0, 0x3c020001, 0x8c425ecc, +0x1440000b, 0x0, 0x24020002, 0x3c010001, +0x10000007, 0xac225ec0, 0x3c020001, 0x8c425ef0, +0x10400003, 0x0, 0xc003bad, 0x0, +0x8f820220, 0x3c03f700, 0x431025, 0xaf820220, +0x8fbf0010, 0x3e00008, 0x27bd0018, 0x3c030001, +0x24635f18, 0x8c620000, 0x10400005, 0x34422000, +0x3c010001, 0xac225f0c, 0x10000003, 0xac600000, +0x3c010001, 0xac245f0c, 0x3e00008, 0x0, +0x27bdffe0, 0x30820030, 0xafbf0018, 0x3c010001, +0xac225f14, 0x14400067, 0x3c02ffff, 0x34421f0e, +0x821024, 0x14400061, 0x24020030, 0x30822000, +0x1040005d, 0x30838000, 0x31a02, 0x30820001, +0x21200, 0x3c040001, 0x8c843e5c, 0x621825, +0x331c2, 0x3c030001, 0x24633da8, 0x30828000, +0x21202, 0x30840001, 0x42200, 0x441025, +0x239c2, 0x61080, 0x431021, 0x471021, +0x90430000, 0x24020001, 0x10620025, 0x0, +0x10600007, 0x24020002, 0x10620013, 0x24020003, +0x1062002c, 0x3c05000f, 0x10000037, 0x0, +0x8f820200, 0x2403feff, 0x431024, 0xaf820200, +0x8f820220, 0x3c03fffe, 0x3463ffff, 0x431024, +0xaf820220, 0x3c010001, 0xac205f34, 0x3c010001, +0x10000034, 0xac205f3c, 0x8f820200, 0x34420100, +0xaf820200, 0x8f820220, 0x3c03fffe, 0x3463ffff, +0x431024, 0xaf820220, 0x24020100, 0x3c010001, +0xac225f34, 0x3c010001, 0x10000026, 0xac205f3c, +0x8f820200, 0x2403feff, 0x431024, 0xaf820200, +0x8f820220, 0x3c030001, 0x431025, 0xaf820220, +0x3c010001, 0xac205f34, 0x3c010001, 0x10000019, +0xac235f3c, 0x8f820200, 0x34420100, 0xaf820200, +0x8f820220, 0x3c030001, 0x431025, 0xaf820220, +0x24020100, 0x3c010001, 0xac225f34, 0x3c010001, +0x1000000c, 0xac235f3c, 0x34a5ffff, 0x3c040001, +0x24843c08, 0xafa30010, 0xc0029d3, 0xafa00014, +0x10000004, 0x0, 0x24020030, 0x3c010001, +0xac225f18, 0x8fbf0018, 0x3e00008, 0x27bd0020, +0x0, 0x0, 0x0, 0x27bdffc8, +0xafb10024, 0x808821, 0xafb3002c, 0xa09821, +0xafb00020, 0xc08021, 0x3c040001, 0x24843c20, +0x3c050009, 0x3c020001, 0x8c423d18, 0x34a59001, +0x2203021, 0x2603821, 0xafbf0030, 0xafb20028, +0xa7a0001a, 0xafb00014, 0xc0029d3, 0xafa20010, +0x24020002, 0x126200eb, 0x2e620003, 0x10400005, +0x24020001, 0x1262000a, 0x3c02fffb, 0x100000e5, +0x0, 0x24020004, 0x1262006d, 0x24020008, +0x1262006c, 0x3c02ffec, 0x100000de, 0x0, +0x3442ffff, 0x2028024, 0x119140, 0x3c010001, +0x320821, 0xac305f2c, 0x3c024000, 0x2021024, +0x10400046, 0x1023c2, 0x30840030, 0x101382, +0x3042000c, 0x3c030001, 0x24633d44, 0x431021, +0x823821, 0x3c020020, 0x2021024, 0x10400006, +0x24020100, 0x3c010001, 0x320821, 0xac225f30, +0x10000005, 0x3c020080, 0x3c010001, 0x320821, +0xac205f30, 0x3c020080, 0x2021024, 0x10400006, +0x111940, 0x3c020001, 0x3c010001, 0x230821, +0x10000005, 0xac225f38, 0x111140, 0x3c010001, +0x220821, 0xac205f38, 0x94e30000, 0x32024000, +0x10400003, 0xa7a30018, 0x34624000, 0xa7a20018, +0x24040001, 0x94e20002, 0x24050004, 0x24e60002, +0x34420001, 0xc00420a, 0xa4e20002, 0x24040001, +0x2821, 0xc00420a, 0x27a60018, 0x3c020001, +0x8c423d18, 0x24110001, 0x3c010001, 0xac313d24, +0x14530004, 0x32028000, 0xc003bad, 0x0, +0x32028000, 0x10400097, 0x0, 0xc003bad, +0x0, 0x24020002, 0x3c010001, 0xac313d1c, +0x3c010001, 0x1000008f, 0xac223d18, 0x24040001, +0x24050004, 0x27b0001a, 0xc00420a, 0x2003021, +0x24040001, 0x2821, 0xc00420a, 0x2003021, +0x3c020001, 0x521021, 0x8c425f24, 0x3c040001, +0x8c843d18, 0x3c03bfff, 0x3463ffff, 0x3c010001, +0xac333d24, 0x431024, 0x3c010001, 0x320821, +0x10930076, 0xac225f24, 0x10000076, 0x0, +0x3c02ffec, 0x3442ffff, 0x2028024, 0x3c020008, +0x2028025, 0x111140, 0x3c010001, 0x220821, +0xac305f28, 0x3c022000, 0x2021024, 0x10400009, +0x0, 0x3c020001, 0x8c423da4, 0x14400005, +0x24020001, 0x3c010001, 0xac223e58, 0x10000004, +0x3c024000, 0x3c010001, 0xac203e58, 0x3c024000, +0x2021024, 0x1440001a, 0x0, 0x3c020001, +0x8c423e58, 0x10400005, 0x24022020, 0x3c010001, +0xac223e5c, 0x24020001, 0xaee204b8, 0x3c04bfff, +0x111940, 0x3c020001, 0x431021, 0x8c425f20, +0x3c050001, 0x8ca53d18, 0x3484ffff, 0x441024, +0x3c010001, 0x230821, 0xac225f20, 0x24020001, +0x10a20044, 0x0, 0x10000040, 0x0, +0x3c020001, 0x8c423e58, 0x1040001c, 0x24022000, +0x3c010001, 0xac223e5c, 0x3c0300a0, 0x2031024, +0x14430005, 0x111140, 0x3402a000, 0x3c010001, +0x1000002d, 0xac223e5c, 0x3c030001, 0x621821, +0x8c635f28, 0x3c020020, 0x621024, 0x10400004, +0x24022001, 0x3c010001, 0x10000023, 0xac223e5c, +0x3c020080, 0x621024, 0x1040001f, 0x3402a001, +0x3c010001, 0x1000001c, 0xac223e5c, 0x3c020020, +0x2021024, 0x10400007, 0x111940, 0x24020100, +0x3c010001, 0x230821, 0xac225f34, 0x10000006, +0x3c020080, 0x111140, 0x3c010001, 0x220821, +0xac205f34, 0x3c020080, 0x2021024, 0x10400006, +0x111940, 0x3c020001, 0x3c010001, 0x230821, +0x10000005, 0xac225f3c, 0x111140, 0x3c010001, +0x220821, 0xac205f3c, 0x3c030001, 0x8c633d18, +0x24020001, 0x10620003, 0x0, 0xc003bad, +0x0, 0x8fbf0030, 0x8fb3002c, 0x8fb20028, +0x8fb10024, 0x8fb00020, 0x3e00008, 0x27bd0038, +0x27bdffd0, 0xafb50028, 0x80a821, 0xafb20020, +0x9021, 0xafb30024, 0x9821, 0xafb1001c, +0x8821, 0x24020002, 0xafbf002c, 0xafb00018, +0xa7a00012, 0x10a20068, 0xa7a00010, 0x2ca20003, +0x10400005, 0x24020001, 0x10a2000a, 0x158140, +0x100000ae, 0x2201021, 0x24020004, 0x10a2005e, +0x24020008, 0x10a2005d, 0x152940, 0x100000a7, +0x2201021, 0x3c030001, 0x701821, 0x8c635f2c, +0x3c024000, 0x621024, 0x14400009, 0x24040001, +0x3c027fff, 0x3442ffff, 0x628824, 0x3c010001, +0x300821, 0xac315f24, 0x10000098, 0x2201021, +0x24050001, 0xc0041c8, 0x27a60010, 0x24040001, +0x24050001, 0xc0041c8, 0x27a60010, 0x97a20010, +0x30420004, 0x10400034, 0x3c114000, 0x3c030001, +0x8c633e70, 0x24020003, 0x10620008, 0x2c620004, +0x14400029, 0x3c028000, 0x24020004, 0x10620014, +0x24040001, 0x10000024, 0x3c028000, 0x24040001, +0x24050011, 0x27b00012, 0xc0041c8, 0x2003021, +0x24040001, 0x24050011, 0xc0041c8, 0x2003021, +0x97a30012, 0x30624000, 0x10400002, 0x3c130010, +0x3c130008, 0x3c120001, 0x10000010, 0x30628000, +0x24050014, 0x27b00012, 0xc0041c8, 0x2003021, +0x24040001, 0x24050014, 0xc0041c8, 0x2003021, +0x97a30012, 0x30621000, 0x10400002, 0x3c130010, +0x3c130008, 0x3c120001, 0x30620800, 0x54400001, +0x3c120002, 0x3c028000, 0x2221025, 0x2531825, +0x10000007, 0x438825, 0x3c110001, 0x2308821, +0x8e315f2c, 0x3c027fff, 0x3442ffff, 0x2228824, +0x151140, 0x3c010001, 0x220821, 0xac315f24, +0x1000004e, 0x2201021, 0x152940, 0x3c030001, +0x651821, 0x8c635f28, 0x3c024000, 0x621024, +0x14400008, 0x3c027fff, 0x3442ffff, 0x628824, +0x3c010001, 0x250821, 0xac315f20, 0x1000003f, +0x2201021, 0x3c020001, 0x8c423d28, 0x10400033, +0x3c11c00c, 0x3c020001, 0x8c423da4, 0x3c04c00c, +0x34842000, 0x3c030001, 0x8c633e58, 0x2102b, +0x21023, 0x441024, 0x10600003, 0x518825, +0x3c022000, 0x2228825, 0x3c020001, 0x451021, +0x8c425f34, 0x10400003, 0x3c020020, 0x10000004, +0x2228825, 0x3c02ffdf, 0x3442ffff, 0x2228824, +0x151140, 0x3c010001, 0x220821, 0x8c225f3c, +0x10400003, 0x3c020080, 0x10000004, 0x2228825, +0x3c02ff7f, 0x3442ffff, 0x2228824, 0x3c020001, +0x8c423d90, 0x10400002, 0x3c020800, 0x2228825, +0x3c020001, 0x8c423d94, 0x10400002, 0x3c020400, +0x2228825, 0x3c020001, 0x8c423d98, 0x10400006, +0x3c020100, 0x10000004, 0x2228825, 0x3c027fff, +0x3442ffff, 0x628824, 0x151140, 0x3c010001, +0x220821, 0xac315f20, 0x2201021, 0x8fbf002c, +0x8fb50028, 0x8fb30024, 0x8fb20020, 0x8fb1001c, +0x8fb00018, 0x3e00008, 0x27bd0030, 0x27bdffe0, +0xafb20018, 0x809021, 0xafbf001c, 0xafb10014, +0xafb00010, 0x8f840200, 0x3c030001, 0x8c633d18, +0x8f860220, 0x24020002, 0x106200a6, 0x2c620003, +0x10400005, 0x24020001, 0x1062000a, 0x121940, +0x100000a0, 0x0, 0x24020004, 0x10620053, +0x24020008, 0x10620052, 0x128940, 0x10000099, +0x0, 0x3c050001, 0xa32821, 0x8ca55f2c, +0x3c100001, 0x2038021, 0x8e105f24, 0x3c024000, +0xa21024, 0x10400038, 0x3c020008, 0x2021024, +0x10400020, 0x34840002, 0x3c020001, 0x431021, +0x8c425f30, 0x10400005, 0x34840020, 0x34840100, +0x3c020020, 0x10000006, 0x2028025, 0x2402feff, +0x822024, 0x3c02ffdf, 0x3442ffff, 0x2028024, +0x121140, 0x3c010001, 0x220821, 0x8c225f38, +0x10400005, 0x3c020001, 0xc23025, 0x3c020080, +0x10000016, 0x2028025, 0x3c02fffe, 0x3442ffff, +0xc23024, 0x3c02ff7f, 0x3442ffff, 0x1000000f, +0x2028024, 0x2402fedf, 0x822024, 0x3c02fffe, +0x3442ffff, 0xc23024, 0x3c02ff5f, 0x3442ffff, +0x2028024, 0x3c010001, 0x230821, 0xac205f30, +0x3c010001, 0x230821, 0xac205f38, 0xaf840200, +0xaf860220, 0x8f820220, 0x34420002, 0xaf820220, +0x1000000a, 0x121140, 0x3c02bfff, 0x3442ffff, +0x8f830200, 0x2028024, 0x2402fffd, 0x621824, +0xc003bad, 0xaf830200, 0x121140, 0x3c010001, +0x220821, 0x1000004b, 0xac305f24, 0x128940, +0x3c050001, 0xb12821, 0x8ca55f28, 0x3c100001, +0x2118021, 0x8e105f20, 0x3c024000, 0xa21024, +0x14400010, 0x0, 0x3c020001, 0x8c423e58, +0x14400005, 0x3c02bfff, 0x8f820200, 0x34420002, +0xaf820200, 0x3c02bfff, 0x3442ffff, 0xc003bad, +0x2028024, 0x3c010001, 0x310821, 0x10000031, +0xac305f20, 0x3c020001, 0x8c423e58, 0x10400005, +0x3c020020, 0x3c020001, 0x8c423da4, 0x10400025, +0x3c020020, 0xa21024, 0x10400007, 0x34840020, +0x24020100, 0x3c010001, 0x310821, 0xac225f34, +0x10000006, 0x34840100, 0x3c010001, 0x310821, +0xac205f34, 0x2402feff, 0x822024, 0x3c020080, +0xa21024, 0x10400007, 0x121940, 0x3c020001, +0x3c010001, 0x230821, 0xac225f3c, 0x10000008, +0xc23025, 0x121140, 0x3c010001, 0x220821, +0xac205f3c, 0x3c02fffe, 0x3442ffff, 0xc23024, +0xaf840200, 0xaf860220, 0x8f820220, 0x34420002, +0xaf820220, 0x121140, 0x3c010001, 0x220821, +0xac305f20, 0x8fbf001c, 0x8fb20018, 0x8fb10014, +0x8fb00010, 0x3e00008, 0x27bd0020, 0x1821, +0x308400ff, 0x2405ffdf, 0x2406ffbf, 0x641007, +0x30420001, 0x10400004, 0x0, 0x8f820044, +0x10000003, 0x34420040, 0x8f820044, 0x461024, +0xaf820044, 0x8f820044, 0x34420020, 0xaf820044, +0x8f820044, 0x451024, 0xaf820044, 0x24630001, +0x28620008, 0x5440ffee, 0x641007, 0x3e00008, +0x0, 0x0, 0x0, 0x0 }; u32 tigon2FwRodata[(MAX_RODATA_LEN/4) + 1] __initdata = { -0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563, 0x74732f72, 0x63732f73, -0x772f6765, 0x2f6e6963, 0x2f667732, 0x2f636f6d, 0x6d6f6e2f, 0x66776d61, -0x696e2e63, 0x2c762031, 0x2e312e34, 0x372e3420, 0x31393938, 0x2f31302f, -0x31342031, 0x393a3330, 0x3a323920, 0x73687561, 0x6e672045, 0x78702024, -0x0, 0x3f6e6f51, 0x64547845, 0x0, 0x3f6e6f51, 0x64527845, -0x0, 0x6576526e, 0x6746756c, 0x6c000000, 0x3f456e71, 0x45767400, -0x3f6e6f51, 0x64457650, 0x0, 0x6661696c, 0x456e454d, 0x0, -0x656e714d, 0x45764661, 0x696c0000, 0x656e714d, 0x45765046, 0x61696c00, -0x3f6d656d, 0x53697a65, 0x0, 0x65787453, 0x746b5067, 0x0, -0x4441574e, 0x2d310000, 0x4441574e, 0x2d320000, 0x4441574e, 0x2d330000, -0x5245445a, 0x4f4e4531, 0x0, 0x42616453, 0x6e64526e, 0x67000000, -0x496e666f, 0x2d336d42, 0x0, 0x76357373, 0x72616d00, 0x3f737731, -0x646d6100, 0x536e6443, 0x6b53756d, 0x0, 0x646d6141, 0x6c69676e, -0x0, 0x52637643, 0x6b53756d, 0x0, 0x496c6c43, 0x6f6e6652, -0x78000000, 0x766c616e, 0x52434200, 0x52656376, 0x566c616e, 0x0, -0x496e666f, 0x2d336d45, 0x0, 0x66774f50, 0x6661696c, 0x0, -0x696e7453, 0x746b4572, 0x0, 0x70726f62, 0x654d656d, 0x0, -0x436f7079, 0x0, 0x4e6f7443, 0x6f707900, 0x4441574e, 0x2d420000, -0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563, 0x74732f72, 0x63732f73, -0x772f6765, 0x2f6e6963, 0x2f667732, 0x2f636f6d, 0x6d6f6e2f, 0x74696d65, -0x722e632c, 0x7620312e, 0x312e3139, 0x2e332031, 0x3939382f, 0x31302f30, -0x37203233, 0x3a34333a, 0x30302066, 0x6877616e, 0x67204578, 0x70202400, -0x3f6e6f51, 0x64547845, 0x0, 0x3f6e6f51, 0x64527845, 0x0, -0x6576526e, 0x6746756c, 0x6c000000, 0x3f456e71, 0x45767400, 0x3f6e6f51, -0x64457650, 0x0, 0x6661696c, 0x456e454d, 0x0, 0x656e714d, -0x45764661, 0x696c0000, 0x656e714d, 0x45765046, 0x61696c00, 0x542d446d, -0x61526432, 0x0, 0x542d446d, 0x61526431, 0x0, 0x542d446d, -0x61526442, 0x0, 0x542d446d, 0x61577232, 0x0, 0x542d446d, -0x61577231, 0x0, 0x542d446d, 0x61577242, 0x0, 0x0, -0x0, 0x0, 0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563, -0x74732f72, 0x63732f73, 0x772f6765, 0x2f6e6963, 0x2f667732, 0x2f636f6d, -0x6d6f6e2f, 0x636f6d6d, 0x616e642e, 0x632c7620, 0x312e312e, 0x322e3232, -0x20313939, 0x382f3037, 0x2f323920, 0x32323a33, 0x313a3030, 0x20736875, -0x616e6720, 0x45787020, 0x24000000, 0x3f6e6f51, 0x64547845, 0x0, -0x3f6e6f51, 0x64527845, 0x0, 0x6576526e, 0x6746756c, 0x6c000000, -0x3f456e71, 0x45767400, 0x3f6e6f51, 0x64457650, 0x0, 0x6661696c, -0x456e454d, 0x0, 0x656e714d, 0x45764661, 0x696c0000, 0x656e714d, -0x45765046, 0x61696c00, 0x3f4d626f, 0x78457674, 0x0, 0x68737465, -0x5f455252, 0x0, 0x6d437374, 0x4d644552, 0x52000000, 0x70726f6d, -0x4d644552, 0x52000000, 0x6c6e6b43, 0x6d644572, 0x72000000, 0x636d645f, -0x45525200, 0x0, 0x7fa0, 0x8630, 0x8630, 0x85ac, -0x835c, 0x85f8, 0x8630, 0x8080, 0x8090, 0x8178, -0x824c, 0x8218, 0x8630, 0x80a0, 0x8308, 0x8630, -0x8318, 0x0, 0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563, -0x74732f72, 0x63732f73, 0x772f6765, 0x2f6e6963, 0x2f667732, 0x2f636f6d, -0x6d6f6e2f, 0x6d636173, 0x742e632c, 0x7620312e, 0x312e322e, 0x35203139, -0x39382f30, 0x342f3234, 0x2030303a, 0x30303a33, 0x39206861, 0x79657320, -0x45787020, 0x24000000, 0x3f6e6f51, 0x64547845, 0x0, 0x3f6e6f51, -0x64527845, 0x0, 0x6576526e, 0x6746756c, 0x6c000000, 0x3f456e71, -0x45767400, 0x3f6e6f51, 0x64457650, 0x0, 0x6661696c, 0x456e454d, -0x0, 0x656e714d, 0x45764661, 0x696c0000, 0x656e714d, 0x45765046, -0x61696c00, 0x4d634164, 0x64447570, 0x0, 0x4d634164, 0x6446756c, -0x0, 0x4d634465, 0x6c4e6f45, 0x0, 0x24486561, 0x6465723a, -0x202f7072, 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, 0x2f6e6963, -0x2f667732, 0x2f636f6d, 0x6d6f6e2f, 0x646d612e, 0x632c7620, 0x312e312e, -0x31322e33, 0x20313939, 0x382f3132, 0x2f303420, 0x32323a35, 0x313a3135, -0x20736875, 0x616e6720, 0x45787020, 0x24000000, 0x3f6e6f51, 0x64547845, -0x0, 0x3f6e6f51, 0x64527845, 0x0, 0x6576526e, 0x6746756c, -0x6c000000, 0x3f456e71, 0x45767400, 0x3f6e6f51, 0x64457650, 0x0, -0x6661696c, 0x456e454d, 0x0, 0x656e714d, 0x45764661, 0x696c0000, -0x656e714d, 0x45765046, 0x61696c00, 0x646d6172, 0x6441544e, 0x0, -0x2a50414e, 0x49432a00, 0x2e2e2f2e, 0x2e2f2e2e, 0x2f2e2e2f, 0x2e2e2f73, -0x72632f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f, 0x6e2f646d, 0x612e6300, -0x646d6177, 0x7241544e, 0x0, 0x0, 0x0, 0x0, -0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563, 0x74732f72, 0x63732f73, -0x772f6765, 0x2f6e6963, 0x2f667732, 0x2f636f6d, 0x6d6f6e2f, 0x74726163, -0x652e632c, 0x7620312e, 0x312e322e, 0x34203139, 0x39382f30, 0x342f3234, -0x2030303a, 0x30303a34, 0x35206861, 0x79657320, 0x45787020, 0x24000000, -0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563, 0x74732f72, 0x63732f73, -0x772f6765, 0x2f6e6963, 0x2f667732, 0x2f636f6d, 0x6d6f6e2f, 0x64617461, -0x2e632c76, 0x20312e31, 0x2e322e34, 0x20313939, 0x382f3036, 0x2f323320, -0x30313a32, 0x393a3330, 0x20736875, 0x616e6720, 0x45787020, 0x24000000, -0x46575f56, 0x45525349, 0x4f4e3a20, 0x2331204d, 0x6f6e2044, 0x65632037, -0x2031343a, 0x35383a32, 0x34205053, 0x54203139, 0x39380000, 0x46575f43, -0x4f4d5049, 0x4c455f54, 0x494d453a, 0x2031343a, 0x35383a32, 0x34000000, -0x46575f43, 0x4f4d5049, 0x4c455f42, 0x593a2064, 0x65767263, 0x73000000, -0x46575f43, 0x4f4d5049, 0x4c455f48, 0x4f53543a, 0x20636f6d, 0x70757465, -0x0, 0x46575f43, 0x4f4d5049, 0x4c455f44, 0x4f4d4149, 0x4e3a2065, -0x6e672e61, 0x6374656f, 0x6e2e636f, 0x6d000000, 0x46575f43, 0x4f4d5049, -0x4c45523a, 0x20676363, 0x20766572, 0x73696f6e, 0x20322e37, 0x2e320000, -0x0, 0x0, 0x0, 0x0, 0x24486561, 0x6465723a, -0x202f7072, 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, 0x2f6e6963, -0x2f667732, 0x2f636f6d, 0x6d6f6e2f, 0x6d656d2e, 0x632c7620, 0x312e312e, -0x322e3420, 0x31393938, 0x2f30342f, 0x32342030, 0x303a3030, 0x3a343020, -0x68617965, 0x73204578, 0x70202400, 0x0, 0x24486561, 0x6465723a, -0x202f7072, 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, 0x2f6e6963, -0x2f667732, 0x2f636f6d, 0x6d6f6e2f, 0x73656e64, 0x2e632c76, 0x20312e31, -0x2e32322e, 0x33203139, 0x39382f30, 0x392f3137, 0x2032313a, 0x32343a33, -0x38207368, 0x75616e67, 0x20457870, 0x20240000, 0x3f6e6f51, 0x64547845, -0x0, 0x3f6e6f51, 0x64527845, 0x0, 0x6576526e, 0x6746756c, -0x6c000000, 0x3f456e71, 0x45767400, 0x3f6e6f51, 0x64457650, 0x0, -0x6661696c, 0x456e454d, 0x0, 0x656e714d, 0x45764661, 0x696c0000, -0x656e714d, 0x45765046, 0x61696c00, 0x736e6464, 0x654e6f51, 0x20000000, -0x6e6f454e, 0x515f5458, 0x0, 0x736e6464, 0x744e6f51, 0x20000000, -0x756e6b72, 0x64747970, 0x65000000, 0x3f546370, 0x436b7375, 0x6d000000, -0x0, 0x0, 0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563, -0x74732f72, 0x63732f73, 0x772f6765, 0x2f6e6963, 0x2f667732, 0x2f636f6d, -0x6d6f6e2f, 0x72656376, 0x2e632c76, 0x20312e31, 0x2e34322e, 0x33203139, -0x39382f31, 0x322f3034, 0x2030303a, 0x31303a33, 0x38207368, 0x75616e67, -0x20457870, 0x20240000, 0x3f6e6f51, 0x64547845, 0x0, 0x3f6e6f51, -0x64527845, 0x0, 0x6576526e, 0x6746756c, 0x6c000000, 0x3f456e71, -0x45767400, 0x3f6e6f51, 0x64457650, 0x0, 0x6661696c, 0x456e454d, -0x0, 0x656e714d, 0x45764661, 0x696c0000, 0x656e714d, 0x45765046, -0x61696c00, 0x66726d32, 0x4c617267, 0x65000000, 0x72784e6f, 0x52784264, -0x0, 0x72785144, 0x6d447446, 0x0, 0x72785144, 0x6d614446, -0x0, 0x72785144, 0x6d614246, 0x0, 0x3f724264, 0x446d6146, -0x0, 0x3f724a42, 0x64446d46, 0x0, 0xdbe8, 0xdbe8, -0xdbe8, 0xdbe8, 0xdbe8, 0xdbe8, 0xdbe8, 0xdbe8, -0xdbe8, 0xdbe8, 0xdbe8, 0xdbe8, 0xdbe8, 0xdbe8, -0xdbe8, 0xdbd8, 0xdbd8, 0xdbd8, 0xdbe8, 0xdbe8, -0xdbe8, 0xdbe8, 0xdbe8, 0xdbe8, 0x572d444d, 0x41456e46, -0x0, 0x0, 0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563, -0x74732f72, 0x63732f73, 0x772f6765, 0x2f6e6963, 0x2f667732, 0x2f636f6d, -0x6d6f6e2f, 0x6d61632e, 0x632c7620, 0x312e312e, 0x31372e31, 0x20313939, -0x382f3038, 0x2f323720, 0x32323a31, 0x333a3230, 0x20736875, 0x616e6720, -0x45787020, 0x24000000, 0x3f6e6f51, 0x64547845, 0x0, 0x3f6e6f51, -0x64527845, 0x0, 0x6576526e, 0x6746756c, 0x6c000000, 0x3f456e71, -0x45767400, 0x3f6e6f51, 0x64457650, 0x0, 0x6661696c, 0x456e454d, -0x0, 0x656e714d, 0x45764661, 0x696c0000, 0x656e714d, 0x45765046, -0x61696c00, 0x6d616374, 0x7841544e, 0x0, 0x684d6352, 0x7841746e, -0x0, 0x72656d61, 0x73737274, 0x0, 0x6c696e6b, 0x444f574e, -0x0, 0x6c696e6b, 0x55500000, 0x0, 0x0, 0x0, -0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563, 0x74732f72, 0x63732f73, -0x772f6765, 0x2f6e6963, 0x2f667732, 0x2f636f6d, 0x6d6f6e2f, 0x636b7375, -0x6d2e632c, 0x7620312e, 0x312e322e, 0x36203139, 0x39382f30, 0x362f3233, -0x2030313a, 0x32393a32, 0x37207368, 0x75616e67, 0x20457870, 0x20240000, -0x3f6e6f51, 0x64547845, 0x0, 0x3f6e6f51, 0x64527845, 0x0, -0x6576526e, 0x6746756c, 0x6c000000, 0x3f456e71, 0x45767400, 0x3f6e6f51, -0x64457650, 0x0, 0x6661696c, 0x456e454d, 0x0, 0x656e714d, -0x45764661, 0x696c0000, 0x656e714d, 0x45765046, 0x61696c00, 0x0, -0x50726f62, 0x65506879, 0x0, 0x6c6e6b41, 0x53535254, 0x0, -0xf94c, 0xf97c, 0xf9a0, 0xf9cc, 0xf9f8, 0xfa0c, -0xfa48, 0xfdd0, 0xfaf8, 0xfc24, 0xfb44, 0xfc7c, -0xfca4, 0xfcd8, 0xfb88, 0xfdd0, 0xfbf0, 0xfc24, -0xfc4c, 0xfc7c, 0xfca4, 0xfcd8, 0xfd14, 0x0, -0x0, 0x0, 0x1032c, 0x103fc, 0x104d4, 0x105a4, -0x10600, 0x106dc, 0x10704, 0x107e0, 0x10808, 0x109b0, -0x109d8, 0x10b80, 0x10d78, 0x1100c, 0x10f20, 0x1100c, -0x11038, 0x10ba8, 0x10d50, 0x0, 0x1133c, 0x11390, -0x1140c, 0x11438, 0x11488, 0x114c4, 0x114f8, 0x11584, -0x1163c, 0x1170c, 0x1174c, 0x117d0, 0x117f4, 0x11904, -0x646f4261, 0x73655067, 0x0, 0x0, 0x0, 0x0, -0x73746d61, 0x634c4e4b, 0x0, 0x0, 0x0 }; +0x24486561, 0x6465723a, 0x202f7072, +0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, +0x2f6e6963, 0x2f667732, 0x2f636f6d, 0x6d6f6e2f, +0x66776d61, 0x696e2e63, 0x2c762031, 0x2e312e32, +0x2e343520, 0x31393939, 0x2f30312f, 0x32342030, +0x303a3130, 0x3a353520, 0x73687561, 0x6e672045, +0x78702024, 0x0, 0x65767452, 0x6e674600, +0x51657674, 0x46000000, 0x51657674, 0x505f4600, +0x4d657674, 0x526e6746, 0x0, 0x4d516576, +0x74460000, 0x4d516576, 0x505f4600, 0x5173436f, +0x6e495f46, 0x0, 0x5173436f, 0x6e734600, +0x51725072, 0x6f644600, 0x6261644d, 0x656d537a, +0x0, 0x68774677, 0x56657200, 0x62616448, +0x77566572, 0x0, 0x2a2a4441, 0x574e5f41, +0x0, 0x74785278, 0x4266537a, 0x0, +0x62664174, 0x6e4d726b, 0x0, 0x7265645a, +0x6f6e6531, 0x0, 0x70636943, 0x6f6e6600, +0x67656e43, 0x6f6e6600, 0x72636246, 0x6c616773, +0x0, 0x62616452, 0x78526362, 0x0, +0x676c6f62, 0x466c6773, 0x0, 0x2b5f6469, +0x73705f6c, 0x6f6f7000, 0x2b65765f, 0x68616e64, +0x6c657200, 0x63616e74, 0x31446d61, 0x0, +0x2b715f64, 0x6d615f74, 0x6f5f6e69, 0x635f636b, +0x73756d00, 0x2b685f73, 0x656e645f, 0x64617461, +0x5f726561, 0x64795f63, 0x6b73756d, 0x0, +0x2b685f64, 0x6d615f72, 0x645f6173, 0x73697374, +0x5f636b73, 0x756d0000, 0x74436b73, 0x6d4f6e00, +0x2b715f64, 0x6d615f74, 0x6f5f6e69, 0x63000000, +0x2b685f73, 0x656e645f, 0x64617461, 0x5f726561, +0x64790000, 0x2b685f64, 0x6d615f72, 0x645f6173, +0x73697374, 0x0, 0x74436b73, 0x6d4f6666, +0x0, 0x2b685f73, 0x656e645f, 0x62645f72, +0x65616479, 0x0, 0x68737453, 0x52696e67, +0x0, 0x62616453, 0x52696e67, 0x0, +0x6e696353, 0x52696e67, 0x0, 0x77446d61, +0x416c6c41, 0x0, 0x2b715f64, 0x6d615f74, +0x6f5f686f, 0x73745f63, 0x6b73756d, 0x0, +0x2b685f6d, 0x61635f72, 0x785f636f, 0x6d705f63, +0x6b73756d, 0x0, 0x2b685f64, 0x6d615f77, +0x725f6173, 0x73697374, 0x5f636b73, 0x756d0000, +0x72436b73, 0x6d4f6e00, 0x2b715f64, 0x6d615f74, +0x6f5f686f, 0x73740000, 0x2b685f6d, 0x61635f72, +0x785f636f, 0x6d700000, 0x2b685f64, 0x6d615f77, +0x725f6173, 0x73697374, 0x0, 0x72436b73, +0x6d4f6666, 0x0, 0x2b685f72, 0x6563765f, +0x62645f72, 0x65616479, 0x0, 0x2b685f72, +0x6563765f, 0x6a756d62, 0x6f5f6264, 0x5f726561, +0x64790000, 0x2b685f72, 0x6563765f, 0x6d696e69, +0x5f62645f, 0x72656164, 0x79000000, 0x2b6d685f, +0x636f6d6d, 0x616e6400, 0x2b685f74, 0x696d6572, +0x0, 0x2b685f64, 0x6f5f7570, 0x64617465, +0x5f74785f, 0x636f6e73, 0x0, 0x2b685f64, +0x6f5f7570, 0x64617465, 0x5f72785f, 0x70726f64, +0x0, 0x2b636b73, 0x756d3136, 0x0, +0x2b706565, 0x6b5f6d61, 0x635f7278, 0x0, +0x2b646571, 0x5f6d6163, 0x5f727800, 0x2b685f6d, +0x61635f72, 0x785f6174, 0x746e0000, 0x62616452, +0x6574537a, 0x0, 0x72784264, 0x4266537a, +0x0, 0x2b6e756c, 0x6c5f6861, 0x6e646c65, +0x72000000, 0x66774f70, 0x4661696c, 0x0, +0x2b685f75, 0x70646174, 0x655f6c65, 0x64360000, +0x2b685f75, 0x70646174, 0x655f6c65, 0x64320000, +0x696e7453, 0x74617465, 0x0, 0x2a2a696e, +0x69744370, 0x0, 0x23736372, 0x65616d00, +0x69537461, 0x636b4572, 0x0, 0x70726f62, +0x654d656d, 0x0, 0x2a2a4441, 0x574e5f42, +0x0, 0x2b73775f, 0x646d615f, 0x61737369, +0x73745f70, 0x6c75735f, 0x74696d65, 0x72000000, +0x2b267072, 0x656c6f61, 0x645f7772, 0x5f646573, +0x63720000, 0x2b267072, 0x656c6f61, 0x645f7264, +0x5f646573, 0x63720000, 0x2b685f68, 0x665f7469, +0x6d657200, 0x24486561, 0x6465723a, 0x202f7072, +0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, +0x2f6e6963, 0x2f667732, 0x2f636f6d, 0x6d6f6e2f, +0x74696d65, 0x722e632c, 0x7620312e, 0x312e322e, +0x33352031, 0x3939392f, 0x30312f32, 0x37203139, +0x3a30393a, 0x35302068, 0x61796573, 0x20457870, +0x20240000, 0x65767452, 0x6e674600, 0x51657674, +0x46000000, 0x51657674, 0x505f4600, 0x4d657674, +0x526e6746, 0x0, 0x4d516576, 0x74460000, +0x4d516576, 0x505f4600, 0x5173436f, 0x6e495f46, +0x0, 0x5173436f, 0x6e734600, 0x51725072, +0x6f644600, 0x542d446d, 0x61526432, 0x0, +0x542d446d, 0x61526431, 0x0, 0x542d446d, +0x61526442, 0x0, 0x542d446d, 0x61577232, +0x0, 0x542d446d, 0x61577231, 0x0, +0x542d446d, 0x61577242, 0x0, 0x0, +0x0, 0x24486561, 0x6465723a, 0x202f7072, +0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, +0x2f6e6963, 0x2f667732, 0x2f636f6d, 0x6d6f6e2f, +0x636f6d6d, 0x616e642e, 0x632c7620, 0x312e312e, +0x322e3238, 0x20313939, 0x392f3031, 0x2f323020, +0x31393a34, 0x393a3439, 0x20736875, 0x616e6720, +0x45787020, 0x24000000, 0x65767452, 0x6e674600, +0x51657674, 0x46000000, 0x51657674, 0x505f4600, +0x4d657674, 0x526e6746, 0x0, 0x4d516576, +0x74460000, 0x4d516576, 0x505f4600, 0x5173436f, +0x6e495f46, 0x0, 0x5173436f, 0x6e734600, +0x51725072, 0x6f644600, 0x3f48636d, 0x644d6278, +0x0, 0x3f636d64, 0x48737453, 0x0, +0x3f636d64, 0x4d634d64, 0x0, 0x3f636d64, +0x50726f6d, 0x0, 0x3f636d64, 0x4c696e6b, +0x0, 0x3f636d64, 0x45727200, 0x811c, +0x8898, 0x8898, 0x8820, 0x85c4, +0x886c, 0x8898, 0x81f4, 0x8258, +0x83dc, 0x84b4, 0x8480, 0x8898, +0x82bc, 0x8570, 0x8898, 0x8580, +0x8218, 0x827c, 0x0, 0x0, +0x0, 0x24486561, 0x6465723a, 0x202f7072, +0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, +0x2f6e6963, 0x2f667732, 0x2f636f6d, 0x6d6f6e2f, +0x6d636173, 0x742e632c, 0x7620312e, 0x312e322e, +0x38203139, 0x39382f31, 0x322f3038, 0x2030323a, +0x33363a33, 0x36207368, 0x75616e67, 0x20457870, +0x20240000, 0x65767452, 0x6e674600, 0x51657674, +0x46000000, 0x51657674, 0x505f4600, 0x4d657674, +0x526e6746, 0x0, 0x4d516576, 0x74460000, +0x4d516576, 0x505f4600, 0x5173436f, 0x6e495f46, +0x0, 0x5173436f, 0x6e734600, 0x51725072, +0x6f644600, 0x6164644d, 0x63447570, 0x0, +0x6164644d, 0x6346756c, 0x0, 0x64656c4d, +0x634e6f45, 0x0, 0x0, 0x0, +0x0, 0x24486561, 0x6465723a, 0x202f7072, +0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, +0x2f6e6963, 0x2f667732, 0x2f636f6d, 0x6d6f6e2f, +0x646d612e, 0x632c7620, 0x312e312e, 0x322e3234, +0x20313939, 0x382f3132, 0x2f323120, 0x30303a33, +0x333a3039, 0x20736875, 0x616e6720, 0x45787020, +0x24000000, 0x65767452, 0x6e674600, 0x51657674, +0x46000000, 0x51657674, 0x505f4600, 0x4d657674, +0x526e6746, 0x0, 0x4d516576, 0x74460000, +0x4d516576, 0x505f4600, 0x5173436f, 0x6e495f46, +0x0, 0x5173436f, 0x6e734600, 0x51725072, +0x6f644600, 0x7377446d, 0x614f6666, 0x0, +0x31446d61, 0x4f6e0000, 0x7377446d, 0x614f6e00, +0x2372446d, 0x6141544e, 0x0, 0x72446d61, +0x41544e30, 0x0, 0x72446d61, 0x41544e31, +0x0, 0x2a50414e, 0x49432a00, 0x2e2e2f2e, +0x2e2f2e2e, 0x2f2e2e2f, 0x2e2e2f73, 0x72632f6e, +0x69632f66, 0x77322f63, 0x6f6d6d6f, 0x6e2f646d, +0x612e6300, 0x2377446d, 0x6141544e, 0x0, +0x77446d61, 0x41544e30, 0x0, 0x77446d61, +0x41544e31, 0x0, 0x0, 0x0, +0x0, 0x24486561, 0x6465723a, 0x202f7072, +0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, +0x2f6e6963, 0x2f667732, 0x2f636f6d, 0x6d6f6e2f, +0x74726163, 0x652e632c, 0x7620312e, 0x312e322e, +0x35203139, 0x39382f30, 0x392f3330, 0x2031383a, +0x35303a32, 0x38207368, 0x75616e67, 0x20457870, +0x20240000, 0x24486561, 0x6465723a, 0x202f7072, +0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, +0x2f6e6963, 0x2f667732, 0x2f636f6d, 0x6d6f6e2f, +0x64617461, 0x2e632c76, 0x20312e31, 0x2e322e31, +0x32203139, 0x39392f30, 0x312f3230, 0x2031393a, +0x34393a35, 0x31207368, 0x75616e67, 0x20457870, +0x20240000, 0x46575f56, 0x45525349, 0x4f4e3a20, +0x2331204d, 0x6f6e2046, 0x65622031, 0x2031373a, +0x30313a30, 0x36205053, 0x54203139, 0x39390000, +0x46575f43, 0x4f4d5049, 0x4c455f54, 0x494d453a, +0x2031373a, 0x30313a30, 0x36000000, 0x46575f43, +0x4f4d5049, 0x4c455f42, 0x593a2064, 0x65767263, +0x73000000, 0x46575f43, 0x4f4d5049, 0x4c455f48, +0x4f53543a, 0x20636f6d, 0x70757465, 0x0, +0x46575f43, 0x4f4d5049, 0x4c455f44, 0x4f4d4149, +0x4e3a2065, 0x6e672e61, 0x6374656f, 0x6e2e636f, +0x6d000000, 0x46575f43, 0x4f4d5049, 0x4c45523a, +0x20676363, 0x20766572, 0x73696f6e, 0x20322e37, +0x2e320000, 0x0, 0x12030303, 0x0, +0x0, 0x24486561, 0x6465723a, 0x202f7072, +0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, +0x2f6e6963, 0x2f667732, 0x2f636f6d, 0x6d6f6e2f, +0x6d656d2e, 0x632c7620, 0x312e312e, 0x322e3520, +0x31393938, 0x2f30392f, 0x33302031, 0x383a3530, +0x3a303820, 0x73687561, 0x6e672045, 0x78702024, +0x0, 0x24486561, 0x6465723a, 0x202f7072, +0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, +0x2f6e6963, 0x2f667732, 0x2f636f6d, 0x6d6f6e2f, +0x73656e64, 0x2e632c76, 0x20312e31, 0x2e322e34, +0x34203139, 0x39382f31, 0x322f3231, 0x2030303a, +0x33333a31, 0x38207368, 0x75616e67, 0x20457870, +0x20240000, 0x65767452, 0x6e674600, 0x51657674, +0x46000000, 0x51657674, 0x505f4600, 0x4d657674, +0x526e6746, 0x0, 0x4d516576, 0x74460000, +0x4d516576, 0x505f4600, 0x5173436f, 0x6e495f46, +0x0, 0x5173436f, 0x6e734600, 0x51725072, +0x6f644600, 0x69736e74, 0x54637055, 0x0, +0x0, 0x24486561, 0x6465723a, 0x202f7072, +0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, +0x2f6e6963, 0x2f667732, 0x2f636f6d, 0x6d6f6e2f, +0x72656376, 0x2e632c76, 0x20312e31, 0x2e322e35, +0x33203139, 0x39392f30, 0x312f3136, 0x2030323a, +0x35353a34, 0x33207368, 0x75616e67, 0x20457870, +0x20240000, 0x65767452, 0x6e674600, 0x51657674, +0x46000000, 0x51657674, 0x505f4600, 0x4d657674, +0x526e6746, 0x0, 0x4d516576, 0x74460000, +0x4d516576, 0x505f4600, 0x5173436f, 0x6e495f46, +0x0, 0x5173436f, 0x6e734600, 0x51725072, +0x6f644600, 0x72784672, 0x6d324c67, 0x0, +0x72784e6f, 0x53744264, 0x0, 0x72784e6f, +0x4d694264, 0x0, 0x72784e6f, 0x4a6d4264, +0x0, 0x7278436b, 0x446d6146, 0x0, +0x72785144, 0x6d457846, 0x0, 0x72785144, +0x6d614600, 0x72785144, 0x4c426446, 0x0, +0x72785144, 0x6d426446, 0x0, 0x72784372, +0x63506164, 0x0, 0x72536d51, 0x446d6146, +0x0, 0x24486561, 0x6465723a, 0x202f7072, +0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, +0x2f6e6963, 0x2f667732, 0x2f636f6d, 0x6d6f6e2f, +0x6d61632e, 0x632c7620, 0x312e312e, 0x322e3232, +0x20313939, 0x382f3132, 0x2f303820, 0x30323a33, +0x363a3330, 0x20736875, 0x616e6720, 0x45787020, +0x24000000, 0x65767452, 0x6e674600, 0x51657674, +0x46000000, 0x51657674, 0x505f4600, 0x4d657674, +0x526e6746, 0x0, 0x4d516576, 0x74460000, +0x4d516576, 0x505f4600, 0x5173436f, 0x6e495f46, +0x0, 0x5173436f, 0x6e734600, 0x51725072, +0x6f644600, 0x6d616354, 0x68726573, 0x0, +0x23744d61, 0x6341544e, 0x0, 0x23724d61, +0x6341544e, 0x0, 0x72656d41, 0x73737274, +0x0, 0x6c696e6b, 0x444f574e, 0x0, +0x6c696e6b, 0x55500000, 0x0, 0x0, +0x0, 0x24486561, 0x6465723a, 0x202f7072, +0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, +0x2f6e6963, 0x2f667732, 0x2f636f6d, 0x6d6f6e2f, +0x636b7375, 0x6d2e632c, 0x7620312e, 0x312e322e, +0x39203139, 0x39392f30, 0x312f3134, 0x2030303a, +0x30333a34, 0x38207368, 0x75616e67, 0x20457870, +0x20240000, 0x65767452, 0x6e674600, 0x51657674, +0x46000000, 0x51657674, 0x505f4600, 0x4d657674, +0x526e6746, 0x0, 0x4d516576, 0x74460000, +0x4d516576, 0x505f4600, 0x5173436f, 0x6e495f46, +0x0, 0x5173436f, 0x6e734600, 0x51725072, +0x6f644600, 0x50726f62, 0x65506879, 0x0, +0x6c6e6b41, 0x53535254, 0x0, 0xff04, +0xff34, 0xff4c, 0xff78, 0xffa4, +0xffb8, 0xfff4, 0x10394, 0x10174, +0x101ac, 0x100a4, 0x10200, 0x10228, +0x1025c, 0x100e8, 0x10394, 0x10174, +0x101ac, 0x101d0, 0x10200, 0x10228, +0x1025c, 0x10288, 0x0, 0x0, +0x0, 0x1097c, 0x10a4c, 0x10b24, +0x10bf4, 0x10c50, 0x10d2c, 0x10d54, +0x10e30, 0x10e58, 0x11000, 0x11028, +0x111d0, 0x113c8, 0x1165c, 0x11570, +0x1165c, 0x11688, 0x111f8, 0x113a0, +0x0, 0x1198c, 0x119cc, 0x11a5c, +0x11aa0, 0x11b04, 0x11b90, 0x11bc4, +0x11c4c, 0x11ce4, 0x11db4, 0x11df4, +0x11e78, 0x11e9c, 0x11fac, 0x646f4261, +0x73655067, 0x0, 0x0, 0x0, +0x0, 0x73746d61, 0x634c4e4b, 0x0, +0x0, 0x0 }; +u32 tigon2FwData[(MAX_DATA_LEN/4) + 1] __initdata = { +0x1, +0x1, 0x1, 0xc001fc, 0x3ffc, +0xc00000, 0x416c7465, 0x6f6e2041, 0x63654e49, +0x43205600, 0x0, 0x0, 0x416c7465, +0x6f6e2041, 0x63654e49, 0x43205600, 0x42424242, +0x0, 0x0, 0x0, 0x1ffffc, +0x1fff7c, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x60cf00, +0x60, 0xcf000000, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x3, 0x0, +0x1, 0x0, 0x0, 0x1, +0x0, 0x0, 0x0, 0x1, +0x0, 0x0, 0x0, 0x0, +0x0, 0x1000000, 0x21000000, 0x12000140, +0x0, 0x0, 0x20000000, 0x120000a0, +0x0, 0x12000060, 0x12000180, 0x120001e0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x2, +0x0, 0x0, 0x30001, 0x1, +0x30201, 0x0, 0x0, 0x0 }; diff -ur --new-file old/linux/drivers/net/ariadne.c new/linux/drivers/net/ariadne.c --- old/linux/drivers/net/ariadne.c Mon Sep 14 21:35:25 1998 +++ new/linux/drivers/net/ariadne.c Thu Feb 25 19:02:13 1999 @@ -171,6 +171,8 @@ init_etherdev(dev, 0); dev->priv = kmalloc(sizeof(struct ariadne_private), GFP_KERNEL); + if (dev->priv == NULL) + return -ENOMEM; priv = (struct ariadne_private *)dev->priv; memset(priv, 0, sizeof(struct ariadne_private)); diff -ur --new-file old/linux/drivers/net/bsd_comp.c new/linux/drivers/net/bsd_comp.c --- old/linux/drivers/net/bsd_comp.c Tue Feb 10 21:56:44 1998 +++ new/linux/drivers/net/bsd_comp.c Thu Mar 11 01:51:35 1999 @@ -70,7 +70,6 @@ #include #include #include -#include /* to get the struct task_struct */ #include /* used in new tty drivers */ #include /* used in new tty drivers */ diff -ur --new-file old/linux/drivers/net/cosa.c new/linux/drivers/net/cosa.c --- old/linux/drivers/net/cosa.c Mon Dec 28 20:05:14 1998 +++ new/linux/drivers/net/cosa.c Mon Mar 8 00:47:46 1999 @@ -1,4 +1,4 @@ -/* $Id: cosa.c,v 1.11 1998/12/24 23:44:23 kas Exp $ */ +/* $Id: cosa.c,v 1.21 1999/02/06 19:49:18 kas Exp $ */ /* * Copyright (C) 1995-1997 Jan "Yenya" Kasprzak @@ -27,7 +27,7 @@ * Masaryk University (http://www.ics.muni.cz/). The hardware is * developed by Jiri Novotny . More information * and the photo of both cards is available at - * http://www.kozakmartin.cz/cosa.html. The card documentation, firmwares + * http://www.pavoucek.cz/cosa.html. The card documentation, firmwares * and other goods can be downloaded from ftp://ftp.ics.muni.cz/pub/cosa/. * For Linux-specific utilities, see below in the "Software info" section. * If you want to order the card, contact Jiri Novotny. @@ -141,11 +141,13 @@ unsigned int datareg, statusreg; /* I/O ports */ unsigned short irq, dma; /* IRQ and DMA number */ unsigned short startaddr; /* Firmware start address */ + unsigned short busmaster; /* Use busmastering? */ int nchannels; /* # of channels on this card */ int driver_status; /* For communicating with firware */ int firmware_status; /* Downloaded, reseted, etc. */ int rxbitmap, txbitmap; /* Bitmap of channels who are willing to send/receive data */ int rxtx; /* RX or TX in progress? */ + int enabled; int usage; /* usage count */ int txchan, txsize, rxsize; struct channel_data *rxchan; @@ -331,9 +333,8 @@ static int get_wait_data(struct cosa_data *cosa); static int put_wait_data(struct cosa_data *cosa, int data); static int puthexnumber(struct cosa_data *cosa, int number); -static void put_driver_status_common(struct cosa_data *cosa, int nolock); -#define put_driver_status(x) put_driver_status_common((x), 0) -#define put_driver_status_nolock(x) put_driver_status_common((x), 1) +static void put_driver_status(struct cosa_data *cosa); +static void put_driver_status_nolock(struct cosa_data *cosa); /* Interrupt handling */ static void cosa_interrupt(int irq, void *cosa, struct pt_regs *regs); @@ -357,7 +358,7 @@ #endif { int i; - printk(KERN_INFO "cosa v1.03 (c) 1997-8 Jan Kasprzak \n"); + printk(KERN_INFO "cosa v1.04 (c) 1997-8 Jan Kasprzak \n"); #ifdef __SMP__ printk(KERN_INFO "cosa: SMP found. Please mail any success/failure reports to the author.\n"); #endif @@ -630,9 +631,14 @@ if (dev->tbusy) { if (time_before(jiffies, dev->trans_start+2*HZ)) return 1; /* Two seconds timeout */ + if (test_bit(RXBIT, &chan->cosa->rxtx)) { + chan->stats.rx_errors++; + chan->stats.rx_missed_errors++; + } else { + chan->stats.tx_errors++; + chan->stats.tx_aborted_errors++; + } cosa_kick(chan->cosa); - chan->stats.tx_errors++; - chan->stats.tx_aborted_errors++; if (chan->tx_skb) { dev_kfree_skb(chan->tx_skb); chan->tx_skb = 0; @@ -659,6 +665,14 @@ d->tbusy = 1; cosa_disable_rx(chan); spin_lock_irqsave(&chan->cosa->lock, flags); + if (chan->rx_skb) { + kfree_skb(chan->rx_skb); + chan->rx_skb = 0; + } + if (chan->tx_skb) { + kfree_skb(chan->tx_skb); + chan->tx_skb = 0; + } chan->usage=0; chan->cosa->usage--; MOD_DEC_USE_COUNT; @@ -1128,6 +1142,17 @@ return nr_cards; case COSAIONRCHANS: return cosa->nchannels; + case COSAIOBMSET: + if (!suser()) + return -EACCES; + if (is_8bit(cosa)) + return -EINVAL; + if (arg != COSA_BM_OFF && arg != COSA_BM_ON) + return -EINVAL; + cosa->busmaster = arg; + return 0; + case COSAIOBMGET: + return cosa->busmaster; } return -ENOIOCTLCMD; } @@ -1208,37 +1233,67 @@ return 0; } -static void put_driver_status_common(struct cosa_data *cosa, int nolock) +static void put_driver_status(struct cosa_data *cosa) { unsigned flags=0; int status; - if (!nolock) - spin_lock_irqsave(&cosa->lock, flags); + spin_lock_irqsave(&cosa->lock, flags); status = (cosa->rxbitmap ? DRIVER_RX_READY : 0) | (cosa->txbitmap ? DRIVER_TX_READY : 0) | (cosa->txbitmap? ~(cosa->txbitmap<rxtx || nolock) { -#ifdef DEBUG_IO - debug_data_cmd(cosa, status); -#endif - cosa_putdata8(cosa, status); + if (!cosa->rxtx) { if (cosa->rxbitmap|cosa->txbitmap) { - cosa_putstatus(cosa, SR_RX_INT_ENA); + if (!cosa->enabled) { + cosa_putstatus(cosa, SR_RX_INT_ENA); #ifdef DEBUG_IO - debug_status_out(cosa, SR_RX_INT_ENA); + debug_status_out(cosa, SR_RX_INT_ENA); #endif - } else { + cosa->enabled = 1; + } + } else if (cosa->enabled) { + cosa->enabled = 0; cosa_putstatus(cosa, 0); #ifdef DEBUG_IO debug_status_out(cosa, 0); #endif } + cosa_putdata8(cosa, status); +#ifdef DEBUG_IO + debug_data_cmd(cosa, status); +#endif } - if (!nolock) - spin_unlock_irqrestore(&cosa->lock, flags); + spin_unlock_irqrestore(&cosa->lock, flags); +} + +static void put_driver_status_nolock(struct cosa_data *cosa) +{ + int status; + + status = (cosa->rxbitmap ? DRIVER_RX_READY : 0) + | (cosa->txbitmap ? DRIVER_TX_READY : 0) + | (cosa->txbitmap? ~(cosa->txbitmap<rxbitmap|cosa->txbitmap) { + cosa_putstatus(cosa, SR_RX_INT_ENA); +#ifdef DEBUG_IO + debug_status_out(cosa, SR_RX_INT_ENA); +#endif + cosa->enabled = 1; + } else { + cosa_putstatus(cosa, 0); +#ifdef DEBUG_IO + debug_status_out(cosa, 0); +#endif + cosa->enabled = 0; + } + cosa_putdata8(cosa, status); +#ifdef DEBUG_IO + debug_data_cmd(cosa, status); +#endif } /* @@ -1249,9 +1304,14 @@ static void cosa_kick(struct cosa_data *cosa) { unsigned flags, flags1; + char *s = "Unknown"; - printk(KERN_INFO "%s: DMA timeout - restarting.\n", cosa->name); + if (test_bit(RXBIT, &cosa->rxtx)) + s = "RX"; + if (test_bit(TXBIT, &cosa->rxtx)) + s = "TX"; + printk(KERN_INFO "%s: %s DMA timeout - restarting.\n", cosa->name, s); spin_lock_irqsave(&cosa->lock, flags); cosa->rxtx = 0; @@ -1261,6 +1321,13 @@ release_dma_lock(flags1); /* FIXME: Anything else? */ + udelay(100); + cosa_putstatus(cosa, 0); + udelay(100); + (void) cosa_getdata8(cosa); + udelay(100); + cosa_putdata8(cosa, 0); + udelay(100); put_driver_status_nolock(cosa); spin_unlock_irqrestore(&cosa->lock, flags); } @@ -1556,6 +1623,10 @@ * COSA status byte. I have moved the rx/tx/eot interrupt handling into * separate functions to make it more readable. These functions are inline, * so there should be no overhead of function call. + * + * In the COSA bus-master mode, we need to tell the card the address of a + * buffer. Unfortunately, COSA may be too slow for us, so we must busy-wait. + * It's time to use the bottom half :-( */ /* @@ -1606,13 +1677,13 @@ if (is_8bit(cosa)) { if (!test_bit(IRQBIT, &cosa->rxtx)) { + cosa_putstatus(cosa, SR_TX_INT_ENA); cosa_putdata8(cosa, ((cosa->txchan << 5) & 0xe0)| ((cosa->txsize >> 8) & 0x1f)); - cosa_putstatus(cosa, SR_TX_INT_ENA); #ifdef DEBUG_IO + debug_status_out(cosa, SR_TX_INT_ENA); debug_data_out(cosa, ((cosa->txchan << 5) & 0xe0)| ((cosa->txsize >> 8) & 0x1f)); - debug_status_out(cosa, SR_TX_INT_ENA); debug_data_in(cosa, cosa_getdata8(cosa)); #else cosa_getdata8(cosa); @@ -1630,27 +1701,57 @@ #endif } } else { + cosa_putstatus(cosa, SR_TX_INT_ENA); cosa_putdata16(cosa, ((cosa->txchan<<13) & 0xe000) | (cosa->txsize & 0x1fff)); - cosa_getdata16(cosa); #ifdef DEBUG_IO - debug_status_out(cosa, ((cosa->txchan<<13) & 0xe000) + debug_status_out(cosa, SR_TX_INT_ENA); + debug_data_out(cosa, ((cosa->txchan<<13) & 0xe000) | (cosa->txsize & 0x1fff)); - debug_data_in(cosa, cosa_getdata16(cosa)); + debug_data_in(cosa, cosa_getdata8(cosa)); + debug_status_out(cosa, 0); #else - cosa_getdata16(cosa); + cosa_getdata8(cosa); #endif + cosa_putstatus(cosa, 0); } - /* start the DMA */ - flags1 = claim_dma_lock(); - disable_dma(cosa->dma); - clear_dma_ff(cosa->dma); - set_dma_mode(cosa->dma, DMA_MODE_WRITE); - set_dma_addr(cosa->dma, virt_to_bus(cosa->txbuf)); - set_dma_count(cosa->dma, cosa->txsize); - enable_dma(cosa->dma); - release_dma_lock(flags1); + if (cosa->busmaster) { + unsigned long addr = virt_to_bus(cosa->txbuf); + int count=0; + printk(KERN_INFO "busmaster IRQ\n"); + while (!(cosa_getstatus(cosa)&SR_TX_RDY)) { + count++; + udelay(10); + if (count > 1000) break; + } + printk(KERN_INFO "status %x\n", cosa_getstatus(cosa)); + printk(KERN_INFO "ready after %d loops\n", count); + cosa_putdata16(cosa, (addr >> 16)&0xffff); + + count = 0; + while (!(cosa_getstatus(cosa)&SR_TX_RDY)) { + count++; + if (count > 1000) break; + udelay(10); + } + printk(KERN_INFO "ready after %d loops\n", count); + cosa_putdata16(cosa, addr &0xffff); + flags1 = claim_dma_lock(); + set_dma_mode(cosa->dma, DMA_MODE_CASCADE); + enable_dma(cosa->dma); + release_dma_lock(flags1); + } else { + /* start the DMA */ + flags1 = claim_dma_lock(); + disable_dma(cosa->dma); + clear_dma_ff(cosa->dma); + set_dma_mode(cosa->dma, DMA_MODE_WRITE); + set_dma_addr(cosa->dma, virt_to_bus(cosa->txbuf)); + set_dma_count(cosa->dma, cosa->txsize); + enable_dma(cosa->dma); + release_dma_lock(flags1); + } cosa_putstatus(cosa, SR_TX_DMA_ENA|SR_USR_INT_ENA); #ifdef DEBUG_IO debug_status_out(cosa, SR_TX_DMA_ENA|SR_USR_INT_ENA); @@ -1671,21 +1772,16 @@ if (is_8bit(cosa)) { if (!test_bit(IRQBIT, &cosa->rxtx)) { set_bit(IRQBIT, &cosa->rxtx); - cosa_putstatus(cosa, 0); cosa->rxsize = cosa_getdata8(cosa) <<8; #ifdef DEBUG_IO - debug_status_out(cosa, 0); debug_data_in(cosa, cosa->rxsize >> 8); #endif - put_driver_status_nolock(cosa); spin_unlock_irqrestore(&cosa->lock, flags); return; } else { clear_bit(IRQBIT, &cosa->rxtx); - cosa_putstatus(cosa, 0); cosa->rxsize |= cosa_getdata8(cosa) & 0xff; #ifdef DEBUG_IO - debug_status_out(cosa, 0); debug_data_in(cosa, cosa->rxsize & 0xff); #endif #if 0 @@ -1695,12 +1791,8 @@ } } else { cosa->rxsize = cosa_getdata16(cosa); - cosa_putstatus(cosa, 0); - cosa_putdata8(cosa, DRIVER_RX_READY); #ifdef DEBUG_IO debug_data_in(cosa, cosa->rxsize); - debug_status_out(cosa, 0); - debug_cmd_out(cosa, DRIVER_RX_READY); #endif #if 0 printk(KERN_INFO "cosa%d: receive rxsize = (0x%04x).\n", @@ -1725,10 +1817,7 @@ reject: /* Reject the packet */ printk(KERN_INFO "cosa%d: rejecting packet on channel %d\n", cosa->num, cosa->rxchan->num); - /* FIXME: This works for COSA only (not SRP) */ - cosa->rxtx = 0; - put_driver_status(cosa); - return; + cosa->rxbuf = cosa->bouncebuf; } /* start the DMA */ @@ -1746,8 +1835,12 @@ release_dma_lock(flags); spin_lock_irqsave(&cosa->lock, flags); cosa_putstatus(cosa, SR_RX_DMA_ENA|SR_USR_INT_ENA); + if (!is_8bit(cosa) && (status & SR_TX_RDY)) + cosa_putdata8(cosa, DRIVER_RX_READY); #ifdef DEBUG_IO debug_status_out(cosa, SR_RX_DMA_ENA|SR_USR_INT_ENA); + if (!is_8bit(cosa) && (status & SR_TX_RDY)) + debug_data_cmd(cosa, DRIVER_RX_READY); #endif spin_unlock_irqrestore(&cosa->lock, flags); } @@ -1756,11 +1849,12 @@ { unsigned long flags, flags1; spin_lock_irqsave(&cosa->lock, flags); + flags1 = claim_dma_lock(); + disable_dma(cosa->dma); + clear_dma_ff(cosa->dma); + release_dma_lock(flags1); if (test_bit(TXBIT, &cosa->rxtx)) { struct channel_data *chan = cosa->chan+cosa->txchan; -#ifdef DEBUG_IRQS - printk(KERN_INFO "cosa%d: end of transfer.\n", cosa->num); -#endif if (chan->tx_done) if (chan->tx_done(chan, cosa->txsize)) clear_bit(chan->num, &cosa->txbitmap); @@ -1775,6 +1869,9 @@ printk("\n"); } #endif + /* Packet for unknown channel? */ + if (cosa->rxbuf == cosa->bouncebuf) + goto out; if (!cosa_dma_able(cosa->rxchan, cosa->rxbuf, cosa->rxsize)) memcpy(cosa->rxbuf, cosa->bouncebuf, cosa->rxsize); if (cosa->rxchan->rx_done) @@ -1786,12 +1883,11 @@ } /* * Clear the RXBIT, TXBIT and IRQBIT (the latest should be - * cleared anyway). + * cleared anyway). We should do it as soon as possible + * so that we can tell the COSA we are done and to give it a time + * for recovery. */ - flags1 = claim_dma_lock(); - disable_dma(cosa->dma); - clear_dma_ff(cosa->dma); - release_dma_lock(flags1); +out: cosa->rxtx = 0; put_driver_status_nolock(cosa); spin_unlock_irqrestore(&cosa->lock, flags); @@ -1799,7 +1895,7 @@ static void cosa_interrupt(int irq, void *cosa_, struct pt_regs *regs) { - int status; + unsigned status; int count = 0; struct cosa_data *cosa = cosa_; again: diff -ur --new-file old/linux/drivers/net/cosa.h new/linux/drivers/net/cosa.h --- old/linux/drivers/net/cosa.h Mon Dec 28 20:05:14 1998 +++ new/linux/drivers/net/cosa.h Mon Mar 8 00:47:46 1999 @@ -1,4 +1,4 @@ -/* $Id: cosa.h,v 1.5 1998/12/24 12:40:18 kas Exp $ */ +/* $Id: cosa.h,v 1.6 1999/01/06 14:02:44 kas Exp $ */ /* * Copyright (C) 1995-1997 Jan "Yenya" Kasprzak @@ -98,5 +98,14 @@ /* Get the number of channels on this card */ #define COSAIONRCHANS _IO('C',0xf8) + +/* Set the driver for the bus-master operations */ +#define COSAIOBMSET _IOW('C', 0xf9, sizeof(unsigned short)) + +#define COSA_BM_OFF 0 /* Bus-mastering off - use ISA DMA (default) */ +#define COSA_BM_ON 1 /* Bus-mastering on - faster but untested */ + +/* Gets the busmaster status */ +#define COSAIOBMGET _IO('C', 0xfa) #endif /* !COSA_H__ */ diff -ur --new-file old/linux/drivers/net/cs89x0.c new/linux/drivers/net/cs89x0.c --- old/linux/drivers/net/cs89x0.c Thu Nov 5 18:58:44 1998 +++ new/linux/drivers/net/cs89x0.c Thu Mar 11 01:51:35 1999 @@ -991,22 +991,26 @@ 0, 0, 0, 0, 0, NULL, NULL }; -int io=0; -int irq=0; -#endif -#ifdef MODULE -int debug=1; -char *media="auto"; -char *duplex="f"; +static int io=0; +static int irq=0; +static int debug=0; +static char media[8]; +static int duplex=-1; + +MODULE_PARM(io, "i"); +MODULE_PARM(irq, "i"); +MODULE_PARM(debug, "i"); +MODULE_PARM(media, "s"); +MODULE_PARM(duplex, "i"); + +EXPORT_NO_SYMBOLS; /* * media=t - specify media type or media=2 or media=aui or medai=auto -* duplex=f - specify forced half/full/autonegotiate duplex - or duplex=h - or duplex=auto +* duplex=0 - specify forced half/full/autonegotiate duplex * debug=# - debug level @@ -1044,12 +1048,14 @@ /* boy, they'd better get these right */ if (!strcmp(media, "rj45")) lp->adapter_cnf = A_CNF_MEDIA_10B_T | A_CNF_10B_T; - if (!strcmp(media, "aui")) + else if (!strcmp(media, "aui")) lp->adapter_cnf = A_CNF_MEDIA_AUI | A_CNF_AUI; - if (!strcmp(media, "bnc")) + else if (!strcmp(media, "bnc")) lp->adapter_cnf = A_CNF_MEDIA_10B_2 | A_CNF_10B_2; + else + lp->adapter_cnf = A_CNF_MEDIA_10B_T | A_CNF_10B_T; - if (!strcmp(duplex, "auto")) + if (duplex==-1) lp->auto_neg_cnf = AUTO_NEG_ENABLE; if (io == 0) { diff -ur --new-file old/linux/drivers/net/de4x5.c new/linux/drivers/net/de4x5.c --- old/linux/drivers/net/de4x5.c Thu Dec 31 00:09:18 1998 +++ new/linux/drivers/net/de4x5.c Sun May 9 04:46:44 1999 @@ -225,11 +225,18 @@ to determine this in advance other than by trial and error and common sense, e.g. call a BNC connectored port 'BNC', not '10Mb'. - TO DO: - ------ + Changed the bus probing. EISA used to be done first, followed by PCI. + Most people probably don't even know what a de425 is today and the EISA + probe has messed up some SCSI cards in the past, so now PCI is always + probed first followed by EISA if a) the architecture allows EISA and + either b) there have been no PCI cards detected or c) an EISA probe is + forced by the user. To force a probe include "force_eisa" in your + insmod "args" line; for built-in kernels either change the driver to do + this automatically or include #define DE4X5_FORCE_EISA on or before + line 1040 in the driver. - o check what revision numbers the 21142 and 21143 have - o + TO DO: + ------ Revision History ---------------- @@ -416,11 +423,14 @@ access traps. This flag is merely for log messages: should do something more definitive though... 0.543 30-Dec-98 Add SMP spin locking. - + 0.544 8-May-99 Fix for buggy SROM in Motorola embedded boards using + a 21143 by . + Change PCI/EISA bus probing order. + ========================================================================= */ -static const char *version = "de4x5.c:V0.543 1998/12/30 davies@maniac.ultranet.com\n"; +static const char *version = "de4x5.c:V0.544 1999/5/8 davies@maniac.ultranet.com\n"; #include #include @@ -1027,8 +1037,11 @@ #if !defined(__sparc_v9__) && !defined(__powerpc__) && !defined(__alpha__) static u_char de4x5_irq[] = EISA_ALLOWED_IRQ_LIST; static int lastEISA = 0; -#else -static int lastEISA = MAX_EISA_SLOTS; /* Only PCI probes */ +# ifdef DE4X5_FORCE_EISA /* Force an EISA bus probe or not */ +static int forceEISA = 1; +# else +static int forceEISA = 0; +# endif #endif static int num_de4x5s = 0; static int cfrv = 0, useSROM = 0; @@ -1098,12 +1111,12 @@ { u_long iobase = dev->base_addr; + pci_probe(dev, iobase); #if !defined(__sparc_v9__) && !defined(__powerpc__) && !defined(__alpha__) - eisa_probe(dev, iobase); -#endif - if (lastEISA == MAX_EISA_SLOTS) { - pci_probe(dev, iobase); + if ((lastPCI == NO_MORE_PCI) && ((num_de4x5s == 0) || forceEISA)) { + eisa_probe(dev, iobase); } +#endif return (dev->priv ? 0 : -ENODEV); } @@ -1230,6 +1243,7 @@ if ((tmp = (void *)kmalloc(RX_BUFF_SZ * NUM_RX_DESC + ALIGN, GFP_KERNEL)) == NULL) { kfree(lp->cache.priv); + lp->cache.priv = NULL; return -ENOMEM; } @@ -2066,38 +2080,36 @@ } for (status = -ENODEV; (i> 8) & 0x00ffff00; - vendor = (u_short) cfid; + if (check_region(iobase, DE4X5_EISA_TOTAL_SIZE)) continue; + if (!EISA_signature(name, EISA_ID)) continue; + + cfid = (u32) inl(PCI_CFID); + cfrv = (u_short) inl(PCI_CFRV); + device = (cfid >> 8) & 0x00ffff00; + vendor = (u_short) cfid; - /* Read the EISA Configuration Registers */ - irq = inb(EISA_REG0); - irq = de4x5_irq[(irq >> 1) & 0x03]; - - if (is_DC2114x) { - device = ((cfrv & CFRV_RN) < DC2114x_BRK ? DC21142 : DC21143); - } - lp->chipset = device; - - /* Write the PCI Configuration Registers */ - outl(PCI_COMMAND_IO | PCI_COMMAND_MASTER, PCI_CFCS); - outl(0x00006000, PCI_CFLT); - outl(iobase, PCI_CBIO); + /* Read the EISA Configuration Registers */ + irq = inb(EISA_REG0); + irq = de4x5_irq[(irq >> 1) & 0x03]; + + if (is_DC2114x) { + device = ((cfrv & CFRV_RN) < DC2114x_BRK ? DC21142 : DC21143); + } + lp->chipset = device; + + /* Write the PCI Configuration Registers */ + outl(PCI_COMMAND_IO | PCI_COMMAND_MASTER, PCI_CFCS); + outl(0x00006000, PCI_CFLT); + outl(iobase, PCI_CBIO); - DevicePresent(EISA_APROM); - if (check_region(iobase, DE4X5_EISA_TOTAL_SIZE) == 0) { - dev->irq = irq; - if ((status = de4x5_hw_init(dev, iobase)) == 0) { - num_de4x5s++; - if (loading_module) link_modules(lastModule, dev); - lastEISA = i; - return; - } - } else if (ioaddr != 0) { - printk("%s: region already allocated at 0x%04lx.\n", dev->name,iobase); - } + DevicePresent(EISA_APROM); + + dev->irq = irq; + if ((status = de4x5_hw_init(dev, iobase)) == 0) { + num_de4x5s++; + if (loading_module) link_modules(lastModule, dev); + lastEISA = i; + return; } } @@ -4794,6 +4806,7 @@ if (lp->state == INITIALISED) { lp->ibn = 3; lp->active = *p++; + if (MOTO_SROM_BUG) lp->active = 0; lp->phy[lp->active].gep = (*p ? p : 0); p += (2 * (*p) + 1); lp->phy[lp->active].rst = (*p ? p : 0); p += (2 * (*p) + 1); lp->phy[lp->active].mc = TWIDDLE(p); p += 2; @@ -5326,6 +5339,9 @@ t = *q; *q = '\0'; +#if !defined(__sparc_v9__) && !defined(__powerpc__) && !defined(__alpha__) + if (strstr(p, "force_eisa") || strstr(p, "FORCE_EISA")) forceEISA = 1; +#endif if (strstr(p, "fdx") || strstr(p, "FDX")) lp->params.fdx = 1; if (strstr(p, "autosense") || strstr(p, "AUTOSENSE")) { @@ -5766,6 +5782,12 @@ release_region(p->base_addr, (lp->bus == PCI ? DE4X5_PCI_TOTAL_SIZE : DE4X5_EISA_TOTAL_SIZE)); + if (lp->cache.buf) { /* MAC buffers allocated? */ + kfree(lp->cache.buf); /* Free the MAC buffers */ + } + if (lp->cache.priv) { /* Private area allocated? */ + kfree(lp->cache.priv); /* Free the private area */ + } } kfree(p); } else { @@ -5799,10 +5821,10 @@ if (lp->cache.buf) { /* MAC buffers allocated? */ kfree(lp->cache.buf); /* Free the MAC buffers */ } - kfree(lp->cache.priv); /* Free the private area */ release_region(p->base_addr, (lp->bus == PCI ? DE4X5_PCI_TOTAL_SIZE : DE4X5_EISA_TOTAL_SIZE)); + kfree(lp->cache.priv); /* Free the private area */ } unregister_netdev(p); kfree(p); /* Free the device structure */ @@ -5867,6 +5889,9 @@ * Local variables: * compile-command: "gcc -D__KERNEL__ -I/linux/include -Wall -Wstrict-prototypes -fomit-frame-pointer -fno-strength-reduce -malign-loops=2 -malign-jumps=2 -malign-functions=2 -O2 -m486 -c de4x5.c" * - * compile-command: "gcc -D__KERNEL__ -DMODULE -I/linux/include -Wall -Wstrict-prototypes -fomit-frame-pointer -fno-strength-reduce -malign-loops=2 -malign-jumps=2 -malign-functions=2 -O2 -m486 -c de4x5.c" + * Delete -D__SMP__ below if you didn't define this in your kernel + * Delete -DMODVERSIONS below if you didn't define this in your kernel + * + * compile-command: "gcc -D__KERNEL__ -DMODULE -I/linux/include -Wall -Wstrict-prototypes -fomit-frame-pointer -fno-strength-reduce -malign-loops=2 -malign-jumps=2 -malign-functions=2 -O2 -m486 -DMODVERSIONS -include /linux/include/linux/modversions.h -c de4x5.c" * End: */ diff -ur --new-file old/linux/drivers/net/de4x5.h new/linux/drivers/net/de4x5.h --- old/linux/drivers/net/de4x5.h Thu Dec 31 00:09:18 1998 +++ new/linux/drivers/net/de4x5.h Tue May 11 17:34:32 1999 @@ -1027,3 +1027,5 @@ #define DE4X5_GET_REG 0x0e /* Get the DE4X5 Registers */ #define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s)) + +#define MOTO_SROM_BUG ((lp->active == 8) && (((le32_to_cpu(get_unaligned(((s32 *)dev->dev_addr))))&0x00ffffff)==0x3e0008)) diff -ur --new-file old/linux/drivers/net/defxx.c new/linux/drivers/net/defxx.c --- old/linux/drivers/net/defxx.c Fri May 8 09:08:02 1998 +++ new/linux/drivers/net/defxx.c Fri Apr 16 22:58:46 1999 @@ -1911,6 +1911,8 @@ } bp = (DFX_board_t *) dev->priv; + spin_lock(&bp->lock); + /* See if we're already servicing an interrupt */ if (dev->interrupt) @@ -1955,6 +1957,7 @@ } dev->interrupt = DFX_UNMASK_INTERRUPTS; + spin_unlock(&bp->lock); return; } @@ -2881,6 +2884,22 @@ return(DFX_K_SUCCESS); } + +/* + * Align an sk_buff to a boundary power of 2 + * + */ + +void my_skb_align(struct sk_buff *skb, int n) +{ + u32 x=(u32)skb->data; /* We only want the low bits .. */ + u32 v; + + v=(x+n-1)&~(n-1); /* Where we want to be */ + + skb_reserve(skb, v-x); +} + /* * ================ @@ -2950,8 +2969,8 @@ * align to 128 bytes for compatibility with * the old EISA boards. */ - newskb->data = (char *)((unsigned long) - (newskb->data+127) & ~127); + + my_skb_align(newskb,128); bp->descr_block_virt->rcv_data[i+j].long_1 = virt_to_bus(newskb->data); /* * p_rcv_buff_va is only used inside the @@ -3062,10 +3081,10 @@ newskb = dev_alloc_skb(NEW_SKB_SIZE); if (newskb){ rx_in_place = 1; - - newskb->data = (char *)((unsigned long)(newskb->data+127) & ~127); + + my_skb_align(newskb, 128); skb = (struct sk_buff *)bp->p_rcv_buff_va[entry]; - skb->data += RCV_BUFF_K_PADDING; + skb_reserve(skb, RCV_BUFF_K_PADDING); bp->p_rcv_buff_va[entry] = (char *)newskb; bp->descr_block_virt->rcv_data[entry].long_1 = virt_to_bus(newskb->data); } else @@ -3088,9 +3107,9 @@ memcpy(skb->data, p_buff + RCV_BUFF_K_PADDING, pkt_len+3); } - - skb->data += 3; /* adjust data field so that it points to FC byte */ - skb->len = pkt_len; /* pass up packet length, NOT including CRC */ + + skb_reserve(skb,3); /* adjust data field so that it points to FC byte */ + skb_put(skb, pkt_len); /* pass up packet length, NOT including CRC */ skb->dev = bp->dev; /* pass up device pointer */ skb->protocol = fddi_type_trans(skb, bp->dev); @@ -3189,10 +3208,11 @@ ) { - DFX_board_t *bp = (DFX_board_t *) dev->priv; - u8 prod; /* local transmit producer index */ + DFX_board_t *bp = (DFX_board_t *) dev->priv; + u8 prod; /* local transmit producer index */ PI_XMT_DESCR *p_xmt_descr; /* ptr to transmit descriptor block entry */ XMT_DRIVER_DESCR *p_xmt_drv_descr; /* ptr to transmit driver descriptor */ + unsigned long flags; /* * Verify that incoming transmit request is OK @@ -3236,6 +3256,8 @@ } } + spin_lock_irqsave(&bp->lock, flags); + /* Get the current producer and the next free xmt data descriptor */ prod = bp->rcv_xmt_reg.index.xmt_prod; @@ -3256,9 +3278,10 @@ /* Write the three PRH bytes immediately before the FC byte */ - *((char *)skb->data - 3) = DFX_PRH0_BYTE; /* these byte values are defined */ - *((char *)skb->data - 2) = DFX_PRH1_BYTE; /* in the Motorola FDDI MAC chip */ - *((char *)skb->data - 1) = DFX_PRH2_BYTE; /* specification */ + skb_push(skb,3); + skb->data[0] = DFX_PRH0_BYTE; /* these byte values are defined */ + skb->data[1] = DFX_PRH1_BYTE; /* in the Motorola FDDI MAC chip */ + skb->data[2] = DFX_PRH2_BYTE; /* specification */ /* * Write the descriptor with buffer info and bump producer @@ -3288,7 +3311,7 @@ */ p_xmt_descr->long_0 = (u32) (PI_XMT_DESCR_M_SOP | PI_XMT_DESCR_M_EOP | ((skb->len + 3) << PI_XMT_DESCR_V_SEG_LEN)); - p_xmt_descr->long_1 = (u32) virt_to_bus(skb->data - 3); + p_xmt_descr->long_1 = (u32) virt_to_bus(skb->data); /* * Verify that descriptor is actually available @@ -3302,7 +3325,11 @@ */ if (prod == bp->rcv_xmt_reg.index.xmt_comp) + { + skb_pull(skb,3); + spin_unlock_irqrestore(&bp->lock, flags); return(1); /* requeue packet for later */ + } /* * Save info for this packet for xmt done indication routine @@ -3326,6 +3353,7 @@ bp->rcv_xmt_reg.index.xmt_prod = prod; dfx_port_write_long(bp, PI_PDQ_K_REG_TYPE_2_PROD, bp->rcv_xmt_reg.lword); + spin_unlock_irqrestore(&bp->lock, flags); return(0); /* packet queued to adapter */ } diff -ur --new-file old/linux/drivers/net/defxx.h new/linux/drivers/net/defxx.h --- old/linux/drivers/net/defxx.h Fri May 8 09:08:02 1998 +++ new/linux/drivers/net/defxx.h Fri Apr 16 22:58:46 1999 @@ -1748,6 +1748,10 @@ /* Store pointers to transmit buffers for transmit completion code */ XMT_DRIVER_DESCR xmt_drv_descr_blk[PI_XMT_DATA_K_NUM_ENTRIES]; + + /* Transmit spinlocks */ + + spinlock_t lock; /* Store device, bus-specific, and parameter information for this adapter */ diff -ur --new-file old/linux/drivers/net/eepro100.c new/linux/drivers/net/eepro100.c --- old/linux/drivers/net/eepro100.c Fri Jan 15 23:36:21 1999 +++ new/linux/drivers/net/eepro100.c Sat Feb 6 21:46:21 1999 @@ -842,9 +842,6 @@ wait_for_cmd_done(ioaddr + SCBCmd); outw(CU_DUMPSTATS, ioaddr + SCBCmd); - /* No need to wait for the command unit to accept here. */ - if ((sp->phy[0] & 0x8000) == 0) - mdio_read(ioaddr, sp->phy[0] & 0x1f, 0); /* * Request the IRQ last, after we have set up all data structures. @@ -854,6 +851,10 @@ "Intel EtherExpress Pro 10/100 Ethernet", dev)) { return -EAGAIN; } + + /* No need to wait for the command unit to accept here. */ + if ((sp->phy[0] & 0x8000) == 0) + mdio_read(ioaddr, sp->phy[0] & 0x1f, 0); MOD_INC_USE_COUNT; diff -ur --new-file old/linux/drivers/net/eexpress.c new/linux/drivers/net/eexpress.c --- old/linux/drivers/net/eexpress.c Thu Jan 14 19:31:41 1999 +++ new/linux/drivers/net/eexpress.c Fri May 7 08:14:36 1999 @@ -83,6 +83,7 @@ * practice. */ +#include #include #include @@ -107,6 +108,8 @@ #include #include +#include + #ifndef NET_DEBUG #define NET_DEBUG 4 #endif @@ -141,6 +144,7 @@ unsigned char width; /* 0 for 16bit, 1 for 8bit */ unsigned char was_promisc; unsigned char old_mc_count; + spinlock_t lock; }; /* This is the code and data that is downloaded to the EtherExpress card's @@ -502,6 +506,7 @@ static int eexp_xmit(struct sk_buff *buf, struct device *dev) { struct net_local *lp = (struct net_local *)dev->priv; + unsigned long flags; #if NET_DEBUG > 6 printk(KERN_DEBUG "%s: eexp_xmit()\n", dev->name); @@ -509,6 +514,15 @@ disable_irq(dev->irq); + /* + * Best would be to use synchronize_irq(); spin_lock() here + * lets make it work first.. + */ + +#ifdef CONFIG_SMP + spin_lock_irqsave(&lp->lock, flags); +#endif + /* If dev->tbusy is set, all our tx buffers are full but the kernel * is calling us anyway. Check that nothing bad is happening. */ @@ -516,7 +530,13 @@ int status = scb_status(dev); unstick_cu(dev); if ((jiffies - lp->last_tx) < HZ) + { +#ifdef CONFIG_SMP + spin_unlock_irqrestore(&lp->lock, flags); +#endif + return 1; + } printk(KERN_INFO "%s: transmit timed out, %s?", dev->name, (SCB_complete(status)?"lost interrupt": "board on fire")); @@ -544,6 +564,9 @@ eexp_hw_tx_pio(dev,data,length); } dev_kfree_skb(buf); +#ifdef CONFIG_SMP + spin_unlock_irqrestore(&lp->lock, flags); +#endif enable_irq(dev->irq); return 0; } @@ -646,11 +669,14 @@ lp = (struct net_local *)dev->priv; ioaddr = dev->base_addr; + spin_lock(&lp->lock); + old_read_ptr = inw(ioaddr+READ_PTR); old_write_ptr = inw(ioaddr+WRITE_PTR); outb(SIRQ_dis|irqrmap[irq],ioaddr+SET_IRQ); + dev->interrupt = 1; status = scb_status(dev); @@ -726,6 +752,8 @@ #endif outw(old_read_ptr, ioaddr+READ_PTR); outw(old_write_ptr, ioaddr+WRITE_PTR); + + spin_unlock(&lp->lock); return; } diff -ur --new-file old/linux/drivers/net/epic100.c new/linux/drivers/net/epic100.c --- old/linux/drivers/net/epic100.c Sun Jan 10 04:16:43 1999 +++ new/linux/drivers/net/epic100.c Thu Apr 29 20:53:41 1999 @@ -1106,6 +1106,7 @@ memcpy(skb_put(skb, pkt_len), bus_to_virt(ep->rx_ring[entry].bufaddr), pkt_len); #endif + ep->rx_ring[entry].status = 0x8000; } else { skb_put(skb = ep->rx_skbuff[entry], pkt_len); ep->rx_skbuff[entry] = NULL; diff -ur --new-file old/linux/drivers/net/eql.c new/linux/drivers/net/eql.c --- old/linux/drivers/net/eql.c Wed May 6 19:56:04 1998 +++ new/linux/drivers/net/eql.c Mon May 10 22:00:10 1999 @@ -363,8 +363,8 @@ eql_schedule_slaves (eql->queue); - slave_dev = eql_best_slave_dev (eql->queue); slave = eql_best_slave (eql->queue); + slave_dev = slave ? slave->dev : 0; if ( slave_dev != 0 ) { diff -ur --new-file old/linux/drivers/net/ethertap.c new/linux/drivers/net/ethertap.c --- old/linux/drivers/net/ethertap.c Fri Oct 23 17:12:32 1998 +++ new/linux/drivers/net/ethertap.c Tue May 11 17:24:31 1999 @@ -177,11 +177,21 @@ #endif if (skb_headroom(skb) < 2) { - printk(KERN_DEBUG "%s : bug --- xmit with head<2\n", dev->name); + static int once; + struct sk_buff *skb2; + + if (!once) { + once = 1; + printk(KERN_DEBUG "%s: not aligned xmit by protocol %04x\n", dev->name, skb->protocol); + } + + skb2 = skb_realloc_headroom(skb, 2); dev_kfree_skb(skb); - return 0; + if (skb2 == NULL) + return 0; + skb = skb2; } - skb_push(skb, 2); + __skb_push(skb, 2); /* Make the same thing, which loopback does. */ if (skb_shared(skb)) { diff -ur --new-file old/linux/drivers/net/hamradio/baycom_epp.c new/linux/drivers/net/hamradio/baycom_epp.c --- old/linux/drivers/net/hamradio/baycom_epp.c Fri Nov 20 17:44:06 1998 +++ new/linux/drivers/net/hamradio/baycom_epp.c Fri Mar 26 22:57:41 1999 @@ -48,7 +48,6 @@ #include #include #include -#include #include #include #include @@ -1075,6 +1074,7 @@ if (!(pp->modes & (PARPORT_MODE_PCECPEPP|PARPORT_MODE_PCEPP))) { printk(KERN_ERR "%s: parport at 0x%lx does not support any EPP mode\n", bc_drvname, pp->base); + parport_release(bc->pdev); parport_unregister_device(bc->pdev); return -EIO; } diff -ur --new-file old/linux/drivers/net/hostess_sv11.c new/linux/drivers/net/hostess_sv11.c --- old/linux/drivers/net/hostess_sv11.c Fri Nov 13 19:29:44 1998 +++ new/linux/drivers/net/hostess_sv11.c Fri Feb 19 01:28:49 1999 @@ -416,10 +416,8 @@ int init_module(void) { - printk(KERN_INFO "SV-11 Z85230 Synchronous Driver v 0.01.\n"); + printk(KERN_INFO "SV-11 Z85230 Synchronous Driver v 0.02.\n"); printk(KERN_INFO "(c) Copyright 1998, Building Number Three Ltd.\n"); - if(dma) - printk(KERN_WARNING "DMA mode probably wont work right now.\n"); if((sv11_unit=sv11_init(io,irq))==NULL) return -ENODEV; return 0; diff -ur --new-file old/linux/drivers/net/ibmtr.c new/linux/drivers/net/ibmtr.c --- old/linux/drivers/net/ibmtr.c Mon Jan 25 07:04:02 1999 +++ new/linux/drivers/net/ibmtr.c Fri May 7 19:57:42 1999 @@ -70,6 +70,15 @@ * Changes by Joel Sloan (jjs@c-me.com) : * + disable verbose debug messages by default - to enable verbose * debugging, edit the IBMTR_DEBUG_MESSAGES define below + * + * Changes by Mike Phillips : + * + Added extra #ifdef's to work with new PCMCIA Token Ring Code. + * The PCMCIA code now just sets up the card so it can be recognized + * by ibmtr_probe. Also checks allocated memory vs. on-board memory + * for correct figure to use. + * + * Changes by Tim Hockin (thockin@isunix.it.ilstu.edu) : + * + added spinlocks for SMP sanity (10 March 1999) */ /* change the define of IBMTR_DEBUG_MESSAGES to a nonzero value @@ -91,6 +100,7 @@ #undef NO_AUTODETECT #undef ENABLE_PAGING + #define FALSE 0 #define TRUE (!FALSE) @@ -144,6 +154,7 @@ #include #include +#include #include #include @@ -187,6 +198,9 @@ int ibmtr_probe(struct device *dev); static int ibmtr_probe1(struct device *dev, int ioaddr); static unsigned char get_sram_size(struct tok_info *adapt_info); +#ifdef PCMCIA +extern unsigned char pcmcia_reality_check(unsigned char gss); +#endif static int tok_init_card(struct device *dev); void tok_interrupt(int irq, void *dev_id, struct pt_regs *regs); static int trdev_init(struct device *dev); @@ -252,8 +266,10 @@ if (ibmtr_probe1(dev, base_addr)) { #ifndef MODULE +#ifndef PCMCIA tr_freedev(dev); #endif +#endif return -ENODEV; } else return 0; @@ -268,8 +284,10 @@ continue; if (ibmtr_probe1(dev, ioaddr)) { #ifndef MODULE +#ifndef PCMCIA tr_freedev(dev); #endif +#endif } else return 0; } @@ -287,8 +305,10 @@ unsigned long timeout; #ifndef MODULE +#ifndef PCMCIA dev = init_trdev(dev,0); #endif +#endif /* Query the adapter PIO base port which will return * indication of where MMIO was placed. We also have a @@ -296,7 +316,7 @@ */ segment = inb(PIOaddr); - + /* * Out of range values so we'll assume non-existent IO device */ @@ -369,12 +389,19 @@ } /* Now, allocate some of the pl0 buffers for this driver.. */ + + /* If called from PCMCIA, ti is already set up, so no need to + waste the memory, just use the existing structure */ + +#ifndef PCMCIA ti = (struct tok_info *)kmalloc(sizeof(struct tok_info), GFP_KERNEL); if (ti == NULL) return -ENOMEM; memset(ti, 0, sizeof(struct tok_info)); - +#else + ti = dev->priv ; +#endif ti->mmio= t_mmio; ti->readlog_pending = 0; @@ -384,6 +411,10 @@ should fit with out future hope of multiple adapter support as well /dwm */ + /* if PCMCIA, then the card is recognized as TR_ISAPNP + * and there is no need to set up the interrupt, it is already done. */ + +#ifndef PCMCIA switch (cardpresent) { case TR_ISA: @@ -424,7 +455,6 @@ irq=10; if (intr==3) irq=11; - timeout = jiffies + TR_SPIN_INTERVAL; while(!readb(ti->mmio + ACA_OFFSET + ACA_RW + RRR_EVEN)) if (time_after(jiffies, timeout)) { @@ -432,11 +462,13 @@ kfree_s(ti, sizeof(struct tok_info)); return -ENODEV; } + ti->sram=((__u32)readb(ti->mmio + ACA_OFFSET + ACA_RW + RRR_EVEN)<<12); ti->global_int_enable=PIOaddr+ADAPTINTREL; ti->adapter_int_enable=PIOaddr+ADAPTINTREL; break; } +#endif if (ibmtr_debug_trace & TRC_INIT) { /* just report int */ DPRINTK("irq=%d",irq); @@ -479,8 +511,12 @@ ti->token_release = readb(ti->mmio + AIPEARLYTOKEN); /* How much shared RAM is on adapter ? */ +#ifdef PCMCIA + ti->avail_shared_ram = pcmcia_reality_check(get_sram_size(ti)); + ibmtr_mem_base = ti->sram_base ; +#else ti->avail_shared_ram = get_sram_size(ti); - +#endif /* We need to set or do a bunch of work here based on previous results.. */ /* Support paging? What sizes?: F=no, E=16k, D=32k, C=16 & 32k */ ti->shared_ram_paging = readb(ti->mmio + AIPSHRAMPAGE); @@ -589,7 +625,6 @@ } #endif } - /* finish figuring the shared RAM address */ if (cardpresent==TR_ISA) { static __u32 ram_bndry_mask[]={0xffffe000, 0xffffc000, 0xffff8000, 0xffff0000}; @@ -615,15 +650,20 @@ DPRINTK("Using %dK shared RAM\n",ti->mapped_ram_size/2); #endif + /* The PCMCIA has already got the interrupt line and the io port, + so no chance of anybody else getting it - MLP */ + +#ifndef PCMCIA if (request_irq (dev->irq = irq, &tok_interrupt,0,"ibmtr", dev) != 0) { DPRINTK("Could not grab irq %d. Halting Token Ring driver.\n",irq); kfree_s(ti, sizeof(struct tok_info)); return -ENODEV; } + + /*?? Now, allocate some of the PIO PORTs for this driver.. */ + request_region(PIOaddr,IBMTR_IO_EXTENT,"ibmtr"); /* record PIOaddr range as busy */ +#endif - /*?? Now, allocate some of the PIO PORTs for this driver.. */ - request_region(PIOaddr,IBMTR_IO_EXTENT,"ibmtr"); /* record PIOaddr range - as busy */ #if !TR_NEWFORMAT DPRINTK("%s",version); /* As we have passed card identification, let the world know we're here! */ @@ -713,7 +753,6 @@ unsigned char avail_sram_code; static unsigned char size_code[]={ 0,16,32,64,127,128 }; - /* Adapter gives 'F' -- use RRR bits 3,2 'E' -- 8kb 'D' -- 16kb @@ -743,8 +782,10 @@ dev->change_mtu = ibmtr_change_mtu; #ifndef MODULE +#ifndef PCMCIA tr_setup(dev); #endif +#endif return 0; } @@ -754,6 +795,9 @@ { struct tok_info *ti=(struct tok_info *)dev->priv; + /* init the spinlock */ + ti->lock = (spinlock_t) SPIN_LOCK_UNLOCKED; + if (ti->open_status==CLOSED) tok_init_card(dev); if (ti->open_status==IN_PROGRESS) sleep_on(&ti->wait_for_reset); @@ -806,6 +850,7 @@ DPRINTK("Int from tok_driver, dev : %p\n",dev); #endif ti = (struct tok_info *) dev->priv; + spin_lock(&(ti->lock)); /* Disable interrupts till processing is finished */ dev->interrupt=1; @@ -832,14 +877,16 @@ if (status == 0xFF) { DPRINTK("PCMCIA card removed.\n"); + spin_unlock(&(ti->lock)); dev->interrupt = 0; - return; + return; } /* Check ISRP EVEN too. */ if ( readb (ti->mmio + ACA_OFFSET + ACA_RW + ISRP_EVEN) == 0xFF) { DPRINTK("PCMCIA card removed.\n"); + spin_unlock(&(ti->lock)); dev->interrupt = 0; return; } @@ -1167,6 +1214,7 @@ DPRINTK("Unexpected interrupt from tr adapter\n"); } + spin_unlock(&(ti->lock)); } static void initial_tok_int(struct device *dev) @@ -1175,7 +1223,6 @@ __u32 encoded_addr; __u32 hw_encoded_addr; struct tok_info *ti; - ti=(struct tok_info *) dev->priv; ti->do_tok_int=NOT_FIRST; @@ -1452,6 +1499,7 @@ ti->asb + offsetof(struct asb_rec, rec_buf_addr)); lan_hdr_len=readb(ti->arb + offsetof(struct arb_rec_req, lan_hdr_len)); + hdr_len = lan_hdr_len + sizeof(struct trllc) + sizeof(struct iphdr); llc=(rbuffer + offsetof(struct rec_buf, data) + lan_hdr_len); @@ -1478,8 +1526,10 @@ return; } + length = ntohs(readw(ti->arb+offsetof(struct arb_rec_req, frame_len))); if ((readb(llc + offsetof(struct trllc, dsap))==EXTENDED_SAP) && - (readb(llc + offsetof(struct trllc, ssap))==EXTENDED_SAP)) { + (readb(llc + offsetof(struct trllc, ssap))==EXTENDED_SAP) && + (length>=hdr_len)) { IPv4_p = 1; } @@ -1510,7 +1560,6 @@ } #endif - length = ntohs(readw(ti->arb+offsetof(struct arb_rec_req, frame_len))); skb_size = length-lan_hdr_len+sizeof(struct trh_hdr)+sizeof(struct trllc); if (!(skb=dev_alloc_skb(skb_size))) { @@ -1530,7 +1579,6 @@ if (IPv4_p) { /* Copy the headers without checksumming */ - hdr_len = lan_hdr_len + sizeof(struct trllc) + sizeof(struct iphdr); memcpy_fromio(data, rbufdata, hdr_len); /* Watch for padded packets and bogons */ @@ -1598,12 +1646,19 @@ if (test_and_set_bit(0,(void *)&dev->tbusy)!=0) DPRINTK("Transmitter access conflict\n"); else { + int flags; + + /* lock against other CPUs */ + spin_lock_irqsave(&(ti->lock), flags); + /* Save skb; we'll need it when the adapter asks for the data */ ti->current_skb=skb; writeb(XMIT_UI_FRAME, ti->srb + offsetof(struct srb_xmit, command)); writew(ti->exsap_station_id, ti->srb +offsetof(struct srb_xmit, station_id)); writeb(CMD_IN_SRB, (ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD)); + spin_unlock_irqrestore(&(ti->lock), flags); + dev->trans_start=jiffies; } diff -ur --new-file old/linux/drivers/net/ibmtr.h new/linux/drivers/net/ibmtr.h --- old/linux/drivers/net/ibmtr.h Mon Jul 27 08:35:56 1998 +++ new/linux/drivers/net/ibmtr.h Tue Mar 16 23:21:52 1999 @@ -217,6 +217,7 @@ unsigned char ring_speed; __u32 func_addr; unsigned int retry_count; + spinlock_t lock; /* SMP protection */ }; /* token ring adapter commands */ diff -ur --new-file old/linux/drivers/net/irda/Config.in new/linux/drivers/net/irda/Config.in --- old/linux/drivers/net/irda/Config.in Wed Jan 20 20:05:33 1999 +++ new/linux/drivers/net/irda/Config.in Mon Mar 8 00:26:43 1999 @@ -9,6 +9,7 @@ dep_tristate ' ESI JetEye PC dongle' CONFIG_ESI_DONGLE $CONFIG_IRTTY_SIR dep_tristate ' ACTiSYS IR-220L and IR220L+ dongle' CONFIG_ACTISYS_DONGLE $CONFIG_IRTTY_SIR dep_tristate ' Tekram IrMate 210B dongle' CONFIG_TEKRAM_DONGLE $CONFIG_IRTTY_SIR + dep_tristate ' Greenwich GIrBIL dongle' CONFIG_GIRBIL_DONGLE $CONFIG_IRTTY_SIR fi fi dep_tristate ' NSC PC87108' CONFIG_NSC_FIR $CONFIG_IRDA diff -ur --new-file old/linux/drivers/net/irda/Makefile new/linux/drivers/net/irda/Makefile --- old/linux/drivers/net/irda/Makefile Wed Jan 20 20:05:33 1999 +++ new/linux/drivers/net/irda/Makefile Thu Apr 15 14:42:41 1999 @@ -10,7 +10,7 @@ L_TARGET := irda_drivers.a L_OBJS := M_OBJS := -MOD_LIST_NAME := IRDA_MODULES +MOD_LIST_NAME := IRDA_DRIVERS_MODULES ifeq ($(CONFIG_IRTTY_SIR),y) L_OBJS += irtty.o @@ -65,6 +65,14 @@ else ifeq ($(CONFIG_ACTISYS_DONGLE),m) M_OBJS += actisys.o + endif +endif + +ifeq ($(CONFIG_GIRBIL_DONGLE),y) +L_OBJS += girbil.o +else + ifeq ($(CONFIG_GIRBIL_DONGLE),m) + M_OBJS += girbil.o endif endif diff -ur --new-file old/linux/drivers/net/irda/actisys.c new/linux/drivers/net/irda/actisys.c --- old/linux/drivers/net/irda/actisys.c Wed Jan 20 20:05:33 1999 +++ new/linux/drivers/net/irda/actisys.c Sun Apr 25 02:49:37 1999 @@ -1,13 +1,13 @@ /********************************************************************* * * Filename: actisys.c - * Version: 0.4 + * Version: 0.5 * Description: Implementation for the ACTiSYS IR-220L and IR-220L+ * dongles * Status: Experimental. * Author: Dag Brattli * Created at: Wed Oct 21 20:02:35 1998 - * Modified at: Mon Jan 18 11:30:25 1999 + * Modified at: Mon Apr 12 11:56:35 1999 * Modified by: Dag Brattli * * Copyright (c) 1998 Dag Brattli, All Rights Reserved. @@ -70,9 +70,10 @@ static void actisys_open( struct irda_device *idev, int type) { - strcat( idev->name, " <-> actisys"); + strcat(idev->description, " <-> actisys"); idev->io.dongle_id = type; + idev->flags |= IFF_DONGLE; MOD_INC_USE_COUNT; } @@ -85,24 +86,20 @@ /* * Function actisys_change_speed (tty, baud) * - * Change speed of the ACTiSYS IR-220L and IR-220L+ type IrDA dongles. - * To cycle through the available baud rates, pulse RTS low for a few ms. - * To be compatible with the new IR-220L+, we have to reset the dongle - * first since its not possible cycle around anymore and still be - * compatible with both dongles :-( + * Change speed of the ACTiSYS IR-220L and IR-220L+ type IrDA dongles. + * To cycle through the available baud rates, pulse RTS low for a few + * ms. */ static void actisys_change_speed( struct irda_device *idev, int baudrate) { struct irtty_cb *self; struct tty_struct *tty; - int arg; struct termios old_termios; int cflag; int current_baudrate; int index = 0; - mm_segment_t fs; - DEBUG( 0, __FUNCTION__ "()\n"); + DEBUG( 4, __FUNCTION__ "()\n"); ASSERT( idev != NULL, return;); ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return;); @@ -115,10 +112,10 @@ current_baudrate = idev->qos.baud_rate.value; /* Find the correct baudrate index for the currently used baudrate */ - while ( current_baudrate != baud_rates[index]) + while (current_baudrate != baud_rates[index]) index++; - DEBUG( 0, __FUNCTION__ "(), index=%d\n", index); + DEBUG( 4, __FUNCTION__ "(), index=%d\n", index); if ( !self->tty) return; @@ -127,38 +124,18 @@ /* Cycle through avaiable baudrates until we reach the correct one */ while ( current_baudrate != baudrate) { - DEBUG( 0, __FUNCTION__ "(), current baudrate = %d\n", + DEBUG( 4, __FUNCTION__ "(), current baudrate = %d\n", baud_rates[index]); - DEBUG( 0, __FUNCTION__ "(), Clearing RTS\n"); /* Set DTR, clear RTS */ - arg = TIOCM_DTR|TIOCM_OUT2; - - fs = get_fs(); - set_fs( get_ds()); - - if ( tty->driver.ioctl( tty, NULL, TIOCMSET, - (unsigned long) &arg)) { - DEBUG( 0, __FUNCTION__ - "Error clearing RTS!\n"); - } - set_fs(fs); + irtty_set_dtr_rts(tty, TRUE, FALSE); /* Wait at a few ms */ current->state = TASK_INTERRUPTIBLE; schedule_timeout(2); /* Set DTR, Set RTS */ - arg = TIOCM_DTR | TIOCM_RTS |TIOCM_OUT2; - - fs = get_fs(); - set_fs( get_ds()); - - if ( tty->driver.ioctl( tty, NULL, TIOCMSET, - (unsigned long) &arg)) { - DEBUG( 0, __FUNCTION__ "Error setting RTS!\n"); - } - set_fs(fs); + irtty_set_dtr_rts(tty, TRUE, TRUE); /* Wait at a few ms again */ current->state = TASK_INTERRUPTIBLE; @@ -172,8 +149,8 @@ current_baudrate = baud_rates[index]; } - DEBUG( 0, __FUNCTION__ "(), current baudrate = %d\n", - baud_rates[index]); + DEBUG(4, __FUNCTION__ "(), current baudrate = %d\n", + baud_rates[index]); /* Now change the speed of the serial port */ old_termios = *(tty->termios); @@ -200,9 +177,8 @@ break; } + /* Change speed of serial port */ tty->termios->c_cflag = cflag; - - DEBUG( 0, __FUNCTION__ "(), Setting the speed of the serial port\n"); tty->driver.set_termios( tty, &old_termios); } @@ -219,10 +195,6 @@ { struct irtty_cb *self; struct tty_struct *tty; - int arg = 0; - mm_segment_t fs; - - DEBUG( 4, __FUNCTION__ "()\n"); ASSERT( idev != NULL, return;); ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return;); @@ -236,36 +208,16 @@ if ( !tty) return; - DEBUG( 0, __FUNCTION__ "(), Clearing DTR\n"); - arg = TIOCM_RTS | TIOCM_OUT2; - - fs = get_fs(); - set_fs( get_ds()); - - if ( tty->driver.ioctl( tty, NULL, TIOCMSET, - (unsigned long) &arg)) - { - DEBUG( 0, __FUNCTION__"(), ioctl error!\n"); - } - set_fs(fs); + /* Clear DTR */ + irtty_set_dtr_rts(tty, FALSE, TRUE); /* Sleep 10-20 ms*/ current->state = TASK_INTERRUPTIBLE; schedule_timeout(2); - DEBUG( 0, __FUNCTION__ "(), Setting DTR\n"); - arg = TIOCM_RTS | TIOCM_DTR | TIOCM_OUT2; + /* Go back to normal mode */ + irtty_set_dtr_rts(tty, TRUE, TRUE); - fs = get_fs(); - set_fs( get_ds()); - - if ( tty->driver.ioctl( tty, NULL, TIOCMSET, - (unsigned long) &arg)) - { - DEBUG( 0, __FUNCTION__"(), ioctl error!\n"); - } - set_fs(fs); - idev->qos.baud_rate.value = 9600; } @@ -282,11 +234,14 @@ /* Remove support for 38400 if this is not a 220L+ dongle */ if ( idev->io.dongle_id == ACTISYS_DONGLE) qos->baud_rate.bits &= ~IR_38400; - - qos->min_turn_time.bits &= 0xfe; /* All except 0 ms */ + + qos->min_turn_time.bits &= 0x40; /* Needs 0.01 ms */ } #ifdef MODULE + +MODULE_AUTHOR("Dag Brattli "); +MODULE_DESCRIPTION("ACTiSYS IR-220L and IR-220L+ dongle driver"); /* * Function init_module (void) diff -ur --new-file old/linux/drivers/net/irda/esi.c new/linux/drivers/net/irda/esi.c --- old/linux/drivers/net/irda/esi.c Wed Jan 20 20:05:33 1999 +++ new/linux/drivers/net/irda/esi.c Sun Apr 25 02:49:37 1999 @@ -1,12 +1,12 @@ /********************************************************************* * * Filename: esi.c - * Version: 1.1 - * Description: Driver for the Extended Systems JetEye PC + * Version: 1.2 + * Description: Driver for the Extended Systems JetEye PC dongle * Status: Experimental. * Author: Thomas Davis, * Created at: Sat Feb 21 18:54:38 1998 - * Modified at: Mon Jan 18 11:30:32 1999 + * Modified at: Mon Apr 12 11:55:30 1999 * Modified by: Dag Brattli * Sources: esi.c * @@ -56,9 +56,9 @@ esi_qos_init, }; -__initfunc(void esi_init(void)) +__initfunc(int esi_init(void)) { - irtty_register_dongle( &dongle); + return irtty_register_dongle(&dongle); } void esi_cleanup(void) @@ -71,6 +71,7 @@ strcat( idev->description, " <-> esi"); idev->io.dongle_id = type; + idev->flags |= IFF_DONGLE; MOD_INC_USE_COUNT; } @@ -90,10 +91,9 @@ { struct irtty_cb *self; struct tty_struct *tty; - int arg = TIOCM_OUT2; + int dtr, rts; struct termios old_termios; int cflag; - mm_segment_t fs; ASSERT( idev != NULL, return;); ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return;); @@ -116,37 +116,25 @@ switch (baud) { case 19200: cflag |= B19200; - arg |= TIOCM_DTR; + dtr = TRUE; + rts = FALSE; break; case 115200: cflag |= B115200; - arg |= TIOCM_RTS | TIOCM_DTR; + dtr = rts = TRUE; break; case 9600: default: cflag |= B9600; - arg |= TIOCM_RTS; + dtr = FALSE; + rts = TRUE; break; } - + /* Change speed of serial driver */ tty->termios->c_cflag = cflag; - tty->driver.set_termios( tty, &old_termios); - - /* - * The ioctl function, or actually set_modem_info in serial.c - * expects a pointer to the argument in user space. To hack us - * around this we use the set_fs function to fool the routines - * that check if they are called from user space. We also need - * to send a pointer to the argument so get_user() gets happy. - * DB. - */ - fs = get_fs(); - set_fs( get_ds()); + tty->driver.set_termios(tty, &old_termios); - if ( tty->driver.ioctl( tty, NULL, TIOCMSET, (unsigned long) &arg)) { - DEBUG( 0, __FUNCTION__ "(), error setting ESI speed!\n"); - } - set_fs(fs); + irtty_set_dtr_rts(tty, dtr, rts); } static void esi_reset( struct irda_device *idev, int unused) @@ -163,6 +151,7 @@ static void esi_qos_init( struct irda_device *idev, struct qos_info *qos) { qos->baud_rate.bits &= IR_9600|IR_19200|IR_115200; + qos->min_turn_time.bits &= 0x01; /* Needs at least 10 ms */ } #ifdef MODULE @@ -175,8 +164,7 @@ */ int init_module(void) { - esi_init(); - return(0); + return esi_init(); } /* diff -ur --new-file old/linux/drivers/net/irda/girbil.c new/linux/drivers/net/irda/girbil.c --- old/linux/drivers/net/irda/girbil.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/net/irda/girbil.c Sun Apr 25 02:49:37 1999 @@ -0,0 +1,276 @@ +/********************************************************************* + * + * Filename: girbil.c + * Version: 1.0 + * Description: Implementation for the Greenwich GIrBIL dongle + * Status: Experimental. + * Author: Dag Brattli + * Created at: Sat Feb 6 21:02:33 1999 + * Modified at: Sat Apr 10 19:53:12 1999 + * Modified by: Dag Brattli + * + * Copyright (c) 1999 Dag Brattli, All Rights Reserved. + * + * 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. + * + * Neither Dag Brattli nor University of Tromsø admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + ********************************************************************/ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +static void girbil_reset(struct irda_device *dev, int unused); +static void girbil_open(struct irda_device *dev, int type); +static void girbil_close(struct irda_device *dev); +static void girbil_change_speed(struct irda_device *dev, int baud); +static void girbil_init_qos(struct irda_device *idev, struct qos_info *qos); + +/* Control register 1 */ +#define GIRBIL_TXEN 0x01 /* Enable transmitter */ +#define GIRBIL_RXEN 0x02 /* Enable receiver */ +#define GIRBIL_ECAN 0x04 /* Cancel self emmited data */ +#define GIRBIL_ECHO 0x08 /* Echo control characters */ + +/* LED Current Register (0x2) */ +#define GIRBIL_HIGH 0x20 +#define GIRBIL_MEDIUM 0x21 +#define GIRBIL_LOW 0x22 + +/* Baud register (0x3) */ +#define GIRBIL_2400 0x30 +#define GIRBIL_4800 0x31 +#define GIRBIL_9600 0x32 +#define GIRBIL_19200 0x33 +#define GIRBIL_38400 0x34 +#define GIRBIL_57600 0x35 +#define GIRBIL_115200 0x36 + +/* Mode register (0x4) */ +#define GIRBIL_IRDA 0x40 +#define GIRBIL_ASK 0x41 + +/* Control register 2 (0x5) */ +#define GIRBIL_LOAD 0x51 /* Load the new baud rate value */ + +static struct dongle dongle = { + GIRBIL_DONGLE, + girbil_open, + girbil_close, + girbil_reset, + girbil_change_speed, + girbil_init_qos, +}; + +__initfunc(void girbil_init(void)) +{ + irtty_register_dongle(&dongle); +} + +void girbil_cleanup(void) +{ + irtty_unregister_dongle(&dongle); +} + +static void girbil_open(struct irda_device *idev, int type) +{ + strcat( idev->description, " <-> girbil"); + + idev->io.dongle_id = type; + idev->flags |= IFF_DONGLE; + + MOD_INC_USE_COUNT; +} + +static void girbil_close(struct irda_device *dev) +{ + MOD_DEC_USE_COUNT; +} + +/* + * Function girbil_change_speed (dev, speed) + * + * Set the speed for the Girbil type dongle. Warning, this + * function must be called with a process context! + * + */ +static void girbil_change_speed(struct irda_device *idev, int speed) +{ + struct irtty_cb *self; + struct tty_struct *tty; + struct termios old_termios; + int cflag; + __u8 control[2]; + + ASSERT(idev != NULL, return;); + ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;); + + self = (struct irtty_cb *) idev->priv; + + ASSERT(self != NULL, return;); + ASSERT(self->magic == IRTTY_MAGIC, return;); + + if (!self->tty) + return; + + tty = self->tty; + + old_termios = *(tty->termios); + cflag = tty->termios->c_cflag; + + cflag &= ~CBAUD; + + switch (speed) { + case 9600: + default: + cflag |= B9600; + control[0] = GIRBIL_9600; + break; + case 19200: + cflag |= B19200; + control[0] = GIRBIL_19200; + break; + case 34800: + cflag |= B38400; + control[0] = GIRBIL_38400; + break; + case 57600: + cflag |= B57600; + control[0] = GIRBIL_57600; + break; + case 115200: + cflag |= B115200; + control[0] = GIRBIL_115200; + break; + } + control[1] = GIRBIL_LOAD; + + /* Set DTR and Clear RTS to enter command mode */ + irtty_set_dtr_rts(tty, FALSE, TRUE); + + /* Write control bytes */ + if (tty->driver.write) + tty->driver.write(self->tty, 0, control, 2); + + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(2); + + /* Go back to normal mode */ + irtty_set_dtr_rts(tty, TRUE, TRUE); + + /* Now change the speed of the serial port */ + tty->termios->c_cflag = cflag; + tty->driver.set_termios(tty, &old_termios); +} + +/* + * Function girbil_reset (driver) + * + * This function resets the girbil dongle. Warning, this function + * must be called with a process context!! + * + * Algorithm: + * 0. set RTS, and wait at least 5 ms + * 1. clear RTS + */ +void girbil_reset(struct irda_device *idev, int unused) +{ + struct irtty_cb *self; + struct tty_struct *tty; + __u8 control = GIRBIL_TXEN | GIRBIL_RXEN; + + ASSERT(idev != NULL, return;); + ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;); + + self = (struct irtty_cb *) idev->priv; + + ASSERT(self != NULL, return;); + ASSERT(self->magic == IRTTY_MAGIC, return;); + + tty = self->tty; + if (!tty) + return; + + /* Reset dongle */ + irtty_set_dtr_rts(tty, TRUE, FALSE); + + /* Sleep at least 5 ms */ + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(2); + + /* Set DTR and clear RTS to enter command mode */ + irtty_set_dtr_rts(tty, FALSE, TRUE); + + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(2); + + /* Write control byte */ + if (tty->driver.write) + tty->driver.write(self->tty, 0, &control, 1); + + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(2); + + /* Go back to normal mode */ + irtty_set_dtr_rts(tty, TRUE, TRUE); +} + +/* + * Function girbil_init_qos (qos) + * + * Initialize QoS capabilities + * + */ +static void girbil_init_qos(struct irda_device *idev, struct qos_info *qos) +{ + qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200; + qos->min_turn_time.bits &= 0xfe; /* All except 0 ms */ +} + +#ifdef MODULE + +MODULE_AUTHOR("Dag Brattli "); +MODULE_DESCRIPTION("Greenwich GIrBIL dongle driver"); + +/* + * Function init_module (void) + * + * Initialize Girbil module + * + */ +int init_module(void) +{ + girbil_init(); + return(0); +} + +/* + * Function cleanup_module (void) + * + * Cleanup Girbil module + * + */ +void cleanup_module(void) +{ + girbil_cleanup(); +} + +#endif /* MODULE */ diff -ur --new-file old/linux/drivers/net/irda/irport.c new/linux/drivers/net/irda/irport.c --- old/linux/drivers/net/irda/irport.c Mon Jan 25 06:55:04 1999 +++ new/linux/drivers/net/irda/irport.c Sun Apr 25 02:49:37 1999 @@ -1,7 +1,7 @@ /********************************************************************* * * Filename: irport.c - * Version: 0.8 + * Version: 0.9 * Description: Serial driver for IrDA. * Status: Experimental. * Author: Dag Brattli @@ -9,7 +9,6 @@ * Modified at: Sat May 23 23:15:20 1998 * Modified by: Dag Brattli * Sources: serial.c by Linus Torvalds - * serial_serial.c by Aage Kvalnes * * Copyright (c) 1997,1998 Dag Brattli * All Rights Reserved. @@ -25,10 +24,10 @@ * * NOTICE: * - * This driver is ment to be a small serial driver to be used for - * IR-chipsets that has a UART (16550) compatibility mode. If your - * chipset is is UART only, you should probably use IrTTY instead since - * the Linux serial driver is probably more robust and optimized. + * This driver is ment to be a small half duplex serial driver to be + * used for IR-chipsets that has a UART (16550) compatibility mode. If + * your chipset is is UART only, you should probably use IrTTY instead + * since the Linux serial driver is probably more robust and optimized. * * The functions in this file may be used by FIR drivers, but this * driver knows nothing about FIR drivers so don't ever insert such @@ -65,12 +64,12 @@ #define IO_EXTENT 8 -static unsigned int io[] = { 0x3e8, ~0, ~0, ~0 }; -static unsigned int irq[] = { 11, 0, 0, 0 }; +/* static unsigned int io[] = { 0x3e8, ~0, ~0, ~0 }; */ +/* static unsigned int irq[] = { 11, 0, 0, 0 }; */ -static void irport_write_wakeup( struct irda_device *idev); -static int irport_write( int iobase, int fifo_size, __u8 *buf, int len); -static void irport_receive( struct irda_device *idev); +static void irport_write_wakeup(struct irda_device *idev); +static int irport_write(int iobase, int fifo_size, __u8 *buf, int len); +static void irport_receive(struct irda_device *idev); __initfunc(int irport_init(void)) { @@ -96,7 +95,7 @@ #ifdef MODULE static void irport_cleanup(void) { - int i; +/* int i; */ DEBUG( 4, __FUNCTION__ "()\n"); @@ -113,17 +112,17 @@ * Start IO port * */ -int irport_open( int iobase) +int irport_open(int iobase) { - DEBUG( 0, __FUNCTION__ "(), iobase=%#x\n", iobase); + DEBUG(4, __FUNCTION__ "(), iobase=%#x\n", iobase); /* Initialize UART */ - outb( UART_LCR_WLEN8, iobase+UART_LCR); /* Reset DLAB */ - outb(( UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), iobase+UART_MCR); + outb(UART_LCR_WLEN8, iobase+UART_LCR); /* Reset DLAB */ + outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), iobase+UART_MCR); /* Turn on interrups */ - outb(( UART_IER_THRI |UART_IER_RLSI | UART_IER_RDI), iobase+UART_IER); - + outb((UART_IER_RLSI | UART_IER_RDI), iobase+UART_IER); + return 0; } @@ -133,15 +132,15 @@ * Stop IO port * */ -void irport_close( int iobase) +void irport_close(int iobase) { - DEBUG( 0, __FUNCTION__ "()\n"); + DEBUG(4, __FUNCTION__ "()\n"); /* Reset UART */ - outb( 0, iobase+UART_MCR); + outb(0, iobase+UART_MCR); /* Turn off interrupts */ - outb( 0, iobase+UART_IER); + outb(0, iobase+UART_IER); } /* @@ -158,10 +157,8 @@ DEBUG( 0, __FUNCTION__ "(), Setting speed to: %d\n", speed); - DEBUG( 0, __FUNCTION__ "(), iobase=%#x\n", iobase); - /* Turn off interrupts */ - outb( 0, iobase+UART_IER); + outb(0, iobase+UART_IER); divisor = SPEED_MAX/speed; @@ -170,55 +167,14 @@ /* IrDA ports use 8N1 */ lcr = UART_LCR_WLEN8; - outb( UART_LCR_DLAB | lcr, iobase+UART_LCR); /* Set DLAB */ - outb( divisor & 0xff, iobase+UART_DLL); /* Set speed */ - outb( divisor >> 8, iobase+UART_DLM); - outb( lcr, iobase+UART_LCR); /* Set 8N1 */ - outb( fcr, iobase+UART_FCR); /* Enable FIFO's */ + outb(UART_LCR_DLAB | lcr, iobase+UART_LCR); /* Set DLAB */ + outb(divisor & 0xff, iobase+UART_DLL); /* Set speed */ + outb(divisor >> 8, iobase+UART_DLM); + outb(lcr, iobase+UART_LCR); /* Set 8N1 */ + outb(fcr, iobase+UART_FCR); /* Enable FIFO's */ - /* Turn on interrups */ - outb( UART_IER_THRI|UART_IER_RLSI|UART_IER_RDI, iobase+UART_IER); -} - -/* - * Function irport_interrupt (irq, dev_id, regs) - * - * - */ -void irport_interrupt( int irq, void *dev_id, struct pt_regs *regs) -{ - struct irda_device *idev = (struct irda_device *) dev_id; - - int iobase, status; - int iir; - - DEBUG( 4, __FUNCTION__ "(), irq %d\n", irq); - - if ( !idev) { - printk( KERN_WARNING __FUNCTION__ - "() irq %d for unknown device.\n", irq); - return; - } - - idev->netdev.interrupt = 1; - - iobase = idev->io.iobase2; - - iir = inb(iobase + UART_IIR); - do { - status = inb( iobase+UART_LSR); - - if (status & UART_LSR_DR) { - /* Receive interrupt */ - irport_receive(idev); - } - if (status & UART_LSR_THRE) { - /* Transmitter ready for data */ - irport_write_wakeup(idev); - } - } while (!(inb(iobase+UART_IIR) & UART_IIR_NO_INT)); - - idev->netdev.interrupt = 0; + /* Turn on receive interrups */ + outb(UART_IER_RLSI|UART_IER_RDI, iobase+UART_IER); } /* @@ -228,39 +184,40 @@ * more packets to send, we send them here. * */ -static void irport_write_wakeup( struct irda_device *idev) +static void irport_write_wakeup(struct irda_device *idev) { - int actual = 0, count; - - DEBUG( 4, __FUNCTION__ "() <%ld>\n", jiffies); - - ASSERT( idev != NULL, return;); - ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return;); + int actual = 0; + int iobase; - /* Finished with frame? */ - if ( idev->tx_buff.offset == idev->tx_buff.len) { + ASSERT(idev != NULL, return;); + ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;); + /* Finished with frame? */ + if (idev->tx_buff.len > 0) { + /* Write data left in transmit buffer */ + actual = irport_write(idev->io.iobase2, idev->io.fifo_size, + idev->tx_buff.data, idev->tx_buff.len); + idev->tx_buff.data += actual; + idev->tx_buff.len -= actual; + } else { + iobase = idev->io.iobase2; /* * Now serial buffer is almost free & we can start * transmission of another packet */ - DEBUG( 4, __FUNCTION__ "(), finished with frame!\n"); - idev->netdev.tbusy = 0; /* Unlock */ idev->stats.tx_packets++; /* Schedule network layer, so we can get some more frames */ - mark_bh( NET_BH); + mark_bh(NET_BH); - return; - } + outb(UART_FCR_ENABLE_FIFO | + UART_FCR_TRIGGER_14 | + UART_FCR_CLEAR_RCVR, iobase+UART_FCR); /* Enable FIFO's */ - /* Write data left in transmit buffer */ - count = idev->tx_buff.len - idev->tx_buff.offset; - actual = irport_write( idev->io.iobase2, idev->io.fifo_size, - idev->tx_buff.head, count); - idev->tx_buff.offset += actual; - idev->tx_buff.head += actual; + /* Turn on receive interrupts */ + outb(UART_IER_RLSI|UART_IER_RDI, iobase+UART_IER); + } } /* @@ -269,12 +226,12 @@ * * */ -static int irport_write( int iobase, int fifo_size, __u8 *buf, int len) +static int irport_write(int iobase, int fifo_size, __u8 *buf, int len) { int actual = 0; /* Tx FIFO should be empty! */ - if (!(inb( iobase+UART_LSR) & UART_LSR_THRE)) { + if (!(inb(iobase+UART_LSR) & UART_LSR_THRE)) { DEBUG( 0, __FUNCTION__ "(), failed, fifo not empty!\n"); return -1; } @@ -287,8 +244,8 @@ actual++; } - DEBUG( 4, __FUNCTION__ "(), fifo_size %d ; %d sent of %d\n", - fifo_size, actual, len); + DEBUG(4, __FUNCTION__ "(), fifo_size %d ; %d sent of %d\n", + fifo_size, actual, len); return actual; } @@ -300,44 +257,41 @@ * waits until the next transmitt interrupt, and continues until the * frame is transmited. */ -int irport_hard_xmit( struct sk_buff *skb, struct device *dev) +int irport_hard_xmit(struct sk_buff *skb, struct device *dev) { struct irda_device *idev; - int xbofs; - int actual; - - DEBUG( 4, __FUNCTION__ "()\n"); + int actual = 0; + int iobase; - ASSERT( dev != NULL, return -1;); + DEBUG(5, __FUNCTION__ "(), dev=%p\n", dev); - if ( dev->tbusy) { - DEBUG( 4, __FUNCTION__ "(), tbusy==TRUE\n"); - - return -EBUSY; - } + ASSERT(dev != NULL, return 0;); idev = (struct irda_device *) dev->priv; - ASSERT( idev != NULL, return -1;); - ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return -1;); + ASSERT(idev != NULL, return 0;); + ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return 0;); + + iobase = idev->io.iobase2; /* Lock transmit buffer */ - if ( irda_lock( (void *) &dev->tbusy) == FALSE) + if (irda_lock((void *) &dev->tbusy) == FALSE) return -EBUSY; - /* - * Transfer skb to tx_buff while wrapping, stuffing and making CRC - */ - idev->tx_buff.len = async_wrap_skb( skb, idev->tx_buff.data, - idev->tx_buff.truesize); - - actual = irport_write( idev->io.iobase2, idev->io.fifo_size, - idev->tx_buff.data, idev->tx_buff.len); - - idev->tx_buff.offset = actual; - idev->tx_buff.head = idev->tx_buff.data + actual; + /* Init tx buffer */ + idev->tx_buff.data = idev->tx_buff.head; + + /* Copy skb to tx_buff while wrapping, stuffing and making CRC */ + idev->tx_buff.len = async_wrap_skb(skb, idev->tx_buff.data, + idev->tx_buff.truesize); - dev_kfree_skb( skb); + idev->tx_buff.data += actual; + idev->tx_buff.len -= actual; + + /* Turn on transmit finished interrupt. Will fire immediately! */ + outb(UART_IER_THRI, iobase+UART_IER); + + dev_kfree_skb(skb); return 0; } @@ -348,28 +302,75 @@ * Receive one frame from the infrared port * */ -static void irport_receive( struct irda_device *idev) +static void irport_receive(struct irda_device *idev) { int iobase; + int boguscount = 0; - if ( !idev) + if (!idev) return; - DEBUG( 4, __FUNCTION__ "()\n"); + DEBUG(4, __FUNCTION__ "()\n"); iobase = idev->io.iobase2; - if ( idev->rx_buff.len == 0) - idev->rx_buff.head = idev->rx_buff.data; - /* * Receive all characters in Rx FIFO, unwrap and unstuff them. * async_unwrap_char will deliver all found frames */ do { - async_unwrap_char( idev, inb( iobase+UART_RX)); + async_unwrap_char(idev, inb(iobase+UART_RX)); + + /* Make sure we don't stay here to long */ + if (boguscount++ > 32) { + DEBUG(0,__FUNCTION__ "(), breaking!\n"); + break; + } + } while (inb(iobase+UART_LSR) & UART_LSR_DR); +} + +/* + * Function irport_interrupt (irq, dev_id, regs) + * + * Interrupt handler + */ +void irport_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct irda_device *idev = (struct irda_device *) dev_id; + int iobase; + int iir, lsr; + int boguscount = 0; + + if (!idev) { + printk(KERN_WARNING __FUNCTION__ + "() irq %d for unknown device.\n", irq); + return; + } + + idev->netdev.interrupt = 1; + + iobase = idev->io.iobase2; + + iir = inb(iobase + UART_IIR) & UART_IIR_ID; + while (iir) { + /* Clear interrupt */ + lsr = inb(iobase+UART_LSR); + + if ((iir & UART_IIR_THRI) && (lsr & UART_LSR_THRE)) { + /* Transmitter ready for data */ + irport_write_wakeup(idev); + } else if ((iir & UART_IIR_RDI) && (lsr & UART_LSR_DR)) { + /* Receive interrupt */ + irport_receive(idev); + } - } while ( inb( iobase+UART_LSR) & UART_LSR_DR); + /* Make sure we don't stay here to long */ + if (boguscount++ > 32) + break; + + iir = inb(iobase + UART_IIR) & UART_IIR_ID; + } + idev->netdev.interrupt = 0; } #ifdef MODULE diff -ur --new-file old/linux/drivers/net/irda/irtty.c new/linux/drivers/net/irda/irtty.c --- old/linux/drivers/net/irda/irtty.c Wed Jan 20 20:05:33 1999 +++ new/linux/drivers/net/irda/irtty.c Sun Apr 25 02:49:37 1999 @@ -1,12 +1,12 @@ /********************************************************************* * * Filename: irtty.c - * Version: 1.0 + * Version: 1.1 * Description: IrDA line discipline implementation * Status: Experimental. * Author: Dag Brattli * Created at: Tue Dec 9 21:18:38 1997 - * Modified at: Mon Jan 18 15:32:03 1999 + * Modified at: Thu Apr 22 09:20:24 1999 * Modified by: Dag Brattli * Sources: slip.c by Laurence Culhane, * Fred N. van Kempen, @@ -33,7 +33,6 @@ #include #include -#include #include #include #include @@ -46,22 +45,22 @@ static struct tty_ldisc irda_ldisc; -static int irtty_hard_xmit( struct sk_buff *skb, struct device *dev); -static void irtty_wait_until_sent( struct irda_device *driver); -static int irtty_is_receiving( struct irda_device *idev); -static int irtty_net_init( struct device *dev); +static int irtty_hard_xmit(struct sk_buff *skb, struct device *dev); +static void irtty_wait_until_sent(struct irda_device *driver); +static int irtty_is_receiving(struct irda_device *idev); +static int irtty_net_init(struct device *dev); static int irtty_net_open(struct device *dev); static int irtty_net_close(struct device *dev); -static int irtty_open( struct tty_struct *tty); -static void irtty_close( struct tty_struct *tty); -static int irtty_ioctl( struct tty_struct *, void *, int, void *); -static int irtty_receive_room( struct tty_struct *tty); -static void irtty_change_speed( struct irda_device *dev, int baud); -static void irtty_write_wakeup( struct tty_struct *tty); +static int irtty_open(struct tty_struct *tty); +static void irtty_close(struct tty_struct *tty); +static int irtty_ioctl(struct tty_struct *, void *, int, void *); +static int irtty_receive_room(struct tty_struct *tty); +static void irtty_change_speed(struct irda_device *dev, int baud); +static void irtty_write_wakeup(struct tty_struct *tty); -static void irtty_receive_buf( struct tty_struct *, const unsigned char *, - char *, int); +static void irtty_receive_buf(struct tty_struct *, const unsigned char *, + char *, int); char *driver_name = "irtty"; __initfunc(int irtty_init(void)) @@ -74,15 +73,15 @@ return -ENOMEM; } - dongles = hashbin_new( HB_LOCAL); - if ( dongles == NULL) { - printk( KERN_WARNING - "IrDA: Can't allocate dongles hashbin!\n"); + dongles = hashbin_new(HB_LOCAL); + if (dongles == NULL) { + printk(KERN_WARNING + "IrDA: Can't allocate dongles hashbin!\n"); return -ENOMEM; } /* Fill in our line protocol discipline, and register it */ - memset( &irda_ldisc, 0, sizeof( irda_ldisc)); + memset(&irda_ldisc, 0, sizeof( irda_ldisc)); irda_ldisc.magic = TTY_LDISC_MAGIC; irda_ldisc.name = "irda"; @@ -98,10 +97,10 @@ irda_ldisc.receive_room = irtty_receive_room; irda_ldisc.write_wakeup = irtty_write_wakeup; - if (( status = tty_register_ldisc( N_IRDA, &irda_ldisc)) != 0) { - printk( KERN_ERR - "IrDA: can't register line discipline (err = %d)\n", - status); + if (( status = tty_register_ldisc(N_IRDA, &irda_ldisc)) != 0) { + printk(KERN_ERR + "IrDA: can't register line discipline (err = %d)\n", + status); } return status; @@ -121,10 +120,10 @@ /* * Unregister tty line-discipline */ - if (( ret = tty_register_ldisc( N_IRDA, NULL))) { - printk( KERN_ERR - "IrTTY: can't unregister line discipline (err = %d)\n", - ret); + if ((ret = tty_register_ldisc(N_IRDA, NULL))) { + ERROR(__FUNCTION__ + "(), can't unregister line discipline (err = %d)\n", + ret); } /* @@ -132,8 +131,8 @@ * callback to irtty_close(), therefore we do give any deallocation * function to hashbin_destroy(). */ - hashbin_delete( irtty, NULL); - hashbin_delete( dongles, NULL); + hashbin_delete(irtty, NULL); + hashbin_delete(dongles, NULL); } #endif /* MODULE */ @@ -144,54 +143,51 @@ * discipline is called for. Because we are sure the tty line exists, * we only have to link it to a free IrDA channel. */ -static int irtty_open( struct tty_struct *tty) +static int irtty_open(struct tty_struct *tty) { struct irtty_cb *self; char name[16]; - ASSERT( tty != NULL, return -EEXIST;); + ASSERT(tty != NULL, return -EEXIST;); /* First make sure we're not already connected. */ self = (struct irtty_cb *) tty->disc_data; - if ( self != NULL && self->magic == IRTTY_MAGIC) + if (self != NULL && self->magic == IRTTY_MAGIC) return -EEXIST; /* * Allocate new instance of the driver */ - self = kmalloc( sizeof(struct irtty_cb), GFP_KERNEL); - if ( self == NULL) { - printk( KERN_ERR "IrDA: Can't allocate memory for " - "IrDA control block!\n"); + self = kmalloc(sizeof(struct irtty_cb), GFP_KERNEL); + if (self == NULL) { + printk(KERN_ERR "IrDA: Can't allocate memory for " + "IrDA control block!\n"); return -ENOMEM; } - memset( self, 0, sizeof(struct irtty_cb)); + memset(self, 0, sizeof(struct irtty_cb)); self->tty = tty; tty->disc_data = self; /* Give self a name */ - sprintf( name, "%s%d", tty->driver.name, - MINOR(tty->device) - tty->driver.minor_start + - tty->driver.name_base); - + sprintf(name, "%s%d", tty->driver.name, + MINOR(tty->device) - tty->driver.minor_start + + tty->driver.name_base); + /* hashbin_insert( irtty, (QUEUE*) self, 0, self->name); */ - hashbin_insert( irtty, (QUEUE*) self, (int) self, NULL); + hashbin_insert(irtty, (QUEUE*) self, (int) self, NULL); - if (tty->driver.flush_buffer) { + if (tty->driver.flush_buffer) tty->driver.flush_buffer(tty); - } - - if (tty->ldisc.flush_buffer) { + + if (tty->ldisc.flush_buffer) tty->ldisc.flush_buffer(tty); - } self->magic = IRTTY_MAGIC; /* * Initialize driver */ - /* self->idev.flags |= SIR_MODE | IO_PIO; */ self->idev.rx_buff.state = OUTSIDE_FRAME; /* @@ -200,13 +196,14 @@ * that are not device dependent (such as link disconnect time) so * this parameter can be set by IrLAP (or the user) instead. DB */ - irda_init_max_qos_capabilies( &self->idev.qos); + irda_init_max_qos_capabilies(&self->idev.qos); /* The only value we must override it the baudrate */ self->idev.qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600| IR_115200; - self->idev.qos.min_turn_time.bits = 0x03; - irda_qos_bits_to_value( &self->idev.qos); + self->idev.qos.min_turn_time.bits = 0x0f; + self->idev.flags = IFF_SIR | IFF_PIO; + irda_qos_bits_to_value(&self->idev.qos); /* Specify which buffer allocation policy we need */ self->idev.rx_buff.flags = GFP_KERNEL; @@ -229,7 +226,7 @@ self->idev.netdev.stop = irtty_net_close; /* Open the IrDA device */ - irda_device_open( &self->idev, name, self); + irda_device_open(&self->idev, name, self); MOD_INC_USE_COUNT; @@ -237,26 +234,26 @@ } /* - * Function irtty_close ( tty) + * Function irtty_close (tty) * * Close down a IrDA channel. This means flushing out any pending queues, * and then restoring the TTY line discipline to what it was before it got * hooked to IrDA (which usually is TTY again). */ -static void irtty_close( struct tty_struct *tty) +static void irtty_close(struct tty_struct *tty) { struct irtty_cb *self = (struct irtty_cb *) tty->disc_data; /* First make sure we're connected. */ - ASSERT( self != NULL, return;); - ASSERT( self->magic == IRTTY_MAGIC, return;); + ASSERT(self != NULL, return;); + ASSERT(self->magic == IRTTY_MAGIC, return;); /* We are not using any dongle anymore! */ - if ( self->dongle_q) - self->dongle_q->dongle->close( &self->idev); + if (self->dongle_q) + self->dongle_q->dongle->close(&self->idev); /* Remove driver */ - irda_device_close( &self->idev); + irda_device_close(&self->idev); /* Stop tty */ tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); @@ -265,46 +262,71 @@ self->tty = NULL; self->magic = 0; - /* hashbin_remove( irtty, 0, self->name); */ - self = hashbin_remove( irtty, (int) self, NULL); + self = hashbin_remove(irtty, (int) self, NULL); - if ( self != NULL) - kfree( self); + if (self != NULL) + kfree(self); MOD_DEC_USE_COUNT; +} + +/* + * Function irtty_stop_receiver (irda_device, stop) + * + * + * + */ +static void irtty_stop_receiver(struct irda_device *idev, int stop) +{ + struct termios old_termios; + struct irtty_cb *self; + int cflag; + + self = (struct irtty_cb *) idev->priv; - DEBUG( 4, "IrTTY: close() -->\n"); + old_termios = *(self->tty->termios); + cflag = self->tty->termios->c_cflag; + + if (stop) + cflag &= ~CREAD; + else + cflag |= CREAD; + + self->tty->termios->c_cflag = cflag; + self->tty->driver.set_termios(self->tty, &old_termios); } /* - * Function irtty_change_speed ( self, baud) + * Function irtty_change_speed (self, baud) * * Change the speed of the serial port. The driver layer must check that * all transmission has finished using the irtty_wait_until_sent() * function. */ -static void irtty_change_speed( struct irda_device *idev, int baud) +static void irtty_change_speed(struct irda_device *idev, int baud) { struct termios old_termios; struct irtty_cb *self; int cflag; - ASSERT( idev != NULL, return;); - ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return;); + DEBUG(4,__FUNCTION__ "(), <%ld>\n", jiffies); + + ASSERT(idev != NULL, return;); + ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;); self = (struct irtty_cb *) idev->priv; - ASSERT( self != NULL, return;); - ASSERT( self->magic == IRTTY_MAGIC, return;); + ASSERT(self != NULL, return;); + ASSERT(self->magic == IRTTY_MAGIC, return;); old_termios = *(self->tty->termios); cflag = self->tty->termios->c_cflag; cflag &= ~CBAUD; - DEBUG( 4, __FUNCTION__ "(), Setting speed to %d\n", baud); + DEBUG(4, __FUNCTION__ "(), Setting speed to %d\n", baud); - switch( baud) { + switch (baud) { case 1200: cflag |= B1200; break; @@ -333,7 +355,7 @@ } self->tty->termios->c_cflag = cflag; - self->tty->driver.set_termios( self->tty, &old_termios); + self->tty->driver.set_termios(self->tty, &old_termios); } /* @@ -342,39 +364,42 @@ * Initialize attached dongle. Warning, must be called with a process * context! */ -static void irtty_init_dongle( struct irtty_cb *self, int type) +static void irtty_init_dongle(struct irtty_cb *self, int type) { struct dongle_q *node; - ASSERT( self != NULL, return;); - ASSERT( self->magic == IRTTY_MAGIC, return;); + ASSERT(self != NULL, return;); + ASSERT(self->magic == IRTTY_MAGIC, return;); #ifdef CONFIG_KMOD /* Try to load the module needed */ switch( type) { case ESI_DONGLE: - DEBUG( 0, __FUNCTION__ "(), ESI dongle!\n"); - request_module( "esi"); + MESSAGE("IrDA: Trying to initialize ESI dongle!\n"); + request_module("esi"); break; case TEKRAM_DONGLE: - DEBUG( 0, __FUNCTION__ "(), Tekram dongle!\n"); - request_module( "tekram"); + MESSAGE("IrDA: Trying to initialize Tekram dongle!\n"); + request_module("tekram"); break; - case ACTISYS_DONGLE: - DEBUG( 0, __FUNCTION__ "(), ACTiSYS dongle!\n"); - request_module( "actisys"); + case ACTISYS_DONGLE: /* FALLTHROUGH */ + case ACTISYS_PLUS_DONGLE: + MESSAGE("IrDA: Trying to initialize ACTiSYS dongle!\n"); + request_module("actisys"); + break; + case GIRBIL_DONGLE: + MESSAGE("IrDA: Trying to initialize GIrBIL dongle!\n"); + request_module("girbil"); break; default: - DEBUG( 0, __FUNCTION__ "(), Unknown dongle type!\n"); + ERROR("Unknown dongle type!\n"); return; - break; } #endif /* CONFIG_KMOD */ - node = hashbin_find( dongles, type, NULL); + node = hashbin_find(dongles, type, NULL); if ( !node) { - DEBUG( 0, __FUNCTION__ - "(), Unable to find requested dongle\n"); + ERROR("Unable to find requested dongle\n"); return; } self->dongle_q = node; @@ -385,14 +410,14 @@ /* * Now initialize the dongle! */ - node->dongle->open( &self->idev, type); - node->dongle->qos_init( &self->idev, &self->idev.qos); + node->dongle->open(&self->idev, type); + node->dongle->qos_init(&self->idev, &self->idev.qos); /* Reset dongle */ - node->dongle->reset( &self->idev, 0); + node->dongle->reset(&self->idev, 0); /* Set to default baudrate */ - node->dongle->change_speed( &self->idev, 9600); + node->dongle->change_speed(&self->idev, 9600); } /* @@ -401,8 +426,7 @@ * The Swiss army knife of system calls :-) * */ -static int irtty_ioctl( struct tty_struct *tty, void *file, int cmd, - void *arg) +static int irtty_ioctl(struct tty_struct *tty, void *file, int cmd, void *arg) { struct irtty_cb *self; int err = 0; @@ -410,25 +434,25 @@ self = (struct irtty_cb *) tty->disc_data; - ASSERT( self != NULL, return -ENODEV;); - ASSERT( self->magic == IRTTY_MAGIC, return -EBADR;); + ASSERT(self != NULL, return -ENODEV;); + ASSERT(self->magic == IRTTY_MAGIC, return -EBADR;); - if ( _IOC_DIR(cmd) & _IOC_READ) + if (_IOC_DIR(cmd) & _IOC_READ) err = verify_area( VERIFY_WRITE, (void *) arg, size); - else if ( _IOC_DIR(cmd) & _IOC_WRITE) + else if (_IOC_DIR(cmd) & _IOC_WRITE) err = verify_area( VERIFY_READ, (void *) arg, size); - if ( err) + if (err) return err; switch(cmd) { case TCGETS: case TCGETA: - return n_tty_ioctl( tty, (struct file *) file, cmd, - (unsigned long) arg); + return n_tty_ioctl(tty, (struct file *) file, cmd, + (unsigned long) arg); break; case IRTTY_IOCTDONGLE: /* Initialize dongle */ - irtty_init_dongle( self, (int) arg); + irtty_init_dongle(self, (int) arg); break; default: return -ENOIOCTLCMD; @@ -444,13 +468,13 @@ * been received, which can now be decapsulated and delivered for * further processing */ -static void irtty_receive_buf( struct tty_struct *tty, const unsigned - char *cp, char *fp, int count) +static void irtty_receive_buf(struct tty_struct *tty, const unsigned char *cp, + char *fp, int count) { struct irtty_cb *self = (struct irtty_cb *) tty->disc_data; - ASSERT( self != NULL, return;); - ASSERT( self->magic == IRTTY_MAGIC, return;); + ASSERT(self != NULL, return;); + ASSERT(self->magic == IRTTY_MAGIC, return;); /* Read the characters out of the buffer */ while (count--) { @@ -460,83 +484,75 @@ if (fp && *fp++) { DEBUG( 0, "Framing or parity error!\n"); irda_device_set_media_busy( &self->idev, TRUE); - /* sl->rx_errors++; */ + cp++; continue; } - /* - * Unwrap and destuff one byte - */ - async_unwrap_char( &self->idev, *cp++); - /* self->rx_over_errors++; */ + /* Unwrap and destuff one byte */ + async_unwrap_char(&self->idev, *cp++); } } /* * Function irtty_hard_xmit (skb, dev) * - * Transmit skb + * Transmit frame * */ -static int irtty_hard_xmit( struct sk_buff *skb, struct device *dev) +static int irtty_hard_xmit(struct sk_buff *skb, struct device *dev) { struct irtty_cb *self; struct irda_device *idev; int actual = 0; - ASSERT( dev != NULL, return 0;); - ASSERT( skb != NULL, return 0;); - - if ( dev->tbusy) { - DEBUG( 4, __FUNCTION__ "(), tbusy==TRUE\n"); - - return -EBUSY; - } - idev = (struct irda_device *) dev->priv; - ASSERT( idev != NULL, return 0;); - ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return -1;); + ASSERT(idev != NULL, return 0;); + ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return -1;); self = (struct irtty_cb *) idev->priv; - ASSERT( self != NULL, return 0;); - ASSERT( self->magic == IRTTY_MAGIC, return 0;); + ASSERT(self != NULL, return 0;); + ASSERT(self->magic == IRTTY_MAGIC, return 0;); /* Lock transmit buffer */ - if ( irda_lock( (void *) &dev->tbusy) == FALSE) - return 0; - - /* - * Transfer skb to tx_buff while wrapping, stuffing and making CRC - */ - idev->tx_buff.len = async_wrap_skb( skb, idev->tx_buff.data, - idev->tx_buff.truesize); + if (irda_lock((void *) &dev->tbusy) == FALSE) + return -EBUSY; + + /* Init tx buffer*/ + idev->tx_buff.data = idev->tx_buff.head; + + /* Copy skb to tx_buff while wrapping, stuffing and making CRC */ + idev->tx_buff.len = async_wrap_skb(skb, idev->tx_buff.data, + idev->tx_buff.truesize); self->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP); dev->trans_start = jiffies; - if ( self->tty->driver.write) - actual = self->tty->driver.write( self->tty, 0, - idev->tx_buff.data, - idev->tx_buff.len); + if (self->tty->driver.write) + actual = self->tty->driver.write(self->tty, 0, + idev->tx_buff.data, + idev->tx_buff.len); + + /* Hide the part we just transmitted */ + idev->tx_buff.data += actual; + idev->tx_buff.len -= actual; - idev->tx_buff.offset = actual; - idev->tx_buff.head = idev->tx_buff.data + actual; + idev->stats.tx_packets++; + idev->stats.tx_bytes += idev->tx_buff.len; #if 0 /* * Did we transmit the whole frame? Commented out for now since * I must check if this optimalization really works. DB. */ - if (( idev->tx.count - idev->tx.ptr) <= 0) { + if ((idev->tx_buff.len) == 0) { DEBUG( 4, "irtty_xmit_buf: finished with frame!\n"); self->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); irda_unlock( &self->tbusy); } #endif - - dev_kfree_skb( skb); + dev_kfree_skb(skb); return 0; } @@ -547,8 +563,9 @@ * Used by the TTY to find out how much data we can receive at a time * */ -static int irtty_receive_room( struct tty_struct *tty) +static int irtty_receive_room(struct tty_struct *tty) { + DEBUG(0, __FUNCTION__ "()\n"); return 65536; /* We can handle an infinite amount of data. :-) */ } @@ -559,51 +576,42 @@ * more packets to send, we send them here. * */ -static void irtty_write_wakeup( struct tty_struct *tty) +static void irtty_write_wakeup(struct tty_struct *tty) { - int actual = 0, count; struct irtty_cb *self = (struct irtty_cb *) tty->disc_data; struct irda_device *idev; + int actual = 0; /* * First make sure we're connected. */ - ASSERT( self != NULL, return;); - ASSERT( self->magic == IRTTY_MAGIC, return;); + ASSERT(self != NULL, return;); + ASSERT(self->magic == IRTTY_MAGIC, return;); idev = &self->idev; - /* - * Finished with frame? - */ - if ( idev->tx_buff.offset == idev->tx_buff.len) { - + /* Finished with frame? */ + if (idev->tx_buff.len > 0) { + /* Write data left in transmit buffer */ + actual = tty->driver.write(tty, 0, idev->tx_buff.data, + idev->tx_buff.len); + + idev->tx_buff.data += actual; + idev->tx_buff.len -= actual; + } else { /* * Now serial buffer is almost free & we can start * transmission of another packet */ - DEBUG( 4, __FUNCTION__ "(), finished with frame!\n"); - + DEBUG(5, __FUNCTION__ "(), finished with frame!\n"); + tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); idev->netdev.tbusy = 0; /* Unlock */ - idev->stats.tx_packets++; - idev->stats.tx_bytes += idev->tx_buff.len; - + /* Tell network layer that we want more frames */ - mark_bh( NET_BH); - - return; + mark_bh(NET_BH); } - /* - * Write data left in transmit buffer - */ - count = idev->tx_buff.len - idev->tx_buff.offset; - actual = tty->driver.write( tty, 0, idev->tx_buff.head, count); - idev->tx_buff.offset += actual; - idev->tx_buff.head += actual; - - DEBUG( 4, "actual=%d, sent %d\n", actual, count); } /* @@ -612,9 +620,9 @@ * Return TRUE is we are currently receiving a frame * */ -static int irtty_is_receiving( struct irda_device *idev) +static int irtty_is_receiving(struct irda_device *idev) { - return ( idev->rx_buff.state != OUTSIDE_FRAME); + return (idev->rx_buff.state != OUTSIDE_FRAME); } /* @@ -624,20 +632,20 @@ * to change the speed of the serial port. Warning this function must * be called with a process context! */ -static void irtty_wait_until_sent( struct irda_device *idev) +static void irtty_wait_until_sent(struct irda_device *idev) { struct irtty_cb *self = (struct irtty_cb *) idev->priv; - ASSERT( self != NULL, return;); - ASSERT( self->magic == IRTTY_MAGIC, return;); + ASSERT(self != NULL, return;); + ASSERT(self->magic == IRTTY_MAGIC, return;); - DEBUG( 4, "Chars in buffer %d\n", - self->tty->driver.chars_in_buffer( self->tty)); + DEBUG(4, "Chars in buffer %d\n", + self->tty->driver.chars_in_buffer(self->tty)); - tty_wait_until_sent( self->tty, 0); + tty_wait_until_sent(self->tty, 0); } -int irtty_register_dongle( struct dongle *dongle) +int irtty_register_dongle(struct dongle *dongle) { struct dongle_q *new; @@ -648,47 +656,81 @@ } /* Make new IrDA dongle */ - new = (struct dongle_q *) kmalloc (sizeof (struct dongle_q), - GFP_KERNEL); - if (new == NULL) { - return 1; + new = (struct dongle_q *) kmalloc(sizeof(struct dongle_q), GFP_KERNEL); + if (new == NULL) + return -1; - } - memset( new, 0, sizeof( struct dongle_q)); + memset(new, 0, sizeof( struct dongle_q)); new->dongle = dongle; - /* Insert IrDA compressor into hashbin */ - hashbin_insert( dongles, (QUEUE *) new, dongle->type, NULL); + /* Insert IrDA dongle into hashbin */ + hashbin_insert(dongles, (QUEUE *) new, dongle->type, NULL); return 0; } -void irtty_unregister_dongle( struct dongle *dongle) +void irtty_unregister_dongle(struct dongle *dongle) { struct dongle_q *node; - node = hashbin_remove( dongles, dongle->type, NULL); - if ( !node) { - DEBUG( 0, __FUNCTION__ "(), dongle not found!\n"); + node = hashbin_remove(dongles, dongle->type, NULL); + if (!node) { + ERROR(__FUNCTION__ "(), dongle not found!\n"); return; } - kfree( node); + kfree(node); } -static int irtty_net_init( struct device *dev) + +/* + * Function irtty_set_dtr_rts (tty, dtr, rts) + * + * This function can be used by dongles etc. to set or reset the status + * of the dtr and rts lines + */ +void irtty_set_dtr_rts(struct tty_struct *tty, int dtr, int rts) +{ + mm_segment_t fs; + int arg = 0; + +#ifdef TIOCM_OUT2 /* Not defined for ARM */ + arg = TIOCM_OUT2; +#endif + if (rts) + arg |= TIOCM_RTS; + if (dtr) + arg |= TIOCM_DTR; + + /* + * The ioctl() function, or actually set_modem_info() in serial.c + * expects a pointer to the argument in user space. To hack us + * around this, we use the set_fs() function to fool the routines + * that check if they are called from user space. We also need + * to send a pointer to the argument so get_user() gets happy. DB. + */ + + fs = get_fs(); + set_fs(get_ds()); + + if (tty->driver.ioctl(tty, NULL, TIOCMSET, (unsigned long) &arg)) { + ERROR(__FUNCTION__ "(), error doing ioctl!\n"); + } + set_fs(fs); +} + +static int irtty_net_init(struct device *dev) { /* Set up to be a normal IrDA network device driver */ - irda_device_setup( dev); + irda_device_setup(dev); /* Insert overrides below this line! */ return 0; } - -static int irtty_net_open( struct device *dev) +static int irtty_net_open(struct device *dev) { - ASSERT( dev != NULL, return -1;); + ASSERT(dev != NULL, return -1;); /* Ready to play! */ dev->tbusy = 0; @@ -702,7 +744,7 @@ static int irtty_net_close(struct device *dev) { - ASSERT( dev != NULL, return -1;); + ASSERT(dev != NULL, return -1;); /* Stop device */ dev->tbusy = 1; @@ -715,6 +757,9 @@ #ifdef MODULE +MODULE_AUTHOR("Dag Brattli "); +MODULE_DESCRIPTION("IrDA TTY device driver"); + /* * Function init_module (void) * @@ -723,8 +768,7 @@ */ int init_module(void) { - irtty_init(); - return(0); + return irtty_init(); } /* diff -ur --new-file old/linux/drivers/net/irda/pc87108.c new/linux/drivers/net/irda/pc87108.c --- old/linux/drivers/net/irda/pc87108.c Wed Jan 20 20:05:33 1999 +++ new/linux/drivers/net/irda/pc87108.c Sun Apr 25 02:49:37 1999 @@ -6,7 +6,7 @@ * Status: Experimental. * Author: Dag Brattli * Created at: Sat Nov 7 21:43:15 1998 - * Modified at: Mon Dec 28 08:46:16 1998 + * Modified at: Tue Apr 20 11:11:39 1999 * Modified by: Dag Brattli * * Copyright (c) 1998 Dag Brattli @@ -50,7 +50,6 @@ #include #include #include -#include #include #include @@ -100,7 +99,9 @@ /* Some prototypes */ static int pc87108_open( int i, unsigned int iobase, unsigned int board_addr, unsigned int irq, unsigned int dma); +#ifdef MODULE static int pc87108_close( struct irda_device *idev); +#endif /* MODULE */ static int pc87108_probe( int iobase, int board_addr, int irq, int dma); static void pc87108_pio_receive( struct irda_device *idev); static int pc87108_dma_receive( struct irda_device *idev); @@ -131,7 +132,7 @@ for ( i=0; (io[i] < 2000) && (i < 4); i++) { int ioaddr = io[i]; - if (check_region(ioaddr, CHIP_IO_EXTENT)) + if (check_region(ioaddr, CHIP_IO_EXTENT) < 0) continue; if (pc87108_open( i, io[i], io2[i], irq[i], dma[i]) == 0) return 0; @@ -150,11 +151,11 @@ { int i; - DEBUG( 4, __FUNCTION__ "()\n"); + DEBUG(4, __FUNCTION__ "()\n"); - for ( i=0; i < 4; i++) { - if ( dev_self[i]) - pc87108_close( &(dev_self[i]->idev)); + for (i=0; i < 4; i++) { + if (dev_self[i]) + pc87108_close(&(dev_self[i]->idev)); } } #endif /* MODULE */ @@ -221,6 +222,8 @@ idev->qos.min_turn_time.bits = 0x07; irda_qos_bits_to_value( &idev->qos); + idev->flags = IFF_FIR|IFF_MIR|IFF_SIR|IFF_DMA|IFF_PIO|IFF_DONGLE; + /* Specify which buffer allocation policy we need */ idev->rx_buff.flags = GFP_KERNEL | GFP_DMA; idev->tx_buff.flags = GFP_KERNEL | GFP_DMA; @@ -230,7 +233,6 @@ idev->tx_buff.truesize = 4000; /* Initialize callbacks */ - idev->hard_xmit = pc87108_hard_xmit; idev->change_speed = pc87108_change_speed; idev->wait_until_sent = pc87108_wait_until_sent; idev->is_receiving = pc87108_is_receiving; @@ -250,6 +252,7 @@ return 0; } +#ifdef MODULE /* * Function pc87108_close (idev) * @@ -276,6 +279,7 @@ return 0; } +#endif /* MODULE */ /* * Function pc87108_probe (iobase, board_addr, irq, dma) @@ -666,7 +670,7 @@ /* Set appropriate speed mode */ switch_bank(iobase, BANK0); - outb( mcr|MCR_TX_DFR, iobase+MCR); + outb(mcr | MCR_TX_DFR, iobase+MCR); /* Give some hits to the transceiver */ pc87108_change_dongle_speed( iobase, speed, idev->io.dongle_id); @@ -720,12 +724,6 @@ iobase = idev->io.iobase; DEBUG(4, __FUNCTION__ "(%ld), skb->len=%d\n", jiffies, (int) skb->len); - - if ( dev->tbusy) { - DEBUG( 4, __FUNCTION__ "(), tbusy==TRUE\n"); - - return -EBUSY; - } /* Lock transmit buffer */ if ( irda_lock( (void *) &dev->tbusy) == FALSE) @@ -736,10 +734,9 @@ /* Decide if we should use PIO or DMA transfer */ if ( idev->io.baudrate > 115200) { - memcpy( idev->tx_buff.data, skb->data, skb->len); + idev->tx_buff.data = idev->tx_buff.head; + memcpy(idev->tx_buff.data, skb->data, skb->len); idev->tx_buff.len = skb->len; - idev->tx_buff.head = idev->tx_buff.data; - idev->tx_buff.offset = 0; mtt = irda_get_mtt( skb); if ( mtt > 50) { @@ -769,11 +766,10 @@ pc87108_dma_write( idev, iobase); } } else { - idev->tx_buff.len = async_wrap_skb( skb, idev->tx_buff.data, - idev->tx_buff.truesize); + idev->tx_buff.len = async_wrap_skb(skb, idev->tx_buff.data, + idev->tx_buff.truesize); - idev->tx_buff.offset = 0; - idev->tx_buff.head = idev->tx_buff.data; + idev->tx_buff.data = idev->tx_buff.head; /* Add interrupt on tx low level (will fire immediately) */ switch_bank( iobase, BANK0); @@ -806,8 +802,8 @@ switch_bank(iobase, BANK0); outb( inb( iobase+MCR) & ~MCR_DMA_EN, iobase+MCR); - setup_dma( idev->io.dma, idev->tx_buff.data, idev->tx_buff.len, - DMA_MODE_WRITE); + setup_dma(idev->io.dma, idev->tx_buff.data, idev->tx_buff.len, + DMA_MODE_WRITE); /* idev->media_busy = TRUE; */ idev->io.direction = IO_XMIT; @@ -921,52 +917,51 @@ * if it starts to receive a frame. * */ -static int pc87108_dma_receive( struct irda_device *idev) +static int pc87108_dma_receive(struct irda_device *idev) { struct pc87108 *self; int iobase; __u8 bsr; - ASSERT( idev != NULL, return -1;); - ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return -1;); + ASSERT(idev != NULL, return -1;); + ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return -1;); - DEBUG( 4, __FUNCTION__ "\n"); + DEBUG(4, __FUNCTION__ "\n"); self = idev->priv; - iobase= idev->io.iobase; + iobase = idev->io.iobase; /* Save current bank */ - bsr = inb( iobase+BSR); + bsr = inb(iobase+BSR); /* Disable DMA */ - switch_bank( iobase, BANK0); - outb( inb(iobase+MCR) & ~MCR_DMA_EN, iobase+MCR); + switch_bank(iobase, BANK0); + outb(inb(iobase+MCR) & ~MCR_DMA_EN, iobase+MCR); - setup_dma( idev->io.dma, idev->rx_buff.data, idev->rx_buff.truesize, - DMA_MODE_READ); + setup_dma(idev->io.dma, idev->rx_buff.data, + idev->rx_buff.truesize, DMA_MODE_READ); /* driver->media_busy = FALSE; */ idev->io.direction = IO_RECV; - idev->rx_buff.head = idev->rx_buff.data; - idev->rx_buff.offset = 0; + idev->rx_buff.data = idev->rx_buff.head; /* Reset Rx FIFO. This will also flush the ST_FIFO */ - outb( FCR_RXTH|FCR_TXTH|FCR_RXSR|FCR_FIFO_EN, iobase+FCR); + outb(FCR_RXTH|FCR_TXTH|FCR_RXSR|FCR_FIFO_EN, iobase+FCR); self->st_fifo.len = self->st_fifo.tail = self->st_fifo.head = 0; /* Choose DMA Rx, DMA Fairness, and Advanced mode */ switch_bank(iobase, BANK2); - outb(( inb( iobase+ECR1) & ~ECR1_DMASWP)|ECR1_DMANF|ECR1_EXT_SL, - iobase+ECR1); + outb((inb( iobase+ECR1) & ~ECR1_DMASWP)|ECR1_DMANF|ECR1_EXT_SL, + iobase+ECR1); /* enable DMA */ switch_bank(iobase, BANK0); - outb( inb( iobase+MCR)|MCR_DMA_EN, iobase+MCR); + outb(inb(iobase+MCR)|MCR_DMA_EN, iobase+MCR); /* Restore bank register */ - outb( bsr, iobase+BSR); + outb(bsr, iobase+BSR); - DEBUG( 4, __FUNCTION__ "(), done!\n"); + DEBUG(4, __FUNCTION__ "(), done!\n"); return 0; } @@ -1026,42 +1021,41 @@ /* Skip frame */ idev->stats.rx_errors++; - idev->rx_buff.offset += len; - idev->rx_buff.head += len; + idev->rx_buff.data += len; - if ( status & FRM_ST_MAX_LEN) + if (status & FRM_ST_MAX_LEN) idev->stats.rx_length_errors++; - if ( status & FRM_ST_PHY_ERR) + if (status & FRM_ST_PHY_ERR) idev->stats.rx_frame_errors++; - if ( status & FRM_ST_BAD_CRC) + if (status & FRM_ST_BAD_CRC) idev->stats.rx_crc_errors++; } /* The errors below can be reported in both cases */ - if ( status & FRM_ST_OVR1) + if (status & FRM_ST_OVR1) idev->stats.rx_fifo_errors++; - if ( status & FRM_ST_OVR2) + if (status & FRM_ST_OVR2) idev->stats.rx_fifo_errors++; } else { /* Check if we have transfered all data to memory */ - if ( inb( iobase+LSR) & LSR_RXDA) { + if (inb(iobase+LSR) & LSR_RXDA) { /* Put this entry back in fifo */ st_fifo->head--; st_fifo->len++; st_fifo->entries[st_fifo->head].status = status; - st_fifo->entries[ st_fifo->head].len = len; + st_fifo->entries[st_fifo->head].len = len; /* Restore bank register */ - outb( bank, iobase+BSR); + outb(bank, iobase+BSR); return FALSE; /* I'll be back! */ } /* Should be OK then */ - skb = dev_alloc_skb( len+1); + skb = dev_alloc_skb(len+1); if (skb == NULL) { printk( KERN_INFO __FUNCTION__ "(), memory squeeze, dropping frame.\n"); @@ -1072,20 +1066,19 @@ } /* Make sure IP header gets aligned */ - skb_reserve( skb, 1); + skb_reserve(skb, 1); /* Copy frame without CRC */ - if ( idev->io.baudrate < 4000000) { - skb_put( skb, len-2); - memcpy( skb->data, idev->rx_buff.head, len-2); + if (idev->io.baudrate < 4000000) { + skb_put(skb, len-2); + memcpy(skb->data, idev->rx_buff.data, len-2); } else { - skb_put( skb, len-4); - memcpy( skb->data, idev->rx_buff.head, len-4); + skb_put(skb, len-4); + memcpy(skb->data, idev->rx_buff.data, len-4); } /* Move to next frame */ - idev->rx_buff.offset += len; - idev->rx_buff.head += len; + idev->rx_buff.data += len; idev->stats.rx_packets++; skb->dev = &idev->netdev; @@ -1095,7 +1088,7 @@ } } /* Restore bank register */ - outb( bank, iobase+BSR); + outb(bank, iobase+BSR); return TRUE; } @@ -1111,23 +1104,19 @@ __u8 byte = 0x00; int iobase; - DEBUG( 4, __FUNCTION__ "()\n"); + DEBUG(4, __FUNCTION__ "()\n"); - ASSERT( idev != NULL, return;); - ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return;); + ASSERT(idev != NULL, return;); + ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;); iobase = idev->io.iobase; - if ( idev->rx_buff.len == 0) { - idev->rx_buff.head = idev->rx_buff.data; - } - /* Receive all characters in Rx FIFO */ do { - byte = inb( iobase+RXD); - async_unwrap_char( idev, byte); + byte = inb(iobase+RXD); + async_unwrap_char(idev, byte); - } while ( inb( iobase+LSR) & LSR_RXDA); /* Data available */ + } while (inb(iobase+LSR) & LSR_RXDA); /* Data available */ } /* @@ -1136,38 +1125,35 @@ * Handle SIR interrupt * */ -static __u8 pc87108_sir_interrupt( struct irda_device *idev, int eir) +static __u8 pc87108_sir_interrupt(struct irda_device *idev, int eir) { - int len; int actual; __u8 new_ier = 0; /* Transmit FIFO low on data */ if ( eir & EIR_TXLDL_EV) { /* Write data left in transmit buffer */ - len = idev->tx_buff.len - idev->tx_buff.offset; - - ASSERT( len > 0, return 0;); - actual = pc87108_pio_write( idev->io.iobase, - idev->tx_buff.head, - len, idev->io.fifo_size); - idev->tx_buff.offset += actual; - idev->tx_buff.head += actual; + actual = pc87108_pio_write(idev->io.iobase, + idev->tx_buff.data, + idev->tx_buff.len, + idev->io.fifo_size); + idev->tx_buff.data += actual; + idev->tx_buff.len -= actual; idev->io.direction = IO_XMIT; - ASSERT( actual <= len, return 0;); /* Check if finished */ - if ( actual == len) { - DEBUG( 4, __FUNCTION__ "(), finished with frame!\n"); + if (idev->tx_buff.len > 0) + new_ier |= IER_TXLDL_IE; + else { idev->netdev.tbusy = 0; /* Unlock */ idev->stats.tx_packets++; - + mark_bh(NET_BH); new_ier |= IER_TXEMP_IE; - } else - new_ier |= IER_TXLDL_IE; + } + } /* Check if transmission has completed */ if ( eir & EIR_TXEMP_EV) { @@ -1482,9 +1468,7 @@ */ int init_module(void) { - pc87108_init(); - - return(0); + return pc87108_init(); } /* @@ -1497,6 +1481,5 @@ { pc87108_cleanup(); } - -#endif +#endif /* MODULE */ diff -ur --new-file old/linux/drivers/net/irda/tekram.c new/linux/drivers/net/irda/tekram.c --- old/linux/drivers/net/irda/tekram.c Wed Jan 20 20:05:33 1999 +++ new/linux/drivers/net/irda/tekram.c Sun Apr 25 02:49:37 1999 @@ -1,12 +1,12 @@ /********************************************************************* * * Filename: tekram.c - * Version: 0.4 + * Version: 1.0 * Description: Implementation of the Tekram IrMate IR-210B dongle * Status: Experimental. * Author: Dag Brattli * Created at: Wed Oct 21 20:02:35 1998 - * Modified at: Mon Jan 18 11:30:38 1999 + * Modified at: Tue Apr 13 16:33:54 1999 * Modified by: Dag Brattli * * Copyright (c) 1998 Dag Brattli, All Rights Reserved. @@ -33,16 +33,23 @@ #include #include -#include #include #include #include -static void tekram_reset( struct irda_device *dev, int unused); -static void tekram_open( struct irda_device *dev, int type); -static void tekram_close( struct irda_device *dev); -static void tekram_change_speed( struct irda_device *dev, int baud); -static void tekram_init_qos( struct irda_device *idev, struct qos_info *qos); +static void tekram_reset(struct irda_device *dev, int unused); +static void tekram_open(struct irda_device *dev, int type); +static void tekram_close(struct irda_device *dev); +static void tekram_change_speed(struct irda_device *dev, int baud); +static void tekram_init_qos(struct irda_device *idev, struct qos_info *qos); + +#define TEKRAM_115200 0x00 +#define TEKRAM_57600 0x01 +#define TEKRAM_38400 0x02 +#define TEKRAM_19200 0x03 +#define TEKRAM_9600 0x04 + +#define TEKRAM_PW 0x10 /* Pulse select bit */ static struct dongle dongle = { TEKRAM_DONGLE, @@ -53,9 +60,9 @@ tekram_init_qos, }; -__initfunc(void tekram_init(void)) +__initfunc(int tekram_init(void)) { - irtty_register_dongle( &dongle); + return irtty_register_dongle(&dongle); } void tekram_cleanup(void) @@ -63,9 +70,12 @@ irtty_unregister_dongle( &dongle); } -static void tekram_open( struct irda_device *dev, int type) +static void tekram_open( struct irda_device *idev, int type) { - strcat( dev->name, " <-> tekram"); + strcat(idev->description, " <-> tekram"); + + idev->io.dongle_id = type; + idev->flags |= IFF_DONGLE; MOD_INC_USE_COUNT; } @@ -96,23 +106,20 @@ struct irtty_cb *self; struct tty_struct *tty; struct termios old_termios; - int arg = 0; int cflag; __u8 byte; - int actual; - mm_segment_t fs; - DEBUG( 4, __FUNCTION__ "()\n"); + DEBUG(4, __FUNCTION__ "()\n"); - ASSERT( dev != NULL, return;); - ASSERT( dev->magic == IRDA_DEVICE_MAGIC, return;); + ASSERT(dev != NULL, return;); + ASSERT(dev->magic == IRDA_DEVICE_MAGIC, return;); self = (struct irtty_cb *) dev->priv; - ASSERT( self != NULL, return;); - ASSERT( self->magic == IRTTY_MAGIC, return;); + ASSERT(self != NULL, return;); + ASSERT(self->magic == IRTTY_MAGIC, return;); - if ( !self->tty) + if (!self->tty) return; tty = self->tty; @@ -123,71 +130,50 @@ cflag &= ~CBAUD; switch (baud) { - case 9600: default: + /* FALLTHROUGH */ + case 9600: cflag |= B9600; - byte = 4; + byte = TEKRAM_PW|TEKRAM_9600; break; case 19200: cflag |= B19200; - byte = 3; + byte = TEKRAM_PW|TEKRAM_19200; break; case 34800: cflag |= B38400; - byte = 2; + byte = TEKRAM_PW|TEKRAM_38400; break; case 57600: cflag |= B57600; - byte = 1; + byte = TEKRAM_PW|TEKRAM_57600; break; case 115200: cflag |= B115200; - byte = 0; + byte = TEKRAM_PW|TEKRAM_115200; break; } /* Set DTR, Clear RTS */ - DEBUG( 0, __FUNCTION__ "(), Setting DTR, Clearing RTS\n"); - arg = TIOCM_DTR | TIOCM_OUT2; - - fs = get_fs(); - set_fs( get_ds()); - - if ( tty->driver.ioctl( tty, NULL, TIOCMSET, - (unsigned long) &arg)) { - DEBUG( 0, "error setting Tekram speed!\n"); - } - set_fs(fs); + irtty_set_dtr_rts(tty, TRUE, FALSE); /* Wait at least 7us */ - udelay( 7); + udelay(7); - DEBUG( 0, __FUNCTION__ "(), Writing control byte\n"); /* Write control byte */ - if ( tty->driver.write) - actual = tty->driver.write( self->tty, 0, &byte, 1); + if (tty->driver.write) + tty->driver.write(self->tty, 0, &byte, 1); /* Wait at least 100 ms */ current->state = TASK_INTERRUPTIBLE; - schedule_timeout( 10); + schedule_timeout(MSECS_TO_JIFFIES(100)); /* Set DTR, Set RTS */ - DEBUG( 0, __FUNCTION__ "(), Setting DTR, Setting RTS\n"); - arg = TIOCM_DTR | TIOCM_RTS | TIOCM_OUT2; - - fs = get_fs(); - set_fs( get_ds()); - - if ( tty->driver.ioctl( tty, NULL, TIOCMSET, - (unsigned long) &arg)) { - DEBUG( 0, "error setting Tekram speed!\n"); - } - set_fs(fs); + irtty_set_dtr_rts(tty, TRUE, TRUE); - DEBUG( 0, __FUNCTION__ "(), Setting new speed on serial port\n"); /* Now change the speed of the serial port */ tty->termios->c_cflag = cflag; - tty->driver.set_termios( tty, &old_termios); + tty->driver.set_termios(tty, &old_termios); } /* @@ -197,80 +183,50 @@ * must be called with a process context!! * * Algorithm: - * 0. set RTS and DTR, and wait 50 ms - * ( power off the IR-210 ) + * 0. Clear RTS and DTR, and wait 50 ms (power off the IR-210 ) * 1. clear RTS * 2. set DTR, and wait at least 1 ms * 3. clear DTR to SPACE state, wait at least 50 us for further * operation */ -void tekram_reset( struct irda_device *dev, int unused) +void tekram_reset(struct irda_device *dev, int unused) { struct irtty_cb *self; struct tty_struct *tty; - int arg = 0; - mm_segment_t fs; - DEBUG( 4, __FUNCTION__ "()\n"); + DEBUG(4, __FUNCTION__ "()\n"); - ASSERT( dev != NULL, return;); - ASSERT( dev->magic == IRDA_DEVICE_MAGIC, return;); + ASSERT(dev != NULL, return;); + ASSERT(dev->magic == IRDA_DEVICE_MAGIC, return;); self = (struct irtty_cb *) dev->priv; - ASSERT( self != NULL, return;); - ASSERT( self->magic == IRTTY_MAGIC, return;); + ASSERT(self != NULL, return;); + ASSERT(self->magic == IRTTY_MAGIC, return;); tty = self->tty; - if ( !tty) + if (!tty) return; - DEBUG( 0, __FUNCTION__ "(), Power off dongle\n"); - arg = TIOCM_RTS | TIOCM_DTR | TIOCM_OUT2; - - fs = get_fs(); - set_fs( get_ds()); - - if ( tty->driver.ioctl( tty, NULL, TIOCMSET, - (unsigned long) &arg)) - { - DEBUG(0, "error setting ESI speed!\n"); - } - set_fs(fs); + /* Power off dongle */ + irtty_set_dtr_rts(tty, FALSE, FALSE); /* Sleep 50 ms */ current->state = TASK_INTERRUPTIBLE; - schedule_timeout(5); - - DEBUG( 0, __FUNCTION__ "(), Set DTR, clear RTS\n"); - /* Set DTR, clear RTS */ - arg = TIOCM_DTR | TIOCM_OUT2; - - fs = get_fs(); - set_fs( get_ds()); - - if ( tty->driver.ioctl( tty, NULL, TIOCMSET, - (unsigned long) &arg)) { - DEBUG( 0, "Error setting Tekram speed!\n"); - } - set_fs(fs); + schedule_timeout(MSECS_TO_JIFFIES(50)); + + /* Clear DTR, Set RTS */ + irtty_set_dtr_rts(tty, FALSE, TRUE); /* Should sleep 1 ms, but 10-20 should not do any harm */ current->state = TASK_INTERRUPTIBLE; - schedule_timeout(2); - - DEBUG( 0, __FUNCTION__ "(), STATE3\n"); - /* Clear DTR, clear RTS */ - arg = TIOCM_OUT2; + schedule_timeout(MSECS_TO_JIFFIES(20)); - fs = get_fs(); - set_fs( get_ds()); - - if ( tty->driver.ioctl( tty, NULL, TIOCMSET, (unsigned long) &arg)) { - DEBUG( 0, "error setting Tekram speed!\n"); - } - set_fs(fs); + /* Set DTR, Set RTS */ + irtty_set_dtr_rts(tty, TRUE, TRUE); + udelay(50); + /* Finished! */ } @@ -280,13 +236,17 @@ * Initialize QoS capabilities * */ -static void tekram_init_qos( struct irda_device *idev, struct qos_info *qos) +static void tekram_init_qos(struct irda_device *idev, struct qos_info *qos) { qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200; - qos->min_turn_time.bits &= 0xfe; /* All except 0 ms */ + qos->min_turn_time.bits &= 0x01; /* Needs at least 10 ms */ + irda_qos_bits_to_value(qos); } #ifdef MODULE + +MODULE_AUTHOR("Dag Brattli "); +MODULE_DESCRIPTION("Tekram IrMate IR-210B dongle driver"); /* * Function init_module (void) @@ -296,8 +256,7 @@ */ int init_module(void) { - tekram_init(); - return(0); + return tekram_init(); } /* @@ -311,4 +270,4 @@ tekram_cleanup(); } -#endif +#endif /* MODULE */ diff -ur --new-file old/linux/drivers/net/irda/uircc.c new/linux/drivers/net/irda/uircc.c --- old/linux/drivers/net/irda/uircc.c Mon Jan 25 06:55:04 1999 +++ new/linux/drivers/net/irda/uircc.c Sun Apr 25 02:49:37 1999 @@ -1,13 +1,13 @@ /********************************************************************* * * Filename: uircc.c - * Version: 0.1 + * Version: 0.3 * Description: Driver for the Sharp Universal Infrared - * Communications Controller (UIRCC) + * Communications Controller (UIRCC v 1.3) * Status: Experimental. * Author: Dag Brattli * Created at: Sat Dec 26 10:59:03 1998 - * Modified at: Tue Jan 19 23:54:04 1999 + * Modified at: Tue Apr 20 11:15:52 1999 * Modified by: Dag Brattli * * Copyright (c) 1998 Dag Brattli, All Rights Reserved. @@ -25,10 +25,6 @@ * 740CDT, Portege 300CT, 660CDT, Satellite 220C Series, * Satellite Pro, 440C Series, 470CDT, 460C Series, 480C Series * - * Notice that FIR mode is not working yet, since I don't know - * how to make the UIRCC drive the interrupt line, and not the - * UART (which is used for SIR speeds). Please mail me if you know! - * ********************************************************************/ #include @@ -69,22 +65,24 @@ static struct uircc_cb *dev_self[] = { NULL, NULL, NULL, NULL}; /* Some prototypes */ -static int uircc_open( int i, unsigned int iobase, unsigned int board_addr, - unsigned int irq, unsigned int dma); -static int uircc_close( struct irda_device *idev); -static int uircc_probe( int iobase, int board_addr, int irq, int dma); -static int uircc_dma_receive( struct irda_device *idev); +static int uircc_open(int i, unsigned int iobase, unsigned int board_addr, + unsigned int irq, unsigned int dma); +#ifdef MODULE +static int uircc_close(struct irda_device *idev); +#endif /* MODULE */ +static int uircc_probe(int iobase, int board_addr, int irq, int dma); +static int uircc_dma_receive(struct irda_device *idev); static int uircc_dma_receive_complete(struct irda_device *idev, int iobase); -static int uircc_hard_xmit( struct sk_buff *skb, struct device *dev); -static void uircc_dma_write( struct irda_device *idev, int iobase); -static void uircc_change_speed( struct irda_device *idev, int baud); +static int uircc_hard_xmit(struct sk_buff *skb, struct device *dev); +static void uircc_dma_write(struct irda_device *idev, int iobase); +static void uircc_change_speed(struct irda_device *idev, int baud); static void uircc_interrupt(int irq, void *dev_id, struct pt_regs *regs); -static void uircc_wait_until_sent( struct irda_device *idev); -static int uircc_is_receiving( struct irda_device *idev); - -static int uircc_net_init( struct device *dev); -static int uircc_net_open( struct device *dev); -static int uircc_net_close( struct device *dev); +static void uircc_wait_until_sent(struct irda_device *idev); +static int uircc_is_receiving(struct irda_device *idev); +static int uircc_toshiba_cmd(int *retval, int arg0, int arg1, int arg2); +static int uircc_net_init(struct device *dev); +static int uircc_net_open(struct device *dev); +static int uircc_net_close(struct device *dev); /* * Function uircc_init () @@ -98,9 +96,9 @@ for ( i=0; (io[i] < 2000) && (i < 4); i++) { int ioaddr = io[i]; - if (check_region(ioaddr, CHIP_IO_EXTENT)) + if (check_region(ioaddr, CHIP_IO_EXTENT) < 0) continue; - if (uircc_open( i, io[i], io2[i], irq[i], dma[i]) == 0) + if (uircc_open(i, io[i], io2[i], irq[i], dma[i]) == 0) return 0; } return -ENODEV; @@ -117,11 +115,11 @@ { int i; - DEBUG( 4, __FUNCTION__ "()\n"); + DEBUG(4, __FUNCTION__ "()\n"); - for ( i=0; i < 4; i++) { - if ( dev_self[i]) - uircc_close( &(dev_self[i]->idev)); + for (i=0; i < 4; i++) { + if (dev_self[i]) + uircc_close(&(dev_self[i]->idev)); } } #endif /* MODULE */ @@ -132,28 +130,28 @@ * Open driver instance * */ -static int uircc_open( int i, unsigned int iobase, unsigned int iobase2, - unsigned int irq, unsigned int dma) +static int uircc_open(int i, unsigned int iobase, unsigned int iobase2, + unsigned int irq, unsigned int dma) { struct uircc_cb *self; struct irda_device *idev; int ret; - DEBUG( 0, __FUNCTION__ "()\n"); + DEBUG(4, __FUNCTION__ "()\n"); - if (( uircc_probe( iobase, iobase2, irq, dma)) == -1) + if ((uircc_probe(iobase, iobase2, irq, dma)) == -1) return -1; /* * Allocate new instance of the driver */ self = kmalloc( sizeof(struct uircc_cb), GFP_KERNEL); - if ( self == NULL) { - printk( KERN_ERR "IrDA: Can't allocate memory for " - "IrDA control block!\n"); + if (self == NULL) { + printk(KERN_ERR "IrDA: Can't allocate memory for " + "IrDA control block!\n"); return -ENOMEM; } - memset( self, 0, sizeof(struct uircc_cb)); + memset(self, 0, sizeof(struct uircc_cb)); /* Need to store self somewhere */ dev_self[i] = self; @@ -170,32 +168,34 @@ idev->io.fifo_size = 16; /* Lock the port that we need */ - ret = check_region( idev->io.iobase, idev->io.io_ext); - if ( ret < 0) { - DEBUG( 0, __FUNCTION__ "(), can't get iobase of 0x%03x\n", - idev->io.iobase); + ret = check_region(idev->io.iobase, idev->io.io_ext); + if (ret < 0) { + DEBUG(0, __FUNCTION__ "(), can't get iobase of 0x%03x\n", + idev->io.iobase); /* uircc_cleanup( self->idev); */ return -ENODEV; } - ret = check_region( idev->io.iobase2, idev->io.io_ext2); - if ( ret < 0) { - DEBUG( 0, __FUNCTION__ "(), can't get iobase of 0x%03x\n", - idev->io.iobase2); + ret = check_region(idev->io.iobase2, idev->io.io_ext2); + if (ret < 0) { + DEBUG(0, __FUNCTION__ "(), can't get iobase of 0x%03x\n", + idev->io.iobase2); /* uircc_cleanup( self->idev); */ return -ENODEV; } - request_region( idev->io.iobase, idev->io.io_ext, idev->name); - request_region( idev->io.iobase2, idev->io.io_ext2, idev->name); + request_region(idev->io.iobase, idev->io.io_ext, idev->name); + request_region(idev->io.iobase2, idev->io.io_ext2, idev->name); /* Initialize QoS for this device */ - irda_init_max_qos_capabilies( &idev->qos); + irda_init_max_qos_capabilies(&idev->qos); /* The only value we must override it the baudrate */ idev->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600| - IR_115200|IR_576000|IR_1152000|(IR_4000000 << 8); + IR_115200/*IR_576000|IR_1152000 |(IR_4000000 << 8)*/; + + idev->qos.min_turn_time.bits = 0x0f; + irda_qos_bits_to_value(&idev->qos); - idev->qos.min_turn_time.bits = 0x07; - irda_qos_bits_to_value( &idev->qos); + idev->flags = IFF_FIR|IFF_SIR|IFF_DMA|IFF_PIO; /* Specify which buffer allocation policy we need */ idev->rx_buff.flags = GFP_KERNEL | GFP_DMA; @@ -206,7 +206,6 @@ idev->tx_buff.truesize = 4000; /* Initialize callbacks */ - idev->hard_xmit = uircc_hard_xmit; idev->change_speed = uircc_change_speed; idev->wait_until_sent = uircc_wait_until_sent; idev->is_receiving = uircc_is_receiving; @@ -217,10 +216,10 @@ idev->netdev.open = uircc_net_open; idev->netdev.stop = uircc_net_close; - irport_open( iobase2); + irport_open(iobase2); /* Open the IrDA device */ - irda_device_open( idev, driver_name, self); + irda_device_open(idev, driver_name, self); return 0; } @@ -231,36 +230,41 @@ * Close driver instance * */ -static int uircc_close( struct irda_device *idev) +#ifdef MODULE +static int uircc_close(struct irda_device *idev) { int iobase; + int status; - DEBUG( 4, __FUNCTION__ "()\n"); + DEBUG(4, __FUNCTION__ "()\n"); - ASSERT( idev != NULL, return -1;); - ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return -1;); + ASSERT(idev != NULL, return -1;); + ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return -1;); iobase = idev->io.iobase; + /* Some magic to disable FIR and enable SIR */ + uircc_toshiba_cmd(&status, 0xffff, 0x001b, 0x0000); + /* Disable modem */ - outb( 0x00, iobase+UIRCC_CR10); + outb(0x00, iobase+UIRCC_CR10); - irport_close( idev->io.iobase2); + irport_close(idev->io.iobase2); /* Release the PORT that this driver is using */ - DEBUG( 4, __FUNCTION__ "(), Releasing Region %03x\n", idev->io.iobase); - release_region( idev->io.iobase, idev->io.io_ext); + DEBUG(4, __FUNCTION__ "(), Releasing Region %03x\n", idev->io.iobase); + release_region(idev->io.iobase, idev->io.io_ext); - if ( idev->io.iobase2) { - DEBUG( 4, __FUNCTION__ "(), Releasing Region %03x\n", - idev->io.iobase2); - release_region( idev->io.iobase2, idev->io.io_ext2); + if (idev->io.iobase2) { + DEBUG(4, __FUNCTION__ "(), Releasing Region %03x\n", + idev->io.iobase2); + release_region(idev->io.iobase2, idev->io.io_ext2); } - - irda_device_close( idev); + irda_device_close(idev); return 0; } +#endif /* MODULE */ /* * Function uircc_probe (iobase, board_addr, irq, dma) @@ -268,81 +272,38 @@ * Returns non-negative on success. * */ -static int uircc_probe( int iobase, int iobase2, int irq, int dma) +static int uircc_probe(int iobase, int iobase2, int irq, int dma) { int version; - int probe_irq=0; - unsigned long mask; - int i; - DEBUG( 0, __FUNCTION__ "()\n"); + DEBUG(4, __FUNCTION__ "()\n"); /* read the chip version, should be 0x03 */ - version = inb( iobase+UIRCC_SR8); + version = inb(iobase+UIRCC_SR8); - if ( version != 0x03) { - DEBUG( 0, __FUNCTION__ "(), Wrong chip version"); + if (version != 0x03) { + DEBUG(0, __FUNCTION__ "(), Wrong chip version"); return -1; } - DEBUG( 0, "UIRCC driver loaded. Version: 0x%02x\n", version); + printk(KERN_INFO "Sharp UIRCC IrDA driver loaded. Version: 0x%02x\n", + version); /* Reset chip */ - outb( UIRCC_CR0_SYS_RST, iobase+UIRCC_CR0); + outb(UIRCC_CR0_SYS_RST, iobase+UIRCC_CR0); /* Initialize some registers */ - outb( 0, iobase+UIRCC_CR11); - outb( 0, iobase+UIRCC_CR9); - - /* Enable DMA single mode */ - outb( UIRCC_CR1_RX_DMA|UIRCC_CR1_TX_DMA|UIRCC_CR1_MUST_SET, - iobase+UIRCC_CR1); - - /* Disable interrupts */ - outb( 0xff, iobase+UIRCC_CR2); + outb(0x03, iobase+UIRCC_CR15); + outb(0, iobase+UIRCC_CR11); + outb(0, iobase+UIRCC_CR9); -#if 0 - irport_close( iobase2); - - for (i=0;i<1;i++) { - - /* Set appropriate speed mode */ - outb( UIRCC_CR10_FIR, iobase+UIRCC_CR10); + DEBUG(0, __FUNCTION__ "(), sr15=%#x\n", inb(iobase+UIRCC_SR15)); /* Enable DMA single mode */ - outb( UIRCC_CR1_RX_DMA|UIRCC_CR1_TX_DMA|UIRCC_CR1_MUST_SET, - iobase+UIRCC_CR1); - - /* Set up timer */ - outb( 0x01, iobase+UIRCC_CR12); - outb( 0x00, iobase+UIRCC_CR13); + outb(UIRCC_CR1_RX_DMA|UIRCC_CR1_TX_DMA|UIRCC_CR1_MUST_SET, + iobase+UIRCC_CR1); - /* Set interrupt mask */ - outb( 0x82, iobase+UIRCC_CR2); - - DEBUG( 0, __FUNCTION__ "(*), sr3=%#x, sr2=%#x, sr10=%#x, sr12=%#x\n", - inb( iobase+UIRCC_SR3), inb( iobase+UIRCC_SR2), - inb( iobase+UIRCC_SR10), inb( iobase+UIRCC_SR12)); - - mask = probe_irq_on(); - - /* Enable timer */ - outb( 0x08, iobase+UIRCC_CR11); - - udelay( 10000); /* Wait for interrupt! */ - - probe_irq = probe_irq_off( mask); - - DEBUG( 0, "Found irq=%d\n", probe_irq); - - DEBUG( 0, __FUNCTION__ "(), sr3=%#x, sr2=%#x, sr10=%#x, sr12=%#x\n", - inb( iobase+UIRCC_SR3), inb( iobase+UIRCC_SR2), - inb( iobase+UIRCC_SR10), inb( iobase+UIRCC_SR12)); - - - /* Diable timer */ - outb( 0x00, iobase+UIRCC_CR11); - } -#endif + /* Disable interrupts */ + outb(0xff, iobase+UIRCC_CR2); /* Set self poll address */ @@ -355,16 +316,20 @@ * Change the speed of the device * */ -static void uircc_change_speed( struct irda_device *idev, int speed) +static void uircc_change_speed(struct irda_device *idev, int speed) { struct uircc_cb *self; int iobase; int modem = UIRCC_CR10_SIR; + int status; + + DEBUG(0, __FUNCTION__ "()\n"); - DEBUG( 0, __FUNCTION__ "()\n"); + /* Just test the high speed stuff */ + /*speed = 4000000;*/ - ASSERT( idev != NULL, return;); - ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return;); + ASSERT(idev != NULL, return;); + ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;); self = idev->priv; iobase = idev->io.iobase; @@ -373,16 +338,20 @@ idev->io.baudrate = speed; /* Disable interrupts */ - outb( 0xff, iobase+UIRCC_CR2); + outb(0xff, iobase+UIRCC_CR2); - switch ( speed) { + switch (speed) { case 9600: case 19200: case 37600: case 57600: case 115200: -/* irport_open( idev->io.iobase2); */ + irport_open(idev->io.iobase2); irport_change_speed( idev->io.iobase2, speed); + + /* Some magic to disable FIR and enable SIR */ + uircc_toshiba_cmd(&status, 0xffff, 0x001b, 0x0000); + modem = UIRCC_CR10_SIR; break; case 576000: @@ -394,9 +363,18 @@ DEBUG(0, __FUNCTION__ "(), handling baud of 1152000\n"); break; case 4000000: - irport_close( idev->io.iobase2); + irport_close(idev->io.iobase2); + + /* Some magic to disable SIR and enable FIR */ + uircc_toshiba_cmd(&status, 0xffff, 0x001b, 0x0001); + modem = UIRCC_CR10_FIR; DEBUG(0, __FUNCTION__ "(), handling baud of 4000000\n"); + + /* Set self pole address */ + //outb(0xfe, iobase+UIRCC_CR8); + + /* outb(0x10, iobase+UIRCC_CR11); */ break; default: DEBUG( 0, __FUNCTION__ "(), unknown baud rate of %d\n", speed); @@ -404,19 +382,19 @@ } /* Set appropriate speed mode */ - outb( modem, iobase+UIRCC_CR10); + outb(modem, iobase+UIRCC_CR10); idev->netdev.tbusy = 0; /* Enable some interrupts so we can receive frames */ - if ( speed > 115200) { + if (speed > 115200) { /* Enable DMA single mode */ - outb( UIRCC_CR1_RX_DMA|UIRCC_CR1_TX_DMA|UIRCC_CR1_MUST_SET, - iobase+UIRCC_CR1); + outb(UIRCC_CR1_RX_DMA|UIRCC_CR1_TX_DMA|UIRCC_CR1_MUST_SET, + iobase+UIRCC_CR1); - /* outb( UIRCC_CR2_RECV_MASK, iobase+UIRCC_CR2); */ - outb( 0, iobase+UIRCC_CR2); - uircc_dma_receive( idev); + /* Enable all interrupts */ + outb(0, iobase+UIRCC_CR2); + uircc_dma_receive(idev); } } @@ -426,7 +404,7 @@ * Transmit the frame! * */ -static int uircc_hard_xmit( struct sk_buff *skb, struct device *dev) +static int uircc_hard_xmit(struct sk_buff *skb, struct device *dev) { struct irda_device *idev; int iobase; @@ -434,94 +412,96 @@ idev = (struct irda_device *) dev->priv; - ASSERT( idev != NULL, return 0;); - ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return 0;); + ASSERT(idev != NULL, return 0;); + ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return 0;); iobase = idev->io.iobase; - DEBUG(0, __FUNCTION__ "(%ld), skb->len=%d\n", jiffies, (int) skb->len); + DEBUG(4, __FUNCTION__ "(%ld), skb->len=%d\n", jiffies, (int) skb->len); + + /* Reset carrier latch */ + /*outb(0x02, iobase+UIRCC_CR0);*/ /* Use irport for SIR speeds */ - if ( idev->io.baudrate <= 115200) { - return irport_hard_xmit( skb, dev); - } - - if ( dev->tbusy) { - __u8 sr3; - - DEBUG( 4, __FUNCTION__ "(), tbusy==TRUE\n"); - - return -EBUSY; + if (idev->io.baudrate <= 115200) { + return irport_hard_xmit(skb, dev); } + DEBUG(0, __FUNCTION__ "(), sr0=%#x, sr1=%#x, sr2=%#x, sr3=%#x, sr10=%#x, sr11=%#x\n", + inb(iobase+UIRCC_SR0), inb(iobase+UIRCC_SR3), + inb(iobase+UIRCC_SR2), inb(iobase+UIRCC_SR3), + inb(iobase+UIRCC_SR10), inb(iobase+UIRCC_SR11)); + /* Lock transmit buffer */ - if ( irda_lock( (void *) &dev->tbusy) == FALSE) + if (irda_lock((void *) &dev->tbusy) == FALSE) return -EBUSY; - memcpy( idev->tx_buff.data, skb->data, skb->len); + memcpy(idev->tx_buff.data, skb->data, skb->len); /* Make sure that the length is a multiple of 16 bits */ - if ( skb->len & 0x01) + if (skb->len & 0x01) skb->len++; idev->tx_buff.len = skb->len; - idev->tx_buff.head = idev->tx_buff.data; - idev->tx_buff.offset = 0; + idev->tx_buff.data = idev->tx_buff.head; - mtt = irda_get_mtt( skb); + mtt = irda_get_mtt(skb); /* Use udelay for delays less than 50 us. */ if (mtt) - udelay( mtt); + udelay(mtt); /* Enable transmit interrupts */ - /* outb( UIRCC_CR2_XMIT_MASK, iobase+UIRCC_CR2); */ - outb( 0, iobase+UIRCC_CR2); + outb(0, iobase+UIRCC_CR2); - uircc_dma_write( idev, iobase); + uircc_dma_write(idev, iobase); - dev_kfree_skb( skb); + dev_kfree_skb(skb); return 0; } /* - * Function uircc_dma_xmit (idev, iobase) + * Function uircc_dma_write (idev, iobase) * * Transmit data using DMA * */ -static void uircc_dma_write( struct irda_device *idev, int iobase) +static void uircc_dma_write(struct irda_device *idev, int iobase) { struct uircc_cb *self; - int i; - DEBUG( 0, __FUNCTION__ "()\n"); + DEBUG(4, __FUNCTION__ "()\n"); - ASSERT( idev != NULL, return;); - ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return;); + ASSERT(idev != NULL, return;); + ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;); self = idev->priv; /* Receiving disable */ self->cr3 &= ~UIRCC_CR3_RECV_EN; - outb( self->cr3, iobase+UIRCC_CR3); + outb(self->cr3, iobase+UIRCC_CR3); - setup_dma( idev->io.dma, idev->tx_buff.data, idev->tx_buff.len, - DMA_MODE_WRITE); - - DEBUG( 0, __FUNCTION__ "residue=%d\n", - get_dma_residue( idev->io.dma)); + /* Set modem */ + outb(0x80, iobase+UIRCC_CR10); + + /* Enable transmit DMA */ + outb(UIRCC_CR1_TX_DMA|UIRCC_CR1_MUST_SET, iobase+UIRCC_CR1); + + ASSERT((((__u32)(idev->tx_buff.data)) & 0x01) != 0x01, return;); + setup_dma(idev->io.dma, idev->tx_buff.data, idev->tx_buff.len, + DMA_MODE_WRITE); + idev->io.direction = IO_XMIT; - /* Set frame length */ - outb( idev->tx_buff.len & 0xff, iobase+UIRCC_CR4); /* Low byte */ - outb( idev->tx_buff.len >> 8, iobase+UIRCC_CR5); /* High byte */ + /* Set frame length (should be the real length without padding */ + outb(idev->tx_buff.len & 0xff, iobase+UIRCC_CR4); /* Low byte */ + outb(idev->tx_buff.len >> 8, iobase+UIRCC_CR5); /* High byte */ /* Enable transmit and transmit CRC */ self->cr3 |= (UIRCC_CR3_XMIT_EN|UIRCC_CR3_TX_CRC_EN); - outb( self->cr3, iobase+UIRCC_CR3); + outb(self->cr3, iobase+UIRCC_CR3); } /* @@ -537,33 +517,38 @@ int iobase; int len; - DEBUG( 4, __FUNCTION__ "()\n"); + DEBUG(4, __FUNCTION__ "()\n"); - ASSERT( idev != NULL, return;); - ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return;); + ASSERT(idev != NULL, return;); + ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;); self = idev->priv; iobase = idev->io.iobase; /* Select TX counter */ - outb( UIRCC_CR0_CNT_SWT, iobase+UIRCC_CR0); + outb(UIRCC_CR0_CNT_SWT, iobase+UIRCC_CR0); /* Read TX length counter */ - len = inb( iobase+UIRCC_SR4); /* Low byte */ - len |= inb( iobase+UIRCC_SR5) << 8; /* High byte */ + len = inb(iobase+UIRCC_SR4); /* Low byte */ + len |= inb(iobase+UIRCC_SR5) << 8; /* High byte */ + + DEBUG(4, __FUNCTION__ "(), sent %d bytes\n", len); /* Disable transmit */ self->cr3 &= ~UIRCC_CR3_XMIT_EN; - outb( self->cr3, iobase+UIRCC_CR3); + outb(self->cr3, iobase+UIRCC_CR3); + + /* Transmit reset (just to be sure) */ + outb(UIRCC_CR0_XMIT_RST, iobase+UIRCC_CR0); /* Check for underrrun! */ - if ( underrun) { + if (underrun) { idev->stats.tx_errors++; idev->stats.tx_fifo_errors++; } else { idev->stats.tx_packets++; - idev->stats.tx_bytes += idev->tx_buff.len; + idev->stats.tx_bytes += idev->tx_buff.len; } /* Unlock tx_buff and request another frame */ @@ -571,7 +556,7 @@ idev->media_busy = FALSE; /* Tell the network layer, that we can accept more frames */ - mark_bh( NET_BH); + mark_bh(NET_BH); } /* @@ -581,37 +566,56 @@ * if it starts to receive a frame. * */ -static int uircc_dma_receive( struct irda_device *idev) +static int uircc_dma_receive(struct irda_device *idev) { struct uircc_cb *self; int iobase; - ASSERT( idev != NULL, return -1;); - ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return -1;); + ASSERT(idev != NULL, return -1;); + ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return -1;); - DEBUG( 0, __FUNCTION__ "\n"); + DEBUG(4, __FUNCTION__ "\n"); self = idev->priv; iobase= idev->io.iobase; - /* Disable DMA */ - - setup_dma( idev->io.dma, idev->rx_buff.data, idev->rx_buff.truesize, - DMA_MODE_READ); + /* Transmit disable */ + /* self->cr3 &= ~UIRCC_CR3_XMIT_EN; */ + self->cr3 = 0; + outb(self->cr3, iobase+UIRCC_CR3); + + /* Transmit reset (just in case) */ + outb(UIRCC_CR0_XMIT_RST|0x17, iobase+UIRCC_CR0); + + /* Set modem */ + outb(0x08, iobase+UIRCC_CR10); + + /* Enable receiving with CRC */ + self->cr3 = (UIRCC_CR3_RECV_EN|UIRCC_CR3_RX_CRC_EN); + outb(self->cr3, iobase+UIRCC_CR3); + + /* Make sure Rx DMA is set */ + outb(UIRCC_CR1_RX_DMA|UIRCC_CR1_MUST_SET, iobase+UIRCC_CR1); + + /* Rx reset */ + /* outb(UIRCC_CR0_RECV_RST, iobase+UIRCC_CR0); */ + + setup_dma(idev->io.dma, idev->rx_buff.data, + idev->rx_buff.truesize, DMA_MODE_READ); /* driver->media_busy = FALSE; */ idev->io.direction = IO_RECV; - idev->rx_buff.head = idev->rx_buff.data; - idev->rx_buff.offset = 0; + idev->rx_buff.data = idev->rx_buff.head; +#if 0 /* Enable receiving with CRC */ - self->cr3 |= (UIRCC_CR3_RECV_EN|UIRCC_CR3_RX_CRC_EN); - outb( self->cr3, iobase+UIRCC_CR3); + self->cr3 = (UIRCC_CR3_RECV_EN|UIRCC_CR3_RX_CRC_EN); + outb(self->cr3, iobase+UIRCC_CR3); +#endif + DEBUG(4, __FUNCTION__ "(), cr3=%#x\n", self->cr3); /* Address check? */ - DEBUG( 4, __FUNCTION__ "(), done!\n"); - return 0; } @@ -622,7 +626,7 @@ * * */ -static int uircc_dma_receive_complete( struct irda_device *idev, int iobase) +static int uircc_dma_receive_complete(struct irda_device *idev, int iobase) { struct sk_buff *skb; struct uircc_cb *self; @@ -630,37 +634,37 @@ self = idev->priv; - DEBUG( 0, __FUNCTION__ "()\n"); + DEBUG(0, __FUNCTION__ "()\n"); /* Check for CRC or framing error */ - if ( inb( iobase+UIRCC_SR0) & UIRCC_SR0_RX_CRCFRM) { - DEBUG( 0, __FUNCTION__ "(), crc or frm error\n"); + if (inb(iobase+UIRCC_SR0) & UIRCC_SR0_RX_CRCFRM) { + DEBUG(0, __FUNCTION__ "(), CRC or FRAME error\n"); return -1; } /* Select receive length counter */ - outb( 0x00, iobase+UIRCC_CR0); + outb(0x00, iobase+UIRCC_CR0); /* Read frame length */ - len = inb( iobase+UIRCC_SR4); /* Low byte */ - len |= inb( iobase+UIRCC_SR5) << 8; /* High byte */ + len = inb(iobase+UIRCC_SR4); /* Low byte */ + len |= inb(iobase+UIRCC_SR5) << 8; /* High byte */ - DEBUG( 0, __FUNCTION__ "(), len=%d\n", len); + DEBUG(0, __FUNCTION__ "(), len=%d\n", len); /* Receiving disable */ self->cr3 &= ~UIRCC_CR3_RECV_EN; - outb( self->cr3, iobase+UIRCC_CR3); + outb(self->cr3, iobase+UIRCC_CR3); - skb = dev_alloc_skb( len+1); + skb = dev_alloc_skb(len+1); if (skb == NULL) { - printk( KERN_INFO __FUNCTION__ - "(), memory squeeze, dropping frame.\n"); + printk(KERN_INFO __FUNCTION__ + "(), memory squeeze, dropping frame.\n"); /* Restore bank register */ return FALSE; } /* Make sure IP header gets aligned */ - skb_reserve( skb, 1); + skb_reserve(skb, 1); /* Copy frame without CRC */ /* if ( idev->io.baudrate < 4000000) { */ @@ -671,14 +675,14 @@ /* memcpy( skb->data, idev->rx_buff.head, len-4); */ /* } */ - skb_put( skb, len); - memcpy( skb->data, idev->rx_buff.head, len); + skb_put(skb, len); + memcpy(skb->data, idev->rx_buff.data, len); idev->stats.rx_packets++; skb->dev = &idev->netdev; skb->mac.raw = skb->data; skb->protocol = htons(ETH_P_IRDA); - netif_rx( skb); + netif_rx(skb); return TRUE; } @@ -710,40 +714,44 @@ /* Read interrupt status */ sr3 = inb( iobase+UIRCC_SR3); if (!sr3) { + DEBUG(4,"**\n"); return; } - idev->netdev.interrupt = 1; - DEBUG( 4, __FUNCTION__ "(), sr3=%#x, sr2=%#x, sr10=%#x\n", - inb( iobase+UIRCC_SR3), inb( iobase+UIRCC_SR2), - inb( iobase+UIRCC_SR10)); + DEBUG(4, __FUNCTION__ "(), sr3=%#x, sr2=%#x, sr10=%#x\n", + inb( iobase+UIRCC_SR3), inb( iobase+UIRCC_SR2), + inb( iobase+UIRCC_SR10)); /* * Check what interrupt this is. The UIRCC will not report two * different interrupts at the same time! */ - switch( sr3) { - case UIRCC_SR3_RX_EOF: /* Check of end of frame */ - uircc_dma_receive_complete( idev, iobase); + switch(sr3) { + case UIRCC_SR3_RX_EOF: /* Check for end of frame */ + uircc_dma_receive_complete(idev, iobase); break; case UIRCC_SR3_TXUR: /* Check for transmit underrun */ - uircc_dma_xmit_complete( idev, TRUE); + uircc_dma_xmit_complete(idev, TRUE); + uircc_dma_receive(idev); + outb(0, iobase+UIRCC_CR2); break; case UIRCC_SR3_TX_DONE: - uircc_dma_xmit_complete( idev, FALSE); + uircc_dma_xmit_complete(idev, FALSE); + uircc_dma_receive(idev); + + outb(0x0d, iobase+UIRCC_CR2); break; case UIRCC_SR3_TMR_OUT: /* Disable timer */ - outb( inb( iobase+UIRCC_CR11) & ~UIRCC_CR11_TMR_EN, - iobase+UIRCC_CR11); + outb(inb(iobase+UIRCC_CR11) & ~UIRCC_CR11_TMR_EN, + iobase+UIRCC_CR11); break; default: - DEBUG( 0, __FUNCTION__ "(), unknown interrupt status=%#x\n", - sr3); + DEBUG(0, __FUNCTION__ "(), unknown interrupt status=%#x\n", + sr3); break; - } - + } idev->netdev.interrupt = 0; } @@ -771,13 +779,13 @@ int status = FALSE; /* int iobase; */ - ASSERT( idev != NULL, return FALSE;); - ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return FALSE;); + ASSERT(idev != NULL, return FALSE;); + ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return FALSE;); - if ( idev->io.baudrate > 115200) { + if (idev->io.baudrate > 115200) { } else - status = ( idev->rx_buff.state != OUTSIDE_FRAME); + status = (idev->rx_buff.state != OUTSIDE_FRAME); return status; } @@ -793,7 +801,7 @@ DEBUG( 4, __FUNCTION__ "()\n"); /* Setup to be a normal IrDA network device driver */ - irda_device_setup( dev); + irda_device_setup(dev); /* Insert overrides below this line! */ @@ -807,23 +815,23 @@ * Start the device * */ -static int uircc_net_open( struct device *dev) +static int uircc_net_open(struct device *dev) { struct irda_device *idev; int iobase; DEBUG( 4, __FUNCTION__ "()\n"); - ASSERT( dev != NULL, return -1;); + ASSERT(dev != NULL, return -1;); idev = (struct irda_device *) dev->priv; - ASSERT( idev != NULL, return 0;); - ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return 0;); + ASSERT(idev != NULL, return 0;); + ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return 0;); iobase = idev->io.iobase; - if (request_irq( idev->io.irq, uircc_interrupt, 0, idev->name, - (void *) idev)) { + if (request_irq(idev->io.irq, uircc_interrupt, 0, idev->name, + (void *) idev)) { return -EAGAIN; } /* @@ -831,7 +839,7 @@ * and clean up on failure. */ if (request_dma(idev->io.dma, idev->name)) { - free_irq( idev->io.irq, idev); + free_irq(idev->io.irq, idev); return -EAGAIN; } @@ -858,32 +866,62 @@ struct irda_device *idev; int iobase; - DEBUG( 4, __FUNCTION__ "()\n"); + DEBUG(4, __FUNCTION__ "()\n"); /* Stop device */ dev->tbusy = 1; dev->start = 0; - ASSERT( dev != NULL, return -1;); + ASSERT(dev != NULL, return -1;); idev = (struct irda_device *) dev->priv; - ASSERT( idev != NULL, return 0;); - ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return 0;); + ASSERT(idev != NULL, return 0;); + ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return 0;); iobase = idev->io.iobase; - disable_dma( idev->io.dma); + disable_dma(idev->io.dma); /* Disable interrupts */ - free_irq( idev->io.irq, idev); - free_dma( idev->io.dma); + free_irq(idev->io.irq, idev); + free_dma(idev->io.dma); MOD_DEC_USE_COUNT; return 0; } +/* + * Function uircc_toshiba_cmd (arg0, arg1, arg2) + * + * disable FIR: uircc_toshiba_cmd(&status, 0xffff, 0x001b, 0x0000); + * enable FIR: uircc_toshiba_cmd(&status, 0xffff, 0x001b, 0x0001); + * IRDA status: uircc_toshiba_cmd(&status, 0xfefe, 0x001b, 0x0000); + */ +static int uircc_toshiba_cmd(int *retval, int arg0, int arg1, int arg2) +{ + char return_code = 0; + + __asm__ volatile ("inb $0xb2,%%al; " + "movb %%ah,%%al; " + : /* Output */ + "=al" (return_code), + "=ecx" (*retval) + : /* Input */ + "ax" (arg0), + "bx" (arg1), + "cx" (arg2) + ); + /* + * Return + * 0x00 = OK + * 0x80 = Function not supported by system + * 0x83 = Input data error + */ + return (int) return_code; +} + #ifdef MODULE /* @@ -894,9 +932,7 @@ */ int init_module(void) { - uircc_init(); - - return(0); + return uircc_init(); } /* @@ -909,6 +945,5 @@ { uircc_cleanup(); } - -#endif +#endif /* MODULE */ diff -ur --new-file old/linux/drivers/net/irda/w83977af_ir.c new/linux/drivers/net/irda/w83977af_ir.c --- old/linux/drivers/net/irda/w83977af_ir.c Fri Dec 18 17:06:39 1998 +++ new/linux/drivers/net/irda/w83977af_ir.c Sun Apr 25 02:49:37 1999 @@ -6,7 +6,7 @@ * Status: Experimental. * Author: Paul VanderSpek * Created at: Wed Nov 4 11:46:16 1998 - * Modified at: Mon Dec 14 21:51:53 1998 + * Modified at: Tue Apr 20 11:15:00 1999 * Modified by: Dag Brattli * * Copyright (c) 1998 Corel Computer Corp. @@ -22,7 +22,7 @@ * provided "AS-IS" and at no charge. * * If you find bugs in this file, its very likely that the same bug - * will also be in w83977af_ir.c since the implementations is quite + * will also be in pc87108.c since the implementations is quite * similar. * * Notice that all functions that needs to access the chip in _any_ @@ -67,8 +67,8 @@ #define CHIP_IO_EXTENT 8 -static unsigned int io[] = { 0x400, ~0, ~0, ~0 }; -static unsigned int irq[] = { 22, 0, 0, 0 }; +static unsigned int io[] = { 0x180, ~0, ~0, ~0 }; +static unsigned int irq[] = { 6, 0, 0, 0 }; static unsigned int dma[] = { 0, 0, 0, 0 }; static struct irda_device *dev_self[] = { NULL, NULL, NULL, NULL}; @@ -116,7 +116,7 @@ for ( i=0; (io[i] < 2000) && (i < 4); i++) { int ioaddr = io[i]; - if (check_region(ioaddr, CHIP_IO_EXTENT)) + if (check_region(ioaddr, CHIP_IO_EXTENT) < 0) continue; if (w83977af_open( i, io[i], irq[i], dma[i]) == 0) return 0; @@ -204,6 +204,8 @@ /* The HP HDLS-1100 needs 1 ms according to the specs */ idev->qos.min_turn_time.bits = 0x03; /* 1ms and more */ irda_qos_bits_to_value( &idev->qos); + + idev->flags = IFF_FIR|IFF_MIR|IFF_SIR|IFF_DMA|IFF_PIO; /* Specify which buffer allocation policy we need */ idev->rx_buff.flags = GFP_KERNEL | GFP_DMA; @@ -214,7 +216,6 @@ idev->tx_buff.truesize = 4000; /* Initialize callbacks */ - idev->hard_xmit = w83977af_hard_xmit; idev->change_speed = w83977af_change_speed; idev->wait_until_sent = w83977af_wait_until_sent; idev->is_receiving = w83977af_is_receiving; @@ -288,9 +289,10 @@ /* Configure PnP port, IRQ, and DMA channel */ w977_write_reg(0x60, (iobase >> 8) & 0xff); w977_write_reg(0x61, (iobase) & 0xff); - w977_write_reg(0x70, 0x06); + /* w977_write_reg(0x70, 0x06); */ + w977_write_reg(0x70, irq); #ifdef NETWINDER - w977_write_reg(0x74, dma+1); /* Netwinder uses 1 higher than Linux */ + w977_write_reg(0x74, dma+1); /* Netwinder uses one higher than Linux */ #else w977_write_reg(0x74, dma); #endif @@ -431,7 +433,7 @@ /* set FIFO threshold to TX17, RX16 */ switch_bank(iobase, SET0); - outb( UFR_RXTL|UFR_TXTL|UFR_TXF_RST|UFR_RXF_RST|UFR_EN_FIFO, iobase+UFR); + outb(UFR_RXTL|UFR_TXTL|UFR_TXF_RST|UFR_RXF_RST|UFR_EN_FIFO, iobase+UFR); idev->netdev.tbusy = 0; @@ -462,74 +464,65 @@ idev = (struct irda_device *) dev->priv; - ASSERT( idev != NULL, return 0;); - ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return 0;); + ASSERT(idev != NULL, return 0;); + ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return 0;); iobase = idev->io.iobase; DEBUG(4, __FUNCTION__ "(%ld), skb->len=%d\n", jiffies, (int) skb->len); - - if ( dev->tbusy) { - DEBUG( 4, __FUNCTION__ "(), tbusy==TRUE\n"); - - return -EBUSY; - } /* Lock transmit buffer */ - if ( irda_lock( (void *) &dev->tbusy) == FALSE) + if (irda_lock((void *) &dev->tbusy) == FALSE) return -EBUSY; - + /* Save current set */ - set = inb( iobase+SSR); + set = inb(iobase+SSR); /* Decide if we should use PIO or DMA transfer */ - if ( idev->io.baudrate > 115200) { - memcpy( idev->tx_buff.data, skb->data, skb->len); + if (idev->io.baudrate > 115200) { + memcpy(idev->tx_buff.data, skb->data, skb->len); idev->tx_buff.len = skb->len; - idev->tx_buff.head = idev->tx_buff.data; - idev->tx_buff.offset = 0; + idev->tx_buff.data = idev->tx_buff.head; - mtt = irda_get_mtt( skb); - if ( mtt > 50) { + mtt = irda_get_mtt(skb); + if (mtt > 50) { /* Adjust for timer resolution */ - mtt /= 1000+1; + mtt = mtt / 1000 + 1; /* Setup timer */ - switch_bank( iobase, SET4); - outb( mtt & 0xff, iobase+TMRL); - outb(( mtt >> 8) & 0x0f, iobase+TMRH); + switch_bank(iobase, SET4); + outb(mtt & 0xff, iobase+TMRL); + outb((mtt >> 8) & 0x0f, iobase+TMRH); /* Start timer */ - outb( IR_MSL_EN_TMR, iobase+IR_MSL); + outb(IR_MSL_EN_TMR, iobase+IR_MSL); idev->io.direction = IO_XMIT; /* Enable timer interrupt */ - switch_bank( iobase, SET0); - outb( ICR_ETMRI, iobase+ICR); + switch_bank(iobase, SET0); + outb(ICR_ETMRI, iobase+ICR); } else { - if ( mtt) - udelay( mtt); + if (mtt) + udelay(mtt); /* Enable DMA interrupt */ - switch_bank( iobase, SET0); - outb( ICR_EDMAI, iobase+ICR); - w83977af_dma_write( idev, iobase); + switch_bank(iobase, SET0); + outb(ICR_EDMAI, iobase+ICR); + w83977af_dma_write(idev, iobase); } } else { - idev->tx_buff.len = async_wrap_skb( skb, idev->tx_buff.data, - idev->tx_buff.truesize); - - idev->tx_buff.offset = 0; - idev->tx_buff.head = idev->tx_buff.data; + idev->tx_buff.data = idev->tx_buff.head; + idev->tx_buff.len = async_wrap_skb(skb, idev->tx_buff.data, + idev->tx_buff.truesize); /* Add interrupt on tx low level (will fire immediately) */ - switch_bank( iobase, SET0); - outb( ICR_ETXTHI, iobase+ICR); + switch_bank(iobase, SET0); + outb(ICR_ETXTHI, iobase+ICR); } - dev_kfree_skb( skb); + dev_kfree_skb(skb); /* Restore set register */ - outb( set, iobase+SSR); + outb(set, iobase+SSR); return 0; } @@ -554,23 +547,23 @@ switch_bank(iobase, SET0); outb( inb( iobase+HCR) & ~HCR_EN_DMA, iobase+HCR); - setup_dma( idev->io.dma, idev->tx_buff.data, idev->tx_buff.len, - DMA_MODE_WRITE); + setup_dma(idev->io.dma, idev->tx_buff.data, idev->tx_buff.len, + DMA_MODE_WRITE); /* idev->media_busy = TRUE; */ idev->io.direction = IO_XMIT; /* Choose transmit DMA channel */ switch_bank(iobase, SET2); - outb( inb( iobase+ADCR1) | ADCR1_D_CHSW|ADCR1_DMA_F|ADCR1_ADV_SL, - iobase+ADCR1); + outb(inb(iobase+ADCR1) | ADCR1_D_CHSW|ADCR1_DMA_F|ADCR1_ADV_SL, + iobase+ADCR1); /* Enable DMA */ - switch_bank( iobase, SET0); - outb( inb( iobase+HCR) | HCR_EN_DMA, iobase+HCR); + switch_bank(iobase, SET0); + outb(inb(iobase+HCR) | HCR_EN_DMA, iobase+HCR); /* Restore set register */ - outb( set, iobase+SSR); + outb(set, iobase+SSR); } /* @@ -579,7 +572,7 @@ * * */ -static int w83977af_pio_write( int iobase, __u8 *buf, int len, int fifo_size) +static int w83977af_pio_write(int iobase, __u8 *buf, int len, int fifo_size) { int actual = 0; __u8 set; @@ -590,7 +583,7 @@ set = inb( iobase+SSR); switch_bank( iobase, SET0); - if (!( inb_p( iobase+USR) & USR_TSRE)) { + if (!(inb_p(iobase+USR) & USR_TSRE)) { DEBUG( 4, __FUNCTION__ "(), warning, FIFO not empty yet!\n"); fifo_size -= 17; @@ -598,16 +591,16 @@ } /* Fill FIFO with current frame */ - while (( fifo_size-- > 0) && (actual < len)) { + while ((fifo_size-- > 0) && (actual < len)) { /* Transmit next byte */ - outb( buf[actual++], iobase+TBR); + outb(buf[actual++], iobase+TBR); } - DEBUG( 4, __FUNCTION__ "(), fifo_size %d ; %d sent of %d\n", - fifo_size, actual, len); + DEBUG(4, __FUNCTION__ "(), fifo_size %d ; %d sent of %d\n", + fifo_size, actual, len); /* Restore bank */ - outb( set, iobase+SSR); + outb(set, iobase+SSR); return actual; } @@ -619,34 +612,34 @@ * * */ -void w83977af_dma_xmit_complete( struct irda_device *idev) +void w83977af_dma_xmit_complete(struct irda_device *idev) { int iobase; __u8 set; - DEBUG( 4, __FUNCTION__ "()\n"); + DEBUG(4, __FUNCTION__ "()\n"); - ASSERT( idev != NULL, return;); - ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return;); + ASSERT(idev != NULL, return;); + ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;); iobase = idev->io.iobase; /* Save current set */ - set = inb( iobase+SSR); + set = inb(iobase+SSR); /* Disable DMA */ switch_bank(iobase, SET0); - outb( inb(iobase+HCR) & ~HCR_EN_DMA, iobase+HCR); + outb(inb(iobase+HCR) & ~HCR_EN_DMA, iobase+HCR); /* Check for underrrun! */ - if ( inb( iobase+AUDR) & AUDR_UNDR) { - DEBUG( 0, __FUNCTION__ "(), Transmit underrun!\n"); + if (inb(iobase+AUDR) & AUDR_UNDR) { + DEBUG(0, __FUNCTION__ "(), Transmit underrun!\n"); idev->stats.tx_errors++; idev->stats.tx_fifo_errors++; /* Clear bit, by writing 1 to it */ - outb( AUDR_UNDR, iobase+AUDR); + outb(AUDR_UNDR, iobase+AUDR); } else idev->stats.tx_packets++; @@ -655,10 +648,10 @@ idev->media_busy = FALSE; /* Tell the network layer, that we want more frames */ - mark_bh( NET_BH); + mark_bh(NET_BH); /* Restore set */ - outb( set, iobase+SSR); + outb(set, iobase+SSR); } /* @@ -668,7 +661,7 @@ * if it starts to receive a frame. * */ -int w83977af_dma_receive( struct irda_device *idev) +int w83977af_dma_receive(struct irda_device *idev) { int iobase; __u8 set; @@ -677,10 +670,10 @@ __u8 hcr; #endif - ASSERT( idev != NULL, return -1;); - ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return -1;); + ASSERT(idev != NULL, return -1;); + ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return -1;); - DEBUG( 0, __FUNCTION__ "\n"); + DEBUG(0, __FUNCTION__ "\n"); iobase= idev->io.iobase; @@ -701,13 +694,12 @@ set_dma_addr( idev->io.dma, virt_to_bus(idev->rx_buff.data)); set_dma_count( idev->io.dma, idev->rx_buff.truesize); #else - setup_dma( idev->io.dma, idev->rx_buff.data, idev->rx_buff.truesize, - DMA_MODE_READ); + setup_dma(idev->io.dma, idev->rx_buff.data, + idev->rx_buff.truesize, DMA_MODE_READ); #endif /* driver->media_busy = FALSE; */ idev->io.direction = IO_RECV; - idev->rx_buff.head = idev->rx_buff.data; - idev->rx_buff.offset = 0; + idev->rx_buff.data = idev->rx_buff.head; /* * Reset Rx FIFO. This will also flush the ST_FIFO, it's very @@ -755,30 +747,30 @@ __u8 set; __u8 status; - DEBUG( 0, __FUNCTION__ "\n"); + DEBUG(0, __FUNCTION__ "\n"); iobase = idev->io.iobase; /* Save current set */ - set = inb( iobase+SSR); + set = inb(iobase+SSR); iobase = idev->io.iobase; switch_bank(iobase, SET5); - if ( prev.status & FS_FO_FSFDR) { + if (prev.status & FS_FO_FSFDR) { status = prev.status; len = prev.len; - + prev.status = 0; } else { - status = inb( iobase+FS_FO); - len = inb( iobase+RFLFL); - len |= inb( iobase+RFLFH) << 8; + status = inb(iobase+FS_FO); + len = inb(iobase+RFLFL); + len |= inb(iobase+RFLFH) << 8; } - while ( status & FS_FO_FSFDR) { + while (status & FS_FO_FSFDR) { /* Check for errors */ - if ( status & FS_FO_ERR_MSK) { + if (status & FS_FO_ERR_MSK) { if ( status & FS_FO_LST_FR) { /* Add number of lost frames to stats */ idev->stats.rx_errors += len; @@ -786,29 +778,28 @@ /* Skip frame */ idev->stats.rx_errors++; - idev->rx_buff.offset += len; - idev->rx_buff.head += len; + idev->rx_buff.data += len; - if ( status & FS_FO_MX_LEX) + if (status & FS_FO_MX_LEX) idev->stats.rx_length_errors++; - if ( status & FS_FO_PHY_ERR) + if (status & FS_FO_PHY_ERR) idev->stats.rx_frame_errors++; - if ( status & FS_FO_CRC_ERR) + if (status & FS_FO_CRC_ERR) idev->stats.rx_crc_errors++; } /* The errors below can be reported in both cases */ - if ( status & FS_FO_RX_OV) + if (status & FS_FO_RX_OV) idev->stats.rx_fifo_errors++; - if ( status & FS_FO_FSF_OV) + if (status & FS_FO_FSF_OV) idev->stats.rx_fifo_errors++; } else { /* Check if we have transfered all data to memory */ switch_bank(iobase, SET0); - if ( inb( iobase+USR) & USR_RDR) { + if (inb(iobase+USR) & USR_RDR) { /* Put this entry back in fifo */ prev.status = status; prev.len = len; @@ -819,31 +810,30 @@ return FALSE; /* I'll be back! */ } - skb = dev_alloc_skb( len+1); + skb = dev_alloc_skb(len+1); if (skb == NULL) { - printk( KERN_INFO __FUNCTION__ - "(), memory squeeze, dropping frame.\n"); + printk(KERN_INFO __FUNCTION__ + "(), memory squeeze, dropping frame.\n"); /* Restore set register */ - outb( set, iobase+SSR); + outb(set, iobase+SSR); return FALSE; } /* Align to 20 bytes */ - skb_reserve( skb, 1); + skb_reserve(skb, 1); /* Copy frame without CRC */ if ( idev->io.baudrate < 4000000) { skb_put( skb, len-2); - memcpy( skb->data, idev->rx_buff.head, len-2); + memcpy( skb->data, idev->rx_buff.data, len-2); } else { skb_put( skb, len-4); - memcpy( skb->data, idev->rx_buff.head, len-4); + memcpy( skb->data, idev->rx_buff.data, len-4); } /* Move to next frame */ - idev->rx_buff.offset += len; - idev->rx_buff.head += len; + idev->rx_buff.data += len; skb->dev = &idev->netdev; skb->mac.raw = skb->data; @@ -858,7 +848,7 @@ len |= inb( iobase+RFLFH) << 8; } /* Restore set register */ - outb( set, iobase+SSR); + outb(set, iobase+SSR); return TRUE; } @@ -869,28 +859,24 @@ * Receive all data in receiver FIFO * */ -static void w83977af_pio_receive( struct irda_device *idev) +static void w83977af_pio_receive(struct irda_device *idev) { __u8 byte = 0x00; int iobase; - DEBUG( 4, __FUNCTION__ "()\n"); + DEBUG(4, __FUNCTION__ "()\n"); - ASSERT( idev != NULL, return;); - ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return;); + ASSERT(idev != NULL, return;); + ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;); iobase = idev->io.iobase; - if ( idev->rx_buff.len == 0) { - idev->rx_buff.head = idev->rx_buff.data; - } - /* Receive all characters in Rx FIFO */ do { - byte = inb( iobase+RBR); - async_unwrap_char( idev, byte); + byte = inb(iobase+RBR); + async_unwrap_char(idev, byte); - } while ( inb( iobase+USR) & USR_RDR); /* Data available */ + } while (inb(iobase+USR) & USR_RDR); /* Data available */ } /* @@ -899,30 +885,29 @@ * Handle SIR interrupt * */ -static __u8 w83977af_sir_interrupt( struct irda_device *idev, int isr) +static __u8 w83977af_sir_interrupt(struct irda_device *idev, int isr) { - int len; int actual; __u8 new_icr = 0; - DEBUG( 4, __FUNCTION__ "(), isr=%#x\n", isr); + DEBUG(4, __FUNCTION__ "(), isr=%#x\n", isr); /* Transmit FIFO low on data */ - if ( isr & ISR_TXTH_I) { + if (isr & ISR_TXTH_I) { /* Write data left in transmit buffer */ - len = idev->tx_buff.len - idev->tx_buff.offset; - - ASSERT( len > 0, return 0;); - actual = w83977af_pio_write( idev->io.iobase, - idev->tx_buff.head, - len, idev->io.fifo_size); - idev->tx_buff.offset += actual; - idev->tx_buff.head += actual; + actual = w83977af_pio_write(idev->io.iobase, + idev->tx_buff.data, + idev->tx_buff.len, + idev->io.fifo_size); + idev->tx_buff.data += actual; + idev->tx_buff.len -= actual; idev->io.direction = IO_XMIT; - ASSERT( actual <= len, return 0;); + /* Check if finished */ - if ( actual == len) { + if (idev->tx_buff.len > 0) + new_icr |= ICR_ETXTHI; + else { DEBUG( 4, __FUNCTION__ "(), finished with frame!\n"); idev->netdev.tbusy = 0; /* Unlock */ idev->stats.tx_packets++; @@ -931,11 +916,11 @@ mark_bh(NET_BH); new_icr |= ICR_ETBREI; - } else - new_icr |= ICR_ETXTHI; + } + } /* Check if transmission has completed */ - if ( isr & ISR_TXEMP_I) { + if (isr & ISR_TXEMP_I) { /* Turn around and get ready to receive some data */ idev->io.direction = IO_RECV; @@ -943,8 +928,8 @@ } /* Rx FIFO threshold or timeout */ - if ( isr & ISR_RXTH_I) { - w83977af_pio_receive( idev); + if (isr & ISR_RXTH_I) { + w83977af_pio_receive(idev); /* Keep receiving */ new_icr |= ICR_ERBRI; @@ -968,64 +953,64 @@ iobase = idev->io.iobase; - set = inb( iobase+SSR); + set = inb(iobase+SSR); /* End of frame detected in FIFO */ - if ( isr & (ISR_FEND_I|ISR_FSF_I)) { - if ( w83977af_dma_receive_complete( idev)) { + if (isr & (ISR_FEND_I|ISR_FSF_I)) { + if (w83977af_dma_receive_complete(idev)) { new_icr |= ICR_EFSFI; } else { /* DMA not finished yet */ /* Set timer value, resolution 1 ms */ - switch_bank( iobase, SET4); - outb( 0x01, iobase+TMRL); /* 1 ms */ - outb( 0x00, iobase+TMRH); + switch_bank(iobase, SET4); + outb(0x01, iobase+TMRL); /* 1 ms */ + outb(0x00, iobase+TMRH); /* Start timer */ - outb( IR_MSL_EN_TMR, iobase+IR_MSL); + outb(IR_MSL_EN_TMR, iobase+IR_MSL); new_icr |= ICR_ETMRI; } } /* Timer finished */ - if ( isr & ISR_TMR_I) { + if (isr & ISR_TMR_I) { /* Disable timer */ - switch_bank( iobase, SET4); - outb( 0, iobase+IR_MSL); + switch_bank(iobase, SET4); + outb(0, iobase+IR_MSL); /* Clear timer event */ /* switch_bank(iobase, SET0); */ /* outb( ASCR_CTE, iobase+ASCR); */ /* Check if this is a TX timer interrupt */ - if ( idev->io.direction == IO_XMIT) { - w83977af_dma_write( idev, iobase); + if (idev->io.direction == IO_XMIT) { + w83977af_dma_write(idev, iobase); new_icr |= ICR_EDMAI; } else { /* Check if DMA has now finished */ - w83977af_dma_receive_complete( idev); + w83977af_dma_receive_complete(idev); new_icr |= ICR_EFSFI; } } /* Finished with DMA */ - if ( isr & ISR_DMA_I) { + if (isr & ISR_DMA_I) { w83977af_dma_xmit_complete( idev); - + /* Check if there are more frames to be transmitted */ - if ( irda_device_txqueue_empty( idev)) { + if (irda_device_txqueue_empty( idev)) { /* Prepare for receive */ - w83977af_dma_receive( idev); + w83977af_dma_receive(idev); new_icr = ICR_EFSFI; } } /* Restore set */ - outb( set, iobase+SSR); + outb(set, iobase+SSR); return new_icr; } @@ -1043,9 +1028,9 @@ struct irda_device *idev = (struct irda_device *) dev_id; - if ( idev == NULL) { - printk( KERN_WARNING "%s: irq %d for unknown device.\n", - driver_name, irq); + if (idev == NULL) { + printk(KERN_WARNING "%s: irq %d for unknown device.\n", + driver_name, irq); return; } @@ -1054,24 +1039,24 @@ iobase = idev->io.iobase; /* Save current bank */ - set = inb( iobase+SSR); - switch_bank( iobase, SET0); + set = inb(iobase+SSR); + switch_bank(iobase, SET0); - icr = inb( iobase+ICR); - isr = inb( iobase+ISR) & icr; /* Mask out the interesting ones */ + icr = inb(iobase+ICR); + isr = inb(iobase+ISR) & icr; /* Mask out the interesting ones */ - outb( 0, iobase+ICR); /* Disable interrupts */ + outb(0, iobase+ICR); /* Disable interrupts */ - if ( isr) { + if (isr) { /* Dispatch interrupt handler for the current speed */ if ( idev->io.baudrate > 115200) - icr = w83977af_fir_interrupt( idev, isr); + icr = w83977af_fir_interrupt(idev, isr); else - icr = w83977af_sir_interrupt( idev, isr); + icr = w83977af_sir_interrupt(idev, isr); } - outb( icr, iobase+ICR); /* Restore (new) interrupts */ - outb( set, iobase+SSR); /* Restore bank register */ + outb(icr, iobase+ICR); /* Restore (new) interrupts */ + outb(set, iobase+SSR); /* Restore bank register */ idev->netdev.interrupt = 0; } @@ -1082,7 +1067,7 @@ * This function should put the current thread to sleep until all data * have been sent, so it is safe to f.eks. change the speed. */ -static void w83977af_wait_until_sent( struct irda_device *idev) +static void w83977af_wait_until_sent(struct irda_device *idev) { current->state = TASK_INTERRUPTIBLE; schedule_timeout(6); @@ -1094,7 +1079,7 @@ * Return TRUE is we are currently receiving a frame * */ -static int w83977af_is_receiving( struct irda_device *idev) +static int w83977af_is_receiving(struct irda_device *idev) { int status = FALSE; int iobase; @@ -1107,15 +1092,15 @@ iobase = idev->io.iobase; /* Check if rx FIFO is not empty */ - set = inb( iobase+SSR); + set = inb(iobase+SSR); switch_bank( iobase, SET2); if (( inb( iobase+RXFDTH) & 0x3f) != 0) { /* We are receiving something */ status = TRUE; } - outb( set, iobase+SSR); + outb(set, iobase+SSR); } else - status = ( idev->rx_buff.state != OUTSIDE_FRAME); + status = (idev->rx_buff.state != OUTSIDE_FRAME); return status; } @@ -1128,7 +1113,7 @@ */ static int w83977af_net_init( struct device *dev) { - DEBUG( 0, __FUNCTION__ "()\n"); + DEBUG(0, __FUNCTION__ "()\n"); /* Set up to be a normal IrDA network device driver */ irda_device_setup( dev); @@ -1151,18 +1136,18 @@ int iobase; __u8 set; - DEBUG( 0, __FUNCTION__ "()\n"); + DEBUG(0, __FUNCTION__ "()\n"); - ASSERT( dev != NULL, return -1;); + ASSERT(dev != NULL, return -1;); idev = (struct irda_device *) dev->priv; - ASSERT( idev != NULL, return 0;); - ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return 0;); + ASSERT(idev != NULL, return 0;); + ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return 0;); iobase = idev->io.iobase; - if (request_irq( idev->io.irq, w83977af_interrupt, 0, idev->name, - (void *) idev)) { + if (request_irq(idev->io.irq, w83977af_interrupt, 0, idev->name, + (void *) idev)) { return -EAGAIN; } /* @@ -1170,7 +1155,7 @@ * and clean up on failure. */ if (request_dma(idev->io.dma, idev->name)) { - free_irq( idev->io.irq, idev); + free_irq(idev->io.irq, idev); return -EAGAIN; } @@ -1180,11 +1165,11 @@ dev->start = 1; /* Save current set */ - set = inb( iobase+SSR); + set = inb(iobase+SSR); /* Enable some interrupts so we can receive frames again */ switch_bank(iobase, SET0); - if ( idev->io.baudrate > 115200) { + if (idev->io.baudrate > 115200) { outb( ICR_EFSFI, iobase+ICR); w83977af_dma_receive( idev); } else @@ -1254,9 +1239,7 @@ */ int init_module(void) { - w83977af_init(); - - return(0); + return w83977af_init(); } /* @@ -1269,5 +1252,4 @@ { w83977af_cleanup(); } - -#endif +#endif /* MODULE */ diff -ur --new-file old/linux/drivers/net/mace.c new/linux/drivers/net/mace.c --- old/linux/drivers/net/mace.c Sun Oct 4 19:21:00 1998 +++ new/linux/drivers/net/mace.c Thu Mar 11 06:48:46 1999 @@ -4,6 +4,12 @@ * * Copyright (C) 1996 Paul Mackerras. */ + +#ifdef MODULE +#include +#include +#endif + #include #include #include @@ -16,6 +22,10 @@ #include #include "mace.h" +#ifdef MODULE +static struct device *mace_devs = NULL; +#endif + #define N_RX_RING 8 #define N_TX_RING 6 #define MAX_TX_ACTIVE 1 @@ -71,6 +81,9 @@ static void mace_rxdma_intr(int irq, void *dev_id, struct pt_regs *regs); static void mace_set_timeout(struct device *dev); static void mace_tx_timeout(unsigned long data); +static inline void dbdma_reset(volatile struct dbdma_regs *dma); +static inline void mace_clean_rings(struct mace_data *mp); +static void __mace_set_address(struct device *dev, void *addr); /* * If we can't get a skbuff when we need it, we use this area for DMA. @@ -78,7 +91,7 @@ static unsigned char dummy_buf[RX_BUFLEN+2]; /* Bit-reverse one byte of an ethernet hardware address. */ -static int +static inline int bitrev(int b) { int d = 0, i; @@ -144,7 +157,8 @@ dev->dev_addr[j] = rev? bitrev(addr[j]): addr[j]; printk("%c%.2x", (j? ':': ' '), dev->dev_addr[j]); } - printk("\n"); + printk(", chip revision %d.%d\n", + in_8(&mp->mace->chipid_hi), in_8(&mp->mace->chipid_lo)); mp = (struct mace_data *) dev->priv; mp->maccc = ENXMT | ENRCV; @@ -193,6 +207,21 @@ return 0; } +static void dbdma_reset(volatile struct dbdma_regs *dma) +{ + int i; + + out_le32(&dma->control, (WAKE|FLUSH|PAUSE|RUN) << 16); + + /* + * Yes this looks peculiar, but apparently it needs to be this + * way on some machines. + */ + for (i = 200; i > 0; --i) + if (ld_le32(&dma->control) & RUN) + udelay(1); +} + static void mace_reset(struct device *dev) { struct mace_data *mp = (struct mace_data *) dev->priv; @@ -203,14 +232,14 @@ i = 200; while (--i) { out_8(&mb->biucc, SWRST); - if (mb->biucc & SWRST) { - udelay(20); + if (in_8(&mb->biucc) & SWRST) { + udelay(10); continue; } break; } if (!i) { - printk("mace: cannot reset chip!\n"); + printk(KERN_ERR "mace: cannot reset chip!\n"); return; } @@ -218,19 +247,14 @@ i = in_8(&mb->ir); out_8(&mb->maccc, 0); /* turn off tx, rx */ - mb->biucc = XMTSP_64; - mb->utr = RTRD; - mb->fifocc = RCVFW_32 | XMTFW_16 | XMTFWU | RCVFWU | XMTBRST; - mb->xmtfc = AUTO_PAD_XMIT; /* auto-pad short frames */ - mb->rcvfc = 0; + out_8(&mb->biucc, XMTSP_64); + out_8(&mb->utr, RTRD); + out_8(&mb->fifocc, RCVFW_32 | XMTFW_16 | XMTFWU | RCVFWU | XMTBRST); + out_8(&mb->xmtfc, AUTO_PAD_XMIT); /* auto-pad short frames */ + out_8(&mb->rcvfc, 0); /* load up the hardware address */ - out_8(&mb->iac, ADDRCHG | PHYADDR); - while ((in_8(&mb->iac) & ADDRCHG) != 0) - ; - for (i = 0; i < 6; ++i) { - out_8(&mb->padr, dev->dev_addr[i]); - } + __mace_set_address(dev, dev->dev_addr); /* clear the multicast filter */ out_8(&mb->iac, ADDRCHG | LOGADDR); @@ -245,23 +269,30 @@ out_8(&mb->plscc, PORTSEL_GPSI + ENPLSIO); } -static int mace_set_address(struct device *dev, void *addr) +static void __mace_set_address(struct device *dev, void *addr) { + volatile struct mace *mb = ((struct mace_data *) dev->priv)->mace; unsigned char *p = addr; - struct mace_data *mp = (struct mace_data *) dev->priv; - volatile struct mace *mb = mp->mace; int i; - unsigned long flags; - - save_flags(flags); cli(); /* load up the hardware address */ out_8(&mb->iac, ADDRCHG | PHYADDR); while ((in_8(&mb->iac) & ADDRCHG) != 0) ; - for (i = 0; i < 6; ++i) { + for (i = 0; i < 6; ++i) out_8(&mb->padr, dev->dev_addr[i] = p[i]); - } +} + +static int mace_set_address(struct device *dev, void *addr) +{ + struct mace_data *mp = (struct mace_data *) dev->priv; + volatile struct mace *mb = mp->mace; + unsigned long flags; + + save_flags(flags); cli(); + + __mace_set_address(dev, addr); + out_8(&mb->iac, 0); /* note: setting ADDRCHG clears ENRCV */ out_8(&mb->maccc, mp->maccc); @@ -285,6 +316,7 @@ mace_reset(dev); /* initialize list of sk_buffs for receiving and set up recv dma */ + mace_clean_rings(mp); memset((char *)mp->rx_cmds, 0, N_RX_RING * sizeof(struct dbdma_cmd)); cp = mp->rx_cmds; for (i = 0; i < N_RX_RING - 1; ++i) { @@ -335,25 +367,17 @@ out_8(&mb->maccc, mp->maccc); /* enable all interrupts except receive interrupts */ out_8(&mb->imr, RCVINT); + +#ifdef MOD_INC_USE_COUNT + MOD_INC_USE_COUNT; +#endif return 0; } -static int mace_close(struct device *dev) +static inline void mace_clean_rings(struct mace_data *mp) { - struct mace_data *mp = (struct mace_data *) dev->priv; - volatile struct mace *mb = mp->mace; - volatile struct dbdma_regs *rd = mp->rx_dma; - volatile struct dbdma_regs *td = mp->tx_dma; int i; - /* disable rx and tx */ - mb->maccc = 0; - mb->imr = 0xff; /* disable all intrs */ - - /* disable rx and tx dma */ - st_le32(&rd->control, (RUN|PAUSE|FLUSH|WAKE) << 16); /* clear run bit */ - st_le32(&td->control, (RUN|PAUSE|FLUSH|WAKE) << 16); /* clear run bit */ - /* free some skb's */ for (i = 0; i < N_RX_RING; ++i) { if (mp->rx_bufs[i] != 0) { @@ -366,6 +390,28 @@ if (++i >= N_TX_RING) i = 0; } +} + +static int mace_close(struct device *dev) +{ + struct mace_data *mp = (struct mace_data *) dev->priv; + volatile struct mace *mb = mp->mace; + volatile struct dbdma_regs *rd = mp->rx_dma; + volatile struct dbdma_regs *td = mp->tx_dma; + + /* disable rx and tx */ + out_8(&mb->maccc, 0); + out_8(&mb->imr, 0xff); /* disable all intrs */ + + /* disable rx and tx dma */ + st_le32(&rd->control, (RUN|PAUSE|FLUSH|WAKE) << 16); /* clear run bit */ + st_le32(&td->control, (RUN|PAUSE|FLUSH|WAKE) << 16); /* clear run bit */ + + mace_clean_rings(mp); + +#ifdef MOD_DEC_USE_COUNT + MOD_DEC_USE_COUNT; +#endif return 0; } @@ -517,10 +563,10 @@ if (intr & MPCO) mp->stats.rx_missed_errors += 256; - mp->stats.rx_missed_errors += mb->mpc; /* reading clears it */ + mp->stats.rx_missed_errors += in_8(&mb->mpc); /* reading clears it */ if (intr & RNTPCO) mp->stats.rx_length_errors += 256; - mp->stats.rx_length_errors += mb->rntpc; /* reading clears it */ + mp->stats.rx_length_errors += in_8(&mb->rntpc); /* reading clears it */ if (intr & CERR) ++mp->stats.tx_heartbeat_errors; if (intr & BABBLE) @@ -547,7 +593,7 @@ mace_handle_misc_intrs(mp, intr); i = mp->tx_empty; - while (mb->pr & XMTSV) { + while (in_8(&mb->pr) & XMTSV) { del_timer(&mp->tx_timeout); mp->timeout_active = 0; /* @@ -555,13 +601,13 @@ * word. This appears to unlatch any error indication from * the DMA controller. */ - intr = mb->ir; + intr = in_8(&mb->ir); if (intr != 0) mace_handle_misc_intrs(mp, intr); if (mp->tx_bad_runt) { fs = in_8(&mb->xmtfs); mp->tx_bad_runt = 0; - mb->xmtfc = AUTO_PAD_XMIT; + out_8(&mb->xmtfc, AUTO_PAD_XMIT); continue; } dstat = ld_le32(&td->status); @@ -571,7 +617,7 @@ * xcount is the number of complete frames which have been * written to the fifo but for which status has not been read. */ - xcount = (mb->fifofc >> XMTFC_SH) & XMTFC_MASK; + xcount = (in_8(&mb->fifofc) >> XMTFC_SH) & XMTFC_MASK; if (xcount == 0 || (dstat & DEAD)) { /* * If a packet was aborted before the DMA controller has @@ -586,11 +632,15 @@ */ out_8(&mb->xmtfc, DXMTFCS); } - fs = mb->xmtfs; + fs = in_8(&mb->xmtfs); if ((fs & XMTSV) == 0) { printk(KERN_ERR "mace: xmtfs not valid! (fs=%x xc=%d ds=%x)\n", fs, xcount, dstat); - return; + mace_reset(dev); + /* + * XXX mace likes to hang the machine after a xmtfs error. + * This is hard to reproduce, reseting *may* help + */ } cp = mp->tx_cmds + NCMDS_TX * i; stat = ld_le16(&cp->xfer_status); @@ -600,7 +650,7 @@ * the transmit FIFO. */ udelay(1); - x = (mb->fifofc >> XMTFC_SH) & XMTFC_MASK; + x = (in_8(&mb->fifofc) >> XMTFC_SH) & XMTFC_MASK; if (x != 0) { /* there were two bytes with an end-of-packet indication */ mp->tx_bad_runt = 1; @@ -612,10 +662,10 @@ * We flush the transmit FIFO just in case (by setting the * XMTFWU bit with the transmitter disabled). */ - out_8(&mb->maccc, mb->maccc & ~ENXMT); - out_8(&mb->fifocc, mb->fifocc | XMTFWU); + out_8(&mb->maccc, in_8(&mb->maccc) & ~ENXMT); + out_8(&mb->fifocc, in_8(&mb->fifocc) | XMTFWU); udelay(1); - out_8(&mb->maccc, mb->maccc | ENXMT); + out_8(&mb->maccc, in_8(&mb->maccc) | ENXMT); out_8(&mb->xmtfc, AUTO_PAD_XMIT); } } @@ -632,7 +682,7 @@ ++mp->stats.tx_carrier_errors; if (fs & (UFLO|LCOL|RTRY)) ++mp->stats.tx_aborted_errors; - } else + } else ++mp->stats.tx_packets; dev_kfree_skb(mp->tx_bufs[i]); --mp->tx_active; @@ -686,19 +736,19 @@ goto out; /* update various counters */ - mace_handle_misc_intrs(mp, mb->ir); + mace_handle_misc_intrs(mp, in_8(&mb->ir)); cp = mp->tx_cmds + NCMDS_TX * mp->tx_empty; /* turn off both tx and rx and reset the chip */ out_8(&mb->maccc, 0); - out_le32(&td->control, (RUN|PAUSE|FLUSH|WAKE) << 16); printk(KERN_ERR "mace: transmit timeout - resetting\n"); + dbdma_reset(td); mace_reset(dev); /* restart rx dma */ cp = bus_to_virt(ld_le32(&rd->cmdptr)); - out_le32(&rd->control, (RUN|PAUSE|FLUSH|WAKE) << 16); + dbdma_reset(rd); out_le16(&cp->xfer_status, 0); out_le32(&rd->cmdptr, virt_to_bus(cp)); out_le32(&rd->control, (RUN << 16) | RUN); @@ -786,8 +836,8 @@ ++mp->stats.rx_crc_errors; } else { /* Mace feature AUTO_STRIP_RCV is on by default, dropping the - * FCS on frames with 802.3 headers. This means that Ethernet - * frames have 8 extra octets at the end, while 802.3 frames + * FCS on frames with 802.3 headers. This means that Ethernet + * frames have 8 extra octets at the end, while 802.3 frames * have only 4. We need to correctly account for this. */ if (*(unsigned short *)(data+12) < 1536) /* 802.3 header */ nb -= 4; @@ -846,3 +896,35 @@ mp->rx_fill = i; } } + +#ifdef MODULE + +#if LINUX_VERSION_CODE > 0x20118 +MODULE_AUTHOR("Paul Mackerras"); +MODULE_DESCRIPTION("PowerMac MACE driver."); +#endif + +int init_module(void) +{ + int res; + + if(mace_devs != NULL) + return -EBUSY; + res = mace_probe(NULL); + return res; +} + +void cleanup_module(void) +{ + struct mace_data *mp = (struct mace_data *) mace_devs->priv; + unregister_netdev(mace_devs); + + free_irq(mace_devs->irq, mace_interrupt); + free_irq(mp->tx_dma_intr, mace_txdma_intr); + free_irq(mp->rx_dma_intr, mace_rxdma_intr); + + kfree(mace_devs); + mace_devs = NULL; +} + +#endif diff -ur --new-file old/linux/drivers/net/myri_sbus.c new/linux/drivers/net/myri_sbus.c --- old/linux/drivers/net/myri_sbus.c Mon Jul 27 08:35:56 1998 +++ new/linux/drivers/net/myri_sbus.c Fri Mar 26 22:57:41 1999 @@ -34,7 +34,6 @@ #include #include #include -#include #include #include @@ -278,7 +277,7 @@ mp->rx_skbs[i] = skb; skb->dev = dev; skb_put(skb, RX_ALLOC_SIZE); - rxd[i].myri_scatters[0].addr = (u32) ((unsigned long)skb->data); + rxd[i].myri_scatters[0].addr = sbus_dvma_addr(skb->data); rxd[i].myri_scatters[0].len = RX_ALLOC_SIZE; rxd[i].ctx = i; rxd[i].num_sg = 1; @@ -340,12 +339,6 @@ dev_kfree_skb(skb); mp->tx_skbs[entry] = NULL; mp->enet_stats.tx_packets++; - -#ifdef NEED_DMA_SYNCHRONIZATION - mmu_sync_dma(((u32)((unsigned long)skb->data)), - skb->len, mp->myri_sbus_dev->my_bus); -#endif - entry = NEXT_TX(entry); } mp->tx_old = entry; @@ -437,8 +430,7 @@ drops++; DRX(("DROP ")); mp->enet_stats.rx_dropped++; - rxd->myri_scatters[0].addr = - (u32) ((unsigned long)skb->data); + rxd->myri_scatters[0].addr = sbus_dvma_addr(skb->data); rxd->myri_scatters[0].len = RX_ALLOC_SIZE; rxd->ctx = index; rxd->num_sg = 1; @@ -447,7 +439,7 @@ } #ifdef NEED_DMA_SYNCHRONIZATION - mmu_sync_dma(((u32)((unsigned long)skb->data)), + mmu_sync_dma(sbus_dvma_addr(skb->data), skb->len, mp->myri_sbus_dev->my_bus); #endif @@ -464,8 +456,7 @@ mp->rx_skbs[index] = new_skb; new_skb->dev = dev; skb_put(new_skb, RX_ALLOC_SIZE); - rxd->myri_scatters[0].addr = - (u32) ((unsigned long)new_skb->data); + rxd->myri_scatters[0].addr = sbus_dvma_addr(new_skb->data); rxd->myri_scatters[0].len = RX_ALLOC_SIZE; rxd->ctx = index; rxd->num_sg = 1; @@ -489,8 +480,7 @@ /* Reuse original ring buffer. */ DRX(("reuse ")); - rxd->myri_scatters[0].addr = - (u32) ((unsigned long)skb->data); + rxd->myri_scatters[0].addr = sbus_dvma_addr(skb->data); rxd->myri_scatters[0].len = RX_ALLOC_SIZE; rxd->ctx = index; rxd->num_sg = 1; @@ -600,6 +590,12 @@ return 1; } + +#ifdef NEED_DMA_SYNCHRONIZATION + mmu_sync_dma(sbus_dvma_addr(skb->data), + skb->len, mp->myri_sbus_dev->my_bus); +#endif + /* This is just to prevent multiple PIO reads for TX_BUFFS_AVAIL. */ head = sq->head; tail = sq->tail; @@ -628,8 +624,7 @@ txd = &sq->myri_txd[entry]; mp->tx_skbs[entry] = skb; - txd->myri_gathers[0].addr = - (unsigned int) ((unsigned long)skb->data); + txd->myri_gathers[0].addr = sbus_dvma_addr(skb->data); txd->myri_gathers[0].len = len; txd->num_sg = 1; txd->chan = KERNEL_CHANNEL; diff -ur --new-file old/linux/drivers/net/ne.c new/linux/drivers/net/ne.c --- old/linux/drivers/net/ne.c Wed Dec 16 22:35:49 1998 +++ new/linux/drivers/net/ne.c Mon Mar 8 00:47:46 1999 @@ -105,6 +105,7 @@ {"ET-100","ET-200", {0x00, 0x45, 0x54}}, /* YANG and YA clone */ {"COMPEX","COMPEX16",{0x00,0x80,0x48}}, /* Broken ISA Compex cards */ {"E-LAN100", "E-LAN200", {0x00, 0x00, 0x5d}}, /* Broken ne1000 clones */ + {"PCM-4823", "PCM-4823", {0x00, 0xc0, 0x6c}}, /* Broken Advantech MoBo */ {0,} }; #endif diff -ur --new-file old/linux/drivers/net/ne2.c new/linux/drivers/net/ne2.c --- old/linux/drivers/net/ne2.c Thu Jan 7 18:21:53 1999 +++ new/linux/drivers/net/ne2.c Thu Mar 11 01:51:35 1999 @@ -75,7 +75,6 @@ #include #include #include -#include #include #include diff -ur --new-file old/linux/drivers/net/net_init.c new/linux/drivers/net/net_init.c --- old/linux/drivers/net/net_init.c Fri Dec 18 18:40:15 1998 +++ new/linux/drivers/net/net_init.c Sun Apr 25 02:51:48 1999 @@ -252,6 +252,22 @@ return dev; } + +void unregister_hipdev(struct device *dev) +{ + int i; + rtnl_lock(); + unregister_netdevice(dev); + for (i = 0; i < MAX_HIP_CARDS; ++i) { + if (hipdev_index[i] == dev) { + hipdev_index[i] = NULL; + break; + } + } + rtnl_unlock(); +} + + static int hippi_neigh_setup_dev(struct device *dev, struct neigh_parms *p) { /* Never send broadcast/multicast ARP messages */ diff -ur --new-file old/linux/drivers/net/pcnet32.c new/linux/drivers/net/pcnet32.c --- old/linux/drivers/net/pcnet32.c Mon Jan 18 03:28:06 1999 +++ new/linux/drivers/net/pcnet32.c Sun Apr 25 02:51:48 1999 @@ -13,7 +13,7 @@ * This driver is for PCnet32 and PCnetPCI based ethercards */ -static const char *version = "pcnet32.c:v1.11 17.1.99 tsbogend@alpha.franken.de\n"; +static const char *version = "pcnet32.c:v1.21 31.3.99 tsbogend@alpha.franken.de\n"; #include #include @@ -58,9 +58,36 @@ #define PORT_PORTSEL 0x03 #define PORT_ASEL 0x04 +#define PORT_100 0x40 #define PORT_FD 0x80 -static int options = PORT_ASEL; /* port selection */ + +/* + * table to translate option values from tulip + * to internal options + */ +static unsigned char options_mapping[] = { + PORT_ASEL, /* 0 Auto-select */ + PORT_AUI, /* 1 BNC/AUI */ + PORT_AUI, /* 2 AUI/BNC */ + PORT_ASEL, /* 3 not supported */ + PORT_10BT | PORT_FD, /* 4 10baseT-FD */ + PORT_ASEL, /* 5 not supported */ + PORT_ASEL, /* 6 not supported */ + PORT_ASEL, /* 7 not supported */ + PORT_ASEL, /* 8 not supported */ + PORT_MII, /* 9 MII 10baseT */ + PORT_MII | PORT_FD, /* 10 MII 10baseT-FD */ + PORT_MII, /* 11 MII (autosel) */ + PORT_10BT, /* 12 10BaseT */ + PORT_MII | PORT_100, /* 13 MII 100BaseTx */ + PORT_MII | PORT_100 | PORT_FD, /* 14 MII 100BaseTx-FD */ + PORT_ASEL /* 15 not supported */ +}; + +#define MAX_UNITS 8 +static int options[MAX_UNITS] = {0, }; +static int full_duplex[MAX_UNITS] = {0, }; /* * Theory of Operation @@ -116,6 +143,12 @@ * added port selection for modules * detect special T1/E1 WAN card and setup port selection * v1.11: fixed wrong checking of Tx errors + * v1.20: added check of return value kmalloc (cpeterso@cs.washington.edu) + * added save original kmalloc addr for freeing (mcr@solidum.com) + * added support for PCnetHome chip (joe@MIT.EDU) + * rewritten PCI card detection + * added dwio mode to get driver working on some PPC machines + * v1.21: added mii selection and mii ioctl */ @@ -140,202 +173,402 @@ #define PKT_BUF_SZ 1544 /* Offsets from base I/O address. */ -#define PCNET32_DATA 0x10 -#define PCNET32_ADDR 0x12 -#define PCNET32_RESET 0x14 -#define PCNET32_BUS_IF 0x16 -#define PCNET32_TOTAL_SIZE 0x18 +#define PCNET32_WIO_RDP 0x10 +#define PCNET32_WIO_RAP 0x12 +#define PCNET32_WIO_RESET 0x14 +#define PCNET32_WIO_BDP 0x16 + +#define PCNET32_DWIO_RDP 0x10 +#define PCNET32_DWIO_RAP 0x14 +#define PCNET32_DWIO_RESET 0x18 +#define PCNET32_DWIO_BDP 0x1C + +#define PCNET32_TOTAL_SIZE 0x20 #define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */ /* The PCNET32 Rx and Tx ring descriptors. */ struct pcnet32_rx_head { - u32 base; - s16 buf_length; - s16 status; - u32 msg_length; - u32 reserved; + u32 base; + s16 buf_length; + s16 status; + u32 msg_length; + u32 reserved; }; struct pcnet32_tx_head { - u32 base; - s16 length; - s16 status; - u32 misc; - u32 reserved; + u32 base; + s16 length; + s16 status; + u32 misc; + u32 reserved; }; - /* The PCNET32 32-Bit initialization block, described in databook. */ struct pcnet32_init_block { - u16 mode; - u16 tlen_rlen; - u8 phys_addr[6]; - u16 reserved; - u32 filter[2]; - /* Receive and transmit ring base, along with extra bits. */ - u32 rx_ring; - u32 tx_ring; + u16 mode; + u16 tlen_rlen; + u8 phys_addr[6]; + u16 reserved; + u32 filter[2]; + /* Receive and transmit ring base, along with extra bits. */ + u32 rx_ring; + u32 tx_ring; +}; + +/* PCnet32 access functions */ +struct pcnet32_access { + u16 (*read_csr)(unsigned long, int); + void (*write_csr)(unsigned long, int, u16); + u16 (*read_bcr)(unsigned long, int); + void (*write_bcr)(unsigned long, int, u16); + u16 (*read_rap)(unsigned long); + void (*write_rap)(unsigned long, u16); + void (*reset)(unsigned long); }; struct pcnet32_private { - /* The Tx and Rx ring entries must be aligned on 16-byte boundaries in 32bit mode. */ - struct pcnet32_rx_head rx_ring[RX_RING_SIZE]; - struct pcnet32_tx_head tx_ring[TX_RING_SIZE]; - struct pcnet32_init_block init_block; - const char *name; - /* The saved address of a sent-in-place packet/buffer, for skfree(). */ - struct sk_buff *tx_skbuff[TX_RING_SIZE]; - struct sk_buff *rx_skbuff[RX_RING_SIZE]; - int cur_rx, cur_tx; /* The next free ring entry */ - int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */ - struct net_device_stats stats; - char tx_full; - int options; - int shared_irq:1, /* shared irq possible */ - full_duplex:1; /* full duplex possible */ + /* The Tx and Rx ring entries must be aligned on 16-byte boundaries in 32bit mode. */ + struct pcnet32_rx_head rx_ring[RX_RING_SIZE]; + struct pcnet32_tx_head tx_ring[TX_RING_SIZE]; + struct pcnet32_init_block init_block; + const char *name; + /* The saved address of a sent-in-place packet/buffer, for skfree(). */ + struct sk_buff *tx_skbuff[TX_RING_SIZE]; + struct sk_buff *rx_skbuff[RX_RING_SIZE]; + struct pcnet32_access a; + void *origmem; + int cur_rx, cur_tx; /* The next free ring entry */ + int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */ + struct net_device_stats stats; + char tx_full; + int options; + int shared_irq:1, /* shared irq possible */ + full_duplex:1, /* full duplex possible */ + mii:1; /* mii port available */ #ifdef MODULE - struct device *next; + struct device *next; #endif }; -int pcnet32_probe(struct device *dev); -static int pcnet32_probe1(struct device *dev, unsigned int ioaddr, unsigned char irq_line, int shared); -static int pcnet32_open(struct device *dev); -static int pcnet32_init_ring(struct device *dev); -static int pcnet32_start_xmit(struct sk_buff *skb, struct device *dev); -static int pcnet32_rx(struct device *dev); -static void pcnet32_interrupt(int irq, void *dev_id, struct pt_regs *regs); -static int pcnet32_close(struct device *dev); -static struct net_device_stats *pcnet32_get_stats(struct device *dev); -static void pcnet32_set_multicast_list(struct device *dev); +int pcnet32_probe(struct device *); +static int pcnet32_probe1(struct device *, unsigned long, unsigned char, int, int); +static int pcnet32_open(struct device *); +static int pcnet32_init_ring(struct device *); +static int pcnet32_start_xmit(struct sk_buff *, struct device *); +static int pcnet32_rx(struct device *); +static void pcnet32_interrupt(int, void *, struct pt_regs *); +static int pcnet32_close(struct device *); +static struct net_device_stats *pcnet32_get_stats(struct device *); +static void pcnet32_set_multicast_list(struct device *); +#ifdef HAVE_PRIVATE_IOCTL +static int pcnet32_mii_ioctl(struct device *, struct ifreq *, int); +#endif + +enum pci_flags_bit { + PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4, + PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3, +}; + +struct pcnet32_pci_id_info { + const char *name; + u16 vendor_id, device_id, device_id_mask, flags; + int io_size; + int (*probe1) (struct device *, unsigned long, unsigned char, int, int); +}; + +static struct pcnet32_pci_id_info pcnet32_tbl[] = { + { "AMD PCnetPCI series", + 0x1022, 0x2000, 0xfffe, PCI_USES_IO|PCI_USES_MASTER, PCNET32_TOTAL_SIZE, + pcnet32_probe1}, + {0,} +}; + +static u16 pcnet32_wio_read_csr (unsigned long addr, int index) +{ + outw (index, addr+PCNET32_WIO_RAP); + return inw (addr+PCNET32_WIO_RDP); +} + +static void pcnet32_wio_write_csr (unsigned long addr, int index, u16 val) +{ + outw (index, addr+PCNET32_WIO_RAP); + outw (val, addr+PCNET32_WIO_RDP); +} + +static u16 pcnet32_wio_read_bcr (unsigned long addr, int index) +{ + outw (index, addr+PCNET32_WIO_RAP); + return inw (addr+PCNET32_WIO_BDP); +} + +static void pcnet32_wio_write_bcr (unsigned long addr, int index, u16 val) +{ + outw (index, addr+PCNET32_WIO_RAP); + outw (val, addr+PCNET32_WIO_BDP); +} + +static u16 pcnet32_wio_read_rap (unsigned long addr) +{ + return inw (addr+PCNET32_WIO_RAP); +} + +static void pcnet32_wio_write_rap (unsigned long addr, u16 val) +{ + outw (val, addr+PCNET32_WIO_RAP); +} + +static void pcnet32_wio_reset (unsigned long addr) +{ + inw (addr+PCNET32_WIO_RESET); +} + +static int pcnet32_wio_check (unsigned long addr) +{ + outw (88, addr+PCNET32_WIO_RAP); + return (inw (addr+PCNET32_WIO_RAP) == 88); +} + +static struct pcnet32_access pcnet32_wio = { + pcnet32_wio_read_csr, + pcnet32_wio_write_csr, + pcnet32_wio_read_bcr, + pcnet32_wio_write_bcr, + pcnet32_wio_read_rap, + pcnet32_wio_write_rap, + pcnet32_wio_reset +}; + +static u16 pcnet32_dwio_read_csr (unsigned long addr, int index) +{ + outl (index, addr+PCNET32_DWIO_RAP); + return (inl (addr+PCNET32_DWIO_RDP) & 0xffff); +} + +static void pcnet32_dwio_write_csr (unsigned long addr, int index, u16 val) +{ + outl (index, addr+PCNET32_DWIO_RAP); + outl (val, addr+PCNET32_DWIO_RDP); +} + +static u16 pcnet32_dwio_read_bcr (unsigned long addr, int index) +{ + outl (index, addr+PCNET32_DWIO_RAP); + return (inl (addr+PCNET32_DWIO_BDP) & 0xffff); +} + +static void pcnet32_dwio_write_bcr (unsigned long addr, int index, u16 val) +{ + outl (index, addr+PCNET32_DWIO_RAP); + outl (val, addr+PCNET32_DWIO_BDP); +} + +static u16 pcnet32_dwio_read_rap (unsigned long addr) +{ + return (inl (addr+PCNET32_DWIO_RAP) & 0xffff); +} + +static void pcnet32_dwio_write_rap (unsigned long addr, u16 val) +{ + outl (val, addr+PCNET32_DWIO_RAP); +} + +static void pcnet32_dwio_reset (unsigned long addr) +{ + inl (addr+PCNET32_DWIO_RESET); +} + +static int pcnet32_dwio_check (unsigned long addr) +{ + outl (88, addr+PCNET32_DWIO_RAP); + return (inl (addr+PCNET32_DWIO_RAP) == 88); +} + +static struct pcnet32_access pcnet32_dwio = { + pcnet32_dwio_read_csr, + pcnet32_dwio_write_csr, + pcnet32_dwio_read_bcr, + pcnet32_dwio_write_bcr, + pcnet32_dwio_read_rap, + pcnet32_dwio_write_rap, + pcnet32_dwio_reset + +}; -__initfunc(int pcnet32_probe (struct device *dev)) +int __init pcnet32_probe (struct device *dev) { - unsigned int ioaddr = dev ? dev->base_addr: 0; + unsigned long ioaddr = dev ? dev->base_addr: 0; unsigned int irq_line = dev ? dev->irq : 0; int *port; + int cards_found = 0; - if (ioaddr > 0x1ff) - return pcnet32_probe1(dev, ioaddr, irq_line, 0); - else if(ioaddr != 0) - return ENXIO; + +#ifndef __powerpc__ + if (ioaddr > 0x1ff) { + if (check_region(ioaddr, PCNET32_TOTAL_SIZE) == 0) + return pcnet32_probe1(dev, ioaddr, irq_line, 0, 0); + else + return ENODEV; + } else +#endif + if(ioaddr != 0) + return ENXIO; #if defined(CONFIG_PCI) if (pci_present()) { - struct pci_dev *pdev = NULL; + struct pci_dev *pdev; + unsigned char pci_bus, pci_device_fn; + int pci_index; printk("pcnet32.c: PCI bios is present, checking for devices...\n"); - while ((pdev = pci_find_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE, pdev))) { - unsigned short pci_command; + for (pci_index = 0; pci_index < 0xff; pci_index++) { + u16 vendor, device, pci_command; + int chip_idx; - irq_line = pdev->irq; + if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8, + pci_index, &pci_bus, &pci_device_fn) != PCIBIOS_SUCCESSFUL) + break; + + pcibios_read_config_word(pci_bus, pci_device_fn, PCI_VENDOR_ID, &vendor); + pcibios_read_config_word(pci_bus, pci_device_fn, PCI_DEVICE_ID, &device); + + for (chip_idx = 0; pcnet32_tbl[chip_idx].vendor_id; chip_idx++) + if (vendor == pcnet32_tbl[chip_idx].vendor_id && + (device & pcnet32_tbl[chip_idx].device_id_mask) == pcnet32_tbl[chip_idx].device_id) + break; + if (pcnet32_tbl[chip_idx].vendor_id == 0) + continue; + + pdev = pci_find_slot(pci_bus, pci_device_fn); ioaddr = pdev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK; +#if defined(ADDR_64BITS) && defined(__alpha__) + ioaddr |= ((long)pdev->base_address[1]) << 32; +#endif + irq_line = pdev->irq; + + /* Avoid already found cards from previous pcnet32_probe() calls */ + if ((pcnet32_tbl[chip_idx].flags & PCI_USES_IO) && + check_region(ioaddr, pcnet32_tbl[chip_idx].io_size)) + continue; + /* PCI Spec 2.1 states that it is either the driver or PCI card's * responsibility to set the PCI Master Enable Bit if needed. * (From Mark Stockton ) */ pci_read_config_word(pdev, PCI_COMMAND, &pci_command); - - /* Avoid already found cards from previous pcnet32_probe() calls */ - if (check_region(ioaddr, PCNET32_TOTAL_SIZE)) - continue; - if ( ! (pci_command & PCI_COMMAND_MASTER)) { printk("PCI Master Bit has not been set. Setting...\n"); pci_command |= PCI_COMMAND_MASTER|PCI_COMMAND_IO; pci_write_config_word(pdev, PCI_COMMAND, pci_command); } + printk("Found PCnet/PCI at %#lx, irq %d.\n", ioaddr, irq_line); - printk("Found PCnet/PCI at %#x, irq %d.\n", - ioaddr, irq_line); - - if (pcnet32_probe1(dev, ioaddr, irq_line, 1) != 0) { /* Shouldn't happen. */ - printk(KERN_ERR "pcnet32.c: Probe of PCI card at %#x failed.\n", ioaddr); - break; + if (pcnet32_tbl[chip_idx].probe1(dev, ioaddr, irq_line, 1, cards_found) == 0) { + cards_found++; + dev = NULL; } - return 0; } } else #endif /* defined(CONFIG_PCI) */ /* now look for PCnet32 VLB cards */ for (port = pcnet32_portlist; *port; port++) { - unsigned int ioaddr = *port; + unsigned long ioaddr = *port; if ( check_region(ioaddr, PCNET32_TOTAL_SIZE) == 0) { /* check if there is really a pcnet chip on that ioaddr */ if ((inb(ioaddr + 14) == 0x57) && (inb(ioaddr + 15) == 0x57) && - (pcnet32_probe1(dev, ioaddr, 0, 0) == 0)) - return 0; + (pcnet32_probe1(dev, ioaddr, 0, 0, 0) == 0)) + cards_found++; } } - return ENODEV; + return cards_found ? 0: ENODEV; } /* pcnet32_probe1 */ -__initfunc(static int pcnet32_probe1(struct device *dev, unsigned int ioaddr, unsigned char irq_line, int shared)) +static int __init +pcnet32_probe1(struct device *dev, unsigned long ioaddr, unsigned char irq_line, int shared, int card_idx) { struct pcnet32_private *lp; - int i,full_duplex = 0; + int i,media,fdx = 0, mii = 0; + int chip_version; char *chipname; + char *priv; + struct pcnet32_access *a; - inw(ioaddr+PCNET32_RESET); /* Reset the PCNET32 */ + /* reset the chip */ + pcnet32_dwio_reset(ioaddr); + pcnet32_wio_reset(ioaddr); + + if (pcnet32_wio_read_csr (ioaddr, 0) == 4 && pcnet32_wio_check (ioaddr)) { + a = &pcnet32_wio; + } else { + if (pcnet32_dwio_read_csr (ioaddr, 0) == 4 && pcnet32_dwio_check(ioaddr)) { + a = &pcnet32_dwio; + } else + return ENODEV; + } - outw(0x0000, ioaddr+PCNET32_ADDR); /* Switch to window 0 */ - if (inw(ioaddr+PCNET32_DATA) != 0x0004) - return ENODEV; - - /* Get the version of the chip. */ - outw(88, ioaddr+PCNET32_ADDR); - if (inw(ioaddr+PCNET32_ADDR) != 88) { - /* should never happen */ + chip_version = a->read_csr (ioaddr, 88) | (a->read_csr (ioaddr,89) << 16); + if (pcnet32_debug > 2) + printk(" PCnet chip version is %#x.\n", chip_version); + if ((chip_version & 0xfff) != 0x003) return ENODEV; - } else { /* Good, it's a newer chip. */ - int chip_version = inw(ioaddr+PCNET32_DATA); - outw(89, ioaddr+PCNET32_ADDR); - chip_version |= inw(ioaddr+PCNET32_DATA) << 16; + chip_version = (chip_version >> 12) & 0xffff; + switch (chip_version) { + case 0x2420: + chipname = "PCnet/PCI 79C970"; + break; + case 0x2430: + if (shared) + chipname = "PCnet/PCI 79C970"; /* 970 gives the wrong chip id back */ + else + chipname = "PCnet/32 79C965"; + break; + case 0x2621: + chipname = "PCnet/PCI II 79C970A"; + fdx = 1; + break; + case 0x2623: + chipname = "PCnet/FAST 79C971"; + fdx = 1; mii = 1; + break; + case 0x2624: + chipname = "PCnet/FAST+ 79C972"; + fdx = 1; mii = 1; + break; + case 0x2626: + chipname = "PCnet/Home 79C978"; + fdx = 1; + /* + * This is based on specs published at www.amd.com. This section + * assumes that a card with a 79C978 wants to go into 1Mb HomePNA + * mode. The 79C978 can also go into standard ethernet, and there + * probably should be some sort of module option to select the + * mode by which the card should operate + */ + /* switch to home wiring mode */ + media = a->read_bcr (ioaddr, 49); if (pcnet32_debug > 2) - printk(" PCnet chip version is %#x.\n", chip_version); - if ((chip_version & 0xfff) != 0x003) - return ENODEV; - chip_version = (chip_version >> 12) & 0xffff; - switch (chip_version) { - case 0x2420: - chipname = "PCnet/PCI 79C970"; - break; - case 0x2430: - if (shared) - chipname = "PCnet/PCI 79C970"; /* 970 gives the wrong chip id back */ - else - chipname = "PCnet/32 79C965"; - break; - case 0x2621: - chipname = "PCnet/PCI II 79C970A"; - full_duplex = 1; - break; - case 0x2623: - chipname = "PCnet/FAST 79C971"; - full_duplex = 1; - break; - case 0x2624: - chipname = "PCnet/FAST+ 79C972"; - full_duplex = 1; - break; - default: - printk("pcnet32: PCnet version %#x, no PCnet32 chip.\n",chip_version); - return ENODEV; - } + printk("pcnet32: pcnet32 media value %#x.\n", media); + media &= ~3; + media |= 1; + if (pcnet32_debug > 2) + printk("pcnet32: pcnet32 media reset to %#x.\n", media); + a->write_bcr (ioaddr, 49, media); + break; + default: + printk("pcnet32: PCnet version %#x, no PCnet32 chip.\n",chip_version); + return ENODEV; } - if (dev == NULL) - dev = init_etherdev(0, 0); + dev = init_etherdev(dev, 0); - printk("%s: %s at %#3x,", dev->name, chipname, ioaddr); + printk(KERN_INFO "%s: %s at %#3lx,", dev->name, chipname, ioaddr); /* There is a 16 byte station address PROM at the base address. The first six bytes are the station address. */ @@ -345,15 +578,31 @@ dev->base_addr = ioaddr; request_region(ioaddr, PCNET32_TOTAL_SIZE, chipname); - /* Make certain the data structures used by the PCnet32 are 16byte aligned and DMAble. */ - lp = (struct pcnet32_private *) (((unsigned long)kmalloc(sizeof(*lp)+15, GFP_DMA | GFP_KERNEL)+15) & ~15); + if ((priv = kmalloc(sizeof(*lp)+15,GFP_KERNEL)) == NULL) + return ENOMEM; + + /* + * Make certain the data structures used by + * the PCnet32 are 16byte aligned + */ + lp = (struct pcnet32_private *)(((unsigned long)priv+15) & ~15); memset(lp, 0, sizeof(*lp)); dev->priv = lp; lp->name = chipname; lp->shared_irq = shared; - lp->full_duplex = full_duplex; - lp->options = options; + lp->full_duplex = fdx; + lp->mii = mii; + if (options[card_idx] > sizeof (options_mapping)) + lp->options = PORT_ASEL; + else + lp->options = options_mapping[options[card_idx]]; + + if (fdx && !(lp->options & PORT_ASEL) && full_duplex[card_idx]) + lp->options |= PORT_FD; + + lp->origmem = priv; + lp->a = *a; /* detect special T1/E1 WAN card by checking for MAC address */ if (dev->dev_addr[0] == 0x00 && dev->dev_addr[1] == 0xe0 && dev->dev_addr[2] == 0x75) @@ -369,24 +618,17 @@ lp->init_block.tx_ring = (u32)le32_to_cpu(virt_to_bus(lp->tx_ring)); /* switch pcnet32 to 32bit mode */ - outw(0x0014, ioaddr+PCNET32_ADDR); - outw(0x0002, ioaddr+PCNET32_BUS_IF); + a->write_bcr (ioaddr, 20, 2); - outw(0x0001, ioaddr+PCNET32_ADDR); - inw(ioaddr+PCNET32_ADDR); - outw(virt_to_bus(&lp->init_block) & 0xffff, ioaddr+PCNET32_DATA); - outw(0x0002, ioaddr+PCNET32_ADDR); - inw(ioaddr+PCNET32_ADDR); - outw(virt_to_bus(&lp->init_block) >> 16, ioaddr+PCNET32_DATA); - outw(0x0000, ioaddr+PCNET32_ADDR); - inw(ioaddr+PCNET32_ADDR); + a->write_csr (ioaddr, 1, virt_to_bus(&lp->init_block) & 0xffff); + a->write_csr (ioaddr, 2, virt_to_bus(&lp->init_block) >> 16); if (irq_line) { dev->irq = irq_line; } if (dev->irq >= 2) - printk(" assigned IRQ %d.\n", dev->irq); + printk(" assigned IRQ %d.\n", dev->irq); else { unsigned long irq_mask = probe_irq_on(); @@ -396,7 +638,7 @@ * boards will work. */ /* Trigger an initialization just for the interrupt. */ - outw(0x0041, ioaddr+PCNET32_DATA); + a->write_csr (ioaddr, 0, 0x41); mdelay (1); dev->irq = probe_irq_off (irq_mask); @@ -409,7 +651,7 @@ } if (pcnet32_debug > 0) - printk(version); + printk(version); /* The PCNET32-specific entries in the device structure. */ dev->open = &pcnet32_open; @@ -417,6 +659,10 @@ dev->stop = &pcnet32_close; dev->get_stats = &pcnet32_get_stats; dev->set_multicast_list = &pcnet32_set_multicast_list; +#ifdef HAVE_PRIVATE_IOCTL + dev->do_ioctl = &pcnet32_mii_ioctl; +#endif + #ifdef MODULE lp->next = pcnet32_dev; @@ -432,95 +678,96 @@ static int pcnet32_open(struct device *dev) { - struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv; - unsigned int ioaddr = dev->base_addr; - unsigned short val; - int i; - - if (dev->irq == 0 || - request_irq(dev->irq, &pcnet32_interrupt, - lp->shared_irq ? SA_SHIRQ : 0, lp->name, (void *)dev)) { - return -EAGAIN; - } + struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv; + unsigned long ioaddr = dev->base_addr; + u16 val; + int i; + + if (dev->irq == 0 || + request_irq(dev->irq, &pcnet32_interrupt, + lp->shared_irq ? SA_SHIRQ : 0, lp->name, (void *)dev)) { + return -EAGAIN; + } - /* Reset the PCNET32 */ - inw(ioaddr+PCNET32_RESET); + /* Reset the PCNET32 */ + lp->a.reset (ioaddr); - /* switch pcnet32 to 32bit mode */ - outw(0x0014, ioaddr+PCNET32_ADDR); - outw(0x0002, ioaddr+PCNET32_BUS_IF); - - if (pcnet32_debug > 1) - printk("%s: pcnet32_open() irq %d tx/rx rings %#x/%#x init %#x.\n", - dev->name, dev->irq, - (u32) virt_to_bus(lp->tx_ring), - (u32) virt_to_bus(lp->rx_ring), - (u32) virt_to_bus(&lp->init_block)); - - /* set/reset autoselect bit */ - outw(0x0002, ioaddr+PCNET32_ADDR); - val = inw(ioaddr+PCNET32_BUS_IF) & ~2; - if (lp->options & PORT_ASEL) - val |= 2; - outw(val, ioaddr+PCNET32_BUS_IF); - - /* handle full duplex setting */ - if (lp->full_duplex) { - outw (0x0009, ioaddr+PCNET32_ADDR); - val = inw(ioaddr+PCNET32_BUS_IF) & ~3; - if (lp->options & PORT_FD) { - val |= 1; - if (lp->options == (PORT_FD | PORT_AUI)) - val |= 2; - } - outw(val, ioaddr+PCNET32_BUS_IF); + /* switch pcnet32 to 32bit mode */ + lp->a.write_csr (ioaddr, 20, 2); + + if (pcnet32_debug > 1) + printk("%s: pcnet32_open() irq %d tx/rx rings %#x/%#x init %#x.\n", + dev->name, dev->irq, + (u32) virt_to_bus(lp->tx_ring), + (u32) virt_to_bus(lp->rx_ring), + (u32) virt_to_bus(&lp->init_block)); + + /* set/reset autoselect bit */ + val = lp->a.read_bcr (ioaddr, 2) & ~2; + if (lp->options & PORT_ASEL) + val |= 2; + lp->a.write_bcr (ioaddr, 2, val); + + /* handle full duplex setting */ + if (lp->full_duplex) { + val = lp->a.read_bcr (ioaddr, 9) & ~3; + if (lp->options & PORT_FD) { + val |= 1; + if (lp->options == (PORT_FD | PORT_AUI)) + val |= 2; } + lp->a.write_bcr (ioaddr, 9, val); + } - /* set/reset GPSI bit in test register */ - outw (0x007c, ioaddr+PCNET32_ADDR); - val = inw(ioaddr+PCNET32_DATA) & ~0x10; - if ((lp->options & PORT_PORTSEL) == PORT_GPSI) - val |= 0x10; - outw(val, ioaddr+PCNET32_DATA); - - lp->init_block.mode = le16_to_cpu((lp->options & PORT_PORTSEL) << 7); - lp->init_block.filter[0] = 0x00000000; - lp->init_block.filter[1] = 0x00000000; - if (pcnet32_init_ring(dev)) - return -ENOMEM; - - /* Re-initialize the PCNET32, and start it when done. */ - outw(0x0001, ioaddr+PCNET32_ADDR); - outw(virt_to_bus(&lp->init_block) &0xffff, ioaddr+PCNET32_DATA); - outw(0x0002, ioaddr+PCNET32_ADDR); - outw(virt_to_bus(&lp->init_block) >> 16, ioaddr+PCNET32_DATA); - - outw(0x0004, ioaddr+PCNET32_ADDR); - outw(0x0915, ioaddr+PCNET32_DATA); - - outw(0x0000, ioaddr+PCNET32_ADDR); - outw(0x0001, ioaddr+PCNET32_DATA); - - dev->tbusy = 0; - dev->interrupt = 0; - dev->start = 1; - i = 0; - while (i++ < 100) - if (inw(ioaddr+PCNET32_DATA) & 0x0100) - break; - /* - * We used to clear the InitDone bit, 0x0100, here but Mark Stockton - * reports that doing so triggers a bug in the '974. - */ - outw(0x0042, ioaddr+PCNET32_DATA); - - if (pcnet32_debug > 2) - printk("%s: PCNET32 open after %d ticks, init block %#x csr0 %4.4x.\n", - dev->name, i, (u32) virt_to_bus(&lp->init_block), inw(ioaddr+PCNET32_DATA)); + /* set/reset GPSI bit in test register */ + val = lp->a.read_csr (ioaddr, 124) & ~0x10; + if ((lp->options & PORT_PORTSEL) == PORT_GPSI) + val |= 0x10; + lp->a.write_csr (ioaddr, 124, val); + + if (lp->mii & (lp->options & PORT_ASEL)) { + val = lp->a.read_bcr (ioaddr, 32) & ~0x38; /* disable Auto Negotiation, set 10Mpbs, HD */ + if (lp->options & PORT_FD) + val |= 0x10; + if (lp->options & PORT_100) + val |= 0x08; + lp->a.write_bcr (ioaddr, 32, val); + } + + lp->init_block.mode = le16_to_cpu((lp->options & PORT_PORTSEL) << 7); + lp->init_block.filter[0] = 0x00000000; + lp->init_block.filter[1] = 0x00000000; + if (pcnet32_init_ring(dev)) + return -ENOMEM; + + /* Re-initialize the PCNET32, and start it when done. */ + lp->a.write_csr (ioaddr, 1, virt_to_bus(&lp->init_block) &0xffff); + lp->a.write_csr (ioaddr, 2, virt_to_bus(&lp->init_block) >> 16); + + lp->a.write_csr (ioaddr, 4, 0x0915); + lp->a.write_csr (ioaddr, 0, 0x0001); + + dev->tbusy = 0; + dev->interrupt = 0; + dev->start = 1; + i = 0; + while (i++ < 100) + if (lp->a.read_csr (ioaddr, 0) & 0x0100) + break; + /* + * We used to clear the InitDone bit, 0x0100, here but Mark Stockton + * reports that doing so triggers a bug in the '974. + */ + lp->a.write_csr (ioaddr, 0, 0x0042); + + if (pcnet32_debug > 2) + printk("%s: PCNET32 open after %d ticks, init block %#x csr0 %4.4x.\n", + dev->name, i, (u32) virt_to_bus(&lp->init_block), + lp->a.read_csr (ioaddr, 0)); - MOD_INC_USE_COUNT; + MOD_INC_USE_COUNT; - return 0; /* Always succeed */ + return 0; /* Always succeed */ } /* @@ -539,15 +786,15 @@ static void pcnet32_purge_tx_ring(struct device *dev) { - struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv; - int i; + struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv; + int i; - for (i = 0; i < TX_RING_SIZE; i++) { - if (lp->tx_skbuff[i]) { - dev_kfree_skb(lp->tx_skbuff[i]); - lp->tx_skbuff[i] = NULL; - } + for (i = 0; i < TX_RING_SIZE; i++) { + if (lp->tx_skbuff[i]) { + dev_kfree_skb(lp->tx_skbuff[i]); + lp->tx_skbuff[i] = NULL; } + } } @@ -555,445 +802,437 @@ static int pcnet32_init_ring(struct device *dev) { - struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv; - int i; + struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv; + int i; - lp->tx_full = 0; - lp->cur_rx = lp->cur_tx = 0; - lp->dirty_rx = lp->dirty_tx = 0; - - for (i = 0; i < RX_RING_SIZE; i++) { - if (lp->rx_skbuff[i] == NULL) { - if (!(lp->rx_skbuff[i] = dev_alloc_skb (PKT_BUF_SZ))) { - /* there is not much, we can do at this point */ - printk ("%s: pcnet32_init_ring dev_alloc_skb failed.\n",dev->name); - return -1; - } - skb_reserve (lp->rx_skbuff[i], 2); + lp->tx_full = 0; + lp->cur_rx = lp->cur_tx = 0; + lp->dirty_rx = lp->dirty_tx = 0; + + for (i = 0; i < RX_RING_SIZE; i++) { + if (lp->rx_skbuff[i] == NULL) { + if (!(lp->rx_skbuff[i] = dev_alloc_skb (PKT_BUF_SZ))) { + /* there is not much, we can do at this point */ + printk ("%s: pcnet32_init_ring dev_alloc_skb failed.\n",dev->name); + return -1; } - lp->rx_ring[i].base = (u32)le32_to_cpu(virt_to_bus(lp->rx_skbuff[i]->tail)); - lp->rx_ring[i].buf_length = le16_to_cpu(-PKT_BUF_SZ); - lp->rx_ring[i].status = le16_to_cpu(0x8000); - } - /* The Tx buffer address is filled in as needed, but we do need to clear - the upper ownership bit. */ - for (i = 0; i < TX_RING_SIZE; i++) { - lp->tx_ring[i].base = 0; - lp->tx_ring[i].status = 0; + skb_reserve (lp->rx_skbuff[i], 2); } + lp->rx_ring[i].base = (u32)le32_to_cpu(virt_to_bus(lp->rx_skbuff[i]->tail)); + lp->rx_ring[i].buf_length = le16_to_cpu(-PKT_BUF_SZ); + lp->rx_ring[i].status = le16_to_cpu(0x8000); + } + /* The Tx buffer address is filled in as needed, but we do need to clear + the upper ownership bit. */ + for (i = 0; i < TX_RING_SIZE; i++) { + lp->tx_ring[i].base = 0; + lp->tx_ring[i].status = 0; + } - lp->init_block.tlen_rlen = TX_RING_LEN_BITS | RX_RING_LEN_BITS; - for (i = 0; i < 6; i++) - lp->init_block.phys_addr[i] = dev->dev_addr[i]; - lp->init_block.rx_ring = (u32)le32_to_cpu(virt_to_bus(lp->rx_ring)); - lp->init_block.tx_ring = (u32)le32_to_cpu(virt_to_bus(lp->tx_ring)); - return 0; + lp->init_block.tlen_rlen = TX_RING_LEN_BITS | RX_RING_LEN_BITS; + for (i = 0; i < 6; i++) + lp->init_block.phys_addr[i] = dev->dev_addr[i]; + lp->init_block.rx_ring = (u32)le32_to_cpu(virt_to_bus(lp->rx_ring)); + lp->init_block.tx_ring = (u32)le32_to_cpu(virt_to_bus(lp->tx_ring)); + return 0; } static void pcnet32_restart(struct device *dev, unsigned int csr0_bits) { - int i; - unsigned int ioaddr = dev->base_addr; + struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv; + unsigned long ioaddr = dev->base_addr; + int i; - pcnet32_purge_tx_ring(dev); - if (pcnet32_init_ring(dev)) - return; - - outw(0x0000, ioaddr + PCNET32_ADDR); - /* ReInit Ring */ - outw(0x0001, ioaddr + PCNET32_DATA); - i = 0; - while (i++ < 100) - if (inw(ioaddr+PCNET32_DATA) & 0x0100) - break; + pcnet32_purge_tx_ring(dev); + if (pcnet32_init_ring(dev)) + return; + + /* ReInit Ring */ + lp->a.write_csr (ioaddr, 0, 1); + i = 0; + while (i++ < 100) + if (lp->a.read_csr (ioaddr, 0) & 0x0100) + break; - outw(csr0_bits, ioaddr + PCNET32_DATA); + lp->a.write_csr (ioaddr, 0, csr0_bits); } static int pcnet32_start_xmit(struct sk_buff *skb, struct device *dev) { - struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv; - unsigned int ioaddr = dev->base_addr; - int entry; - unsigned long flags; - - /* Transmitter timeout, serious problems. */ - if (dev->tbusy) { - int tickssofar = jiffies - dev->trans_start; - if (tickssofar < HZ/2) - return 1; - outw(0, ioaddr+PCNET32_ADDR); - printk("%s: transmit timed out, status %4.4x, resetting.\n", - dev->name, inw(ioaddr+PCNET32_DATA)); - outw(0x0004, ioaddr+PCNET32_DATA); - lp->stats.tx_errors++; - if (pcnet32_debug > 2) { - int i; - printk(" Ring data dump: dirty_tx %d cur_tx %d%s cur_rx %d.", - lp->dirty_tx, lp->cur_tx, lp->tx_full ? " (full)" : "", - lp->cur_rx); - for (i = 0 ; i < RX_RING_SIZE; i++) - printk("%s %08x %04x %08x %04x", i & 1 ? "" : "\n ", - lp->rx_ring[i].base, -lp->rx_ring[i].buf_length, - lp->rx_ring[i].msg_length, (unsigned)lp->rx_ring[i].status); - for (i = 0 ; i < TX_RING_SIZE; i++) - printk("%s %08x %04x %08x %04x", i & 1 ? "" : "\n ", - lp->tx_ring[i].base, -lp->tx_ring[i].length, - lp->tx_ring[i].misc, (unsigned)lp->tx_ring[i].status); - printk("\n"); - } - pcnet32_restart(dev, 0x0042); - - dev->tbusy = 0; - dev->trans_start = jiffies; - dev_kfree_skb(skb); - return 0; + struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv; + unsigned int ioaddr = dev->base_addr; + int entry; + unsigned long flags; + + /* Transmitter timeout, serious problems. */ + if (dev->tbusy) { + int tickssofar = jiffies - dev->trans_start; + if (tickssofar < HZ/2) + return 1; + printk("%s: transmit timed out, status %4.4x, resetting.\n", + dev->name, lp->a.read_csr (ioaddr, 0)); + lp->a.write_csr (ioaddr, 0, 0x0004); + lp->stats.tx_errors++; + if (pcnet32_debug > 2) { + int i; + printk(" Ring data dump: dirty_tx %d cur_tx %d%s cur_rx %d.", + lp->dirty_tx, lp->cur_tx, lp->tx_full ? " (full)" : "", + lp->cur_rx); + for (i = 0 ; i < RX_RING_SIZE; i++) + printk("%s %08x %04x %08x %04x", i & 1 ? "" : "\n ", + lp->rx_ring[i].base, -lp->rx_ring[i].buf_length, + lp->rx_ring[i].msg_length, (unsigned)lp->rx_ring[i].status); + for (i = 0 ; i < TX_RING_SIZE; i++) + printk("%s %08x %04x %08x %04x", i & 1 ? "" : "\n ", + lp->tx_ring[i].base, -lp->tx_ring[i].length, + lp->tx_ring[i].misc, (unsigned)lp->tx_ring[i].status); + printk("\n"); } + pcnet32_restart(dev, 0x0042); - if (pcnet32_debug > 3) { - outw(0x0000, ioaddr+PCNET32_ADDR); - printk("%s: pcnet32_start_xmit() called, csr0 %4.4x.\n", dev->name, - inw(ioaddr+PCNET32_DATA)); - } + dev->tbusy = 0; + dev->trans_start = jiffies; + dev_kfree_skb(skb); + return 0; + } - /* Block a timer-based transmit from overlapping. This could better be - done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ - if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { - printk("%s: Transmitter access conflict.\n", dev->name); - return 1; - } + if (pcnet32_debug > 3) { + printk("%s: pcnet32_start_xmit() called, csr0 %4.4x.\n", + dev->name, lp->a.read_csr (ioaddr, 0)); + } - save_flags (flags); - cli (); + /* Block a timer-based transmit from overlapping. This could better be + done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { + printk("%s: Transmitter access conflict.\n", dev->name); + return 1; + } - /* Fill in a Tx ring entry */ + save_flags (flags); + cli (); - /* Mask to ring buffer boundary. */ - entry = lp->cur_tx & TX_RING_MOD_MASK; + /* Fill in a Tx ring entry */ - /* Caution: the write order is important here, set the base address - with the "ownership" bits last. */ + /* Mask to ring buffer boundary. */ + entry = lp->cur_tx & TX_RING_MOD_MASK; - lp->tx_ring[entry].length = le16_to_cpu(-skb->len); + /* Caution: the write order is important here, set the base address + with the "ownership" bits last. */ - lp->tx_ring[entry].misc = 0x00000000; + lp->tx_ring[entry].length = le16_to_cpu(-skb->len); - lp->tx_skbuff[entry] = skb; - lp->tx_ring[entry].base = (u32)le32_to_cpu(virt_to_bus(skb->data)); - lp->tx_ring[entry].status = le16_to_cpu(0x8300); + lp->tx_ring[entry].misc = 0x00000000; - lp->cur_tx++; - lp->stats.tx_bytes += skb->len; + lp->tx_skbuff[entry] = skb; + lp->tx_ring[entry].base = (u32)le32_to_cpu(virt_to_bus(skb->data)); + lp->tx_ring[entry].status = le16_to_cpu(0x8300); - /* Trigger an immediate send poll. */ - outw(0x0000, ioaddr+PCNET32_ADDR); - outw(0x0048, ioaddr+PCNET32_DATA); + lp->cur_tx++; + lp->stats.tx_bytes += skb->len; - dev->trans_start = jiffies; + /* Trigger an immediate send poll. */ + lp->a.write_csr (ioaddr, 0, 0x0048); - if (lp->tx_ring[(entry+1) & TX_RING_MOD_MASK].base == 0) - clear_bit (0, (void *)&dev->tbusy); - else - lp->tx_full = 1; - restore_flags(flags); - return 0; + dev->trans_start = jiffies; + + if (lp->tx_ring[(entry+1) & TX_RING_MOD_MASK].base == 0) + clear_bit (0, (void *)&dev->tbusy); + else + lp->tx_full = 1; + restore_flags(flags); + return 0; } /* The PCNET32 interrupt handler. */ static void pcnet32_interrupt(int irq, void *dev_id, struct pt_regs * regs) { - struct device *dev = (struct device *)dev_id; - struct pcnet32_private *lp; - unsigned int csr0, ioaddr; - int boguscnt = max_interrupt_work; - int must_restart; - - if (dev == NULL) { - printk ("pcnet32_interrupt(): irq %d for unknown device.\n", irq); - return; - } + struct device *dev = (struct device *)dev_id; + struct pcnet32_private *lp; + unsigned long ioaddr; + u16 csr0; + int boguscnt = max_interrupt_work; + int must_restart; - ioaddr = dev->base_addr; - lp = (struct pcnet32_private *)dev->priv; - if (dev->interrupt) - printk("%s: Re-entering the interrupt handler.\n", dev->name); + if (dev == NULL) { + printk ("pcnet32_interrupt(): irq %d for unknown device.\n", irq); + return; + } - dev->interrupt = 1; + ioaddr = dev->base_addr; + lp = (struct pcnet32_private *)dev->priv; + if (dev->interrupt) + printk("%s: Re-entering the interrupt handler.\n", dev->name); - outw(0x00, dev->base_addr + PCNET32_ADDR); - while ((csr0 = inw(dev->base_addr + PCNET32_DATA)) & 0x8600 && --boguscnt >= 0) { - /* Acknowledge all of the current interrupt sources ASAP. */ - outw(csr0 & ~0x004f, dev->base_addr + PCNET32_DATA); + dev->interrupt = 1; - must_restart = 0; + while ((csr0 = lp->a.read_csr (ioaddr, 0)) & 0x8600 && --boguscnt >= 0) { + /* Acknowledge all of the current interrupt sources ASAP. */ + lp->a.write_csr (ioaddr, 0, csr0 & ~0x004f); - if (pcnet32_debug > 5) - printk("%s: interrupt csr0=%#2.2x new csr=%#2.2x.\n", - dev->name, csr0, inw(dev->base_addr + PCNET32_DATA)); + must_restart = 0; - if (csr0 & 0x0400) /* Rx interrupt */ - pcnet32_rx(dev); + if (pcnet32_debug > 5) + printk("%s: interrupt csr0=%#2.2x new csr=%#2.2x.\n", + dev->name, csr0, lp->a.read_csr (ioaddr, 0)); - if (csr0 & 0x0200) { /* Tx-done interrupt */ - int dirty_tx = lp->dirty_tx; + if (csr0 & 0x0400) /* Rx interrupt */ + pcnet32_rx(dev); - while (dirty_tx < lp->cur_tx) { - int entry = dirty_tx & TX_RING_MOD_MASK; - int status = (short)le16_to_cpu(lp->tx_ring[entry].status); + if (csr0 & 0x0200) { /* Tx-done interrupt */ + int dirty_tx = lp->dirty_tx; + + while (dirty_tx < lp->cur_tx) { + int entry = dirty_tx & TX_RING_MOD_MASK; + int status = (short)le16_to_cpu(lp->tx_ring[entry].status); - if (status < 0) - break; /* It still hasn't been Txed */ + if (status < 0) + break; /* It still hasn't been Txed */ - lp->tx_ring[entry].base = 0; + lp->tx_ring[entry].base = 0; - if (status & 0x4000) { - /* There was an major error, log it. */ - int err_status = le32_to_cpu(lp->tx_ring[entry].misc); - lp->stats.tx_errors++; - if (err_status & 0x04000000) lp->stats.tx_aborted_errors++; - if (err_status & 0x08000000) lp->stats.tx_carrier_errors++; - if (err_status & 0x10000000) lp->stats.tx_window_errors++; - if (err_status & 0x40000000) { - /* Ackk! On FIFO errors the Tx unit is turned off! */ - lp->stats.tx_fifo_errors++; - /* Remove this verbosity later! */ - printk("%s: Tx FIFO error! Status %4.4x.\n", - dev->name, csr0); - must_restart = 1; + if (status & 0x4000) { + /* There was an major error, log it. */ + int err_status = le32_to_cpu(lp->tx_ring[entry].misc); + lp->stats.tx_errors++; + if (err_status & 0x04000000) lp->stats.tx_aborted_errors++; + if (err_status & 0x08000000) lp->stats.tx_carrier_errors++; + if (err_status & 0x10000000) lp->stats.tx_window_errors++; + if (err_status & 0x40000000) { + /* Ackk! On FIFO errors the Tx unit is turned off! */ + lp->stats.tx_fifo_errors++; + /* Remove this verbosity later! */ + printk("%s: Tx FIFO error! Status %4.4x.\n", + dev->name, csr0); + must_restart = 1; } - } else { - if (status & 0x1800) - lp->stats.collisions++; - lp->stats.tx_packets++; - } - - /* We must free the original skb */ - if (lp->tx_skbuff[entry]) { - dev_kfree_skb(lp->tx_skbuff[entry]); - lp->tx_skbuff[entry] = 0; - } - dirty_tx++; - } + } else { + if (status & 0x1800) + lp->stats.collisions++; + lp->stats.tx_packets++; + } + + /* We must free the original skb */ + if (lp->tx_skbuff[entry]) { + dev_kfree_skb(lp->tx_skbuff[entry]); + lp->tx_skbuff[entry] = 0; + } + dirty_tx++; + } #ifndef final_version - if (lp->cur_tx - dirty_tx >= TX_RING_SIZE) { - printk("out-of-sync dirty pointer, %d vs. %d, full=%d.\n", - dirty_tx, lp->cur_tx, lp->tx_full); - dirty_tx += TX_RING_SIZE; - } + if (lp->cur_tx - dirty_tx >= TX_RING_SIZE) { + printk("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; + clear_bit(0, (void *)&dev->tbusy); + mark_bh(NET_BH); + } + lp->dirty_tx = dirty_tx; + } - 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; - clear_bit(0, (void *)&dev->tbusy); - mark_bh(NET_BH); - } - lp->dirty_tx = dirty_tx; - } - - /* Log misc errors. */ - if (csr0 & 0x4000) lp->stats.tx_errors++; /* Tx babble. */ - if (csr0 & 0x1000) { - /* - * this happens when our receive ring is full. This shouldn't - * be a problem as we will see normal rx interrupts for the frames - * in the receive ring. But there are some PCI chipsets (I can reproduce - * this on SP3G with Intel saturn chipset) which have sometimes problems - * and will fill up the receive ring with error descriptors. In this - * situation we don't get a rx interrupt, but a missed frame interrupt sooner - * or later. So we try to clean up our receive ring here. - */ - pcnet32_rx(dev); - lp->stats.rx_errors++; /* Missed a Rx frame. */ - } - if (csr0 & 0x0800) { - printk("%s: Bus master arbitration failure, status %4.4x.\n", - dev->name, csr0); - /* unlike for the lance, there is no restart needed */ - } + /* Log misc errors. */ + if (csr0 & 0x4000) lp->stats.tx_errors++; /* Tx babble. */ + if (csr0 & 0x1000) { + /* + * this happens when our receive ring is full. This shouldn't + * be a problem as we will see normal rx interrupts for the frames + * in the receive ring. But there are some PCI chipsets (I can reproduce + * this on SP3G with Intel saturn chipset) which have sometimes problems + * and will fill up the receive ring with error descriptors. In this + * situation we don't get a rx interrupt, but a missed frame interrupt sooner + * or later. So we try to clean up our receive ring here. + */ + pcnet32_rx(dev); + lp->stats.rx_errors++; /* Missed a Rx frame. */ + } + if (csr0 & 0x0800) { + printk("%s: Bus master arbitration failure, status %4.4x.\n", + dev->name, csr0); + /* unlike for the lance, there is no restart needed */ + } - if (must_restart) { - /* stop the chip to clear the error condition, then restart */ - outw(0x0000, dev->base_addr + PCNET32_ADDR); - outw(0x0004, dev->base_addr + PCNET32_DATA); - pcnet32_restart(dev, 0x0002); - } + if (must_restart) { + /* stop the chip to clear the error condition, then restart */ + lp->a.write_csr (ioaddr, 0, 0x0004); + pcnet32_restart(dev, 0x0002); } + } /* Clear any other interrupt, and set interrupt enable. */ - outw(0x0000, dev->base_addr + PCNET32_ADDR); - outw(0x7940, dev->base_addr + PCNET32_DATA); + lp->a.write_csr (ioaddr, 0, 0x7940); - if (pcnet32_debug > 4) - printk("%s: exiting interrupt, csr%d=%#4.4x.\n", - dev->name, inw(ioaddr + PCNET32_ADDR), - inw(dev->base_addr + PCNET32_DATA)); + if (pcnet32_debug > 4) + printk("%s: exiting interrupt, csr0=%#4.4x.\n", + dev->name, lp->a.read_csr (ioaddr, 0)); - dev->interrupt = 0; - return; + dev->interrupt = 0; + return; } static int pcnet32_rx(struct device *dev) { - struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv; - int entry = lp->cur_rx & RX_RING_MOD_MASK; - int i; - - /* If we own the next entry, it's a new packet. Send it up. */ - while ((short)le16_to_cpu(lp->rx_ring[entry].status) >= 0) { - int status = (short)le16_to_cpu(lp->rx_ring[entry].status) >> 8; - - if (status != 0x03) { /* 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 & 0x01) /* Only count a general error at the */ - lp->stats.rx_errors++; /* end of a packet.*/ - if (status & 0x20) lp->stats.rx_frame_errors++; - if (status & 0x10) lp->stats.rx_over_errors++; - if (status & 0x08) lp->stats.rx_crc_errors++; - if (status & 0x04) lp->stats.rx_fifo_errors++; - lp->rx_ring[entry].status &= le16_to_cpu(0x03ff); - } - else - { - /* Malloc up new buffer, compatible with net-2e. */ - short pkt_len = (le32_to_cpu(lp->rx_ring[entry].msg_length) & 0xfff)-4; - struct sk_buff *skb; + struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv; + int entry = lp->cur_rx & RX_RING_MOD_MASK; + int i; + + /* If we own the next entry, it's a new packet. Send it up. */ + while ((short)le16_to_cpu(lp->rx_ring[entry].status) >= 0) { + int status = (short)le16_to_cpu(lp->rx_ring[entry].status) >> 8; + + if (status != 0x03) { /* 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 & 0x01) /* Only count a general error at the */ + lp->stats.rx_errors++; /* end of a packet.*/ + if (status & 0x20) lp->stats.rx_frame_errors++; + if (status & 0x10) lp->stats.rx_over_errors++; + if (status & 0x08) lp->stats.rx_crc_errors++; + if (status & 0x04) lp->stats.rx_fifo_errors++; + lp->rx_ring[entry].status &= le16_to_cpu(0x03ff); + } else { + /* Malloc up new buffer, compatible with net-2e. */ + short pkt_len = (le32_to_cpu(lp->rx_ring[entry].msg_length) & 0xfff)-4; + struct sk_buff *skb; - if(pkt_len < 60) { - printk("%s: Runt packet!\n",dev->name); - lp->stats.rx_errors++; - } else { - int rx_in_place = 0; + if(pkt_len < 60) { + printk("%s: Runt packet!\n",dev->name); + lp->stats.rx_errors++; + } else { + int rx_in_place = 0; - if (pkt_len > rx_copybreak) { - struct sk_buff *newskb; + if (pkt_len > rx_copybreak) { + struct sk_buff *newskb; - if ((newskb = dev_alloc_skb (PKT_BUF_SZ))) { - skb_reserve (newskb, 2); - skb = lp->rx_skbuff[entry]; - skb_put (skb, pkt_len); - lp->rx_skbuff[entry] = newskb; - newskb->dev = dev; - lp->rx_ring[entry].base = le32_to_cpu(virt_to_bus(newskb->tail)); - rx_in_place = 1; - } else - skb = NULL; - } else - skb = dev_alloc_skb(pkt_len+2); + if ((newskb = dev_alloc_skb (PKT_BUF_SZ))) { + skb_reserve (newskb, 2); + skb = lp->rx_skbuff[entry]; + skb_put (skb, pkt_len); + lp->rx_skbuff[entry] = newskb; + newskb->dev = dev; + lp->rx_ring[entry].base = le32_to_cpu(virt_to_bus(newskb->tail)); + rx_in_place = 1; + } else + skb = NULL; + } else + skb = dev_alloc_skb(pkt_len+2); - if (skb == NULL) { - printk("%s: Memory squeeze, deferring packet.\n", dev->name); - for (i=0; i < RX_RING_SIZE; i++) - if ((short)le16_to_cpu(lp->rx_ring[(entry+i) & RX_RING_MOD_MASK].status) < 0) - break; - - if (i > RX_RING_SIZE -2) { - lp->stats.rx_dropped++; - lp->rx_ring[entry].status |= le16_to_cpu(0x8000); - lp->cur_rx++; - } - break; - } - skb->dev = dev; - if (!rx_in_place) { - skb_reserve(skb,2); /* 16 byte align */ - skb_put(skb,pkt_len); /* Make room */ - eth_copy_and_sum(skb, - (unsigned char *)bus_to_virt(le32_to_cpu(lp->rx_ring[entry].base)), - pkt_len,0); - } - lp->stats.rx_bytes += skb->len; - skb->protocol=eth_type_trans(skb,dev); - netif_rx(skb); - lp->stats.rx_packets++; - } + if (skb == NULL) { + printk("%s: Memory squeeze, deferring packet.\n", dev->name); + for (i=0; i < RX_RING_SIZE; i++) + if ((short)le16_to_cpu(lp->rx_ring[(entry+i) & RX_RING_MOD_MASK].status) < 0) + break; + + if (i > RX_RING_SIZE -2) { + lp->stats.rx_dropped++; + lp->rx_ring[entry].status |= le16_to_cpu(0x8000); + lp->cur_rx++; + } + break; } - /* The docs say that the buffer length isn't touched, but Andrew Boyd - of QNX reports that some revs of the 79C965 clear it. */ - lp->rx_ring[entry].buf_length = le16_to_cpu(-PKT_BUF_SZ); - lp->rx_ring[entry].status |= le16_to_cpu(0x8000); - entry = (++lp->cur_rx) & RX_RING_MOD_MASK; + skb->dev = dev; + if (!rx_in_place) { + skb_reserve(skb,2); /* 16 byte align */ + skb_put(skb,pkt_len); /* Make room */ + eth_copy_and_sum(skb, + (unsigned char *)bus_to_virt(le32_to_cpu(lp->rx_ring[entry].base)), + pkt_len,0); + } + lp->stats.rx_bytes += skb->len; + skb->protocol=eth_type_trans(skb,dev); + netif_rx(skb); + lp->stats.rx_packets++; + } } + /* + * The docs say that the buffer length isn't touched, but Andrew Boyd + * of QNX reports that some revs of the 79C965 clear it. + */ + lp->rx_ring[entry].buf_length = le16_to_cpu(-PKT_BUF_SZ); + lp->rx_ring[entry].status |= le16_to_cpu(0x8000); + entry = (++lp->cur_rx) & RX_RING_MOD_MASK; + } - /* We should check that at least two ring entries are free. If not, - we should free one and mark stats->rx_dropped++. */ - - return 0; + return 0; } static int pcnet32_close(struct device *dev) { - unsigned int ioaddr = dev->base_addr; - struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv; - int i; - - dev->start = 0; - set_bit (0, (void *)&dev->tbusy); - - outw(112, ioaddr+PCNET32_ADDR); - lp->stats.rx_missed_errors = inw(ioaddr+PCNET32_DATA); - - outw(0, ioaddr+PCNET32_ADDR); - - if (pcnet32_debug > 1) - printk("%s: Shutting down ethercard, status was %2.2x.\n", - dev->name, inw(ioaddr+PCNET32_DATA)); - - /* We stop the PCNET32 here -- it occasionally polls - memory if we don't. */ - outw(0x0004, ioaddr+PCNET32_DATA); - - free_irq(dev->irq, dev); - - /* free all allocated skbuffs */ - for (i = 0; i < RX_RING_SIZE; i++) { - lp->rx_ring[i].status = 0; - if (lp->rx_skbuff[i]) - dev_kfree_skb(lp->rx_skbuff[i]); - lp->rx_skbuff[i] = NULL; - } + unsigned long ioaddr = dev->base_addr; + struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv; + int i; + + dev->start = 0; + set_bit (0, (void *)&dev->tbusy); + + lp->stats.rx_missed_errors = lp->a.read_csr (ioaddr, 112); + + if (pcnet32_debug > 1) + printk("%s: Shutting down ethercard, status was %2.2x.\n", + dev->name, lp->a.read_csr (ioaddr, 0)); + + /* We stop the PCNET32 here -- it occasionally polls memory if we don't. */ + lp->a.write_csr (ioaddr, 0, 0x0004); + + /* + * Switch back to 16bit mode to avoid problems with dumb + * DOS packet driver after a warm reboot + */ + lp->a.write_bcr (ioaddr, 20, 4); + + free_irq(dev->irq, dev); + + /* free all allocated skbuffs */ + for (i = 0; i < RX_RING_SIZE; i++) { + lp->rx_ring[i].status = 0; + if (lp->rx_skbuff[i]) + dev_kfree_skb(lp->rx_skbuff[i]); + lp->rx_skbuff[i] = NULL; + } - for (i = 0; i < TX_RING_SIZE; i++) { - if (lp->tx_skbuff[i]) - dev_kfree_skb(lp->tx_skbuff[i]); - lp->rx_skbuff[i] = NULL; - } + for (i = 0; i < TX_RING_SIZE; i++) { + if (lp->tx_skbuff[i]) + dev_kfree_skb(lp->tx_skbuff[i]); + lp->rx_skbuff[i] = NULL; + } - MOD_DEC_USE_COUNT; + MOD_DEC_USE_COUNT; - return 0; + return 0; } static struct net_device_stats * pcnet32_get_stats(struct device *dev) { - struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv; - unsigned int ioaddr = dev->base_addr; - unsigned short saved_addr; - unsigned long flags; - - save_flags(flags); - cli(); - saved_addr = inw(ioaddr+PCNET32_ADDR); - outw(112, ioaddr+PCNET32_ADDR); - lp->stats.rx_missed_errors = inw(ioaddr+PCNET32_DATA); - outw(saved_addr, ioaddr+PCNET32_ADDR); - restore_flags(flags); + struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv; + unsigned long ioaddr = dev->base_addr; + u16 saved_addr; + unsigned long flags; + + save_flags(flags); + cli(); + saved_addr = lp->a.read_rap(ioaddr); + lp->stats.rx_missed_errors = lp->a.read_csr (ioaddr, 112); + lp->a.write_rap(ioaddr, saved_addr); + restore_flags(flags); - return &lp->stats; + return &lp->stats; } - /* taken from the sunlance driver, which it took from the depca driver */ static void pcnet32_load_multicast (struct device *dev) { @@ -1044,34 +1283,68 @@ } -/* Set or clear the multicast filter for this adaptor. +/* + * Set or clear the multicast filter for this adaptor. */ - static void pcnet32_set_multicast_list(struct device *dev) { - unsigned int ioaddr = dev->base_addr; - struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv; + unsigned long ioaddr = dev->base_addr; + struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv; - if (dev->flags&IFF_PROMISC) { - /* Log any net taps. */ - printk("%s: Promiscuous mode enabled.\n", dev->name); - lp->init_block.mode = le16_to_cpu(0x8000 | (lp->options & PORT_PORTSEL) << 7); - } else { - lp->init_block.mode = le16_to_cpu((lp->options & PORT_PORTSEL) << 7); - pcnet32_load_multicast (dev); - } + if (dev->flags&IFF_PROMISC) { + /* Log any net taps. */ + printk("%s: Promiscuous mode enabled.\n", dev->name); + lp->init_block.mode = le16_to_cpu(0x8000 | (lp->options & PORT_PORTSEL) << 7); + } else { + lp->init_block.mode = le16_to_cpu((lp->options & PORT_PORTSEL) << 7); + pcnet32_load_multicast (dev); + } - outw(0, ioaddr+PCNET32_ADDR); - outw(0x0004, ioaddr+PCNET32_DATA); /* Temporarily stop the lance. */ + lp->a.write_csr (ioaddr, 0, 0x0004); /* Temporarily stop the lance. */ - pcnet32_restart(dev, 0x0042); /* Resume normal operation */ + pcnet32_restart(dev, 0x0042); /* Resume normal operation */ } +#ifdef HAVE_PRIVATE_IOCTL +static int pcnet32_mii_ioctl(struct device *dev, struct ifreq *rq, int cmd) +{ + unsigned long ioaddr = dev->base_addr; + struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv; + u16 *data = (u16 *)&rq->ifr_data; + int phyaddr = lp->a.read_bcr (ioaddr, 33); + + if (lp->mii) { + switch(cmd) { + case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ + data[0] = (phyaddr >> 5) & 0x1f; + /* Fall Through */ + case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ + lp->a.write_bcr (ioaddr, 33, ((data[0] & 0x1f) << 5) | (data[1] & 0x1f)); + data[3] = lp->a.read_bcr (ioaddr, 34); + lp->a.write_bcr (ioaddr, 33, phyaddr); + return 0; + case SIOCDEVPRIVATE+2: /* Write the specified MII register */ + if (!suser()) + return -EPERM; + lp->a.write_bcr (ioaddr, 33, ((data[0] & 0x1f) << 5) | (data[1] & 0x1f)); + lp->a.write_bcr (ioaddr, 34, data[2]); + lp->a.write_bcr (ioaddr, 33, phyaddr); + return 0; + default: + return -EOPNOTSUPP; + } + } + return -EOPNOTSUPP; +} +#endif /* HAVE_PRIVATE_IOCTL */ + #ifdef MODULE MODULE_PARM(debug, "i"); -MODULE_PARM(options, "i"); MODULE_PARM(max_interrupt_work, "i"); MODULE_PARM(rx_copybreak, "i"); +MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); + /* An additional parameter that may be passed in... */ static int debug = -1; @@ -1079,27 +1352,27 @@ int init_module(void) { - if (debug > 0) - pcnet32_debug = debug; + if (debug > 0) + pcnet32_debug = debug; - pcnet32_dev = NULL; - return pcnet32_probe(NULL); + pcnet32_dev = NULL; + return pcnet32_probe(NULL); } void cleanup_module(void) { - struct device *next_dev; + struct device *next_dev; - /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ - while (pcnet32_dev) { - next_dev = ((struct pcnet32_private *) pcnet32_dev->priv)->next; - unregister_netdev(pcnet32_dev); - release_region(pcnet32_dev->base_addr, PCNET32_TOTAL_SIZE); - kfree(pcnet32_dev->priv); - kfree(pcnet32_dev); - pcnet32_dev = next_dev; - } + /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ + while (pcnet32_dev) { + next_dev = ((struct pcnet32_private *) pcnet32_dev->priv)->next; + unregister_netdev(pcnet32_dev); + release_region(pcnet32_dev->base_addr, PCNET32_TOTAL_SIZE); + kfree(((struct pcnet32_private *)pcnet32_dev->priv)->origmem); + kfree(pcnet32_dev); + pcnet32_dev = next_dev; + } } #endif /* MODULE */ diff -ur --new-file old/linux/drivers/net/plip.c new/linux/drivers/net/plip.c --- old/linux/drivers/net/plip.c Tue Jan 5 01:06:00 1999 +++ new/linux/drivers/net/plip.c Mon Mar 8 00:47:46 1999 @@ -1217,7 +1217,7 @@ plip_searchfor(int list[], int a) { int i; - for (i = 0; i < 3 && list[i] != -1; i++) { + for (i = 0; i < PLIP_MAX && list[i] != -1; i++) { if (list[i] == a) return 1; } return 0; @@ -1240,7 +1240,7 @@ /* If the user feeds parameters, use them */ while (pb) { if ((parport[0] == -1 && (!timid || !pb->devices)) || - plip_searchfor(parport, i)) { + plip_searchfor(parport, pb->number)) { if (i == PLIP_MAX) { printk(KERN_ERR "plip: too many devices\n"); break; diff -ur --new-file old/linux/drivers/net/ppp.c new/linux/drivers/net/ppp.c --- old/linux/drivers/net/ppp.c Fri Jan 15 07:56:06 1999 +++ new/linux/drivers/net/ppp.c Tue May 11 18:55:45 1999 @@ -4,7 +4,7 @@ * Al Longyear * Extensively rewritten by Paul Mackerras * - * ==FILEVERSION 990114== + * ==FILEVERSION 990510== * * NOTE TO MAINTAINERS: * If you modify this file at all, please set the number above to the @@ -45,9 +45,8 @@ #define PPP_MAX_RCV_QLEN 32 /* max # frames we queue up for pppd */ -/* $Id: ppp.c,v 1.19 1998/07/07 04:27:37 paulus Exp $ */ +/* $Id: ppp.c,v 1.24 1999/03/31 06:07:57 paulus Exp $ */ -#include #include #include #include @@ -102,9 +101,12 @@ static void ppp_async_init(struct ppp *ppp); static void ppp_async_release(struct ppp *ppp); +static int ppp_tty_sync_push(struct ppp *ppp); static int ppp_tty_push(struct ppp *ppp); static int ppp_async_encode(struct ppp *ppp); static int ppp_async_send(struct ppp *, struct sk_buff *); +static int ppp_sync_send(struct ppp *, struct sk_buff *); +static void ppp_tty_flush_output(struct ppp *); static int ppp_ioctl(struct ppp *, unsigned int, unsigned long); static int ppp_set_compression (struct ppp *ppp, struct ppp_option_data *odp); @@ -442,6 +444,7 @@ ppp->tty = ppp->backup_tty; if (ppp_tty_push(ppp)) ppp_output_wakeup(ppp); + wake_up_interruptible(&ppp->read_wait); } else { ppp->tty = 0; ppp->sc_xfer = 0; @@ -720,6 +723,21 @@ error = n_tty_ioctl (tty, file, param2, param3); break; + case TCFLSH: + /* + * Flush our buffers, then call the generic code to + * flush the serial port's buffer. + */ + if (param3 == TCIFLUSH || param3 == TCIOFLUSH) { + struct sk_buff *skb; + while ((skb = skb_dequeue(&ppp->rcv_q)) != NULL) + kfree_skb(skb); + } + if (param3 == TCIOFLUSH || param3 == TCOFLUSH) + ppp_tty_flush_output(ppp); + error = n_tty_ioctl (tty, file, param2, param3); + break; + case FIONREAD: /* * Returns how many bytes are available for a read(). @@ -800,6 +818,135 @@ } /* + * Send a packet to the peer over a synchronous tty line. + * All encoding and FCS are handled by hardware. + * Addr/Ctrl and Protocol field compression implemented. + * Returns -1 iff the packet could not be accepted at present, + * 0 if the packet was accepted but we can't accept another yet, or + * 1 if we can accept another packet immediately. + * If this procedure returns 0, ppp_output_wakeup will be called + * exactly once. + */ +static int +ppp_sync_send(struct ppp *ppp, struct sk_buff *skb) +{ + unsigned char *data; + int islcp; + + CHECK_PPP(0); + + if (ppp->tpkt != NULL) + return -1; + ppp->tpkt = skb; + + data = ppp->tpkt->data; + + /* + * LCP packets with code values between 1 (configure-reqest) + * and 7 (code-reject) must be sent as though no options + * had been negotiated. + */ + islcp = PPP_PROTOCOL(data) == PPP_LCP + && 1 <= data[PPP_HDRLEN] && data[PPP_HDRLEN] <= 7; + + /* only reset idle time for data packets */ + if (PPP_PROTOCOL(data) < 0x8000) + ppp->last_xmit = jiffies; + ++ppp->stats.ppp_opackets; + ppp->stats.ppp_ooctects += ppp->tpkt->len; + + if ( !(data[2]) && (ppp->flags & SC_COMP_PROT) ) { + /* compress protocol field */ + data[2] = data[1]; + data[1] = data[0]; + skb_pull(ppp->tpkt,1); + data = ppp->tpkt->data; + } + + /* + * Do address/control compression + */ + if ((ppp->flags & SC_COMP_AC) && !islcp + && PPP_ADDRESS(data) == PPP_ALLSTATIONS + && PPP_CONTROL(data) == PPP_UI) { + /* strip addr and control field */ + skb_pull(ppp->tpkt,2); + } + + return ppp_tty_sync_push(ppp); +} + +/* + * Push a synchronous frame out to the tty. + * Returns 1 if frame accepted (or discarded), 0 otherwise. + */ +static int +ppp_tty_sync_push(struct ppp *ppp) +{ + int sent; + struct tty_struct *tty = ppp2tty(ppp); + unsigned long flags; + + CHECK_PPP(0); + + if (ppp->tpkt == NULL) + return 0; + + /* prevent reentrancy with tty_pushing flag */ + save_flags(flags); + cli(); + if (ppp->tty_pushing) { + /* record wakeup attempt so we don't lose */ + /* a wakeup call while doing push processing */ + ppp->woke_up=1; + restore_flags(flags); + return 0; + } + ppp->tty_pushing = 1; + restore_flags(flags); + + if (tty == NULL || tty->disc_data != (void *) ppp) + goto flush; + + for(;;){ + ppp->woke_up=0; + + /* Note: Sync driver accepts complete frame or nothing */ + tty->flags |= (1 << TTY_DO_WRITE_WAKEUP); + sent = tty->driver.write(tty, 0, ppp->tpkt->data, ppp->tpkt->len); + if (sent < 0) { + /* write error (possible loss of CD) */ + /* record error and discard current packet */ + ppp->stats.ppp_oerrors++; + break; + } + ppp->stats.ppp_obytes += sent; + if (sent < ppp->tpkt->len) { + /* driver unable to accept frame just yet */ + save_flags(flags); + cli(); + if (ppp->woke_up) { + /* wake up called while processing */ + /* try to send the frame again */ + restore_flags(flags); + continue; + } + /* wait for wakeup callback to try send again */ + ppp->tty_pushing = 0; + restore_flags(flags); + return 0; + } + break; + } +flush: + /* done with current packet (sent or discarded) */ + kfree_skb(ppp->tpkt); + ppp->tpkt = 0; + ppp->tty_pushing = 0; + return 1; +} + +/* * Send a packet to the peer over an async tty line. * Returns -1 iff the packet could not be accepted at present, * 0 if the packet was accepted but we can't accept another yet, or @@ -831,14 +978,21 @@ { int avail, sent, done = 0; struct tty_struct *tty = ppp2tty(ppp); + + if (ppp->flags & SC_SYNC) + return ppp_tty_sync_push(ppp); CHECK_PPP(0); - if (ppp->tty_pushing) + if (ppp->tty_pushing) { + ppp->woke_up = 1; return 0; + } if (tty == NULL || tty->disc_data != (void *) ppp) goto flush; while (ppp->optr < ppp->olim || ppp->tpkt != 0) { ppp->tty_pushing = 1; + mb(); + ppp->woke_up = 0; avail = ppp->olim - ppp->optr; if (avail > 0) { tty->flags |= (1 << TTY_DO_WRITE_WAKEUP); @@ -848,18 +1002,24 @@ ppp->stats.ppp_obytes += sent; ppp->optr += sent; if (sent < avail) { + wmb(); ppp->tty_pushing = 0; + mb(); + if (ppp->woke_up) + continue; return done; } } if (ppp->tpkt != 0) done = ppp_async_encode(ppp); + wmb(); ppp->tty_pushing = 0; } return done; flush: ppp->tty_pushing = 1; + mb(); ppp->stats.ppp_oerrors++; if (ppp->tpkt != 0) { kfree_skb(ppp->tpkt); @@ -867,6 +1027,7 @@ done = 1; } ppp->optr = ppp->olim; + wmb(); ppp->tty_pushing = 0; return done; } @@ -981,6 +1142,32 @@ } /* + * Flush output from our internal buffers. + * Called for the TCFLSH ioctl. + */ +static void +ppp_tty_flush_output(struct ppp *ppp) +{ + struct sk_buff *skb; + int done = 0; + + while ((skb = skb_dequeue(&ppp->xmt_q)) != NULL) + kfree_skb(skb); + ppp->tty_pushing = 1; + mb(); + ppp->optr = ppp->olim; + if (ppp->tpkt != NULL) { + kfree_skb(ppp->tpkt); + ppp->tpkt = 0; + done = 1; + } + wmb(); + ppp->tty_pushing = 0; + if (done) + ppp_output_wakeup(ppp); +} + +/* * Callback function from tty driver. Return the amount of space left * in the receiver's buffer to decide if remote transmitter is to be * throttled. @@ -1029,6 +1216,73 @@ ppp->stats.ppp_ibytes += count; skb = ppp->rpkt; + + if ( ppp->flags & SC_SYNC ) { + /* synchronous mode */ + + if (ppp->toss==0xE0) { + /* this is the 1st frame, reset vj comp */ + ppp_receive_error(ppp); + ppp->toss = 0; + } + + /* + * Allocate an skbuff for frame. + * The 128 is room for VJ header expansion. + */ + + if (skb == NULL) + skb = dev_alloc_skb(ppp->mru + 128 + PPP_HDRLEN); + + if (skb == NULL) { + if (ppp->flags & SC_DEBUG) + printk(KERN_DEBUG "couldn't " + "alloc skb for recv\n"); + } else { + /* + * Decompress A/C and protocol compression here. + */ + p = skb_put(skb, 2); + p[0] = PPP_ALLSTATIONS; + p[1] = PPP_UI; + if (*data == PPP_ALLSTATIONS) { + data += 2; + count -= 2; + } + if ((*data & 1) != 0) { + p = skb_put(skb, 1); + p[0] = 0; + } + + /* copy frame to socket buffer */ + p = skb_put(skb, count); + memcpy(p,data,count); + + /* + * Check if we've overflowed the MRU + */ + if (skb->len >= ppp->mru + PPP_HDRLEN + 2 + || skb_tailroom(skb) <= 0) { + ++ppp->estats.rx_length_errors; + if (ppp->flags & SC_DEBUG) + printk(KERN_DEBUG "rcv frame too long: " + "len=%d mru=%d hroom=%d troom=%d\n", + skb->len, ppp->mru, skb_headroom(skb), + skb_tailroom(skb)); + } else { + if (!ppp_receive_frame(ppp, skb)) { + kfree_skb(skb); + ppp_receive_error(ppp); + } + } + + /* Reset for the next frame */ + skb = NULL; + } + ppp->rpkt = skb; + return; + } + while (count-- > 0) { /* * Collect the character and error condition for the character. @@ -1292,9 +1546,6 @@ CHECK_PPP_MAGIC(ppp); - /* ppp_dev_close may be called with tbusy==1 so we must set it to 0 */ - dev->tbusy=0; - MOD_DEC_USE_COUNT; return 0; @@ -1851,23 +2102,25 @@ return 0; } - /* - * Verify the FCS of the frame and discard the FCS characters - * from the end of the buffer. - */ - if (ppp->rfcs != PPP_GOODFCS) { - if (ppp->flags & SC_DEBUG) { - printk(KERN_DEBUG - "ppp: frame with bad fcs, length = %d\n", - count); - ppp_print_buffer("bad frame", data, count); + if ( !(ppp->flags & SC_SYNC) ) { + /* + * Verify the FCS of the frame and discard the FCS characters + * from the end of the buffer. + */ + if (ppp->rfcs != PPP_GOODFCS) { + if (ppp->flags & SC_DEBUG) { + printk(KERN_DEBUG + "ppp: frame with bad fcs, length = %d\n", + count); + ppp_print_buffer("bad frame", data, count); + } + ++ppp->estats.rx_crc_errors; + return 0; } - ++ppp->estats.rx_crc_errors; - return 0; + count -= 2; /* ignore the fcs characters */ + skb_trim(skb, count); } - count -= 2; /* ignore the fcs characters */ - skb_trim(skb, count); - + /* * Process the active decompressor. */ @@ -2056,13 +2309,17 @@ return 0; new_count = slhc_uncompress(ppp->slcomp, skb->data + PPP_HDRLEN, skb->len - PPP_HDRLEN); - if (new_count<=0) { + if (new_count <= 0) { if (ppp->flags & SC_DEBUG) printk(KERN_NOTICE "ppp: error in VJ decompression\n"); return 0; } - skb_put(skb, new_count + PPP_HDRLEN - skb->len); + new_count += PPP_HDRLEN; + if (new_count > skb->len) + skb_put(skb, new_count - skb->len); + else + skb_trim(skb, new_count); return rcv_proto_ip(ppp, skb); } @@ -2231,7 +2488,10 @@ /* * Send the frame */ - ret = ppp_async_send(ppp, skb); + if ( ppp->flags & SC_SYNC ) + ret = ppp_sync_send(ppp, skb); + else + ret = ppp_async_send(ppp, skb); if (ret > 0) { /* we can release the lock */ ppp->xmit_busy = 0; diff -ur --new-file old/linux/drivers/net/ppp_deflate.c new/linux/drivers/net/ppp_deflate.c --- old/linux/drivers/net/ppp_deflate.c Sat Mar 28 02:45:16 1998 +++ new/linux/drivers/net/ppp_deflate.c Thu Mar 11 01:51:35 1999 @@ -43,7 +43,6 @@ #include #include #include -#include /* to get the struct task_struct */ #include /* used in new tty drivers */ #include /* used in new tty drivers */ diff -ur --new-file old/linux/drivers/net/rclanmtl.c new/linux/drivers/net/rclanmtl.c --- old/linux/drivers/net/rclanmtl.c Fri Jan 15 07:58:47 1999 +++ new/linux/drivers/net/rclanmtl.c Tue Apr 13 01:18:27 1999 @@ -2,7 +2,7 @@ ** ************************************************************************* ** ** -** R C L A N M T L . C $Revision: 5 $ +** R C L A N M T L . C $Revision: 6 $ ** ** ** RedCreek I2O LAN Message Transport Layer program module. @@ -29,6 +29,10 @@ ** 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. +** +** 1998-1999, LAN API was modified and enhanced by Alice Hennessy. +** +** Sometime in 1997, LAN API was written from scratch by Wendell Nichols. ** ************************************************************************* */ @@ -200,7 +204,7 @@ /* Special TID Assignments */ #define I2O_IOP_TID 0 -#define I2O_HOST_TID 1 +#define I2O_HOST_TID 0xB91 /* RedCreek I2O private message codes */ #define RC_PRIVATE_GET_MAC_ADDR 0x0001/**/ /* OBSOLETE */ diff -ur --new-file old/linux/drivers/net/rclanmtl.h new/linux/drivers/net/rclanmtl.h --- old/linux/drivers/net/rclanmtl.h Fri Jan 15 07:58:47 1999 +++ new/linux/drivers/net/rclanmtl.h Tue Apr 13 01:18:27 1999 @@ -2,7 +2,7 @@ ** ************************************************************************* ** ** -** R C L A N M T L . H $Revision: 5 $ +** R C L A N M T L . H $Revision: 6 $ ** ** ** RedCreek I2O LAN Message Transport Layer header file. diff -ur --new-file old/linux/drivers/net/rcpci45.c new/linux/drivers/net/rcpci45.c --- old/linux/drivers/net/rcpci45.c Fri Jan 15 07:58:47 1999 +++ new/linux/drivers/net/rcpci45.c Tue Apr 13 01:18:27 1999 @@ -1,4 +1,5 @@ /* +** ** RCpci45.c ** ** @@ -36,16 +37,18 @@ ** ** ** Pete Popov, January 11,99: Fixed a couple of 2.1.x problems -** (virt_to_bus() not called), tested it under 2.2pre5, and added a -** #define to enable the use of the same file for both, the 2.0.x kernels -** as well as the 2.1.x. +** (virt_to_bus() not called), tested it under 2.2pre5 (as a module), and +** added a #define(s) to enable the use of the same file for both, the 2.0.x +** kernels as well as the 2.1.x. ** ** Ported to 2.1.x by Alan Cox 1998/12/9. ** +** Sometime in mid 1998, written by Pete Popov and Brian Moyle. +** ***************************************************************************/ static char *version = -"RedCreek Communications PCI linux driver version 2.00\n"; +"RedCreek Communications PCI linux driver version 2.02\n"; #include @@ -155,11 +158,10 @@ }; -static int RCscan(void); -static struct device -*RCfound_device(struct device *, int, int, int, int, int, int); +static int RCinit(struct device *dev); +static int RCscan(struct device *dev); +static int RCfound_device(struct device *, int, int, int, int, int, int); -static int RCprobe1(struct device *); static int RCopen(struct device *); static int RC_xmit_packet(struct sk_buff *, struct device *); static void RCinterrupt(int, void *, struct pt_regs *); @@ -180,134 +182,143 @@ #ifdef MODULE int init_module(void) #else -int rcpci_probe(struct netdevice *dev) +int rcpci_probe(struct device *dev) #endif { int cards_found; - printk(version); - - root_RCdev = NULL; - cards_found = RCscan(); #ifdef MODULE - return cards_found ? 0 : -ENODEV; + cards_found = RCscan(NULL); #else - return -1; + cards_found = RCscan(dev); #endif + if (cards_found) + printk(version); + return cards_found ? 0 : -ENODEV; } -static int RCscan() +static int RCscan(struct device *dev) { int cards_found = 0; - struct device *dev = 0; + static int pci_index = 0; + + if (!pcibios_present()) + return cards_found; - if (pcibios_present()) + for (;pci_index < 0x8; pci_index++) { - static int pci_index = 0; unsigned char pci_bus, pci_device_fn; int scan_status; int board_index = 0; + unsigned char pci_irq_line; + unsigned short pci_command, vendor, device, class; + unsigned int pci_ioaddr; - for (;pci_index < 0xff; pci_index++) - { - unsigned char pci_irq_line; - unsigned short pci_command, vendor, device, class; - unsigned int pci_ioaddr; - - - scan_status = - (pcibios_find_device (RC_PCI45_VENDOR_ID, - RC_PCI45_DEVICE_ID, - pci_index, - &pci_bus, - &pci_device_fn)); -#ifdef RCDEBUG - printk("rc scan_status = 0x%X\n", scan_status); -#endif - if (scan_status != PCIBIOS_SUCCESSFUL) - break; - pcibios_read_config_word(pci_bus, - pci_device_fn, - PCI_VENDOR_ID, &vendor); - pcibios_read_config_word(pci_bus, - pci_device_fn, - PCI_DEVICE_ID, &device); - pcibios_read_config_byte(pci_bus, - pci_device_fn, - PCI_INTERRUPT_LINE, &pci_irq_line); - pcibios_read_config_dword(pci_bus, - pci_device_fn, - PCI_BASE_ADDRESS_0, &pci_ioaddr); - pcibios_read_config_word(pci_bus, - pci_device_fn, - PCI_CLASS_DEVICE, &class); - - pci_ioaddr &= ~0xf; + scan_status = + (pcibios_find_device (RC_PCI45_VENDOR_ID, + RC_PCI45_DEVICE_ID, + pci_index, + &pci_bus, + &pci_device_fn)); #ifdef RCDEBUG - printk("rc: Found RedCreek PCI adapter\n"); - printk("rc: pci class = 0x%x 0x%x \n", class, class>>8); - printk("rc: pci_bus = %d, pci_device_fn = %d\n", pci_bus, pci_device_fn); - printk("rc: pci_irq_line = 0x%x \n", pci_irq_line); - printk("rc: pci_ioaddr = 0x%x\n", pci_ioaddr); + printk("rc scan_status = 0x%X\n", scan_status); +#endif + if (scan_status != PCIBIOS_SUCCESSFUL) + break; + pcibios_read_config_word(pci_bus, + pci_device_fn, + PCI_VENDOR_ID, &vendor); + pcibios_read_config_word(pci_bus, + pci_device_fn, + PCI_DEVICE_ID, &device); + pcibios_read_config_byte(pci_bus, + pci_device_fn, + PCI_INTERRUPT_LINE, &pci_irq_line); + pcibios_read_config_dword(pci_bus, + pci_device_fn, + PCI_BASE_ADDRESS_0, &pci_ioaddr); + pcibios_read_config_word(pci_bus, + pci_device_fn, + PCI_CLASS_DEVICE, &class); + + pci_ioaddr &= ~0xf; + +#ifdef RCDEBUG + printk("rc: Found RedCreek PCI adapter\n"); + printk("rc: pci class = 0x%x 0x%x \n", class, class>>8); + printk("rc: pci_bus = %d, pci_device_fn = %d\n", pci_bus, pci_device_fn); + printk("rc: pci_irq_line = 0x%x \n", pci_irq_line); + printk("rc: pci_ioaddr = 0x%x\n", pci_ioaddr); #endif -#if 1 - if (check_region(pci_ioaddr, 2*32768)) - { - printk("rc: check_region failed\n"); - continue; - } - else - { - printk("rc: check_region passed\n"); - } + if (check_region(pci_ioaddr, 2*32768)) + { + printk("rc: check_region failed\n"); + continue; + } +#ifdef RCDEBUG + else + { + printk("rc: check_region passed\n"); + } #endif - + + /* + * Get and check the bus-master and latency values. + * Some PCI BIOSes fail to set the master-enable bit. + */ + + pcibios_read_config_word(pci_bus, + pci_device_fn, + PCI_COMMAND, + &pci_command); + if ( ! (pci_command & PCI_COMMAND_MASTER)) { + printk("rc: PCI Master Bit has not been set!\n"); + + pci_command |= PCI_COMMAND_MASTER; + pcibios_write_config_word(pci_bus, + pci_device_fn, + PCI_COMMAND, + pci_command); + } + if ( ! (pci_command & PCI_COMMAND_MEMORY)) { /* - * Get and check the bus-master and latency values. - * Some PCI BIOSes fail to set the master-enable bit. + * If the BIOS did not set the memory enable bit, what else + * did it not initialize? Skip this adapter. */ - - pcibios_read_config_word(pci_bus, - pci_device_fn, - PCI_COMMAND, - &pci_command); - if ( ! (pci_command & PCI_COMMAND_MASTER)) { - printk("rc: PCI Master Bit has not been set!\n"); - - pci_command |= PCI_COMMAND_MASTER; - pcibios_write_config_word(pci_bus, - pci_device_fn, - PCI_COMMAND, - pci_command); - } - if ( ! (pci_command & PCI_COMMAND_MEMORY)) { - /* - * If the BIOS did not set the memory enable bit, what else - * did it not initialize? Skip this adapter. - */ - printk("rc: Adapter %d, PCI Memory Bit has not been set!\n", - cards_found); - printk("rc: Bios problem? \n"); - continue; - } - - dev = RCfound_device(dev, pci_ioaddr, pci_irq_line, - pci_bus, pci_device_fn, - board_index++, cards_found); - - if (dev) { - dev = 0; - cards_found++; - } + printk("rc: Adapter %d, PCI Memory Bit has not been set!\n", + cards_found); + printk("rc: Bios problem? \n"); + continue; + } + + if (!RCfound_device(dev, pci_ioaddr, pci_irq_line, + pci_bus, pci_device_fn, + board_index++, cards_found)) + { + dev = 0; + cards_found++; } } +#ifdef RCDEBUG printk("rc: found %d cards \n", cards_found); +#endif return cards_found; } -static struct device * +static int RCinit(struct device *dev) +{ + dev->open = &RCopen; + dev->hard_start_xmit = &RC_xmit_packet; + dev->stop = &RCclose; + dev->get_stats = &RCget_stats; + dev->do_ioctl = &RCioctl; + dev->set_config = &RCconfig; + return 0; +} + +static int RCfound_device(struct device *dev, int memaddr, int irq, int bus, int function, int product_index, int card_idx) { @@ -324,18 +335,37 @@ * assigned to DPA; and finally, the rest will be assigned to the * the LAN API layer. */ + +#ifdef MODULE dev = (struct device *) kmalloc(dev_size, GFP_DMA | GFP_KERNEL |GFP_ATOMIC); + if (!dev) + { + printk("rc: unable to kmalloc dev\n"); + return 1; + } memset(dev, 0, dev_size); -#ifdef RCDEBUG - printk("rc: dev = 0x%08X\n", (uint)dev); -#endif - /* * dev->priv will point to the start of DPA. */ dev->priv = (void *)(((long)dev + sizeof(struct device) + 15) & ~15); +#else + dev->priv = 0; + dev->priv = (struct device *) kmalloc(dev_size, GFP_DMA | GFP_KERNEL |GFP_ATOMIC); + if (!dev->priv) + { + printk("rc: unable to kmalloc private area\n"); + return 1; + } + memset(dev->priv, 0, dev_size); +#endif + +#ifdef RCDEBUG + printk("rc: dev = 0x%x, dev->priv = 0x%x\n", (uint)dev, (uint)dev->priv); +#endif + pDpa = dev->priv; - dev->name = pDpa->devname; + if (!dev->name) + dev->name = pDpa->devname; pDpa->dev = dev; /* this is just for easy reference */ pDpa->function = function; @@ -378,24 +408,21 @@ printk( "RC PCI 45: %s: unable to get IRQ %d\n", (PU8)dev->name, (uint)dev->irq ); iounmap(vaddr); kfree(dev); - return 0; + return 1; } init_status = RCInitI2OMsgLayer(pDpa->id, dev->base_addr, - pDpa->PLanApiPA, (PU8)virt_to_bus((void *)pDpa->PLanApiPA), - (PFNTXCALLBACK)RCxmit_callback, - (PFNRXCALLBACK)RCrecv_callback, - (PFNCALLBACK)RCreboot_callback); -#ifdef RCDEBUG - printk("rc: I2O msg initted: status = 0x%x\n", init_status); -#endif + pDpa->PLanApiPA, (PU8)virt_to_bus((void *)pDpa->PLanApiPA), + (PFNTXCALLBACK)RCxmit_callback, + (PFNRXCALLBACK)RCrecv_callback, + (PFNCALLBACK)RCreboot_callback); if (init_status) { printk("rc: Unable to initialize msg layer\n"); free_irq(dev->irq, dev); iounmap(vaddr); kfree(dev); - return 0; + return 1; } if (RCGetMAC(pDpa->id, dev->dev_addr, NULL)) { @@ -403,38 +430,34 @@ free_irq(dev->irq, dev); iounmap(vaddr); kfree(dev); - return 0; + return 1; } DriverControlWord |= WARM_REBOOT_CAPABLE; RCReportDriverCapability(pDpa->id, DriverControlWord); - dev->init = RCprobe1; + dev->init = &RCinit; ether_setup(dev); /* linux kernel interface */ pDpa->next = root_RCdev; root_RCdev = dev; +#ifdef MODULE if (register_netdev(dev) != 0) /* linux kernel interface */ { printk("rc: unable to register device \n"); free_irq(dev->irq, dev); iounmap(vaddr); kfree(dev); - return 0; + return 1; } - return dev; -} +#else + RCinit(dev); +#endif + printk("%s: RedCreek Communications IPSEC VPN adapter\n", + dev->name); -static int RCprobe1(struct device *dev) -{ - dev->open = RCopen; - dev->hard_start_xmit = RC_xmit_packet; - dev->stop = RCclose; - dev->get_stats = RCget_stats; - dev->do_ioctl = RCioctl; - dev->set_config = RCconfig; - return 0; + return 0; /* success */ } static int @@ -516,6 +539,7 @@ #ifdef RCDEBUG printk("rc: RC_xmit_packet: tbusy!\n"); #endif + dev->tbusy = 1; return 1; } @@ -658,7 +682,7 @@ RCShutdownLANCard(pDpa->id,0,0,0); printk("rc: scheduling timer...\n"); init_timer(&pDpa->timer); - pDpa->timer.expires = RUN_AT((30*HZ)/10); /* 3 sec. */ + pDpa->timer.expires = RUN_AT((40*HZ)/10); /* 4 sec. */ pDpa->timer.data = (unsigned long)dev; pDpa->timer.function = &rc_timer; /* timer handler */ add_timer(&pDpa->timer); @@ -757,9 +781,11 @@ if (!pDpa->shutdown && !pDpa->reboot) printk("rc: RCrecv error: status = 0x%x\n", (uint)Status); +#ifdef RCDEBUG else printk("rc: Returning %d buffers, status = 0x%x\n", PktCount, (uint)Status); +#endif /* * TO DO: check the nature of the failure and put the adapter in * failed mode if it's a hard failure. Send a reset to the adapter @@ -808,6 +834,8 @@ (uint)skb->data[0], (uint)skb->data[1], (uint)skb->data[2], (uint)skb->data[3], (uint)skb->data[4], (uint)skb->data[5]); #endif + +#ifdef PROMISCUOUS_BY_DEFAULT /* early 2.x firmware */ if ( (memcmp(dev->dev_addr, skb->data, 6)) && (!broadcast_packet(skb->data))) { @@ -838,6 +866,7 @@ } } else +#endif /* PROMISCUOUS_BY_DEFAULT */ { len = PacketDescBlock[2]; skb->dev = dev; @@ -883,10 +912,10 @@ pDpa = (PDPA) (dev->priv); +#ifdef RCDEBUG if (pDpa->shutdown) printk("rc: shutdown: service irq\n"); -#ifdef RCDEBUG printk("RC irq: pDpa = 0x%x, dev = 0x%x, id = %d\n", (uint)pDpa, (uint)dev, (uint)pDpa->id); printk("dev = 0x%x\n", (uint)dev); @@ -901,7 +930,8 @@ return; } -#define REBOOT_REINIT_RETRY_LIMIT 10 + +#define REBOOT_REINIT_RETRY_LIMIT 4 static void rc_timer(unsigned long data) { struct device *dev = (struct device *)data; @@ -914,12 +944,12 @@ if (pDpa->reboot) { - init_status = RCInitI2OMsgLayer(pDpa->id, dev->base_addr, - pDpa->PLanApiPA, pDpa->PLanApiPA, - (PFNTXCALLBACK)RCxmit_callback, - (PFNRXCALLBACK)RCrecv_callback, - (PFNCALLBACK)RCreboot_callback); + pDpa->PLanApiPA, + (PU8)virt_to_bus((void *)pDpa->PLanApiPA), + (PFNTXCALLBACK)RCxmit_callback, + (PFNRXCALLBACK)RCrecv_callback, + (PFNCALLBACK)RCreboot_callback); switch(init_status) { @@ -949,14 +979,16 @@ (uint)pDpa->numOutRcvBuffers); } printk("rc: Initialization done.\n"); + dev->tbusy=0; + retry=0; return; case RC_RTN_FREE_Q_EMPTY: retry++; - printk("rc: inbound free q emtpy\n"); + printk("rc: inbound free q empty\n"); break; default: retry++; - printk("rc: unexpected bad status after reboot\n"); + printk("rc: bad status after reboot: %d\n", init_status); break; } @@ -972,7 +1004,7 @@ { printk("rc: rescheduling timer...\n"); init_timer(&pDpa->timer); - pDpa->timer.expires = RUN_AT((30*HZ)/10); /* 3 sec. */ + pDpa->timer.expires = RUN_AT((40*HZ)/10); /* 3 sec. */ pDpa->timer.data = (unsigned long)dev; pDpa->timer.function = &rc_timer; /* timer handler */ add_timer(&pDpa->timer); @@ -1286,6 +1318,8 @@ return 0; } + +#ifdef MODULE void cleanup_module(void) { @@ -1315,6 +1349,8 @@ root_RCdev = next; } } +#endif + static int RC_allocate_and_post_buffers(struct device *dev, int numBuffers) diff -ur --new-file old/linux/drivers/net/rrunner.c new/linux/drivers/net/rrunner.c --- old/linux/drivers/net/rrunner.c Thu Dec 17 18:04:49 1998 +++ new/linux/drivers/net/rrunner.c Sun Apr 25 02:51:48 1999 @@ -59,15 +59,7 @@ * stack will need to know about I/O vectors or something similar. */ -static const char *version = "rrunner.c: v0.09 12/14/98 Jes Sorensen (Jes.Sorensen@cern.ch)\n"; - -static unsigned int read_eeprom(struct rr_private *rrpriv, - unsigned long offset, - unsigned char *buf, - unsigned long length); -static u32 read_eeprom_word(struct rr_private *rrpriv, - void * offset); -static int rr_load_firmware(struct device *dev); +static const char __initdata *version = "rrunner.c: v0.17 03/09/99 Jes Sorensen (Jes.Sorensen@cern.ch)\n"; /* @@ -78,44 +70,32 @@ extern __u32 sysctl_wmem_max; extern __u32 sysctl_rmem_max; +static int probed __initdata = 0; + __initfunc(int rr_hippi_probe (struct device *dev)) { - static int i = 0; int boards_found = 0; int version_disp; /* was version info already displayed? */ - u8 pci_bus; /* PCI bus number (0-255) */ - u8 pci_dev_fun; /* PCI device and function numbers (0-255) */ + struct pci_dev *pdev = NULL; + struct pci_dev *opdev = NULL; u8 pci_latency; - u16 command; /* PCI Configuration space Command register */ - unsigned int tmp; - u8 irq; struct rr_private *rrpriv; + if (probed) + return -ENODEV; + probed++; + if (!pci_present()) /* is PCI BIOS even present? */ return -ENODEV; version_disp = 0; - for (; i < 255; i++) + while((pdev = pci_find_device(PCI_VENDOR_ID_ESSENTIAL, + PCI_DEVICE_ID_ESSENTIAL_ROADRUNNER, + pdev))) { - if (pcibios_find_device(PCI_VENDOR_ID_ESSENTIAL, - PCI_DEVICE_ID_ESSENTIAL_ROADRUNNER, - i, &pci_bus, &pci_dev_fun) != 0) - break; - - pcibios_read_config_word(pci_bus, pci_dev_fun, - PCI_COMMAND, &command); - - /* Enable mastering */ - - command |= PCI_COMMAND_MASTER; - pcibios_write_config_word(pci_bus, pci_dev_fun, - PCI_COMMAND, command); - - if (!(command & PCI_COMMAND_MEMORY)){ - printk("shared mem not enabled - unable to configure RoadRunner\n"); - break; - } + if (pdev == opdev) + return 0; /* * So we found our HIPPI ... time to tell the system. @@ -123,31 +103,24 @@ dev = init_hippi_dev(dev, sizeof(struct rr_private)); - if (dev == NULL) + if (!dev) break; if (!dev->priv) dev->priv = kmalloc(sizeof(*rrpriv), GFP_KERNEL); - rrpriv = (struct rr_private *)dev->priv; - - /* Read register base address from - PCI Configuration Space */ - - pcibios_read_config_dword(pci_bus, pci_dev_fun, - PCI_BASE_ADDRESS_0, &tmp); + if (!dev->priv) + return -ENOMEM; - pcibios_read_config_byte(pci_bus, pci_dev_fun, - PCI_INTERRUPT_LINE, &irq); + rrpriv = (struct rr_private *)dev->priv; + memset(rrpriv, 0, sizeof(*rrpriv)); - dev->irq = irq; - rrpriv->pci_bus = pci_bus; - rrpriv->pci_dev_fun = pci_dev_fun; - sprintf(rrpriv->name, "RoadRunner serial HIPPI"); #ifdef __SMP__ spin_lock_init(&rrpriv->lock); #endif + sprintf(rrpriv->name, "RoadRunner serial HIPPI"); + dev->irq = pdev->irq; dev->open = &rr_open; dev->hard_start_xmit = &rr_start_xmit; dev->stop = &rr_close; @@ -168,29 +141,30 @@ printk(version); } - printk(KERN_INFO "%s: Essential RoadRunner serial HIPPI at 0x%08x, irq %i\n", - dev->name, tmp, dev->irq); - - pcibios_read_config_byte(pci_bus, pci_dev_fun, - PCI_LATENCY_TIMER, &pci_latency); -#if 0 - if (pci_latency <= 48){ - printk(" PCI latency counter too low (%i), setting to 48 clocks\n", pci_latency); - pcibios_write_config_byte(pci_bus, pci_dev_fun, - PCI_LATENCY_TIMER, 48); + pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &pci_latency); + if (pci_latency <= 0x58){ + pci_latency = 0x58; + pci_write_config_byte(pdev, PCI_LATENCY_TIMER, + pci_latency); } -#else - if (pci_latency <= 0x58) - pcibios_write_config_byte(pci_bus, pci_dev_fun, - PCI_LATENCY_TIMER, 0x58); -#endif + + pci_set_master(pdev); + + printk(KERN_INFO "%s: Essential RoadRunner serial HIPPI " + "at 0x%08lx, irq %i, PCI latency %i\n", dev->name, + pdev->base_address[0], dev->irq, pci_latency); + /* * Remap the regs into kernel space. */ - rrpriv->regs = (struct rr_regs *)ioremap(tmp, 0x1000); + rrpriv->regs = (struct rr_regs *) + ioremap(pdev->base_address[0], 0x1000); + if (!rrpriv->regs){ - printk(KERN_ERR "%s: Unable to map I/O register, RoadRunner %i will be disabled.\n", dev->name, i); + printk(KERN_ERR "%s: Unable to map I/O register, " + "RoadRunner %i will be disabled.\n", + dev->name, boards_found); break; } @@ -198,7 +172,7 @@ * Don't access any registes before this point! */ #ifdef __BIG_ENDIAN - regs->HostCtrl |= NO_SWAP; + writel(readl(®s->HostCtrl) | NO_SWAP, ®s->HostCtrl); #endif /* * Need to add a case for little-endian 64-bit hosts here. @@ -209,6 +183,7 @@ boards_found++; dev->base_addr = 0; dev = NULL; + opdev = pdev; } /* @@ -217,12 +192,59 @@ * 1 or more boards. Otherwise, return failure (-ENODEV). */ +#ifdef MODULE + return boards_found; +#else if (boards_found > 0) return 0; else return -ENODEV; +#endif +} + +static struct device *root_dev = NULL; + +#ifdef MODULE +#if LINUX_VERSION_CODE > 0x20118 +MODULE_AUTHOR("Jes Sorensen "); +MODULE_DESCRIPTION("Essential RoadRunner HIPPI driver"); +#endif + + +int init_module(void) +{ + int cards; + + root_dev = NULL; + + cards = rr_hippi_probe(NULL); + return cards ? 0 : -ENODEV; } +void cleanup_module(void) +{ + struct rr_private *rr; + struct device *next; + + while (root_dev) { + next = ((struct rr_private *)root_dev->priv)->next; + rr = (struct rr_private *)root_dev->priv; + + if (!(readl(&rr->regs->HostCtrl) & NIC_HALTED)){ + printk(KERN_ERR "%s: trying to unload running NIC\n", + root_dev->name); + writel(HALT_NIC, &rr->regs->HostCtrl); + } + + iounmap(rr->regs); + unregister_hipdev(root_dev); + kfree(root_dev); + + root_dev = next; + } +} +#endif + /* * Commands are considered to be slow, thus there is no reason to @@ -238,21 +260,25 @@ * This is temporary - it will go away in the final version. * We probably also want to make this function inline. */ - if (regs->HostCtrl & NIC_HALTED){ - printk("issuing command for halted NIC, code 0x%x, HostCtrl %08x\n", cmd->code, regs->HostCtrl); - if (regs->Mode & FATAL_ERR) - printk("error code %02x\n", regs->Fail1); + if (readl(®s->HostCtrl) & NIC_HALTED){ + printk("issuing command for halted NIC, code 0x%x, " + "HostCtrl %08x\n", cmd->code, readl(®s->HostCtrl)); + if (readl(®s->Mode) & FATAL_ERR) + printk("error codes Fail1 %02x, Fail2 %02x\n", + readl(®s->Fail1), readl(®s->Fail2)); } idx = rrpriv->info->cmd_ctrl.pi; - regs->CmdRing[idx] = *(u32*)(cmd); + writel(*(u32*)(cmd), ®s->CmdRing[idx]); + mb(); idx = (idx - 1) % CMD_RING_ENTRIES; rrpriv->info->cmd_ctrl.pi = idx; + mb(); - if (regs->Mode & FATAL_ERR) - printk("error code %02x\n", regs->Fail1); + if (readl(®s->Mode) & FATAL_ERR) + printk("error code %02x\n", readl(®s->Fail1)); } @@ -273,85 +299,97 @@ rr_load_firmware(dev); - regs->TX_state = 0x01000000; - regs->RX_state = 0xff800000; - regs->AssistState = 0; - regs->LocalCtrl = CLEAR_INTA; - regs->BrkPt = 0x01; - regs->Timer = 0; - regs->TimerRef = 0; - regs->DmaReadState = RESET_DMA; - regs->DmaWriteState = RESET_DMA; - regs->DmaWriteHostHi = 0; - regs->DmaWriteHostLo = 0; - regs->DmaReadHostHi = 0; - regs->DmaReadHostLo = 0; - regs->DmaReadLen = 0; - regs->DmaWriteLen = 0; - regs->DmaWriteLcl = 0; - regs->DmaWriteIPchecksum = 0; - regs->DmaReadLcl = 0; - regs->DmaReadIPchecksum = 0; - regs->PciState = 0; /* 0x90 for GE? */ - regs->Mode = SWAP_DATA; + writel(0x01000000, ®s->TX_state); + writel(0xff800000, ®s->RX_state); + writel(0, ®s->AssistState); + writel(CLEAR_INTA, ®s->LocalCtrl); + writel(0x01, ®s->BrkPt); + writel(0, ®s->Timer); + writel(0, ®s->TimerRef); + writel(RESET_DMA, ®s->DmaReadState); + writel(RESET_DMA, ®s->DmaWriteState); + writel(0, ®s->DmaWriteHostHi); + writel(0, ®s->DmaWriteHostLo); + writel(0, ®s->DmaReadHostHi); + writel(0, ®s->DmaReadHostLo); + writel(0, ®s->DmaReadLen); + writel(0, ®s->DmaWriteLen); + writel(0, ®s->DmaWriteLcl); + writel(0, ®s->DmaWriteIPchecksum); + writel(0, ®s->DmaReadLcl); + writel(0, ®s->DmaReadIPchecksum); + writel(0, ®s->PciState); +#if (BITS_PER_LONG == 64) && defined __LITTLE_ENDIAN + writel(SWAP_DATA | PTR64BIT | PTR_WD_SWAP, ®s->Mode); +#elif (BITS_PER_LONG == 64) + writel(SWAP_DATA | PTR64BIT | PTR_WD_NOSWAP, ®s->Mode); +#else + writel(SWAP_DATA | PTR32BIT | PTR_WD_NOSWAP, ®s->Mode); +#endif #if 0 /* * Don't worry, this is just black magic. */ - regs->RxBase = 0xdf000; - regs->RxPrd = 0xdf000; - regs->RxCon = 0xdf000; - regs->TxBase = 0xce000; - regs->TxPrd = 0xce000; - regs->TxCon = 0xce000; - regs->RxIndPro = 0; - regs->RxIndCon = 0; - regs->RxIndRef = 0; - regs->TxIndPro = 0; - regs->TxIndCon = 0; - regs->TxIndRef = 0; - regs->pad10[0] = 0xcc000; - regs->DrCmndPro = 0; - regs->DrCmndCon = 0; - regs->DwCmndPro = 0; - regs->DwCmndCon = 0; - regs->DwCmndRef = 0; - regs->DrDataPro = 0; - regs->DrDataCon = 0; - regs->DrDataRef = 0; - regs->DwDataPro = 0; - regs->DwDataCon = 0; - regs->DwDataRef = 0; + writel(0xdf000, ®s->RxBase); + writel(0xdf000, ®s->RxPrd); + writel(0xdf000, ®s->RxCon); + writel(0xce000, ®s->TxBase); + writel(0xce000, ®s->TxPrd); + writel(0xce000, ®s->TxCon); + writel(0, ®s->RxIndPro); + writel(0, ®s->RxIndCon); + writel(0, ®s->RxIndRef); + writel(0, ®s->TxIndPro); + writel(0, ®s->TxIndCon); + writel(0, ®s->TxIndRef); + writel(0xcc000, ®s->pad10[0]); + writel(0, ®s->DrCmndPro); + writel(0, ®s->DrCmndCon); + writel(0, ®s->DwCmndPro); + writel(0, ®s->DwCmndCon); + writel(0, ®s->DwCmndRef); + writel(0, ®s->DrDataPro); + writel(0, ®s->DrDataCon); + writel(0, ®s->DrDataRef); + writel(0, ®s->DwDataPro); + writel(0, ®s->DwDataCon); + writel(0, ®s->DwDataRef); #endif - regs->MbEvent = 0xffffffff; - regs->Event = 0; + writel(0xffffffff, ®s->MbEvent); + writel(0, ®s->Event); - regs->TxPi = 0; - regs->IpRxPi = 0; + writel(0, ®s->TxPi); + writel(0, ®s->IpRxPi); - regs->EvtCon = 0; - regs->EvtPrd = 0; + writel(0, ®s->EvtCon); + writel(0, ®s->EvtPrd); rrpriv->info->evt_ctrl.pi = 0; for (i = 0; i < CMD_RING_ENTRIES; i++) - regs->CmdRing[i] = 0; + writel(0, ®s->CmdRing[i]); - regs->PciState = 0; +/* + * Why 32 ? is this not cache line size dependant? + */ + writel(WBURST_32, ®s->PciState); + mb(); - start_pc = read_eeprom_word(rrpriv, &hw->rncd_info.FwStart); + start_pc = rr_read_eeprom_word(rrpriv, &hw->rncd_info.FwStart); #if (DEBUG > 1) printk("%s: Executing firmware at address 0x%06x\n", dev->name, start_pc); #endif - regs->Pc = start_pc + 0x800; + writel(start_pc + 0x800, ®s->Pc); + mb(); udelay(5); - regs->Pc = start_pc; + writel(start_pc, ®s->Pc); + mb(); return 0; } @@ -360,7 +398,7 @@ /* * Read a string from the EEPROM. */ -static unsigned int read_eeprom(struct rr_private *rrpriv, +static unsigned int rr_read_eeprom(struct rr_private *rrpriv, unsigned long offset, unsigned char *buf, unsigned long length) @@ -368,22 +406,25 @@ struct rr_regs *regs = rrpriv->regs; u32 misc, io, host, i; - io = regs->ExtIo; - regs->ExtIo = 0; - misc = regs->LocalCtrl; - regs->LocalCtrl = 0; - host = regs->HostCtrl; - regs->HostCtrl |= HALT_NIC; + io = readl(®s->ExtIo); + writel(0, ®s->ExtIo); + misc = readl(®s->LocalCtrl); + writel(0, ®s->LocalCtrl); + host = readl(®s->HostCtrl); + writel(host | HALT_NIC, ®s->HostCtrl); + mb(); for (i = 0; i < length; i++){ - regs->WinBase = (EEPROM_BASE + ((offset+i) << 3)); - buf[i] = (regs->WinData >> 24) & 0xff; + writel((EEPROM_BASE + ((offset+i) << 3)), ®s->WinBase); + mb(); + buf[i] = (readl(®s->WinData) >> 24) & 0xff; + mb(); } - regs->HostCtrl = host; - regs->LocalCtrl = misc; - regs->ExtIo = io; - + writel(host, ®s->HostCtrl); + writel(misc, ®s->LocalCtrl); + writel(io, ®s->ExtIo); + mb(); return i; } @@ -392,13 +433,13 @@ * Shortcut to read one word (4 bytes) out of the EEPROM and convert * it to our CPU byte-order. */ -static u32 read_eeprom_word(struct rr_private *rrpriv, +static u32 rr_read_eeprom_word(struct rr_private *rrpriv, void * offset) { u32 word; - if ((read_eeprom(rrpriv, (unsigned long)offset, - (char *)&word, 4) == 4)) + if ((rr_read_eeprom(rrpriv, (unsigned long)offset, + (char *)&word, 4) == 4)) return be32_to_cpu(word); return 0; } @@ -410,38 +451,42 @@ * This is only called when the firmware is not running. */ static unsigned int write_eeprom(struct rr_private *rrpriv, - unsigned long offset, - unsigned char *buf, - unsigned long length) + unsigned long offset, + unsigned char *buf, + unsigned long length) { struct rr_regs *regs = rrpriv->regs; u32 misc, io, data, i, j, ready, error = 0; - io = regs->ExtIo; - regs->ExtIo = 0; - misc = regs->LocalCtrl; - regs->LocalCtrl = ENABLE_EEPROM_WRITE; + io = readl(®s->ExtIo); + writel(0, ®s->ExtIo); + misc = readl(®s->LocalCtrl); + writel(ENABLE_EEPROM_WRITE, ®s->LocalCtrl); + mb(); for (i = 0; i < length; i++){ - regs->WinBase = (EEPROM_BASE + ((offset+i) << 3)); + writel((EEPROM_BASE + ((offset+i) << 3)), ®s->WinBase); + mb(); data = buf[i] << 24; /* * Only try to write the data if it is not the same * value already. */ - if ((regs->WinData & 0xff000000) != data){ - regs->WinData = data; + if ((readl(®s->WinData) & 0xff000000) != data){ + writel(data, ®s->WinData); ready = 0; j = 0; mb(); while(!ready){ - udelay(1000); - if ((regs->WinData & 0xff000000) == data) + udelay(20); + if ((readl(®s->WinData) & 0xff000000) == + data) ready = 1; + mb(); if (j++ > 5000){ printk("data mismatch: %08x, " "WinData %08x\n", data, - regs->WinData); + readl(®s->WinData)); ready = 1; error = 1; } @@ -449,8 +494,9 @@ } } - regs->LocalCtrl = misc; - regs->ExtIo = io; + writel(misc, ®s->LocalCtrl); + writel(io, ®s->ExtIo); + mb(); return error; } @@ -465,7 +511,8 @@ rrpriv = (struct rr_private *)dev->priv; regs = rrpriv->regs; - rev = regs->FwRev; + rev = readl(®s->FwRev); + rrpriv->fw_rev = rev; if (rev > 0x00020024) printk(" Firmware revision: %i.%i.%i\n", (rev >> 16), ((rev >> 8) & 0xff), (rev & 0xff)); @@ -477,13 +524,13 @@ printk(" Firmware revision too old: %i.%i.%i, please " "upgrade to 2.0.37 or later.\n", (rev >> 16), ((rev >> 8) & 0xff), (rev & 0xff)); - return -EFAULT; - } - printk(" Maximum receive rings %i\n", regs->MaxRxRng); +#if (DEBUG > 2) + printk(" Maximum receive rings %i\n", readl(®s->MaxRxRng)); +#endif - sram_size = read_eeprom_word(rrpriv, (void *)8); + sram_size = rr_read_eeprom_word(rrpriv, (void *)8); printk(" SRAM size 0x%06x\n", sram_size); if (sysctl_rmem_max < 262144){ @@ -498,6 +545,9 @@ sysctl_wmem_max = 262144; } + rrpriv->next = root_dev; + root_dev = dev; + return 0; } @@ -507,7 +557,7 @@ struct rr_private *rrpriv; struct rr_regs *regs; u32 hostctrl; - unsigned long myjif, flags, tmp_ptr; + unsigned long myjif, flags; struct cmd cmd; short i; @@ -516,8 +566,9 @@ spin_lock_irqsave(&rrpriv->lock, flags); - hostctrl = regs->HostCtrl; - regs->HostCtrl |= HALT_NIC; + hostctrl = readl(®s->HostCtrl); + writel(hostctrl | HALT_NIC | RR_CLEAR_INT, ®s->HostCtrl); + mb(); if (hostctrl & PARITY_ERR){ printk("%s: Parity error halting NIC - this is serious!\n", @@ -526,31 +577,14 @@ return -EFAULT; } - - memset(rrpriv->rx_ctrl, 0, 256 * sizeof(struct ring_ctrl)); - memset(rrpriv->info, 0, sizeof(struct rr_info)); - - tmp_ptr = virt_to_bus((void *)rrpriv->rx_ctrl); -#if (BITS_PER_LONG == 64) - regs->RxRingHi = (tmp_ptr >> 32); -#else - regs->RxRingHi = 0; -#endif - regs->RxRingLo = ((tmp_ptr) & 0xffffffff); - - tmp_ptr = virt_to_bus((void *)rrpriv->info); -#if (BITS_PER_LONG == 64) - regs->InfoPtrHi = (tmp_ptr >> 32); -#else - regs->InfoPtrHi = 0; -#endif - regs->InfoPtrLo = ((tmp_ptr) & 0xffffffff); + set_rxaddr(regs, rrpriv->rx_ctrl); + set_infoaddr(regs, rrpriv->info); rrpriv->info->evt_ctrl.entry_size = sizeof(struct event); rrpriv->info->evt_ctrl.entries = EVT_RING_ENTRIES; rrpriv->info->evt_ctrl.mode = 0; rrpriv->info->evt_ctrl.pi = 0; - rrpriv->info->evt_ctrl.rngptr = virt_to_bus(rrpriv->evt_ring); + set_rraddr(&rrpriv->info->evt_ctrl.rngptr, rrpriv->evt_ring); rrpriv->info->cmd_ctrl.entry_size = sizeof(struct cmd); rrpriv->info->cmd_ctrl.entries = CMD_RING_ENTRIES; @@ -558,20 +592,19 @@ rrpriv->info->cmd_ctrl.pi = 15; for (i = 0; i < CMD_RING_ENTRIES; i++) { - regs->CmdRing[i] = 0; + writel(0, ®s->CmdRing[i]); } for (i = 0; i < TX_RING_ENTRIES; i++) { rrpriv->tx_ring[i].size = 0; - rrpriv->tx_ring[i].addr = 0; + set_rraddr(&rrpriv->tx_ring[i].addr, 0); rrpriv->tx_skbuff[i] = 0; } - rrpriv->info->tx_ctrl.entry_size = sizeof(struct tx_desc); rrpriv->info->tx_ctrl.entries = TX_RING_ENTRIES; rrpriv->info->tx_ctrl.mode = 0; rrpriv->info->tx_ctrl.pi = 0; - rrpriv->info->tx_ctrl.rngptr = virt_to_bus(rrpriv->tx_ring); + set_rraddr(&rrpriv->info->tx_ctrl.rngptr, rrpriv->tx_ring); /* * Set dirty_tx before we start receiving interrupts, otherwise @@ -585,14 +618,20 @@ rr_reset(dev); - regs->IntrTmr = 0x60; - regs->WriteDmaThresh = 0x80 | 0x1f; - regs->ReadDmaThresh = 0x80 | 0x1f; + writel(0x60, ®s->IntrTmr); + /* + * These seem to have no real effect as the Firmware sets + * it's own default values + */ + writel(0x10, ®s->WriteDmaThresh); + writel(0x20, ®s->ReadDmaThresh); rrpriv->fw_running = 0; + mb(); hostctrl &= ~(HALT_NIC | INVALID_INST_B | PARITY_ERR); - regs->HostCtrl = hostctrl; + writel(hostctrl, ®s->HostCtrl); + mb(); spin_unlock_irqrestore(&rrpriv->lock, flags); @@ -626,10 +665,7 @@ if ((((unsigned long)skb->data) & 0xfff) > ~65320) printk("skb alloc error\n"); -#if (BITS_PER_LONG == 32) - rrpriv->rx_ring[i].zero = 0; -#endif - rrpriv->rx_ring[i].addr = virt_to_bus(skb->data); + set_rraddr(&rrpriv->rx_ring[i].addr, skb->data); rrpriv->rx_ring[i].size = dev->mtu + HIPPI_HLEN; } @@ -637,7 +673,8 @@ rrpriv->rx_ctrl[4].entries = RX_RING_ENTRIES; rrpriv->rx_ctrl[4].mode = 8; rrpriv->rx_ctrl[4].pi = 0; - rrpriv->rx_ctrl[4].rngptr = virt_to_bus(rrpriv->rx_ring); + mb(); + set_rraddr(&rrpriv->rx_ctrl[4].rngptr, rrpriv->rx_ring); cmd.code = C_NEW_RNG; cmd.ring = 4; @@ -647,18 +684,15 @@ #if 0 { u32 tmp; - tmp = regs->ExtIo; - regs->ExtIo = 0x80; + tmp = readl(®s->ExtIo); + writel(0x80, ®s->ExtIo); i = jiffies + 1 * HZ; while (jiffies < i); - regs->ExtIo = tmp; + writel(tmp, ®s->ExtIo); } #endif dev->tbusy = 0; -#if 0 - dev->interrupt = 0; -#endif dev->start = 1; return 0; } @@ -669,24 +703,24 @@ * events) and are handled here, outside the main interrupt handler, * to reduce the size of the handler. */ -static u32 rr_handle_event(struct device *dev, u32 prodidx) +static u32 rr_handle_event(struct device *dev, u32 prodidx, u32 eidx) { struct rr_private *rrpriv; struct rr_regs *regs; - u32 tmp, eidx; + u32 tmp; rrpriv = (struct rr_private *)dev->priv; regs = rrpriv->regs; - eidx = rrpriv->info->evt_ctrl.pi; while (prodidx != eidx){ switch (rrpriv->evt_ring[eidx].code){ case E_NIC_UP: - tmp = regs->FwRev; + tmp = readl(®s->FwRev); printk("%s: Firmware revision %i.%i.%i up and running\n", dev->name, (tmp >> 16), ((tmp >> 8) & 0xff), (tmp & 0xff)); rrpriv->fw_running = 1; + mb(); break; case E_LINK_ON: printk("%s: Optical link ON\n", dev->name); @@ -729,7 +763,7 @@ #if (DEBUG > 2) printk("%s: RX ring valid event\n", dev->name); #endif - regs->IpRxPi = RX_RING_ENTRIES - 1; + writel(RX_RING_ENTRIES - 1, ®s->IpRxPi); break; case E_INV_RNG: printk("%s: RX ring invalid event\n", dev->name); @@ -756,35 +790,24 @@ } rrpriv->info->evt_ctrl.pi = eidx; + mb(); return eidx; } -static int rx_int(struct device *dev, u32 rxlimit) +static void rx_int(struct device *dev, u32 rxlimit, u32 index) { struct rr_private *rrpriv = (struct rr_private *)dev->priv; - u32 index, pkt_len; + u32 pkt_len; struct rr_regs *regs = rrpriv->regs; - index = rrpriv->cur_rx; - - while(index != rxlimit){ + do { pkt_len = rrpriv->rx_ring[index].size; #if (DEBUG > 2) printk("index %i, rxlimit %i\n", index, rxlimit); printk("len %x, mode %x\n", pkt_len, rrpriv->rx_ring[index].mode); #endif -#if 0 -/* - * I have never seen this occur - */ - if(!(rrpriv->rx_skbuff[index])){ - printk("Trying to receive in empty skbuff\n"); - goto out; - } -#endif - if (pkt_len > 0){ struct sk_buff *skb; @@ -808,7 +831,7 @@ skb = rrpriv->rx_skbuff[index]; skb_put(skb, pkt_len); rrpriv->rx_skbuff[index] = newskb; - rrpriv->rx_ring[index].addr = virt_to_bus(newskb->data); + set_rraddr(&rrpriv->rx_ring[index].addr, newskb->data); }else{ printk("%s: Out of memory, deferring " "packet\n", dev->name); @@ -829,13 +852,13 @@ rrpriv->rx_ring[index].size = dev->mtu + HIPPI_HLEN; if ((index & 7) == 7) - regs->IpRxPi = index; + writel(index, ®s->IpRxPi); index = (index + 1) % RX_RING_ENTRIES; - } + } while(index != rxlimit); rrpriv->cur_rx = index; - return index; + mb(); } @@ -844,25 +867,18 @@ struct rr_private *rrpriv; struct rr_regs *regs; struct device *dev = (struct device *)dev_id; - u32 prodidx, eidx, txcsmr, rxlimit, txcon; + u32 prodidx, rxindex, eidx, txcsmr, rxlimit, txcon; unsigned long flags; rrpriv = (struct rr_private *)dev->priv; regs = rrpriv->regs; - if (!(regs->HostCtrl & RR_INT)) + if (!(readl(®s->HostCtrl) & RR_INT)) return; -#if 0 - if (test_and_set_bit(0, (void*)&dev->interrupt) != 0) { - printk("%s: Re-entering the interrupt handler.\n", dev->name); - return; - } -#endif - spin_lock_irqsave(&rrpriv->lock, flags); - prodidx = regs->EvtPrd; + prodidx = readl(®s->EvtPrd); txcsmr = (prodidx >> 8) & 0xff; rxlimit = (prodidx >> 16) & 0xff; prodidx &= 0xff; @@ -872,6 +888,10 @@ prodidx, rrpriv->info->evt_ctrl.pi); #endif + rxindex = rrpriv->cur_rx; + if (rxindex != rxlimit) + rx_int(dev, rxlimit, rxindex); + txcon = rrpriv->dirty_tx; if (txcsmr != txcon) { do { @@ -881,11 +901,12 @@ rrpriv->tx_skbuff[txcon] = NULL; rrpriv->tx_ring[txcon].size = 0; - rrpriv->tx_ring[txcon].addr = 0; + set_rraddr(&rrpriv->tx_ring[txcon].addr, 0); rrpriv->tx_ring[txcon].mode = 0; txcon = (txcon + 1) % TX_RING_ENTRIES; } while (txcsmr != txcon); + mb(); rrpriv->dirty_tx = txcon; if (rrpriv->tx_full && dev->tbusy && @@ -897,21 +918,15 @@ } } - rx_int(dev, rxlimit); - eidx = rrpriv->info->evt_ctrl.pi; - if (prodidx != eidx) - eidx = rr_handle_event(dev, prodidx); + eidx = rr_handle_event(dev, prodidx, eidx); eidx |= ((txcsmr << 8) | (rxlimit << 16)); - regs->EvtCon = eidx; + writel(eidx, ®s->EvtCon); + mb(); spin_unlock_irqrestore(&rrpriv->lock, flags); - -#if 0 - dev->interrupt = 0; -#endif } @@ -919,35 +934,64 @@ { struct rr_private *rrpriv; struct rr_regs *regs; + int ecode = 0; + unsigned long flags; rrpriv = (struct rr_private *)dev->priv; regs = rrpriv->regs; -#if 0 - regs->HostCtrl |= (HALT_NIC | RR_CLEAR_INT); -#endif + if (rrpriv->fw_rev < 0x00020000) { + printk(KERN_WARNING "%s: trying to configure device with " + "obsolete firmware\n", dev->name); + ecode = -EBUSY; + goto error; + } + + rrpriv->rx_ctrl = kmalloc(256*sizeof(struct ring_ctrl), + GFP_KERNEL | GFP_DMA); + if (!rrpriv->rx_ctrl) { + ecode = -ENOMEM; + goto error; + } + + rrpriv->info = kmalloc(sizeof(struct rr_info), GFP_KERNEL | GFP_DMA); + if (!rrpriv->info){ + kfree(rrpriv->rx_ctrl); + ecode = -ENOMEM; + goto error; + } + memset(rrpriv->rx_ctrl, 0, 256 * sizeof(struct ring_ctrl)); + memset(rrpriv->info, 0, sizeof(struct rr_info)); + mb(); + + spin_lock_irqsave(&rrpriv->lock, flags); + writel(readl(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT, ®s->HostCtrl); + spin_unlock_irqrestore(&rrpriv->lock, flags); if (request_irq(dev->irq, rr_interrupt, SA_SHIRQ, rrpriv->name, dev)) { printk(KERN_WARNING "%s: Requested IRQ %d is busy\n", dev->name, dev->irq); - return -EAGAIN; + ecode = -EAGAIN; + goto error; } - rrpriv->rx_ctrl = kmalloc(256*sizeof(struct ring_ctrl), - GFP_KERNEL | GFP_DMA); - rrpriv->info = kmalloc(sizeof(struct rr_info), GFP_KERNEL | GFP_DMA); - rr_init1(dev); dev->tbusy = 0; -#if 0 - dev->interrupt = 0; -#endif dev->start = 1; MOD_INC_USE_COUNT; return 0; + + error: + spin_lock_irqsave(&rrpriv->lock, flags); + writel(readl(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT, ®s->HostCtrl); + spin_unlock_irqrestore(&rrpriv->lock, flags); + + dev->tbusy = 1; + dev->start = 0; + return -ENOMEM; } @@ -965,12 +1009,13 @@ printk("%s: dumping NIC TX rings\n", dev->name); printk("RxPrd %08x, TxPrd %02x, EvtPrd %08x, TxPi %02x, TxCtrlPi %02x\n", - regs->RxPrd, regs->TxPrd, regs->EvtPrd, regs->TxPi, + readl(®s->RxPrd), readl(®s->TxPrd), + readl(®s->EvtPrd), readl(®s->TxPi), rrpriv->info->tx_ctrl.pi); - printk("Error code 0x%x\n", regs->Fail1); + printk("Error code 0x%x\n", readl(®s->Fail1)); - index = (((regs->EvtPrd >> 8) & 0xff ) - 1) % EVT_RING_ENTRIES; + index = (((readl(®s->EvtPrd) >> 8) & 0xff ) - 1) % EVT_RING_ENTRIES; cons = rrpriv->dirty_tx; printk("TX ring index %i, TX consumer %i\n", index, cons); @@ -989,12 +1034,12 @@ if (rrpriv->tx_skbuff[cons]){ len = min(0x80, rrpriv->tx_skbuff[cons]->len); printk("skbuff for cons %i is valid - dumping data (0x%x bytes - skbuff len 0x%x)\n", cons, len, rrpriv->tx_skbuff[cons]->len); - printk("mode 0x%x, size 0x%x,\n phys %08x (virt %08x), skbuff-addr %08x, truesize 0x%x\n", + printk("mode 0x%x, size 0x%x,\n phys %08x (virt %08lx), skbuff-addr %08lx, truesize 0x%x\n", rrpriv->tx_ring[cons].mode, rrpriv->tx_ring[cons].size, - rrpriv->tx_ring[cons].addr, - (unsigned int)bus_to_virt(rrpriv->tx_ring[cons].addr), - (unsigned int)rrpriv->tx_skbuff[cons]->data, + rrpriv->tx_ring[cons].addr.addrlo, + (unsigned long)bus_to_virt(rrpriv->tx_ring[cons].addr.addrlo), + (unsigned long)rrpriv->tx_skbuff[cons]->data, (unsigned int)rrpriv->tx_skbuff[cons]->truesize); for (i = 0; i < len; i++){ if (!(i & 7)) @@ -1009,7 +1054,7 @@ printk("mode 0x%x, size 0x%x, phys-addr %08x\n", rrpriv->tx_ring[i].mode, rrpriv->tx_ring[i].size, - rrpriv->tx_ring[i].addr); + rrpriv->tx_ring[i].addr.addrlo); } @@ -1033,24 +1078,26 @@ */ spin_lock(&rrpriv->lock); - tmp = regs->HostCtrl; + tmp = readl(®s->HostCtrl); if (tmp & NIC_HALTED){ printk("%s: NIC already halted\n", dev->name); rr_dump(dev); - }else - tmp |= HALT_NIC; - regs->HostCtrl = tmp; + }else{ + tmp |= HALT_NIC | RR_CLEAR_INT; + writel(tmp, ®s->HostCtrl); + mb(); + } rrpriv->fw_running = 0; - regs->TxPi = 0; - regs->IpRxPi = 0; + writel(0, ®s->TxPi); + writel(0, ®s->IpRxPi); - regs->EvtCon = 0; - regs->EvtPrd = 0; + writel(0, ®s->EvtCon); + writel(0, ®s->EvtPrd); for (i = 0; i < CMD_RING_ENTRIES; i++) - regs->CmdRing[i] = 0; + writel(0, ®s->CmdRing[i]); rrpriv->info->tx_ctrl.entries = 0; rrpriv->info->cmd_ctrl.pi = 0; @@ -1060,7 +1107,7 @@ for (i = 0; i < TX_RING_ENTRIES; i++) { if (rrpriv->tx_skbuff[i]) { rrpriv->tx_ring[i].size = 0; - rrpriv->tx_ring[i].addr = 0; + set_rraddr(&rrpriv->tx_ring[i].addr, 0); dev_kfree_skb(rrpriv->tx_skbuff[i]); } } @@ -1068,7 +1115,7 @@ for (i = 0; i < RX_RING_ENTRIES; i++) { if (rrpriv->rx_skbuff[i]) { rrpriv->rx_ring[i].size = 0; - rrpriv->rx_ring[i].addr = 0; + set_rraddr(&rrpriv->rx_ring[i].addr, 0); dev_kfree_skb(rrpriv->rx_skbuff[i]); } } @@ -1094,6 +1141,10 @@ u32 *ifield; struct sk_buff *new_skb; + if (readl(®s->Mode) & FATAL_ERR) + printk("error codes Fail1 %02x, Fail2 %02x\n", + readl(®s->Fail1), readl(®s->Fail2)); + /* * We probably need to deal with tbusy here to prevent overruns. */ @@ -1128,11 +1179,11 @@ index = txctrl->pi; rrpriv->tx_skbuff[index] = skb; - rrpriv->tx_ring[index].addr = virt_to_bus(skb->data); + set_rraddr(&rrpriv->tx_ring[index].addr, skb->data); rrpriv->tx_ring[index].size = len + 8; /* include IFIELD */ rrpriv->tx_ring[index].mode = PACKET_START | PACKET_END; txctrl->pi = (index + 1) % TX_RING_ENTRIES; - regs->TxPi = txctrl->pi; + writel(txctrl->pi, ®s->TxPi); if (txctrl->pi == rrpriv->dirty_tx){ rrpriv->tx_full = 1; @@ -1167,8 +1218,9 @@ { struct rr_private *rrpriv; struct rr_regs *regs; + unsigned long eptr, segptr; int i, j; - u32 localctrl, eptr, sptr, segptr, len, tmp; + u32 localctrl, sptr, len, tmp; u32 p2len, p2size, nr_seg, revision, io, sram_size; struct eeprom *hw = NULL; @@ -1178,40 +1230,44 @@ if (dev->flags & IFF_UP) return -EBUSY; - if (!(regs->HostCtrl & NIC_HALTED)){ + if (!(readl(®s->HostCtrl) & NIC_HALTED)){ printk("%s: Trying to load firmware to a running NIC.\n", dev->name); return -EBUSY; } - localctrl = regs->LocalCtrl; - regs->LocalCtrl = 0; + localctrl = readl(®s->LocalCtrl); + writel(0, ®s->LocalCtrl); - regs->EvtPrd = 0; - regs->RxPrd = 0; - regs->TxPrd = 0; + writel(0, ®s->EvtPrd); + writel(0, ®s->RxPrd); + writel(0, ®s->TxPrd); /* * First wipe the entire SRAM, otherwise we might run into all * kinds of trouble ... sigh, this took almost all afternoon * to track down ;-( */ - io = regs->ExtIo; - regs->ExtIo = 0; - sram_size = read_eeprom_word(rrpriv, (void *)8); + io = readl(®s->ExtIo); + writel(0, ®s->ExtIo); + sram_size = rr_read_eeprom_word(rrpriv, (void *)8); for (i = 200; i < sram_size / 4; i++){ - regs->WinBase = i * 4; - regs->WinData = 0; + writel(i * 4, ®s->WinBase); + mb(); + writel(0, ®s->WinData); + mb(); } - regs->ExtIo = io; + writel(io, ®s->ExtIo); + mb(); - eptr = read_eeprom_word(rrpriv, &hw->rncd_info.AddrRunCodeSegs); + eptr = (unsigned long)rr_read_eeprom_word(rrpriv, + &hw->rncd_info.AddrRunCodeSegs); eptr = ((eptr & 0x1fffff) >> 3); - p2len = read_eeprom_word(rrpriv, (void *)(0x83*4)); + p2len = rr_read_eeprom_word(rrpriv, (void *)(0x83*4)); p2len = (p2len << 2); - p2size = read_eeprom_word(rrpriv, (void *)(0x84*4)); + p2size = rr_read_eeprom_word(rrpriv, (void *)(0x84*4)); p2size = ((p2size & 0x1fffff) >> 3); if ((eptr < p2size) || (eptr > (p2size + p2len))){ @@ -1219,7 +1275,7 @@ goto out; } - revision = read_eeprom_word(rrpriv, &hw->manf.HeaderFmt); + revision = rr_read_eeprom_word(rrpriv, &hw->manf.HeaderFmt); if (revision != 1){ printk("%s: invalid firmware format (%i)\n", @@ -1227,18 +1283,18 @@ goto out; } - nr_seg = read_eeprom_word(rrpriv, (void *)eptr); + nr_seg = rr_read_eeprom_word(rrpriv, (void *)eptr); eptr +=4; #if (DEBUG > 1) printk("%s: nr_seg %i\n", dev->name, nr_seg); #endif for (i = 0; i < nr_seg; i++){ - sptr = read_eeprom_word(rrpriv, (void *)eptr); + sptr = rr_read_eeprom_word(rrpriv, (void *)eptr); eptr += 4; - len = read_eeprom_word(rrpriv, (void *)eptr); + len = rr_read_eeprom_word(rrpriv, (void *)eptr); eptr += 4; - segptr = read_eeprom_word(rrpriv, (void *)eptr); + segptr = (unsigned long)rr_read_eeprom_word(rrpriv, (void *)eptr); segptr = ((segptr & 0x1fffff) >> 3); eptr += 4; #if (DEBUG > 1) @@ -1246,16 +1302,19 @@ dev->name, i, sptr, len, segptr); #endif for (j = 0; j < len; j++){ - tmp = read_eeprom_word(rrpriv, (void *)segptr); - regs->WinBase = sptr; - regs->WinData = tmp; + tmp = rr_read_eeprom_word(rrpriv, (void *)segptr); + writel(sptr, ®s->WinBase); + mb(); + writel(tmp, ®s->WinData); + mb(); segptr += 4; sptr += 4; } } out: - regs->LocalCtrl = localctrl; + writel(localctrl, ®s->LocalCtrl); + mb(); return 0; } @@ -1291,7 +1350,7 @@ error = -ENOMEM; goto out; } - i = read_eeprom(rrpriv, 0, image, EEPROM_BYTES); + i = rr_read_eeprom(rrpriv, 0, image, EEPROM_BYTES); if (i != EEPROM_BYTES){ kfree(image); printk(KERN_ERR "%s: Error reading EEPROM\n", @@ -1325,7 +1384,7 @@ } oldimage = kmalloc(EEPROM_WORDS * sizeof(u32), GFP_KERNEL); - if (!image){ + if (!oldimage){ printk(KERN_ERR "%s: Unable to allocate memory " "for old EEPROM image\n", dev->name); error = -ENOMEM; @@ -1343,7 +1402,7 @@ printk(KERN_ERR "%s: Error writing EEPROM\n", dev->name); - i = read_eeprom(rrpriv, 0, oldimage, EEPROM_BYTES); + i = rr_read_eeprom(rrpriv, 0, oldimage, EEPROM_BYTES); if (i != EEPROM_BYTES) printk(KERN_ERR "%s: Error reading back EEPROM " "image\n", dev->name); @@ -1354,7 +1413,6 @@ dev->name); error = -EFAULT; } - kfree(image); kfree(oldimage); break; @@ -1374,6 +1432,6 @@ /* * Local variables: - * compile-command: "gcc -D__SMP__ -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -pipe -fomit-frame-pointer -fno-strength-reduce -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2 -DCPU=686 -c rrunner.c" + * compile-command: "gcc -D__SMP__ -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -pipe -fomit-frame-pointer -fno-strength-reduce -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2 -DCPU=686 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h -c rrunner.c" * End: */ diff -ur --new-file old/linux/drivers/net/rrunner.h new/linux/drivers/net/rrunner.h --- old/linux/drivers/net/rrunner.h Thu Dec 17 18:04:49 1998 +++ new/linux/drivers/net/rrunner.h Sun Apr 25 02:51:48 1999 @@ -278,7 +278,6 @@ #define TRACE_ON_WHAT_BIT 0x00020000 /* Traces on */ #define ONEM_BUF_WHAT_BIT 0x00040000 /* 1Meg vs 256K */ #define CHAR_API_WHAT_BIT 0x00080000 /* Char API vs network only */ -#define MS_DOS_WHAT_BIT 0x00100000 /* MS_DOS */ #define CMD_EVT_WHAT_BIT 0x00200000 /* Command event */ #define LONG_TX_WHAT_BIT 0x00400000 #define LONG_RX_WHAT_BIT 0x00800000 @@ -486,6 +485,63 @@ #define SAME_IFIELD 0x80 +typedef struct { +#if (BITS_PER_LONG == 64) + u64 addrlo; +#else + u32 addrhi; + u32 addrlo; +#endif +} rraddr; + + +static inline void set_rraddr(rraddr *ra, volatile void *addr) +{ + unsigned long baddr = virt_to_bus((void *)addr); +#if (BITS_PER_LONG == 64) + ra->addrlo = baddr; +#else + /* Don't bother setting zero every time */ + ra->addrlo = baddr; +#endif + mb(); +} + + +static inline void set_rxaddr(struct rr_regs *regs, volatile void *addr) +{ + unsigned long baddr = virt_to_bus((void *)addr); +#if (BITS_PER_LONG == 64) && defined(__LITTLE_ENDIAN) + writel(baddr & 0xffffffff, ®s->RxRingHi); + writel(baddr >> 32, ®s->RxRingLo); +#elif (BITS_PER_LONG == 64) + writel(baddr >> 32, ®s->RxRingHi); + writel(baddr & 0xffffffff, ®s->RxRingLo); +#else + writel(0, ®s->RxRingHi); + writel(baddr, ®s->RxRingLo); +#endif + mb(); +} + + +static inline void set_infoaddr(struct rr_regs *regs, volatile void *addr) +{ + unsigned long baddr = virt_to_bus((void *)addr); +#if (BITS_PER_LONG == 64) && defined(__LITTLE_ENDIAN) + writel(baddr & 0xffffffff, ®s->InfoPtrHi); + writel(baddr >> 32, ®s->InfoPtrLo); +#elif (BITS_PER_LONG == 64) + writel(baddr >> 32, ®s->InfoPtrHi); + writel(baddr & 0xffffffff, ®s->InfoPtrLo); +#else + writel(0, ®s->InfoPtrHi); + writel(baddr, ®s->InfoPtrLo); +#endif + mb(); +} + + /* * TX ring */ @@ -498,12 +554,7 @@ #define TX_RING_SIZE (TX_RING_ENTRIES * sizeof(struct tx_desc)) struct tx_desc{ -#if (BITS_PER_LONG == 64) - u64 addr; -#else - u32 zero; - u32 addr; -#endif + rraddr addr; u32 res; #ifdef __LITTLE_ENDIAN u16 size; @@ -525,12 +576,7 @@ #define RX_RING_SIZE (RX_RING_ENTRIES * sizeof(struct rx_desc)) struct rx_desc{ -#if (BITS_PER_LONG == 64) - u64 addr; -#else - u32 zero; - u32 addr; -#endif + rraddr addr; u32 res; #ifdef __LITTLE_ENDIAN u16 size; @@ -714,12 +760,7 @@ * This struct is shared with the NIC firmware. */ struct ring_ctrl { -#if (BITS_PER_LONG == 64) - u64 rngptr; -#else - u32 zero; - u32 rngptr; -#endif + rraddr rngptr; #ifdef __LITTLE_ENDIAN u16 entries; u8 pad; @@ -759,19 +800,19 @@ struct rx_desc rx_ring[RX_RING_ENTRIES]; struct tx_desc tx_ring[TX_RING_ENTRIES]; struct event evt_ring[EVT_RING_ENTRIES]; - struct sk_buff *tx_skbuff[TX_RING_ENTRIES]; struct sk_buff *rx_skbuff[RX_RING_ENTRIES]; + struct sk_buff *tx_skbuff[TX_RING_ENTRIES]; struct rr_regs *regs; /* Register base */ struct ring_ctrl *rx_ctrl; /* Receive ring control */ struct rr_info *info; /* Shared info page */ + struct device *next; spinlock_t lock; struct timer_list timer; u32 cur_rx, cur_cmd, cur_evt; u32 dirty_rx, dirty_tx; u32 tx_full; + u32 fw_rev; short fw_running; - u8 pci_bus; /* PCI bus number */ - u8 pci_dev_fun; /* PCI device numbers */ char name[24]; /* The assigned name */ struct net_device_stats stats; }; @@ -789,5 +830,11 @@ static int rr_close(struct device *dev); static struct net_device_stats *rr_get_stats(struct device *dev); static int rr_ioctl(struct device *dev, struct ifreq *rq, int cmd); +static unsigned int rr_read_eeprom(struct rr_private *rrpriv, + unsigned long offset, + unsigned char *buf, + unsigned long length); +static u32 rr_read_eeprom_word(struct rr_private *rrpriv, void * offset); +static int rr_load_firmware(struct device *dev); #endif /* _RRUNNER_H_ */ diff -ur --new-file old/linux/drivers/net/shaper.c new/linux/drivers/net/shaper.c --- old/linux/drivers/net/shaper.c Fri Nov 13 19:29:44 1998 +++ new/linux/drivers/net/shaper.c Thu Mar 11 01:51:35 1999 @@ -53,13 +53,19 @@ * 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. + * 1999 Andrea Arcangeli + */ #include #include #include #include #include -#include #include #include #include @@ -83,21 +89,17 @@ static int shaper_lock(struct shaper *sh) { - unsigned long flags; - save_flags(flags); - cli(); /* - * Lock in an interrupt may fail + * Lock in an interrupt must fail */ - if(sh->locked && in_interrupt()) + while (test_and_set_bit(0, &sh->locked)) { - restore_flags(flags); - return 0; + if (!in_interrupt()) + sleep_on(&sh->wait_queue); + else + return 0; + } - while(sh->locked) - sleep_on(&sh->wait_queue); - sh->locked=1; - restore_flags(flags); return 1; } @@ -105,7 +107,7 @@ static void shaper_unlock(struct shaper *sh) { - sh->locked=0; + clear_bit(0, &sh->locked); wake_up(&sh->wait_queue); shaper_kick(sh); } @@ -240,7 +242,6 @@ dev_kfree_skb(ptr); } shaper_unlock(shaper); - shaper_kick(shaper); return 0; } @@ -285,24 +286,16 @@ static void shaper_kick(struct shaper *shaper) { struct sk_buff *skb; - unsigned long flags; - save_flags(flags); - cli(); - - del_timer(&shaper->timer); - /* * Shaper unlock will kick */ - if(shaper->locked) - { + if (test_and_set_bit(0, &shaper->locked)) + { if(sh_debug) printk("Shaper locked.\n"); - shaper->timer.expires=jiffies+1; - add_timer(&shaper->timer); - restore_flags(flags); + mod_timer(&shaper->timer, jiffies); return; } @@ -320,7 +313,7 @@ if(sh_debug) printk("Clock = %d, jiffies = %ld\n", skb->shapeclock, jiffies); - if(skb->shapeclock - jiffies <= SHAPER_BURST) + if(time_before_eq(skb->shapeclock - jiffies, SHAPER_BURST)) { /* * Pull the frame and get interrupts back on. @@ -329,8 +322,6 @@ skb_unlink(skb); if (shaper->recovery < skb->shapeclock + skb->shapelen) shaper->recovery = skb->shapeclock + skb->shapelen; - restore_flags(flags); - /* * Pass on to the physical target device via * our low level packet thrower. @@ -338,7 +329,6 @@ skb->shapepend=0; shaper_queue_xmit(shaper, skb); /* Fire */ - cli(); } else break; @@ -349,17 +339,9 @@ */ if(skb!=NULL) - { - del_timer(&shaper->timer); - shaper->timer.expires=skb->shapeclock; - add_timer(&shaper->timer); - } - - /* - * Interrupts on, mission complete - */ - - restore_flags(flags); + mod_timer(&shaper->timer, skb->shapeclock); + + clear_bit(0, &shaper->locked); } @@ -370,8 +352,14 @@ static void shaper_flush(struct shaper *shaper) { struct sk_buff *skb; + if(!shaper_lock(shaper)) + { + printk(KERN_ERR "shaper: shaper_flush() called by an irq!\n"); + return; + } while((skb=skb_dequeue(&shaper->sendq))!=NULL) dev_kfree_skb(skb); + shaper_unlock(shaper); } /* @@ -405,7 +393,9 @@ { struct shaper *shaper=dev->priv; shaper_flush(shaper); + start_bh_atomic(); del_timer(&shaper->timer); + end_bh_atomic(); MOD_DEC_USE_COUNT; return 0; } diff -ur --new-file old/linux/drivers/net/sk_g16.c new/linux/drivers/net/sk_g16.c --- old/linux/drivers/net/sk_g16.c Mon Jul 27 08:35:56 1998 +++ new/linux/drivers/net/sk_g16.c Mon Mar 8 00:47:46 1999 @@ -733,7 +733,7 @@ SK_print_pos(dev, "POS registers after ROM, RAM config"); #endif - board = (SK_RAM *) rom_addr; + board = (SK_RAM *) bus_to_virt(rom_addr); /* Read in station address */ for (i = 0, j = 0; i < ETH_ALEN; i++, j+=2) diff -ur --new-file old/linux/drivers/net/smc-ultra.c new/linux/drivers/net/smc-ultra.c --- old/linux/drivers/net/smc-ultra.c Wed Dec 16 22:35:49 1998 +++ new/linux/drivers/net/smc-ultra.c Thu Feb 25 01:27:54 1999 @@ -2,7 +2,7 @@ /* This is a driver for the SMC Ultra and SMC EtherEZ ISA ethercards. - Written 1993-1996 by Donald Becker. + Written 1993-1998 by Donald Becker. Copyright 1993 United States Government as represented by the Director, National Security Agency. @@ -14,7 +14,7 @@ Center of Excellence in Space Data and Information Sciences Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771 - This driver uses the cards in the 8390-compatible, shared memory mode. + This driver uses the cards in the 8390-compatible mode. Most of the run-time complexity is handled by the generic code in 8390.c. The code in this file is responsible for @@ -27,6 +27,8 @@ ultra_block_input() Routines for reading and writing blocks of ultra_block_output() packet buffer memory. + ultra_pio_input() + ultra_pio_output() This driver enables the shared memory only when doing the actual data transfers to avoid a bug in early version of the card that corrupted @@ -34,7 +36,7 @@ This driver now supports the programmed-I/O (PIO) data transfer mode of the EtherEZ. It does not use the non-8390-compatible "Altego" mode. - That support (if available) is smc-ez.c. + That support (if available) is in smc-ez.c. Changelog: @@ -44,8 +46,7 @@ */ static const char *version = - "smc-ultra.c:v2.00 6/6/96 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n"; - + "smc-ultra.c:v2.02 2/3/98 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n"; #include @@ -75,13 +76,13 @@ static void ultra_block_input(struct device *dev, int count, struct sk_buff *skb, int ring_offset); static void ultra_block_output(struct device *dev, int count, - const unsigned char *buf, int start_page); + const unsigned char *buf, const int start_page); static void ultra_pio_get_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, int ring_page); static void ultra_pio_input(struct device *dev, int count, struct sk_buff *skb, int ring_offset); static void ultra_pio_output(struct device *dev, int count, - const unsigned char *buf, int start_page); + const unsigned char *buf, const int start_page); static int ultra_close_card(struct device *dev); @@ -155,11 +156,8 @@ if (load_8390_module("smc-ultra.c")) return -ENOSYS; - /* We should have a "dev" from Space.c or the static module table. */ - if (dev == NULL) { - printk("smc-ultra.c: Passed a NULL device.\n"); + if (dev == NULL) dev = init_etherdev(0, 0); - } if (ei_debug && version_printed++ == 0) printk(version); @@ -255,12 +253,19 @@ ultra_open(struct device *dev) { int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET; /* ASIC addr */ + unsigned char irq2reg[] = {0, 0, 0x04, 0x08, 0, 0x0C, 0, 0x40, + 0, 0x04, 0x44, 0x48, 0, 0, 0, 0x4C, }; if (request_irq(dev->irq, ei_interrupt, 0, ei_status.name, dev)) return -EAGAIN; outb(0x00, ioaddr); /* Disable shared memory for safety. */ outb(0x80, ioaddr + 5); + /* Set the IRQ line. */ + outb(inb(ioaddr + 4) | 0x80, ioaddr + 4); + outb((inb(ioaddr + 13) & ~0x4C) | irq2reg[dev->irq], ioaddr + 13); + outb(inb(ioaddr + 4) & 0x7f, ioaddr + 4); + if (ei_status.block_input == &ultra_pio_input) { outb(0x11, ioaddr + 6); /* Enable interrupts and PIO. */ outb(0x01, ioaddr + 0x19); /* Enable ring read auto-wrap. */ @@ -358,7 +363,7 @@ byte-sequentially to IOPA, with no intervening I/O operations, and the data is read or written to the IOPD data port. The only potential complication is that the address register is shared - must be always be rewritten between each read/write direction change. + and must be always be rewritten between each read/write direction change. This is no problem for us, as the 8390 code ensures that we are single threaded. */ static void ultra_pio_get_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, @@ -379,20 +384,17 @@ /* For now set the address again, although it should already be correct. */ outb(ring_offset, ioaddr + IOPA); /* Set the address, LSB first. */ outb(ring_offset >> 8, ioaddr + IOPA); + /* We know skbuffs are padded to at least word alignment. */ insw(ioaddr + IOPD, buf, (count+1)>>1); -#ifdef notdef - /* We don't need this -- skbuffs are padded to at least word alignment. */ - if (count & 0x01) { - buf[count-1] = inb(ioaddr + IOPD); -#endif } static void ultra_pio_output(struct device *dev, int count, - const unsigned char *buf, int start_page) + const unsigned char *buf, const int start_page) { int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET; /* ASIC addr */ outb(0x00, ioaddr + IOPA); /* Set the address, LSB first. */ outb(start_page, ioaddr + IOPA); + /* An extra odd byte is OK here as well. */ outsw(ioaddr + IOPD, buf, (count+1)>>1); } @@ -440,6 +442,8 @@ MODULE_PARM(io, "1-" __MODULE_STRING(MAX_ULTRA_CARDS) "i"); MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_ULTRA_CARDS) "i"); +EXPORT_NO_SYMBOLS; + /* This is set up so that only a single autoprobe takes place per call. ISA device autoprobes on a running machine are not recommended. */ int @@ -459,15 +463,12 @@ } if (register_netdev(dev) != 0) { printk(KERN_WARNING "smc-ultra.c: No SMC Ultra card found (i/o = 0x%x).\n", io[this_dev]); - if (found != 0) { /* Got at least one. */ - lock_8390_module(); - return 0; - } + if (found != 0) return 0; /* Got at least one. */ return -ENXIO; } found++; } - lock_8390_module(); + return 0; } @@ -479,15 +480,14 @@ for (this_dev = 0; this_dev < MAX_ULTRA_CARDS; this_dev++) { struct device *dev = &dev_ultra[this_dev]; if (dev->priv != NULL) { + /* NB: ultra_close_card() does free_irq + irq2dev */ int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET; - void *priv = dev->priv; - /* NB: ultra_close_card() does free_irq */ + kfree(dev->priv); + dev->priv = NULL; release_region(ioaddr, ULTRA_IO_EXTENT); unregister_netdev(dev); - kfree(priv); } } - unlock_8390_module(); } #endif /* MODULE */ @@ -498,6 +498,7 @@ * version-control: t * kept-new-versions: 5 * c-indent-level: 4 + * c-basic-offset: 4 * tab-width: 4 * End: */ diff -ur --new-file old/linux/drivers/net/smc9194.c new/linux/drivers/net/smc9194.c --- old/linux/drivers/net/smc9194.c Tue Feb 10 21:56:45 1998 +++ new/linux/drivers/net/smc9194.c Thu Mar 11 01:51:35 1999 @@ -65,7 +65,6 @@ #include #include #include -#include #include #include #include diff -ur --new-file old/linux/drivers/net/sunbmac.c new/linux/drivers/net/sunbmac.c --- old/linux/drivers/net/sunbmac.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/net/sunbmac.c Tue Mar 16 01:11:30 1999 @@ -0,0 +1,1557 @@ +/* sunbmac.c: Driver for Sparc BigMAC 100baseT ethernet adapters. + * + * Copyright (C) 1997, 1998 David S. Miller (davem@caip.rutgers.edu) + */ + +static char *version = + "sunbmac.c:v1.1 8/Dec/98 David S. Miller (davem@caipfs.rutgers.edu)\n"; + +#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 +#include + +#include "sunbmac.h" + +#undef DEBUG_PROBE +#undef DEBUG_TX +#undef DEBUG_IRQ + +#ifdef DEBUG_PROBE +#define DP(x) printk x +#else +#define DP(x) +#endif + +#ifdef DEBUG_TX +#define DTX(x) printk x +#else +#define DTX(x) +#endif + +#ifdef DEBUG_IRQ +#define DIRQ(x) printk x +#else +#define DIRQ(x) +#endif + +#ifdef MODULE +static struct bigmac *root_bigmac_dev = NULL; +#endif + +#define DEFAULT_JAMSIZE 4 /* Toe jam */ + +#define QEC_RESET_TRIES 200 + +static inline int qec_global_reset(struct qe_globreg *gregs) +{ + int tries = QEC_RESET_TRIES; + + gregs->ctrl = GLOB_CTRL_RESET; + while(--tries) { + if(gregs->ctrl & GLOB_CTRL_RESET) { + udelay(20); + continue; + } + break; + } + if(tries) + return 0; + printk("BigMAC: Cannot reset the QEC.\n"); + return -1; +} + +static void qec_init(struct bigmac *bp) +{ + struct qe_globreg *gregs = bp->gregs; + struct linux_sbus_device *qec_sdev = bp->qec_sbus_dev; + unsigned char bsizes = bp->bigmac_bursts; + unsigned int regval; + + /* 64byte bursts do not work at the moment, do + * not even try to enable them. -DaveM + */ + if(bsizes & DMA_BURST32) + regval = GLOB_CTRL_B32; + else + regval = GLOB_CTRL_B16; + gregs->ctrl = regval | GLOB_CTRL_BMODE; + + gregs->psize = GLOB_PSIZE_2048; + + /* All of memsize is given to bigmac. */ + gregs->msize = qec_sdev->reg_addrs[1].reg_size; + + /* Half to the transmitter, half to the receiver. */ + gregs->rsize = gregs->tsize = qec_sdev->reg_addrs[1].reg_size >> 1; +} + +/* XXX auto negotiation on these things might not be pleasant... */ + +#define TX_RESET_TRIES 32 +#define RX_RESET_TRIES 32 + +static inline void bigmac_tx_reset(struct BIG_MAC_regs *bregs) +{ + int tries = TX_RESET_TRIES; + + bregs->tx_cfg = 0; + + /* The fifo threshold bit is read-only and does + * not clear. -DaveM + */ + while((bregs->tx_cfg & ~(BIGMAC_TXCFG_FIFO)) != 0 && + --tries != 0) + udelay(20); + + if(!tries) { + printk("BIGMAC: Transmitter will not reset.\n"); + printk("BIGMAC: tx_cfg is %08x\n", bregs->tx_cfg); + } +} + +static inline void bigmac_rx_reset(struct BIG_MAC_regs *bregs) +{ + int tries = RX_RESET_TRIES; + + bregs->rx_cfg = 0; + while((bregs->rx_cfg) && --tries) + udelay(20); + + if(!tries) { + printk("BIGMAC: Receiver will not reset.\n"); + printk("BIGMAC: rx_cfg is %08x\n", bregs->rx_cfg); + } +} + +/* Reset the transmitter and receiver. */ +static void bigmac_stop(struct bigmac *bp) +{ + bigmac_tx_reset(bp->bregs); + bigmac_rx_reset(bp->bregs); +} + +static void bigmac_get_counters(struct bigmac *bp, struct BIG_MAC_regs *bregs) +{ + struct enet_statistics *stats = &bp->enet_stats; + + stats->rx_crc_errors += bregs->rcrce_ctr; + bregs->rcrce_ctr = 0; + + stats->rx_frame_errors += bregs->unale_ctr; + bregs->unale_ctr = 0; + + stats->rx_length_errors += bregs->gle_ctr; + bregs->gle_ctr = 0; + + stats->tx_aborted_errors += bregs->ex_ctr; + + stats->collisions += (bregs->ex_ctr + bregs->lt_ctr); + bregs->ex_ctr = bregs->lt_ctr = 0; +} + +static inline void bigmac_clean_rings(struct bigmac *bp) +{ + int i; + + for(i = 0; i < RX_RING_SIZE; i++) { + if(bp->rx_skbs[i] != NULL) { + dev_kfree_skb(bp->rx_skbs[i]); + bp->rx_skbs[i] = NULL; + } + } + + for(i = 0; i < TX_RING_SIZE; i++) { + if(bp->tx_skbs[i] != NULL) { + dev_kfree_skb(bp->tx_skbs[i]); + bp->tx_skbs[i] = NULL; + } + } +} + +static void bigmac_init_rings(struct bigmac *bp, int from_irq) +{ + struct bmac_init_block *bb = bp->bmac_block; + struct device *dev = bp->dev; + int i, gfp_flags = GFP_KERNEL; + + if(from_irq || in_interrupt()) + gfp_flags = GFP_ATOMIC; + + bp->rx_new = bp->rx_old = bp->tx_new = bp->tx_old = 0; + + /* Free any skippy bufs left around in the rings. */ + bigmac_clean_rings(bp); + + /* Now get new skippy bufs for the receive ring. */ + for(i = 0; i < RX_RING_SIZE; i++) { + struct sk_buff *skb; + + skb = big_mac_alloc_skb(RX_BUF_ALLOC_SIZE, gfp_flags); + if(!skb) + continue; + + bp->rx_skbs[i] = skb; + skb->dev = dev; + + /* Because we reserve afterwards. */ + skb_put(skb, ETH_FRAME_LEN); + skb_reserve(skb, 34); + + bb->be_rxd[i].rx_addr = sbus_dvma_addr(skb->data); + bb->be_rxd[i].rx_flags = + (RXD_OWN | ((RX_BUF_ALLOC_SIZE - 34) & RXD_LENGTH)); + } + + for(i = 0; i < TX_RING_SIZE; i++) + bb->be_txd[i].tx_flags = bb->be_txd[i].tx_addr = 0; +} + +#ifndef __sparc_v9__ +static void sun4c_bigmac_init_rings(struct bigmac *bp) +{ + struct bmac_init_block *bb = bp->bmac_block; + __u32 bbufs_dvma = bp->s4c_buf_dvma; + int i; + + bp->rx_new = bp->rx_old = bp->tx_new = bp->tx_old = 0; + + for(i = 0; i < RX_RING_SIZE; i++) { + bb->be_rxd[i].rx_addr = bbufs_dvma + bbuf_offset(rx_buf, i); + bb->be_rxd[i].rx_flags = + (RXD_OWN | (SUN4C_RX_BUFF_SIZE & RXD_LENGTH)); + } + + for(i = 0; i < TX_RING_SIZE; i++) + bb->be_txd[i].tx_flags = bb->be_txd[i].tx_addr = 0; +} +#endif + +#define MGMT_CLKON (MGMT_PAL_INT_MDIO|MGMT_PAL_EXT_MDIO|MGMT_PAL_OENAB|MGMT_PAL_DCLOCK) +#define MGMT_CLKOFF (MGMT_PAL_INT_MDIO|MGMT_PAL_EXT_MDIO|MGMT_PAL_OENAB) + +static inline void idle_transceiver(struct bmac_tcvr *tregs) +{ + volatile unsigned int garbage; + int i = 20; + + while(i--) { + tregs->mgmt_pal = MGMT_CLKOFF; + garbage = tregs->mgmt_pal; + tregs->mgmt_pal = MGMT_CLKON; + garbage = tregs->mgmt_pal; + } +} + +static void write_tcvr_bit(struct bigmac *bp, struct bmac_tcvr *tregs, int bit) +{ + volatile unsigned int garbage; + + if(bp->tcvr_type == internal) { + bit = (bit & 1) << 3; + tregs->mgmt_pal = bit | (MGMT_PAL_OENAB | MGMT_PAL_EXT_MDIO); + garbage = tregs->mgmt_pal; + tregs->mgmt_pal = bit | (MGMT_PAL_OENAB | + MGMT_PAL_EXT_MDIO | + MGMT_PAL_DCLOCK); + garbage = tregs->mgmt_pal; + } else if(bp->tcvr_type == external) { + bit = (bit & 1) << 2; + tregs->mgmt_pal = bit | (MGMT_PAL_INT_MDIO | MGMT_PAL_OENAB); + garbage = tregs->mgmt_pal; + tregs->mgmt_pal = bit | (MGMT_PAL_INT_MDIO | + MGMT_PAL_OENAB | + MGMT_PAL_DCLOCK); + garbage = tregs->mgmt_pal; + } else { + printk("write_tcvr_bit: No transceiver type known!\n"); + } +} + +static int read_tcvr_bit(struct bigmac *bp, struct bmac_tcvr *tregs) +{ + volatile unsigned int garbage; + int retval = 0; + + if(bp->tcvr_type == internal) { + tregs->mgmt_pal = MGMT_PAL_EXT_MDIO; + garbage = tregs->mgmt_pal; + tregs->mgmt_pal = MGMT_PAL_EXT_MDIO | MGMT_PAL_DCLOCK; + garbage = tregs->mgmt_pal; + retval = (tregs->mgmt_pal & MGMT_PAL_INT_MDIO) >> 3; + } else if(bp->tcvr_type == external) { + tregs->mgmt_pal = MGMT_PAL_INT_MDIO; + garbage = tregs->mgmt_pal; + tregs->mgmt_pal = MGMT_PAL_INT_MDIO | MGMT_PAL_DCLOCK; + garbage = tregs->mgmt_pal; + retval = (tregs->mgmt_pal & MGMT_PAL_EXT_MDIO) >> 2; + } else { + printk("read_tcvr_bit: No transceiver type known!\n"); + } + return retval; +} + +static int read_tcvr_bit2(struct bigmac *bp, struct bmac_tcvr *tregs) +{ + volatile unsigned int garbage; + int retval = 0; + + if(bp->tcvr_type == internal) { + tregs->mgmt_pal = MGMT_PAL_EXT_MDIO; + garbage = tregs->mgmt_pal; + retval = (tregs->mgmt_pal & MGMT_PAL_INT_MDIO) >> 3; + tregs->mgmt_pal = (MGMT_PAL_EXT_MDIO | MGMT_PAL_DCLOCK); + garbage = tregs->mgmt_pal; + } else if(bp->tcvr_type == external) { + tregs->mgmt_pal = MGMT_PAL_INT_MDIO; + garbage = tregs->mgmt_pal; + retval = (tregs->mgmt_pal & MGMT_PAL_EXT_MDIO) >> 2; + tregs->mgmt_pal = (MGMT_PAL_INT_MDIO | MGMT_PAL_DCLOCK); + garbage = tregs->mgmt_pal; + } else { + printk("read_tcvr_bit2: No transceiver type known!\n"); + } + return retval; +} + +static inline void put_tcvr_byte(struct bigmac *bp, + struct bmac_tcvr *tregs, + unsigned int byte) +{ + int shift = 4; + + do { + write_tcvr_bit(bp, tregs, ((byte >> shift) & 1)); + shift -= 1; + } while (shift >= 0); +} + +static void bigmac_tcvr_write(struct bigmac *bp, struct bmac_tcvr *tregs, + int reg, unsigned short val) +{ + int shift; + + reg &= 0xff; + val &= 0xffff; + switch(bp->tcvr_type) { + case internal: + case external: + break; + + default: + printk("bigmac_tcvr_read: Whoops, no known transceiver type.\n"); + return; + }; + + idle_transceiver(tregs); + write_tcvr_bit(bp, tregs, 0); + write_tcvr_bit(bp, tregs, 1); + write_tcvr_bit(bp, tregs, 0); + write_tcvr_bit(bp, tregs, 1); + + put_tcvr_byte(bp, tregs, + ((bp->tcvr_type == internal) ? + BIGMAC_PHY_INTERNAL : BIGMAC_PHY_EXTERNAL)); + + put_tcvr_byte(bp, tregs, reg); + + write_tcvr_bit(bp, tregs, 1); + write_tcvr_bit(bp, tregs, 0); + + shift = 15; + do { + write_tcvr_bit(bp, tregs, (val >> shift) & 1); + shift -= 1; + } while(shift >= 0); +} + +static unsigned short bigmac_tcvr_read(struct bigmac *bp, + struct bmac_tcvr *tregs, + int reg) +{ + unsigned short retval = 0; + + reg &= 0xff; + switch(bp->tcvr_type) { + case internal: + case external: + break; + + default: + printk("bigmac_tcvr_read: Whoops, no known transceiver type.\n"); + return 0xffff; + }; + + idle_transceiver(tregs); + write_tcvr_bit(bp, tregs, 0); + write_tcvr_bit(bp, tregs, 1); + write_tcvr_bit(bp, tregs, 1); + write_tcvr_bit(bp, tregs, 0); + + put_tcvr_byte(bp, tregs, + ((bp->tcvr_type == internal) ? + BIGMAC_PHY_INTERNAL : BIGMAC_PHY_EXTERNAL)); + + put_tcvr_byte(bp, tregs, reg); + + if(bp->tcvr_type == external) { + int shift = 15; + + (void) read_tcvr_bit2(bp, tregs); + (void) read_tcvr_bit2(bp, tregs); + + do { + int tmp; + + tmp = read_tcvr_bit2(bp, tregs); + retval |= ((tmp & 1) << shift); + shift -= 1; + } while(shift >= 0); + + (void) read_tcvr_bit2(bp, tregs); + (void) read_tcvr_bit2(bp, tregs); + (void) read_tcvr_bit2(bp, tregs); + } else { + int shift = 15; + + (void) read_tcvr_bit(bp, tregs); + (void) read_tcvr_bit(bp, tregs); + + do { + int tmp; + + tmp = read_tcvr_bit(bp, tregs); + retval |= ((tmp & 1) << shift); + shift -= 1; + } while(shift >= 0); + + (void) read_tcvr_bit(bp, tregs); + (void) read_tcvr_bit(bp, tregs); + (void) read_tcvr_bit(bp, tregs); + } + return retval; +} + +static void bigmac_tcvr_init(struct bigmac *bp) +{ + volatile unsigned int garbage; + struct bmac_tcvr *tregs = bp->tregs; + + idle_transceiver(tregs); + tregs->mgmt_pal = (MGMT_PAL_INT_MDIO | + MGMT_PAL_EXT_MDIO | + MGMT_PAL_DCLOCK); + garbage = tregs->mgmt_pal; + + /* Only the bit for the present transceiver (internal or + * external) will stick, set them both and see what stays. + */ + tregs->mgmt_pal = (MGMT_PAL_INT_MDIO | + MGMT_PAL_EXT_MDIO); + garbage = tregs->mgmt_pal; + udelay(20); + + if(tregs->mgmt_pal & MGMT_PAL_EXT_MDIO) { + bp->tcvr_type = external; + tregs->tcvr_pal = ~(TCVR_PAL_EXTLBACK | + TCVR_PAL_MSENSE | + TCVR_PAL_LTENABLE); + garbage = tregs->tcvr_pal; + } else if(tregs->mgmt_pal & MGMT_PAL_INT_MDIO) { + bp->tcvr_type = internal; + tregs->tcvr_pal = ~(TCVR_PAL_SERIAL | + TCVR_PAL_EXTLBACK | + TCVR_PAL_MSENSE | + TCVR_PAL_LTENABLE); + garbage = tregs->tcvr_pal; + } else { + printk("BIGMAC: AIEEE, neither internal nor " + "external MDIO available!\n"); + printk("BIGMAC: mgmt_pal[%08x] tcvr_pal[%08x]\n", + tregs->mgmt_pal, tregs->tcvr_pal); + } +} + +static int bigmac_init(struct bigmac *, int); + +static int try_next_permutation(struct bigmac *bp, struct bmac_tcvr *tregs) +{ + if(bp->sw_bmcr & BMCR_SPEED100) { + int timeout; + + /* Reset the PHY. */ + bp->sw_bmcr = (BMCR_ISOLATE | BMCR_PDOWN | BMCR_LOOPBACK); + bigmac_tcvr_write(bp, tregs, BIGMAC_BMCR, bp->sw_bmcr); + bp->sw_bmcr = (BMCR_RESET); + bigmac_tcvr_write(bp, tregs, BIGMAC_BMCR, bp->sw_bmcr); + + timeout = 64; + while(--timeout) { + bp->sw_bmcr = bigmac_tcvr_read(bp, tregs, BIGMAC_BMCR); + if((bp->sw_bmcr & BMCR_RESET) == 0) + break; + udelay(20); + } + if(timeout == 0) + printk("%s: PHY reset failed.\n", bp->dev->name); + + bp->sw_bmcr = bigmac_tcvr_read(bp, tregs, BIGMAC_BMCR); + + /* Now we try 10baseT. */ + bp->sw_bmcr &= ~(BMCR_SPEED100); + bigmac_tcvr_write(bp, tregs, BIGMAC_BMCR, bp->sw_bmcr); + return 0; + } + + /* We've tried them all. */ + return -1; +} + +static void bigmac_timer(unsigned long data) +{ + struct bigmac *bp = (struct bigmac *) data; + struct bmac_tcvr *tregs = bp->tregs; + int restart_timer = 0; + + bp->timer_ticks++; + if(bp->timer_state == ltrywait) { + bp->sw_bmsr = bigmac_tcvr_read(bp, tregs, BIGMAC_BMSR); + bp->sw_bmcr = bigmac_tcvr_read(bp, tregs, BIGMAC_BMCR); + if(bp->sw_bmsr & BMSR_LSTATUS) { + printk("%s: Link is now up at %s.\n", + bp->dev->name, + (bp->sw_bmcr & BMCR_SPEED100) ? + "100baseT" : "10baseT"); + bp->timer_state = asleep; + restart_timer = 0; + } else { + if(bp->timer_ticks >= 4) { + int ret; + + ret = try_next_permutation(bp, tregs); + if(ret == -1) { + printk("%s: Link down, cable problem?\n", + bp->dev->name); + ret = bigmac_init(bp, 0); + if(ret) { + printk("%s: Error, cannot re-init the " + "BigMAC.\n", bp->dev->name); + } + return; + } + bp->timer_ticks = 0; + restart_timer = 1; + } else { + restart_timer = 1; + } + } + } else { + /* Can't happens.... */ + printk("%s: Aieee, link timer is asleep but we got one anyways!\n", + bp->dev->name); + restart_timer = 0; + bp->timer_ticks = 0; + bp->timer_state = asleep; /* foo on you */ + } + + if(restart_timer != 0) { + bp->bigmac_timer.expires = jiffies + ((12 * HZ)/10); /* 1.2 sec. */ + add_timer(&bp->bigmac_timer); + } +} + +/* Well, really we just force the chip into 100baseT then + * 10baseT, each time checking for a link status. + */ +static void bigmac_begin_auto_negotiation(struct bigmac *bp) +{ + struct bmac_tcvr *tregs = bp->tregs; + int timeout; + + /* Grab new software copies of PHY registers. */ + bp->sw_bmsr = bigmac_tcvr_read(bp, tregs, BIGMAC_BMSR); + bp->sw_bmcr = bigmac_tcvr_read(bp, tregs, BIGMAC_BMCR); + + /* Reset the PHY. */ + bp->sw_bmcr = (BMCR_ISOLATE | BMCR_PDOWN | BMCR_LOOPBACK); + bigmac_tcvr_write(bp, tregs, BIGMAC_BMCR, bp->sw_bmcr); + bp->sw_bmcr = (BMCR_RESET); + bigmac_tcvr_write(bp, tregs, BIGMAC_BMCR, bp->sw_bmcr); + + timeout = 64; + while(--timeout) { + bp->sw_bmcr = bigmac_tcvr_read(bp, tregs, BIGMAC_BMCR); + if((bp->sw_bmcr & BMCR_RESET) == 0) + break; + udelay(20); + } + if(timeout == 0) + printk("%s: PHY reset failed.\n", bp->dev->name); + + bp->sw_bmcr = bigmac_tcvr_read(bp, tregs, BIGMAC_BMCR); + + /* First we try 100baseT. */ + bp->sw_bmcr |= BMCR_SPEED100; + bigmac_tcvr_write(bp, tregs, BIGMAC_BMCR, bp->sw_bmcr); + + bp->timer_state = ltrywait; + bp->timer_ticks = 0; + bp->bigmac_timer.expires = jiffies + (12 * HZ) / 10; + bp->bigmac_timer.data = (unsigned long) bp; + bp->bigmac_timer.function = &bigmac_timer; + add_timer(&bp->bigmac_timer); +} + +static int bigmac_init(struct bigmac *bp, int from_irq) +{ + struct qe_globreg *gregs = bp->gregs; + struct qe_creg *cregs = bp->creg; + struct BIG_MAC_regs *bregs = bp->bregs; + unsigned char *e = &bp->dev->dev_addr[0]; + + /* Latch current counters into statistics. */ + bigmac_get_counters(bp, bregs); + + /* Reset QEC. */ + qec_global_reset(gregs); + + /* Init QEC. */ + qec_init(bp); + + /* Alloc and reset the tx/rx descriptor chains. */ +#ifndef __sparc_v9__ + if(sparc_cpu_model == sun4c) + sun4c_bigmac_init_rings(bp); + else +#endif + bigmac_init_rings(bp, from_irq); + + /* Initialize the PHY. */ + bigmac_tcvr_init(bp); + + /* Stop transmitter and receiver. */ + bigmac_stop(bp); + + /* Set hardware ethernet address. */ + bregs->mac_addr2 = ((e[4] << 8) | e[5]); + bregs->mac_addr1 = ((e[2] << 8) | e[3]); + bregs->mac_addr0 = ((e[0] << 8) | e[1]); + + /* Clear the hash table until mc upload occurs. */ + bregs->htable3 = 0; + bregs->htable2 = 0; + bregs->htable1 = 0; + bregs->htable0 = 0; + + /* Enable Big Mac hash table filter. */ + bregs->rx_cfg = (BIGMAC_RXCFG_HENABLE | BIGMAC_RXCFG_FIFO); + + udelay(20); + + /* Ok, configure the Big Mac transmitter. */ + bregs->tx_cfg = BIGMAC_TXCFG_FIFO; + + /* The HME docs recommend to use the 10LSB of our MAC here. */ + bregs->rand_seed = ((e[5] | e[4] << 8) & 0x3ff); + + /* Enable the output drivers no matter what. */ + bregs->xif_cfg = (BIGMAC_XCFG_ODENABLE | BIGMAC_XCFG_RESV); + + /* Tell the QEC where the ring descriptors are. */ + cregs->rxds = bp->bblock_dvma + bib_offset(be_rxd, 0); + cregs->txds = bp->bblock_dvma + bib_offset(be_txd, 0); + + /* Setup the FIFO pointers into QEC local memory. */ + cregs->rxwbufptr = cregs->rxrbufptr = 0; + cregs->txwbufptr = cregs->txrbufptr = gregs->rsize; + + /* Tell bigmac what interrupts we don't want to hear about. */ + bregs->imask = (BIGMAC_IMASK_GOTFRAME | BIGMAC_IMASK_SENTFRAME); + + /* Enable the various other irq's. */ + cregs->rimask = 0; + cregs->timask = 0; + cregs->qmask = 0; + cregs->bmask = 0; + + /* Set jam size to a reasonable default. */ + bregs->jsize = DEFAULT_JAMSIZE; + + /* Clear collision counter. */ + cregs->ccnt = 0; + + /* Enable transmitter and receiver. */ + bregs->tx_cfg |= BIGMAC_TXCFG_ENABLE; + bregs->rx_cfg |= BIGMAC_RXCFG_ENABLE; + + /* Ok, start detecting link speed/duplex. */ + bigmac_begin_auto_negotiation(bp); + + /* Success. */ + return 0; +} + +/* Error interrupts get sent here. */ +static void bigmac_is_medium_rare(struct bigmac *bp, + unsigned int qec_status, + unsigned int bmac_status) +{ + printk("bigmac_is_medium_rare: "); + if(qec_status & (GLOB_STAT_ER | GLOB_STAT_BM)) { + if(qec_status & GLOB_STAT_ER) + printk("QEC_ERROR, "); + if(qec_status & GLOB_STAT_BM) + printk("QEC_BMAC_ERROR, "); + } + if(bmac_status & CREG_STAT_ERRORS) { + if(bmac_status & CREG_STAT_BERROR) + printk("BMAC_ERROR, "); + if(bmac_status & CREG_STAT_TXDERROR) + printk("TXD_ERROR, "); + if(bmac_status & CREG_STAT_TXLERR) + printk("TX_LATE_ERROR, "); + if(bmac_status & CREG_STAT_TXPERR) + printk("TX_PARITY_ERROR, "); + if(bmac_status & CREG_STAT_TXSERR) + printk("TX_SBUS_ERROR, "); + + if(bmac_status & CREG_STAT_RXDROP) + printk("RX_DROP_ERROR, "); + + if(bmac_status & CREG_STAT_RXSMALL) + printk("RX_SMALL_ERROR, "); + if(bmac_status & CREG_STAT_RXLERR) + printk("RX_LATE_ERROR, "); + if(bmac_status & CREG_STAT_RXPERR) + printk("RX_PARITY_ERROR, "); + if(bmac_status & CREG_STAT_RXSERR) + printk("RX_SBUS_ERROR, "); + } + + printk(" RESET\n"); + bigmac_init(bp, 1); +} + +/* BigMAC transmit complete service routines. */ +static inline void bigmac_tx(struct bigmac *bp) +{ + struct be_txd *txbase = &bp->bmac_block->be_txd[0]; + struct be_txd *this; + int elem = bp->tx_old; + + DTX(("bigmac_tx: tx_old[%d] ", elem)); + while(elem != bp->tx_new) { + struct sk_buff *skb; + + this = &txbase[elem]; + + DTX(("this(%p) [flags(%08x)addr(%08x)]", + this, this->tx_flags, this->tx_addr)); + + if(this->tx_flags & TXD_OWN) + break; + skb = bp->tx_skbs[elem]; + DTX(("skb(%p) ", skb)); + bp->tx_skbs[elem] = NULL; + dev_kfree_skb(skb); + + bp->enet_stats.tx_packets++; + elem = NEXT_TX(elem); + } + DTX((" DONE, tx_old=%d\n", elem)); + bp->tx_old = elem; +} + +#ifndef __sparc_v9__ +static inline void sun4c_bigmac_tx(struct bigmac *bp) +{ + struct be_txd *txbase = &bp->bmac_block->be_txd[0]; + struct be_txd *this; + int elem = bp->tx_old; + + while(elem != bp->tx_new) { + this = &txbase[elem]; + if(this->tx_flags & TXD_OWN) + break; + bp->enet_stats.tx_packets++; + elem = NEXT_TX(elem); + } + bp->tx_old = elem; +} +#endif + +/* BigMAC receive complete service routines. */ +static inline void bigmac_rx(struct bigmac *bp) +{ + struct be_rxd *rxbase = &bp->bmac_block->be_rxd[0]; + struct be_rxd *this; + int elem = bp->rx_new, drops = 0; + + this = &rxbase[elem]; + while(!(this->rx_flags & RXD_OWN)) { + struct sk_buff *skb; + unsigned int flags = this->rx_flags; + int len = (flags & RXD_LENGTH); /* FCS not included */ + + /* Check for errors. */ + if(len < ETH_ZLEN) { + bp->enet_stats.rx_errors++; + bp->enet_stats.rx_length_errors++; + + drop_it: + /* Return it to the BigMAC. */ + bp->enet_stats.rx_dropped++; + this->rx_addr = sbus_dvma_addr(bp->rx_skbs[elem]->data); + this->rx_flags = + (RXD_OWN | (RX_BUF_ALLOC_SIZE & RXD_LENGTH)); + goto next; + } + skb = bp->rx_skbs[elem]; +#ifdef NEED_DMA_SYNCHRONIZATION +#ifdef __sparc_v9__ + if ((unsigned long) (skb->data + skb->len) >= MAX_DMA_ADDRESS) { + printk("sunbmac: Bogus DMA buffer address " + "[%016lx]\n", ((unsigned long) skb->data)); + panic("DMA address too large, tell DaveM"); + } +#endif + mmu_sync_dma(sbus_dvma_addr(skb->data), + skb->len, bp->bigmac_sbus_dev->my_bus); +#endif + if(len > RX_COPY_THRESHOLD) { + struct sk_buff *new_skb; + + /* Now refill the entry, if we can. */ + new_skb = big_mac_alloc_skb(RX_BUF_ALLOC_SIZE, GFP_ATOMIC); + if(!new_skb) { + drops++; + goto drop_it; + } + bp->rx_skbs[elem] = new_skb; + new_skb->dev = bp->dev; + skb_put(new_skb, ETH_FRAME_LEN); + skb_reserve(new_skb, 34); + rxbase[elem].rx_addr = sbus_dvma_addr(new_skb->data); + rxbase[elem].rx_flags = + (RXD_OWN | ((RX_BUF_ALLOC_SIZE - 34) & RXD_LENGTH)); + + /* Trim the original skb for the netif. */ + skb_trim(skb, len); + } else { + struct sk_buff *copy_skb = dev_alloc_skb(len + 2); + + if(!copy_skb) { + drops++; + goto drop_it; + } + copy_skb->dev = bp->dev; + skb_reserve(copy_skb, 2); + skb_put(copy_skb, len); + eth_copy_and_sum(copy_skb, (unsigned char *)skb->data, len, 0); + + /* Reuse otiginal ring buffer. */ + rxbase[elem].rx_addr = sbus_dvma_addr(skb->data); + rxbase[elem].rx_flags = + (RXD_OWN | ((RX_BUF_ALLOC_SIZE - 34) & RXD_LENGTH)); + + skb = copy_skb; + } + + /* No checksums done by the BigMAC ;-( */ + skb->protocol = eth_type_trans(skb, bp->dev); + netif_rx(skb); + bp->enet_stats.rx_packets++; + next: + elem = NEXT_RX(elem); + this = &rxbase[elem]; + } + bp->rx_new = elem; + if(drops) + printk("%s: Memory squeeze, deferring packet.\n", bp->dev->name); +} + +#ifndef __sparc_v9__ +static inline void sun4c_bigmac_rx(struct bigmac *bp) +{ + struct be_rxd *rxbase = &bp->bmac_block->be_rxd[0]; + struct be_rxd *this; + struct bigmac_buffers *bbufs = bp->sun4c_buffers; + __u32 bbufs_dvma = bp->s4c_buf_dvma; + int elem = bp->rx_new, drops = 0; + + this = &rxbase[elem]; + while(!(this->rx_flags & RXD_OWN)) { + struct sk_buff *skb; + unsigned char *this_bbuf = + bbufs->rx_buf[elem & (SUN4C_RX_RING_SIZE - 1)]; + __u32 this_bbuf_dvma = bbufs_dvma + + bbuf_offset(rx_buf, (elem & (SUN4C_RX_RING_SIZE - 1))); + struct be_rxd *end_rxd = + &rxbase[(elem+SUN4C_RX_RING_SIZE)&(RX_RING_SIZE-1)]; + unsigned int flags = this->rx_flags; + int len = (flags & RXD_LENGTH) - 4; /* FCS not included */ + + /* Check for errors. */ + if(len < ETH_ZLEN) { + bp->enet_stats.rx_errors++; + bp->enet_stats.rx_length_errors++; + bp->enet_stats.rx_dropped++; + } else { + skb = dev_alloc_skb(len + 2); + if(skb == 0) { + drops++; + bp->enet_stats.rx_dropped++; + } else { + skb->dev = bp->dev; + skb_reserve(skb, 2); + skb_put(skb, len); + eth_copy_and_sum(skb, (unsigned char *)this_bbuf, + len, 0); + skb->protocol = eth_type_trans(skb, bp->dev); + netif_rx(skb); + bp->enet_stats.rx_packets++; + } + } + end_rxd->rx_addr = this_bbuf_dvma; + end_rxd->rx_flags = (RXD_OWN | (SUN4C_RX_BUFF_SIZE & RXD_LENGTH)); + + elem = NEXT_RX(elem); + this = &rxbase[elem]; + } + bp->rx_new = elem; + if(drops) + printk("%s: Memory squeeze, deferring packet.\n", bp->dev->name); +} +#endif + +static void bigmac_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct bigmac *bp = (struct bigmac *) dev_id; + unsigned int qec_status, bmac_status; + + DIRQ(("bigmac_interrupt: ")); + + /* Latch status registers now. */ + bmac_status = bp->creg->stat; + qec_status = bp->gregs->stat; + + bp->dev->interrupt = 1; + + DIRQ(("qec_status=%08x bmac_status=%08x\n", qec_status, bmac_status)); + if((qec_status & (GLOB_STAT_ER | GLOB_STAT_BM)) || + (bmac_status & CREG_STAT_ERRORS)) + bigmac_is_medium_rare(bp, qec_status, bmac_status); + + if(bmac_status & CREG_STAT_TXIRQ) + bigmac_tx(bp); + + if(bmac_status & CREG_STAT_RXIRQ) + bigmac_rx(bp); + + if(bp->dev->tbusy && (TX_BUFFS_AVAIL(bp) >= 0)) { + bp->dev->tbusy = 0; + mark_bh(NET_BH); + } + + bp->dev->interrupt = 0; +} + +#ifndef __sparc_v9__ +static void sun4c_bigmac_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct bigmac *bp = (struct bigmac *) dev_id; + unsigned int qec_status, bmac_status; + + /* Latch status registers now. */ + bmac_status = bp->creg->stat; + qec_status = bp->gregs->stat; + + bp->dev->interrupt = 1; + + if(qec_status & (GLOB_STAT_ER | GLOB_STAT_BM) || + (bmac_status & CREG_STAT_ERRORS)) + bigmac_is_medium_rare(bp, qec_status, bmac_status); + + if(bmac_status & CREG_STAT_TXIRQ) + sun4c_bigmac_tx(bp); + + if(bmac_status & CREG_STAT_RXIRQ) + sun4c_bigmac_rx(bp); + + if(bp->dev->tbusy && (SUN4C_TX_BUFFS_AVAIL(bp) >= 0)) { + bp->dev->tbusy = 0; + mark_bh(NET_BH); + } + + bp->dev->interrupt = 0; +} +#endif + +static int bigmac_open(struct device *dev) +{ + struct bigmac *bp = (struct bigmac *) dev->priv; + int res; + +#ifndef __sparc_v9__ + if(sparc_cpu_model == sun4c) { + if(request_irq(dev->irq, &sun4c_bigmac_interrupt, + SA_SHIRQ, "BIG MAC", (void *) bp)) { + printk("BIGMAC: Can't order irq %d to go.\n", dev->irq); + return -EAGAIN; + } + } else +#endif + if(request_irq(dev->irq, &bigmac_interrupt, + SA_SHIRQ, "BIG MAC", (void *) bp)) { + printk("BIGMAC: Can't order irq %d to go.\n", dev->irq); + return -EAGAIN; + } + init_timer(&bp->bigmac_timer); + res = bigmac_init(bp, 0); + if(!res) { + MOD_INC_USE_COUNT; + } + return res; +} + +static int bigmac_close(struct device *dev) +{ + struct bigmac *bp = (struct bigmac *) dev->priv; + + del_timer(&bp->bigmac_timer); + bp->timer_state = asleep; + bp->timer_ticks = 0; + + bigmac_stop(bp); + bigmac_clean_rings(bp); + free_irq(dev->irq, (void *)bp); + MOD_DEC_USE_COUNT; + return 0; +} + +/* Put a packet on the wire. */ +static int bigmac_start_xmit(struct sk_buff *skb, struct device *dev) +{ + struct bigmac *bp = (struct bigmac *) dev->priv; + int len, entry; + + if(dev->tbusy) { + int tickssofar = jiffies - dev->trans_start; + + if (tickssofar < 40) { + return 1; + } else { + printk ("%s: transmit timed out, resetting\n", dev->name); + bp->enet_stats.tx_errors++; + bigmac_init(bp, 0); + dev->tbusy = 0; + dev->trans_start = jiffies; + dev_kfree_skb(skb); + return 0; + } + } + + if(test_and_set_bit(0, (void *) &dev->tbusy) != 0) { + printk("%s: Transmitter access conflict.\n", dev->name); + return 1; + } + + if(!TX_BUFFS_AVAIL(bp)) + return 1; + +#ifdef NEED_DMA_SYNCHRONIZATION +#ifdef __sparc_v9__ + if ((unsigned long) (skb->data + skb->len) >= MAX_DMA_ADDRESS) { + struct sk_buff *new_skb = skb_copy(skb, GFP_DMA | GFP_ATOMIC); + if(!new_skb) + return 1; + dev_kfree_skb(skb); + skb = new_skb; + } +#endif + mmu_sync_dma(sbus_dvma_addr(skb->data), + skb->len, bp->bigmac_sbus_dev->my_bus); +#endif + len = skb->len; + entry = bp->tx_new; + DTX(("bigmac_start_xmit: len(%d) entry(%d)\n", len, entry)); + + /* Avoid a race... */ + bp->bmac_block->be_txd[entry].tx_flags = TXD_UPDATE; + + bp->tx_skbs[entry] = skb; + bp->bmac_block->be_txd[entry].tx_addr = sbus_dvma_addr(skb->data); + bp->bmac_block->be_txd[entry].tx_flags = + (TXD_OWN | TXD_SOP | TXD_EOP | (len & TXD_LENGTH)); + dev->trans_start = jiffies; + bp->tx_new = NEXT_TX(entry); + + /* Get it going. */ + bp->creg->ctrl = CREG_CTRL_TWAKEUP; + + if(TX_BUFFS_AVAIL(bp)) + dev->tbusy = 0; + + return 0; +} + +#ifndef __sparc_v9__ +static int sun4c_bigmac_start_xmit(struct sk_buff *skb, struct device *dev) +{ + struct bigmac *bp = (struct bigmac *) dev->priv; + struct bigmac_buffers *bbufs = bp->sun4c_buffers; + __u32 txbuf_dvma, bbufs_dvma = bp->s4c_buf_dvma; + unsigned char *txbuf; + int len, entry; + + if(dev->tbusy) { + int tickssofar = jiffies - dev->trans_start; + + if (tickssofar < 40) { + return 1; + } else { + printk ("%s: transmit timed out, resetting\n", dev->name); + bp->enet_stats.tx_errors++; + bigmac_init(bp, 0); + dev->tbusy = 0; + dev->trans_start = jiffies; + return 0; + } + } + + if(test_and_set_bit(0, (void *) &dev->tbusy) != 0) { + printk("%s: Transmitter access conflict.\n", dev->name); + return 1; + } + + if(!SUN4C_TX_BUFFS_AVAIL(bp)) + return 1; + + len = skb->len; + entry = bp->tx_new; + + txbuf = &bbufs->tx_buf[entry][0]; + txbuf_dvma = bbufs_dvma + bbuf_offset(tx_buf, entry); + memcpy(txbuf, skb->data, len); + + /* Avoid a race... */ + bp->bmac_block->be_txd[entry].tx_flags = TXD_UPDATE; + + bp->bmac_block->be_txd[entry].tx_addr = txbuf_dvma; + bp->bmac_block->be_txd[entry].tx_flags = + (TXD_OWN | TXD_SOP | TXD_EOP | (len & TXD_LENGTH)); + bp->tx_new = NEXT_TX(entry); + + /* Get it going. */ + dev->trans_start = jiffies; + bp->creg->ctrl = CREG_CTRL_TWAKEUP; + + dev_kfree_skb(skb); + + if(SUN4C_TX_BUFFS_AVAIL(bp)) + dev->tbusy = 0; + + return 0; +} +#endif + +static struct enet_statistics *bigmac_get_stats(struct device *dev) +{ + struct bigmac *bp = (struct bigmac *) dev->priv; + + bigmac_get_counters(bp, bp->bregs); + return &bp->enet_stats; +} + +#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */ +#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */ + +static void bigmac_set_multicast(struct device *dev) +{ + struct bigmac *bp = (struct bigmac *) dev->priv; + struct BIG_MAC_regs *bregs = bp->bregs; + struct dev_mc_list *dmi = dev->mc_list; + char *addrs; + int i, j, bit, byte; + u32 crc, poly = CRC_POLYNOMIAL_LE; + + /* Disable the receiver. The bit self-clears when + * the operation is complete. + */ + bregs->rx_cfg &= ~(BIGMAC_RXCFG_ENABLE); + while((bregs->rx_cfg & BIGMAC_RXCFG_ENABLE) != 0) + udelay(20); + + if((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 64)) { + bregs->htable0 = 0xffff; + bregs->htable1 = 0xffff; + bregs->htable2 = 0xffff; + bregs->htable3 = 0xffff; + } else if(dev->flags & IFF_PROMISC) { + bregs->rx_cfg |= BIGMAC_RXCFG_PMISC; + } else { + u16 hash_table[4]; + + for(i = 0; i < 4; i++) + hash_table[i] = 0; + + for(i = 0; i < dev->mc_count; i++) { + addrs = dmi->dmi_addr; + dmi = dmi->next; + + if(!(*addrs & 1)) + continue; + + crc = 0xffffffffU; + 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 >>= 26; + hash_table[crc >> 4] |= 1 << (crc & 0xf); + } + bregs->htable0 = hash_table[0]; + bregs->htable1 = hash_table[1]; + bregs->htable2 = hash_table[2]; + bregs->htable3 = hash_table[3]; + } + + /* Re-enable the receiver. */ + bregs->rx_cfg |= BIGMAC_RXCFG_ENABLE; +} + +__initfunc(static int bigmac_ether_init(struct device *dev, struct linux_sbus_device *qec_sdev)) +{ + static unsigned version_printed = 0; + struct bigmac *bp = 0; + unsigned char bsizes, bsizes_more; + int i, j, num_qranges, res = ENOMEM; + struct linux_prom_ranges qranges[8]; + + /* Get a new device struct for this interface. */ + dev = init_etherdev(0, sizeof(struct bigmac)); + + if(version_printed++ == 0) + printk(version); + + /* Report what we have found to the user. */ + printk("%s: BigMAC 100baseT Ethernet ", dev->name); + dev->base_addr = (long) qec_sdev; + for(i = 0; i < 6; i++) + printk("%2.2x%c", dev->dev_addr[i] = idprom->id_ethaddr[i], + i == 5 ? ' ' : ':'); + printk("\n"); + + /* Setup softc, with backpointers to QEC and BigMAC SBUS device structs. */ + bp = (struct bigmac *) dev->priv; + bp->qec_sbus_dev = qec_sdev; + bp->bigmac_sbus_dev = qec_sdev->child; + + /* All further failures we find return this. */ + res = ENODEV; + + /* Verify the registers we expect, are actually there. */ + if((bp->bigmac_sbus_dev->num_registers != 3) || + (bp->qec_sbus_dev->num_registers != 2)) { + printk("BIGMAC: Device does not have 2 and 3 regs, it has %d and %d.\n", + bp->qec_sbus_dev->num_registers, + bp->bigmac_sbus_dev->num_registers); + printk("BIGMAC: Would you like that for here or to go?\n"); + goto fail_and_cleanup; + } + + /* Fun with QEC ranges... */ + if(bp->bigmac_sbus_dev->ranges_applied == 0) { + i = prom_getproperty(bp->qec_sbus_dev->prom_node, "ranges", + (char *)&qranges[0], sizeof(qranges)); + num_qranges = (i / sizeof(struct linux_prom_ranges)); + + /* Now, apply all the ranges for the BigMAC. */ + for(j = 0; j < bp->bigmac_sbus_dev->num_registers; j++) { + int k; + + for(k = 0; k < num_qranges; k++) + if(bp->bigmac_sbus_dev->reg_addrs[j].which_io == + qranges[k].ot_child_space) + break; + if(k >= num_qranges) { + printk("BigMAC: Aieee, bogus QEC range for space %08x\n", + bp->bigmac_sbus_dev->reg_addrs[j].which_io); + goto fail_and_cleanup; + } + bp->bigmac_sbus_dev->reg_addrs[j].which_io = qranges[k].ot_parent_space; + bp->bigmac_sbus_dev->reg_addrs[j].phys_addr += qranges[k].ot_parent_base; + } + + /* Next, apply SBUS ranges on top of what we just changed. */ + prom_apply_sbus_ranges(bp->bigmac_sbus_dev->my_bus, + &bp->bigmac_sbus_dev->reg_addrs[0], + bp->bigmac_sbus_dev->num_registers, + bp->bigmac_sbus_dev); + } + + /* Apply SBUS ranges for the QEC parent. */ + prom_apply_sbus_ranges(bp->qec_sbus_dev->my_bus, + &bp->qec_sbus_dev->reg_addrs[0], + bp->qec_sbus_dev->num_registers, + bp->qec_sbus_dev); + + /* Map in QEC global control registers. */ + bp->gregs = sparc_alloc_io(bp->qec_sbus_dev->reg_addrs[0].phys_addr, + 0, + sizeof(struct qe_globreg), + "BigMAC QEC Global Regs", + bp->qec_sbus_dev->reg_addrs[0].which_io, + 0); + if(!bp->gregs) { + printk("BIGMAC: Cannot map QEC global registers.\n"); + goto fail_and_cleanup; + } + + /* Make sure QEC is in BigMAC mode. */ + if((bp->gregs->ctrl & 0xf0000000) != GLOB_CTRL_BMODE) { + printk("BigMAC: AIEEE, QEC is not in BigMAC mode!\n"); + goto fail_and_cleanup; + } + + /* Reset the QEC. */ + if(qec_global_reset(bp->gregs)) + goto fail_and_cleanup; + + /* Get supported SBUS burst sizes. */ + bsizes = prom_getintdefault(bp->qec_sbus_dev->prom_node, + "burst-sizes", + 0xff); + + bsizes_more = prom_getintdefault(bp->qec_sbus_dev->my_bus->prom_node, + "burst-sizes", + 0xff); + + bsizes &= 0xff; + if(bsizes_more != 0xff) + bsizes &= bsizes_more; + if(bsizes == 0xff || (bsizes & DMA_BURST16) == 0 || + (bsizes & DMA_BURST32) == 0) + bsizes = (DMA_BURST32 - 1); + bp->bigmac_bursts = bsizes; + + /* Perform QEC initialization. */ + qec_init(bp); + + /* Map in the BigMAC channel registers. */ + bp->creg = sparc_alloc_io(bp->bigmac_sbus_dev->reg_addrs[0].phys_addr, + 0, + sizeof(struct qe_creg), + "BigMAC QEC Channel Regs", + bp->bigmac_sbus_dev->reg_addrs[0].which_io, + 0); + if(!bp->creg) { + printk("BIGMAC: Cannot map QEC channel registers.\n"); + goto fail_and_cleanup; + } + + /* Map in the BigMAC control registers. */ + bp->bregs = sparc_alloc_io(bp->bigmac_sbus_dev->reg_addrs[1].phys_addr, + 0, + sizeof(struct BIG_MAC_regs), + "BigMAC Primary Regs", + bp->bigmac_sbus_dev->reg_addrs[1].which_io, + 0); + if(!bp->bregs) { + printk("BIGMAC: Cannot map BigMAC primary registers.\n"); + goto fail_and_cleanup; + } + + /* Map in the BigMAC transceiver registers, this is how you poke at + * the BigMAC's PHY. + */ + bp->tregs = sparc_alloc_io(bp->bigmac_sbus_dev->reg_addrs[2].phys_addr, + 0, + sizeof(struct bmac_tcvr), + "BigMAC Transceiver Regs", + bp->bigmac_sbus_dev->reg_addrs[2].which_io, + 0); + if(!bp->tregs) { + printk("BIGMAC: Cannot map BigMAC transceiver registers.\n"); + goto fail_and_cleanup; + } + + /* Stop the BigMAC. */ + bigmac_stop(bp); + + /* Allocate transmit/receive descriptor DVMA block. */ + bp->bmac_block = (struct bmac_init_block *) + sparc_dvma_malloc(PAGE_SIZE, "BigMAC Init Block", + &bp->bblock_dvma); + + /* Get the board revision of this BigMAC. */ + bp->board_rev = prom_getintdefault(bp->bigmac_sbus_dev->prom_node, + "board-version", 1); + + /* If on sun4c, we use a static buffer pool, on sun4m we DMA directly + * in and out of sk_buffs instead for speed and one copy to userspace. + */ +#ifndef __sparc_v9__ + if(sparc_cpu_model == sun4c) + bp->sun4c_buffers = (struct bigmac_buffers *) + sparc_dvma_malloc(sizeof(struct bigmac_buffers), + "BigMAC Bufs", + &bp->s4c_buf_dvma); + else +#endif + bp->sun4c_buffers = 0; + + /* Init auto-negotiation timer state. */ + init_timer(&bp->bigmac_timer); + bp->timer_state = asleep; + bp->timer_ticks = 0; + + /* Backlink to generic net device struct. */ + bp->dev = dev; + + /* Set links to our BigMAC open and close routines. */ + dev->open = &bigmac_open; + dev->stop = &bigmac_close; + + /* Choose transmit routine based upon buffering scheme. */ +#ifndef __sparc_v9__ + if(sparc_cpu_model == sun4c) + dev->hard_start_xmit = &sun4c_bigmac_start_xmit; + else +#endif + dev->hard_start_xmit = &bigmac_start_xmit; + + /* Set links to BigMAC statistic and multi-cast loading code. */ + dev->get_stats = &bigmac_get_stats; + dev->set_multicast_list = &bigmac_set_multicast; + + /* Finish net device registration. */ + dev->irq = bp->bigmac_sbus_dev->irqs[0]; + dev->dma = 0; + ether_setup(dev); + +#ifdef MODULE + /* Put us into the list of instances attached for later module unloading. */ + bp->next_module = root_bigmac_dev; + root_bigmac_dev = bp; +#endif + return 0; + +fail_and_cleanup: + /* Something went wrong, undo whatever we did so far. */ + if(bp) { + /* Free register mappings if any. */ + if(bp->gregs) + sparc_free_io(bp->gregs, sizeof(struct qe_globreg)); + if(bp->creg) + sparc_free_io(bp->creg, sizeof(struct qe_creg)); + if(bp->bregs) + sparc_free_io(bp->bregs, sizeof(struct BIG_MAC_regs)); + if(bp->tregs) + sparc_free_io(bp->tregs, sizeof(struct bmac_tcvr)); + + /* XXX todo, bmac_block and sun4c_buffers */ + + /* Free the BigMAC softc. */ + kfree(bp); + dev->priv = 0; + } + return res; /* Return error code. */ +} + +__initfunc(int bigmac_probe(struct device *dev)) +{ + struct linux_sbus *bus; + struct linux_sbus_device *sdev = 0; + static int called = 0; + int cards = 0, v; + + if(called) + return ENODEV; + called++; + + for_each_sbus(bus) { + for_each_sbusdev(sdev, bus) { + if(cards) dev = NULL; + + /* QEC can be the parent of either QuadEthernet or + * a BigMAC. We want the latter. + */ + if(!strcmp(sdev->prom_name, "qec") && sdev->child && + !strcmp(sdev->child->prom_name, "be")) { + cards++; + if((v = bigmac_ether_init(dev, sdev))) + return v; + } + } + } + if(!cards) + return ENODEV; + return 0; +} + +#ifdef MODULE + +int +init_module(void) +{ + root_bigmac_dev = NULL; + return bigmac_probe(NULL); +} + +void +cleanup_module(void) +{ + /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ + while (root_bigmac_dev) { + struct bigmac *bp = root_bigmac_dev; + struct bigmac *bp_nxt = root_bigmac_dev->next_module; + + sparc_free_io(bp->gregs, sizeof(struct qe_globreg)); + sparc_free_io(bp->creg, sizeof(struct qe_creg)); + sparc_free_io(bp->bregs, sizeof(struct BIG_MAC_regs)); + sparc_free_io(bp->tregs, sizeof(struct bmac_tcvr)); + + /* XXX todo, bmac_block and sun4c_buffers */ + + unregister_netdev(bp->dev); + kfree(bp->dev); + root_bigmac_dev = bp_nxt; + } +} + +#endif /* MODULE */ diff -ur --new-file old/linux/drivers/net/sunbmac.h new/linux/drivers/net/sunbmac.h --- old/linux/drivers/net/sunbmac.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/net/sunbmac.h Tue Mar 16 01:11:30 1999 @@ -0,0 +1,381 @@ +/* sunbmac.h: Defines for the Sun "Big MAC" 100baseT ethernet cards. + * + * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) + */ + +#ifndef _SUNBMAC_H +#define _SUNBMAC_H + +/* QEC global registers. */ +struct qe_globreg { + volatile unsigned int ctrl; /* Control */ + volatile unsigned int stat; /* Status */ + volatile unsigned int psize; /* Packet Size */ + volatile unsigned int msize; /* Local-mem size (64K) */ + volatile unsigned int rsize; /* Receive partition size */ + volatile unsigned int tsize; /* Transmit partition size */ +}; + +#define GLOB_CTRL_MMODE 0x40000000 /* MACE qec mode */ +#define GLOB_CTRL_BMODE 0x10000000 /* BigMAC qec mode */ +#define GLOB_CTRL_EPAR 0x00000020 /* Enable parity */ +#define GLOB_CTRL_ACNTRL 0x00000018 /* SBUS arbitration control */ +#define GLOB_CTRL_B64 0x00000004 /* 64 byte dvma bursts */ +#define GLOB_CTRL_B32 0x00000002 /* 32 byte dvma bursts */ +#define GLOB_CTRL_B16 0x00000000 /* 16 byte dvma bursts */ +#define GLOB_CTRL_RESET 0x00000001 /* Reset the QEC */ + +#define GLOB_STAT_TX 0x00000008 /* BigMAC Transmit IRQ */ +#define GLOB_STAT_RX 0x00000004 /* BigMAC Receive IRQ */ +#define GLOB_STAT_BM 0x00000002 /* BigMAC Global IRQ */ +#define GLOB_STAT_ER 0x00000001 /* BigMAC Error IRQ */ + +#define GLOB_PSIZE_2048 0x00 /* 2k packet size */ +#define GLOB_PSIZE_4096 0x01 /* 4k packet size */ +#define GLOB_PSIZE_6144 0x10 /* 6k packet size */ +#define GLOB_PSIZE_8192 0x11 /* 8k packet size */ + +/* QEC BigMAC channel registers. */ +struct qe_creg { + volatile unsigned int ctrl; /* Control */ + volatile unsigned int stat; /* Status */ + volatile unsigned int rxds; /* RX descriptor ring ptr */ + volatile unsigned int txds; /* TX descriptor ring ptr */ + volatile unsigned int rimask; /* RX Interrupt Mask */ + volatile unsigned int timask; /* TX Interrupt Mask */ + volatile unsigned int qmask; /* QEC Error Interrupt Mask */ + volatile unsigned int bmask; /* BigMAC Error Interrupt Mask */ + volatile unsigned int rxwbufptr; /* Local memory rx write ptr */ + volatile unsigned int rxrbufptr; /* Local memory rx read ptr */ + volatile unsigned int txwbufptr; /* Local memory tx write ptr */ + volatile unsigned int txrbufptr; /* Local memory tx read ptr */ + volatile unsigned int ccnt; /* Collision Counter */ +}; + +#define CREG_CTRL_TWAKEUP 0x00000001 /* Transmitter Wakeup, 'go'. */ + +#define CREG_STAT_BERROR 0x80000000 /* BigMAC error */ +#define CREG_STAT_TXIRQ 0x00200000 /* Transmit Interrupt */ +#define CREG_STAT_TXDERROR 0x00080000 /* TX Descriptor is bogus */ +#define CREG_STAT_TXLERR 0x00040000 /* Late Transmit Error */ +#define CREG_STAT_TXPERR 0x00020000 /* Transmit Parity Error */ +#define CREG_STAT_TXSERR 0x00010000 /* Transmit SBUS error ack */ +#define CREG_STAT_RXIRQ 0x00000020 /* Receive Interrupt */ +#define CREG_STAT_RXDROP 0x00000010 /* Dropped a RX'd packet */ +#define CREG_STAT_RXSMALL 0x00000008 /* Receive buffer too small */ +#define CREG_STAT_RXLERR 0x00000004 /* Receive Late Error */ +#define CREG_STAT_RXPERR 0x00000002 /* Receive Parity Error */ +#define CREG_STAT_RXSERR 0x00000001 /* Receive SBUS Error ACK */ + +#define CREG_STAT_ERRORS (CREG_STAT_BERROR|CREG_STAT_TXDERROR|CREG_STAT_TXLERR| \ + CREG_STAT_TXPERR|CREG_STAT_TXSERR|CREG_STAT_RXDROP| \ + CREG_STAT_RXSMALL|CREG_STAT_RXLERR|CREG_STAT_RXPERR| \ + CREG_STAT_RXSERR) + +#define CREG_QMASK_TXDERROR 0x00080000 /* TXD error */ +#define CREG_QMASK_TXLERR 0x00040000 /* TX late error */ +#define CREG_QMASK_TXPERR 0x00020000 /* TX parity error */ +#define CREG_QMASK_TXSERR 0x00010000 /* TX sbus error ack */ +#define CREG_QMASK_RXDROP 0x00000010 /* RX drop */ +#define CREG_QMASK_RXBERROR 0x00000008 /* RX buffer error */ +#define CREG_QMASK_RXLEERR 0x00000004 /* RX late error */ +#define CREG_QMASK_RXPERR 0x00000002 /* RX parity error */ +#define CREG_QMASK_RXSERR 0x00000001 /* RX sbus error ack */ + +struct BIG_MAC_regs { + volatile unsigned int xif_cfg; /* XIF config register */ + volatile unsigned int _unused[63]; /* Reserved... */ + volatile unsigned int status; /* Status register, clear on read */ + volatile unsigned int imask; /* Interrupt mask register */ + volatile unsigned int _unused2[64]; /* Reserved... */ + volatile unsigned int tx_swreset; /* Transmitter software reset */ + volatile unsigned int tx_cfg; /* Transmitter config register */ + volatile unsigned int ipkt_gap1; /* Inter-packet gap 1 */ + volatile unsigned int ipkt_gap2; /* Inter-packet gap 2 */ + volatile unsigned int attempt_limit; /* Transmit attempt limit */ + volatile unsigned int stime; /* Transmit slot time */ + volatile unsigned int preamble_len; /* Size of transmit preamble */ + volatile unsigned int preamble_pattern; /* Pattern for transmit preamble */ + volatile unsigned int tx_sframe_delim; /* Transmit delimiter */ + volatile unsigned int jsize; /* Toe jam... */ + volatile unsigned int tx_pkt_max; /* Transmit max pkt size */ + volatile unsigned int tx_pkt_min; /* Transmit min pkt size */ + volatile unsigned int peak_attempt; /* Count of transmit peak attempts */ + volatile unsigned int dt_ctr; /* Transmit defer timer */ + volatile unsigned int nc_ctr; /* Transmit normal-collision counter */ + volatile unsigned int fc_ctr; /* Transmit first-collision counter */ + volatile unsigned int ex_ctr; /* Transmit excess-collision counter */ + volatile unsigned int lt_ctr; /* Transmit late-collision counter */ + volatile unsigned int rand_seed; /* Transmit random number seed */ + volatile unsigned int tx_smachine; /* Transmit state machine */ + volatile unsigned int _unused3[44]; /* Reserved */ + volatile unsigned int rx_swreset; /* Receiver software reset */ + volatile unsigned int rx_cfg; /* Receiver config register */ + volatile unsigned int rx_pkt_max; /* Receive max pkt size */ + volatile unsigned int rx_pkt_min; /* Receive min pkt size */ + volatile unsigned int mac_addr2; /* Ether address register 2 */ + volatile unsigned int mac_addr1; /* Ether address register 1 */ + volatile unsigned int mac_addr0; /* Ether address register 0 */ + volatile unsigned int fr_ctr; /* Receive frame receive counter */ + volatile unsigned int gle_ctr; /* Receive giant-length error counter */ + volatile unsigned int unale_ctr; /* Receive unaligned error counter */ + volatile unsigned int rcrce_ctr; /* Receive CRC error counter */ + volatile unsigned int rx_smachine; /* Receiver state machine */ + volatile unsigned int rx_cvalid; /* Receiver code violation */ + volatile unsigned int _unused4; /* Reserved... */ + volatile unsigned int htable3; /* Hash table 3 */ + volatile unsigned int htable2; /* Hash table 2 */ + volatile unsigned int htable1; /* Hash table 1 */ + volatile unsigned int htable0; /* Hash table 0 */ + volatile unsigned int afilter2; /* Address filter 2 */ + volatile unsigned int afilter1; /* Address filter 1 */ + volatile unsigned int afilter0; /* Address filter 0 */ + volatile unsigned int afilter_mask; /* Address filter mask */ +}; + +/* BigMac XIF config register. */ +#define BIGMAC_XCFG_ODENABLE 0x00000001 /* Output driver enable */ +#define BIGMAC_XCFG_RESV 0x00000002 /* Reserved, write always as 1 */ +#define BIGMAC_XCFG_MLBACK 0x00000004 /* Loopback-mode MII enable */ +#define BIGMAC_XCFG_SMODE 0x00000008 /* Enable serial mode */ + +/* BigMAC status register. */ +#define BIGMAC_STAT_GOTFRAME 0x00000001 /* Received a frame */ +#define BIGMAC_STAT_RCNTEXP 0x00000002 /* Receive frame counter expired */ +#define BIGMAC_STAT_ACNTEXP 0x00000004 /* Align-error counter expired */ +#define BIGMAC_STAT_CCNTEXP 0x00000008 /* CRC-error counter expired */ +#define BIGMAC_STAT_LCNTEXP 0x00000010 /* Length-error counter expired */ +#define BIGMAC_STAT_RFIFOVF 0x00000020 /* Receive FIFO overflow */ +#define BIGMAC_STAT_CVCNTEXP 0x00000040 /* Code-violation counter expired */ +#define BIGMAC_STAT_SENTFRAME 0x00000100 /* Transmitted a frame */ +#define BIGMAC_STAT_TFIFO_UND 0x00000200 /* Transmit FIFO underrun */ +#define BIGMAC_STAT_MAXPKTERR 0x00000400 /* Max-packet size error */ +#define BIGMAC_STAT_NCNTEXP 0x00000800 /* Normal-collision counter expired */ +#define BIGMAC_STAT_ECNTEXP 0x00001000 /* Excess-collision counter expired */ +#define BIGMAC_STAT_LCCNTEXP 0x00002000 /* Late-collision counter expired */ +#define BIGMAC_STAT_FCNTEXP 0x00004000 /* First-collision counter expired */ +#define BIGMAC_STAT_DTIMEXP 0x00008000 /* Defer-timer expired */ + +/* BigMAC interrupt mask register. */ +#define BIGMAC_IMASK_GOTFRAME 0x00000001 /* Received a frame */ +#define BIGMAC_IMASK_RCNTEXP 0x00000002 /* Receive frame counter expired */ +#define BIGMAC_IMASK_ACNTEXP 0x00000004 /* Align-error counter expired */ +#define BIGMAC_IMASK_CCNTEXP 0x00000008 /* CRC-error counter expired */ +#define BIGMAC_IMASK_LCNTEXP 0x00000010 /* Length-error counter expired */ +#define BIGMAC_IMASK_RFIFOVF 0x00000020 /* Receive FIFO overflow */ +#define BIGMAC_IMASK_CVCNTEXP 0x00000040 /* Code-violation counter expired */ +#define BIGMAC_IMASK_SENTFRAME 0x00000100 /* Transmitted a frame */ +#define BIGMAC_IMASK_TFIFO_UND 0x00000200 /* Transmit FIFO underrun */ +#define BIGMAC_IMASK_MAXPKTERR 0x00000400 /* Max-packet size error */ +#define BIGMAC_IMASK_NCNTEXP 0x00000800 /* Normal-collision counter expired */ +#define BIGMAC_IMASK_ECNTEXP 0x00001000 /* Excess-collision counter expired */ +#define BIGMAC_IMASK_LCCNTEXP 0x00002000 /* Late-collision counter expired */ +#define BIGMAC_IMASK_FCNTEXP 0x00004000 /* First-collision counter expired */ +#define BIGMAC_IMASK_DTIMEXP 0x00008000 /* Defer-timer expired */ + +/* BigMac transmit config register. */ +#define BIGMAC_TXCFG_ENABLE 0x00000001 /* Enable the transmitter */ +#define BIGMAC_TXCFG_FIFO 0x00000010 /* Default tx fthresh... */ +#define BIGMAC_TXCFG_SMODE 0x00000020 /* Enable slow transmit mode */ +#define BIGMAC_TXCFG_CIGN 0x00000040 /* Ignore transmit collisions */ +#define BIGMAC_TXCFG_FCSOFF 0x00000080 /* Do not emit FCS */ +#define BIGMAC_TXCFG_DBACKOFF 0x00000100 /* Disable backoff */ +#define BIGMAC_TXCFG_FULLDPLX 0x00000200 /* Enable full-duplex */ + +/* BigMac receive config register. */ +#define BIGMAC_RXCFG_ENABLE 0x00000001 /* Enable the receiver */ +#define BIGMAC_RXCFG_FIFO 0x0000000e /* Default rx fthresh... */ +#define BIGMAC_RXCFG_PSTRIP 0x00000020 /* Pad byte strip enable */ +#define BIGMAC_RXCFG_PMISC 0x00000040 /* Enable promiscous mode */ +#define BIGMAC_RXCFG_DERR 0x00000080 /* Disable error checking */ +#define BIGMAC_RXCFG_DCRCS 0x00000100 /* Disable CRC stripping */ +#define BIGMAC_RXCFG_ME 0x00000200 /* Receive packets addressed to me */ +#define BIGMAC_RXCFG_PGRP 0x00000400 /* Enable promisc group mode */ +#define BIGMAC_RXCFG_HENABLE 0x00000800 /* Enable the hash filter */ +#define BIGMAC_RXCFG_AENABLE 0x00001000 /* Enable the address filter */ + +/* The BigMAC PHY transceiver. Not nearly as sophisticated as the happy meal + * one. But it does have the "bit banger", oh baby. + */ +struct bmac_tcvr { + unsigned int tcvr_pal; + unsigned int mgmt_pal; +}; + +/* Frame commands. */ +#define FRAME_WRITE 0x50020000 +#define FRAME_READ 0x60020000 + +/* Tranceiver registers. */ +#define TCVR_PAL_SERIAL 0x00000001 /* Enable serial mode */ +#define TCVR_PAL_EXTLBACK 0x00000002 /* Enable external loopback */ +#define TCVR_PAL_MSENSE 0x00000004 /* Media sense */ +#define TCVR_PAL_LTENABLE 0x00000008 /* Link test enable */ +#define TCVR_PAL_LTSTATUS 0x00000010 /* Link test status (P1 only) */ + +/* Management PAL. */ +#define MGMT_PAL_DCLOCK 0x00000001 /* Data clock */ +#define MGMT_PAL_OENAB 0x00000002 /* Output enabler */ +#define MGMT_PAL_MDIO 0x00000004 /* MDIO Data/attached */ +#define MGMT_PAL_TIMEO 0x00000008 /* Transmit enable timeout error */ +#define MGMT_PAL_EXT_MDIO MGMT_PAL_MDIO +#define MGMT_PAL_INT_MDIO MGMT_PAL_TIMEO + +/* Here are some PHY addresses. */ +#define BIGMAC_PHY_EXTERNAL 0 /* External transceiver */ +#define BIGMAC_PHY_INTERNAL 1 /* Internal transceiver */ + +/* PHY registers */ +#define BIGMAC_BMCR 0x00 /* Basic mode control register */ +#define BIGMAC_BMSR 0x01 /* Basic mode status register */ + +/* BMCR bits */ +#define BMCR_ISOLATE 0x0400 /* Disconnect DP83840 from MII */ +#define BMCR_PDOWN 0x0800 /* Powerdown the DP83840 */ +#define BMCR_ANENABLE 0x1000 /* Enable auto negotiation */ +#define BMCR_SPEED100 0x2000 /* Select 100Mbps */ +#define BMCR_LOOPBACK 0x4000 /* TXD loopback bits */ +#define BMCR_RESET 0x8000 /* Reset the DP83840 */ + +/* BMSR bits */ +#define BMSR_ERCAP 0x0001 /* Ext-reg capability */ +#define BMSR_JCD 0x0002 /* Jabber detected */ +#define BMSR_LSTATUS 0x0004 /* Link status */ + +/* Ring descriptors and such, same as Quad Ethernet. */ +struct be_rxd { + unsigned int rx_flags; + unsigned int rx_addr; +}; + +#define RXD_OWN 0x80000000 /* Ownership. */ +#define RXD_UPDATE 0x10000000 /* Being Updated? */ +#define RXD_LENGTH 0x000007ff /* Packet Length. */ + +struct be_txd { + unsigned int tx_flags; + unsigned int tx_addr; +}; + +#define TXD_OWN 0x80000000 /* Ownership. */ +#define TXD_SOP 0x40000000 /* Start Of Packet */ +#define TXD_EOP 0x20000000 /* End Of Packet */ +#define TXD_UPDATE 0x10000000 /* Being Updated? */ +#define TXD_LENGTH 0x000007ff /* Packet Length. */ + +#define TX_RING_MAXSIZE 256 +#define RX_RING_MAXSIZE 256 + +#define TX_RING_SIZE 256 +#define RX_RING_SIZE 256 + +#define NEXT_RX(num) (((num) + 1) & (RX_RING_SIZE - 1)) +#define NEXT_TX(num) (((num) + 1) & (TX_RING_SIZE - 1)) +#define PREV_RX(num) (((num) - 1) & (RX_RING_SIZE - 1)) +#define PREV_TX(num) (((num) - 1) & (TX_RING_SIZE - 1)) + +#define TX_BUFFS_AVAIL(bp) \ + (((bp)->tx_old <= (bp)->tx_new) ? \ + (bp)->tx_old + (TX_RING_SIZE - 1) - (bp)->tx_new : \ + (bp)->tx_old - (bp)->tx_new - 1) + + +#define SUN4C_TX_BUFFS_AVAIL(bp) \ + (((bp)->tx_old <= (bp)->tx_new) ? \ + (bp)->tx_old + (SUN4C_TX_RING_SIZE - 1) - (bp)->tx_new : \ + (bp)->tx_old - (bp)->tx_new - (TX_RING_SIZE - SUN4C_TX_RING_SIZE)) + + +#define RX_COPY_THRESHOLD 128 +#define RX_BUF_ALLOC_SIZE (ETH_FRAME_LEN + (64 * 3)) + +struct bmac_init_block { + struct be_rxd be_rxd[RX_RING_MAXSIZE]; + struct be_txd be_txd[TX_RING_MAXSIZE]; +}; + +#define bib_offset(mem, elem) \ +((__u32)((unsigned long)(&(((struct bmac_init_block *)0)->mem[elem])))) + +#define SUN4C_PKT_BUF_SZ 1546 +#define SUN4C_RX_BUFF_SIZE SUN4C_PKT_BUF_SZ +#define SUN4C_TX_BUFF_SIZE SUN4C_PKT_BUF_SZ + +#define SUN4C_RX_RING_SIZE 16 +#define SUN4C_TX_RING_SIZE 16 + +struct bigmac_buffers { + char tx_buf[SUN4C_TX_RING_SIZE][SUN4C_TX_BUFF_SIZE]; + char pad[2]; /* Align rx_buf for copy_and_sum(). */ + char rx_buf[SUN4C_RX_RING_SIZE][SUN4C_RX_BUFF_SIZE]; +}; + +#define bbuf_offset(mem, elem) \ +((__u32)((unsigned long)(&(((struct bigmac_buffers *)0)->mem[elem][0])))) + +/* Now software state stuff. */ +enum bigmac_transceiver { + external = 0, + internal = 1, + none = 2, +}; + +/* Timer state engine. */ +enum bigmac_timer_state { + ltrywait = 1, /* Forcing try of all modes, from fastest to slowest. */ + asleep = 2, /* Timer inactive. */ +}; + +struct bigmac { + struct qe_globreg *gregs; /* QEC Global Registers */ + struct qe_creg *creg; /* QEC BigMAC Channel Registers */ + struct BIG_MAC_regs *bregs; /* BigMAC Registers */ + struct bmac_tcvr *tregs; /* BigMAC Transceiver */ + struct bmac_init_block *bmac_block; /* RX and TX descriptors */ + __u32 bblock_dvma; /* RX and TX descriptors */ + + struct sk_buff *rx_skbs[RX_RING_SIZE]; + struct sk_buff *tx_skbs[TX_RING_SIZE]; + + int rx_new, tx_new, rx_old, tx_old; + + struct bigmac_buffers *sun4c_buffers; + __u32 s4c_buf_dvma; + + int board_rev; /* BigMAC board revision. */ + + enum bigmac_transceiver tcvr_type; + unsigned int bigmac_bursts; + unsigned int paddr; + unsigned short sw_bmsr; /* SW copy of PHY BMSR */ + unsigned short sw_bmcr; /* SW copy of PHY BMCR */ + struct timer_list bigmac_timer; + enum bigmac_timer_state timer_state; + unsigned int timer_ticks; + + struct enet_statistics enet_stats; + struct linux_sbus_device *qec_sbus_dev; + struct linux_sbus_device *bigmac_sbus_dev; + struct device *dev; + struct bigmac *next_module; +}; + +/* We use this to acquire receive skb's that we can DMA directly into. */ +#define ALIGNED_RX_SKB_ADDR(addr) \ + ((((unsigned long)(addr) + (64 - 1)) & ~(64 - 1)) - (unsigned long)(addr)) + +static inline struct sk_buff *big_mac_alloc_skb(unsigned int length, int gfp_flags) +{ + struct sk_buff *skb; + + skb = alloc_skb(length + 64, gfp_flags); + if(skb) { + int offset = ALIGNED_RX_SKB_ADDR(skb->data); + + if(offset) + skb_reserve(skb, offset); + } + return skb; +} + +#endif /* !(_SUNBMAC_H) */ diff -ur --new-file old/linux/drivers/net/sunhme.c new/linux/drivers/net/sunhme.c --- old/linux/drivers/net/sunhme.c Mon Nov 16 19:37:28 1998 +++ new/linux/drivers/net/sunhme.c Tue Mar 16 01:11:30 1999 @@ -2,11 +2,11 @@ * auto carrier detecting ethernet driver. Also known as the * "Happy Meal Ethernet" found on SunSwift SBUS cards. * - * Copyright (C) 1996 David S. Miller (davem@caipfs.rutgers.edu) + * Copyright (C) 1996, 1998 David S. Miller (davem@caipfs.rutgers.edu) */ static char *version = - "sunhme.c:v1.2 10/Oct/96 David S. Miller (davem@caipfs.rutgers.edu)\n"; + "sunhme.c:v1.10 27/Jan/99 David S. Miller (davem@caipfs.rutgers.edu)\n"; #include @@ -35,12 +35,13 @@ #include #include #include -#include #include #include #ifndef __sparc_v9__ #include #endif +#include +#include #include #include @@ -57,6 +58,11 @@ static struct happy_meal *root_happy_dev = NULL; #endif +static struct quattro *qfe_sbus_list = NULL; +#ifdef CONFIG_PCI +static struct quattro *qfe_pci_list = NULL; +#endif + #undef HMEDEBUG #undef SXDEBUG #undef RXDEBUG @@ -363,6 +369,15 @@ { hp->sw_bmcr = happy_meal_tcvr_read(hp, tregs, DP83840_BMCR); + /* Downgrade from full to half duplex. Only possible + * via ethtool. + */ + if(hp->sw_bmcr & BMCR_FULLDPLX) { + hp->sw_bmcr &= ~(BMCR_FULLDPLX); + happy_meal_tcvr_write(hp, tregs, DP83840_BMCR, hp->sw_bmcr); + return 0; + } + /* Downgrade from 100 to 10. */ if(hp->sw_bmcr & BMCR_SPEED100) { hp->sw_bmcr &= ~(BMCR_SPEED100); @@ -1049,7 +1064,7 @@ for(i = 0; i < RX_RING_SIZE; i++) { struct sk_buff *skb; - skb = happy_meal_alloc_skb(RX_BUF_ALLOC_SIZE, gfp_flags); + skb = happy_meal_alloc_skb(RX_BUF_ALLOC_SIZE, gfp_flags | GFP_DMA); if(!skb) continue; hp->rx_skbs[i] = skb; @@ -1077,7 +1092,7 @@ } else #endif { - hb->happy_meal_rxd[i].rx_addr = (u32)((unsigned long) skb->data); + hb->happy_meal_rxd[i].rx_addr = sbus_dvma_addr(skb->data); hb->happy_meal_rxd[i].rx_flags = (RXFLAG_OWN | ((RX_BUF_ALLOC_SIZE - RX_OFFSET) << 16)); } @@ -1115,7 +1130,8 @@ #endif static void happy_meal_begin_auto_negotiation(struct happy_meal *hp, - struct hmeal_tcvregs *tregs) + struct hmeal_tcvregs *tregs, + struct ethtool_cmd *ep) { int timeout; @@ -1124,93 +1140,108 @@ hp->sw_bmcr = happy_meal_tcvr_read(hp, tregs, DP83840_BMCR); hp->sw_physid1 = happy_meal_tcvr_read(hp, tregs, DP83840_PHYSID1); hp->sw_physid2 = happy_meal_tcvr_read(hp, tregs, DP83840_PHYSID2); - hp->sw_advertise = happy_meal_tcvr_read(hp, tregs, DP83840_ADVERTISE); /* XXX Check BMSR_ANEGCAPABLE, should not be necessary though. */ - /* Advertise everything we can support. */ - if(hp->sw_bmsr & BMSR_10HALF) - hp->sw_advertise |= (ADVERTISE_10HALF); - else - hp->sw_advertise &= ~(ADVERTISE_10HALF); + hp->sw_advertise = happy_meal_tcvr_read(hp, tregs, DP83840_ADVERTISE); + if(ep == NULL || ep->autoneg == AUTONEG_ENABLE) { + /* Advertise everything we can support. */ + if(hp->sw_bmsr & BMSR_10HALF) + hp->sw_advertise |= (ADVERTISE_10HALF); + else + hp->sw_advertise &= ~(ADVERTISE_10HALF); - if(hp->sw_bmsr & BMSR_10FULL) - hp->sw_advertise |= (ADVERTISE_10FULL); - else - hp->sw_advertise &= ~(ADVERTISE_10FULL); - if(hp->sw_bmsr & BMSR_100HALF) - hp->sw_advertise |= (ADVERTISE_100HALF); - else - hp->sw_advertise &= ~(ADVERTISE_100HALF); - if(hp->sw_bmsr & BMSR_100FULL) - hp->sw_advertise |= (ADVERTISE_100FULL); - else - hp->sw_advertise &= ~(ADVERTISE_100FULL); + if(hp->sw_bmsr & BMSR_10FULL) + hp->sw_advertise |= (ADVERTISE_10FULL); + else + hp->sw_advertise &= ~(ADVERTISE_10FULL); + if(hp->sw_bmsr & BMSR_100HALF) + hp->sw_advertise |= (ADVERTISE_100HALF); + else + hp->sw_advertise &= ~(ADVERTISE_100HALF); + if(hp->sw_bmsr & BMSR_100FULL) + hp->sw_advertise |= (ADVERTISE_100FULL); + else + hp->sw_advertise &= ~(ADVERTISE_100FULL); + happy_meal_tcvr_write(hp, tregs, DP83840_ADVERTISE, hp->sw_advertise); - /* XXX Currently no Happy Meal cards I know off support 100BaseT4, - * XXX and this is because the DP83840 does not support it, changes - * XXX would need to be made to the tx/rx logic in the driver as well - * XXX so I completely skip checking for it in the BMSR for now. - */ + /* XXX Currently no Happy Meal cards I know off support 100BaseT4, + * XXX and this is because the DP83840 does not support it, changes + * XXX would need to be made to the tx/rx logic in the driver as well + * XXX so I completely skip checking for it in the BMSR for now. + */ #ifdef AUTO_SWITCH_DEBUG - ASD(("%s: Advertising [ ", hp->dev->name)); - if(hp->sw_advertise & ADVERTISE_10HALF) - ASD(("10H ")); - if(hp->sw_advertise & ADVERTISE_10FULL) - ASD(("10F ")); - if(hp->sw_advertise & ADVERTISE_100HALF) - ASD(("100H ")); - if(hp->sw_advertise & ADVERTISE_100FULL) - ASD(("100F ")); + ASD(("%s: Advertising [ ", hp->dev->name)); + if(hp->sw_advertise & ADVERTISE_10HALF) + ASD(("10H ")); + if(hp->sw_advertise & ADVERTISE_10FULL) + ASD(("10F ")); + if(hp->sw_advertise & ADVERTISE_100HALF) + ASD(("100H ")); + if(hp->sw_advertise & ADVERTISE_100FULL) + ASD(("100F ")); #endif - happy_meal_tcvr_write(hp, tregs, DP83840_ADVERTISE, hp->sw_advertise); + /* Enable Auto-Negotiation, this is usually on already... */ + hp->sw_bmcr |= BMCR_ANENABLE; + happy_meal_tcvr_write(hp, tregs, DP83840_BMCR, hp->sw_bmcr); - /* Enable Auto-Negotiation, this is usually on already... */ - hp->sw_bmcr |= BMCR_ANENABLE; - happy_meal_tcvr_write(hp, tregs, DP83840_BMCR, hp->sw_bmcr); + /* Restart it to make sure it is going. */ + hp->sw_bmcr |= BMCR_ANRESTART; + happy_meal_tcvr_write(hp, tregs, DP83840_BMCR, hp->sw_bmcr); - /* Restart it to make sure it is going. */ - hp->sw_bmcr |= BMCR_ANRESTART; - happy_meal_tcvr_write(hp, tregs, DP83840_BMCR, hp->sw_bmcr); + /* BMCR_ANRESTART self clears when the process has begun. */ - /* BMCR_ANRESTART self clears when the process has begun. */ + timeout = 64; /* More than enough. */ + while(--timeout) { + hp->sw_bmcr = happy_meal_tcvr_read(hp, tregs, DP83840_BMCR); + if(!(hp->sw_bmcr & BMCR_ANRESTART)) + break; /* got it. */ + udelay(10); + } + if(!timeout) { + printk("%s: Happy Meal would not start auto negotiation " + "BMCR=0x%04x\n", hp->dev->name, hp->sw_bmcr); + printk("%s: Performing force link detection.\n", + hp->dev->name); + goto force_link; + } else { + hp->timer_state = arbwait; + } + } else { +force_link: + /* Force the link up, trying first a particular mode. + * Either we are here at the request of ethtool or + * because the Happy Meal would not start to autoneg. + */ - timeout = 64; /* More than enough. */ - while(--timeout) { - hp->sw_bmcr = happy_meal_tcvr_read(hp, tregs, DP83840_BMCR); - if(!(hp->sw_bmcr & BMCR_ANRESTART)) - break; /* got it. */ - udelay(10); - } - if(!timeout) { - printk("%s: Happy Meal would not start auto negotiation BMCR=0x%04x\n", - hp->dev->name, hp->sw_bmcr); - printk("%s: Performing force link detection.\n", hp->dev->name); - - /* Disable auto-negotiation in BMCR, enable FULL duplex and 100mb/s, - * setup the timer state machine, and fire it off. - * - * XXX Should probably reset the DP83840 first - * XXX as this is a gross fatal error... + /* Disable auto-negotiation in BMCR, enable the duplex and + * speed setting, init the timer state machine, and fire it off. */ - hp->sw_bmcr = BMCR_SPEED100; + if(ep == NULL || ep->autoneg == AUTONEG_ENABLE) { + hp->sw_bmcr = BMCR_SPEED100; + } else { + if(ep->speed == SPEED_100) + hp->sw_bmcr = BMCR_SPEED100; + else + hp->sw_bmcr = 0; + if(ep->duplex == DUPLEX_FULL) + hp->sw_bmcr |= BMCR_FULLDPLX; + } happy_meal_tcvr_write(hp, tregs, DP83840_BMCR, hp->sw_bmcr); /* OK, seems we need do disable the transceiver for the first * tick to make sure we get an accurate link state at the * second tick. */ - hp->sw_csconfig = happy_meal_tcvr_read(hp, tregs, DP83840_CSCONFIG); - printk("%s: CSCONFIG [%04x], disabling transceiver\n", hp->dev->name, - hp->sw_csconfig); + hp->sw_csconfig = happy_meal_tcvr_read(hp, tregs, + DP83840_CSCONFIG); hp->sw_csconfig &= ~(CSCONFIG_TCVDISAB); - happy_meal_tcvr_write(hp, tregs, DP83840_CSCONFIG, hp->sw_csconfig); + happy_meal_tcvr_write(hp, tregs, DP83840_CSCONFIG, + hp->sw_csconfig); hp->timer_state = ltrywait; - } else { - hp->timer_state = arbwait; } hp->timer_ticks = 0; @@ -1220,6 +1251,9 @@ add_timer(&hp->happy_timer); } +#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */ +#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */ + static int happy_meal_init(struct happy_meal *hp, int from_irq) { struct hmeal_gregs *gregs = hp->gregs; @@ -1227,9 +1261,12 @@ struct hmeal_erxregs *erxregs = hp->erxregs; struct hmeal_bigmacregs *bregs = hp->bigmacregs; struct hmeal_tcvregs *tregs = hp->tcvregs; - unsigned long regtmp; + unsigned long regtmp, rxcfg; unsigned char *e = &hp->dev->dev_addr[0]; + /* If auto-negotiation timer is running, kill it. */ + del_timer(&hp->happy_timer); + HMD(("happy_meal_init: happy_flags[%08x] ", hp->happy_flags)); if(!(hp->happy_flags & HFLAG_INIT)) { @@ -1322,12 +1359,54 @@ hme_write32(hp, &bregs->mac_addr1, ((e[2] << 8) | e[3])); hme_write32(hp, &bregs->mac_addr0, ((e[0] << 8) | e[1])); - /* Ick, figure out how to properly program the hash table later... */ HMD(("htable, ")); - hme_write32(hp, &bregs->htable3, 0); - hme_write32(hp, &bregs->htable2, 0); - hme_write32(hp, &bregs->htable1, 0); - hme_write32(hp, &bregs->htable0, 0); + if((hp->dev->flags & IFF_ALLMULTI) || + (hp->dev->mc_count > 64)) { + hme_write32(hp, &bregs->htable0, 0xffff); + hme_write32(hp, &bregs->htable1, 0xffff); + hme_write32(hp, &bregs->htable2, 0xffff); + hme_write32(hp, &bregs->htable3, 0xffff); + } else if((hp->dev->flags & IFF_PROMISC) == 0) { + u16 hash_table[4]; + struct dev_mc_list *dmi = hp->dev->mc_list; + char *addrs; + int i, j, bit, byte; + u32 crc, poly = CRC_POLYNOMIAL_LE; + + for(i = 0; i < 4; i++) + hash_table[i] = 0; + + for(i = 0; i < hp->dev->mc_count; i++) { + addrs = dmi->dmi_addr; + dmi = dmi->next; + + if(!(*addrs & 1)) + continue; + + crc = 0xffffffffU; + 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 >>= 26; + hash_table[crc >> 4] |= 1 << (crc & 0xf); + } + hme_write32(hp, &bregs->htable0, hash_table[0]); + hme_write32(hp, &bregs->htable1, hash_table[1]); + hme_write32(hp, &bregs->htable2, hash_table[2]); + hme_write32(hp, &bregs->htable3, hash_table[3]); + } else { + hme_write32(hp, &bregs->htable3, 0); + hme_write32(hp, &bregs->htable2, 0); + hme_write32(hp, &bregs->htable1, 0); + hme_write32(hp, &bregs->htable0, 0); + } /* Set the RX and TX ring ptrs. */ HMD(("ring ptrs rxr[%08x] txr[%08x]\n", @@ -1343,9 +1422,22 @@ hme_read32(hp, &gregs->cfg))); #ifdef __sparc_v9__ + /* XXX Can sun4d do these too? */ if(hp->happy_bursts & DMA_BURST64) { + u32 gcfg = GREG_CFG_BURST64; + + /* I have no idea if I should set the extended + * transfer mode bit for Cheerio, so for now I + * do not. -DaveM + */ + if((hp->happy_flags & HFLAG_PCI) == 0) { + mmu_set_sbus64(hp->happy_sbus_dev, + hp->happy_bursts); + gcfg |= GREG_CFG_64BIT; + } + HMD(("64>")); - hme_write32(hp, &gregs->cfg, GREG_CFG_BURST64); + hme_write32(hp, &gregs->cfg, gcfg); } else #endif if(hp->happy_bursts & DMA_BURST32) { @@ -1396,7 +1488,10 @@ /* Enable Big Mac hash table filter. */ HMD(("happy_meal_init: enable hash rx_cfg_old[%08x], ", hme_read32(hp, &bregs->rx_cfg))); - hme_write32(hp, &bregs->rx_cfg, BIGMAC_RXCFG_HENABLE); + rxcfg = BIGMAC_RXCFG_HENABLE; + if(hp->dev->flags & IFF_PROMISC) + rxcfg |= BIGMAC_RXCFG_PMISC; + hme_write32(hp, &bregs->rx_cfg, rxcfg); /* Let the bits settle in the chip. */ udelay(10); @@ -1433,7 +1528,7 @@ hme_read32(hp, &bregs->rx_cfg) | BIGMAC_RXCFG_ENABLE); /* Get the autonegotiation started, and the watch timer ticking. */ - happy_meal_begin_auto_negotiation(hp, tregs); + happy_meal_begin_auto_negotiation(hp, tregs, NULL); /* Success. */ return 0; @@ -1505,7 +1600,7 @@ /* Only print messages for non-counter related interrupts. */ if(status & (GREG_STAT_RFIFOVF | GREG_STAT_STSTERR | GREG_STAT_TFIFO_UND | - GREG_STAT_MAXPKTERR | GREG_STAT_NORXD | GREG_STAT_RXERR | + GREG_STAT_MAXPKTERR | GREG_STAT_RXERR | GREG_STAT_RXPERR | GREG_STAT_RXTERR | GREG_STAT_EOPERR | GREG_STAT_MIFIRQ | GREG_STAT_TXEACK | GREG_STAT_TXLERR | GREG_STAT_TXPERR | GREG_STAT_TXTERR | GREG_STAT_SLVERR | @@ -1541,13 +1636,14 @@ } if(status & GREG_STAT_NORXD) { - /* AIEEE, out of receive descriptors. Check out our drop - * processing in happy_meal_rx to see how we try very hard - * to avoid this situation. + /* This is harmless, it just means the system is + * quite loaded and the incomming packet rate was + * faster than the interrupt handler could keep up + * with. */ - printk("%s: Happy Meal out of receive descriptors, aieee!\n", + printk(KERN_INFO "%s: Happy Meal out of receive " + "descriptors, packet dropped.\n", hp->dev->name); - reset = 1; } if(status & (GREG_STAT_RXERR|GREG_STAT_RXPERR|GREG_STAT_RXTERR)) { @@ -1662,13 +1758,6 @@ hp->tx_skbs[elem] = NULL; hp->net_stats.tx_bytes+=skb->len; -#ifdef NEED_DMA_SYNCHRONIZATION -#ifdef CONFIG_PCI - if(!(hp->happy_flags & HFLAG_PCI)) -#endif - mmu_sync_dma(kva_to_hva(hp, skb->data), - skb->len, hp->happy_sbus_dev->my_bus); -#endif dev_kfree_skb(skb); hp->net_stats.tx_packets++; @@ -1797,7 +1886,8 @@ struct sk_buff *new_skb; /* Now refill the entry, if we can. */ - new_skb = happy_meal_alloc_skb(RX_BUF_ALLOC_SIZE, GFP_ATOMIC); + new_skb = happy_meal_alloc_skb(RX_BUF_ALLOC_SIZE, + (GFP_DMA|GFP_ATOMIC)); if(!new_skb) { drops++; goto drop_it; @@ -1814,7 +1904,7 @@ /* Trim the original skb for the netif. */ skb_trim(skb, len); } else { - struct sk_buff *copy_skb = dev_alloc_skb(len+2); + struct sk_buff *copy_skb = dev_alloc_skb(len + 2); if(!copy_skb) { drops++; @@ -1908,7 +1998,8 @@ struct sk_buff *new_skb; /* Now refill the entry, if we can. */ - new_skb = happy_meal_alloc_skb(RX_BUF_ALLOC_SIZE, GFP_ATOMIC); + new_skb = happy_meal_alloc_skb(RX_BUF_ALLOC_SIZE, + (GFP_DMA|GFP_ATOMIC)); if(!new_skb) { drops++; goto drop_it; @@ -1925,7 +2016,7 @@ /* Trim the original skb for the netif. */ skb_trim(skb, len); } else { - struct sk_buff *copy_skb = dev_alloc_skb(len+2); + struct sk_buff *copy_skb = dev_alloc_skb(len + 2); if(!copy_skb) { drops++; @@ -2083,7 +2174,8 @@ struct sk_buff *new_skb; /* Now refill the entry, if we can. */ - new_skb = happy_meal_alloc_skb(RX_BUF_ALLOC_SIZE, GFP_ATOMIC); + new_skb = happy_meal_alloc_skb(RX_BUF_ALLOC_SIZE, + (GFP_DMA | GFP_ATOMIC)); if(!new_skb) { drops++; goto drop_it; @@ -2103,7 +2195,7 @@ /* Trim the original skb for the netif. */ skb_trim(skb, len); } else { - struct sk_buff *copy_skb = dev_alloc_skb(len+2); + struct sk_buff *copy_skb = dev_alloc_skb(len + 2); if(!copy_skb) { drops++; @@ -2328,12 +2420,39 @@ } #endif +static void quattro_sbus_interrupt(int irq, void *cookie, struct pt_regs *ptregs) +{ + struct quattro *qp = (struct quattro *)cookie; + int i; + + for(i = 0; i < 4; i++) { + struct device *hdev = qp->happy_meals[i]; + struct happy_meal *hp = (struct happy_meal *) hdev->priv; + volatile u32 *sreg = qp->irq_status[i]; + + if(sreg && + (hme_read32(hp, sreg) & (GREG_STAT_ERRORS | + GREG_STAT_MIFIRQ | + GREG_STAT_TXALL | + GREG_STAT_RXTOHOST)) != 0) + qp->handler(irq, hdev, ptregs); + } +} + static int happy_meal_open(struct device *dev) { struct happy_meal *hp = (struct happy_meal *) dev->priv; int res; HMD(("happy_meal_open: ")); + + /* On SBUS Quattro QFE cards, all hme interrupts are concentrated + * into a single source which we register handling at probe time. + */ + if((hp->happy_flags & (HFLAG_QUATTRO|HFLAG_PCI)) == HFLAG_QUATTRO) { + hp->qfe_parent->irq_status[hp->qfe_ent] = &hp->gregs->stat; + goto after_request_irq; + } #ifndef __sparc_v9__ if(sparc_cpu_model == sun4c) { if(request_irq(dev->irq, &sun4c_happy_meal_interrupt, @@ -2370,8 +2489,8 @@ __irq_itoa(dev->irq)); return -EAGAIN; } - HMD(("Init happy timer\n")); - init_timer(&hp->happy_timer); + +after_request_irq: HMD(("to happy_meal_init\n")); res = happy_meal_init(hp, 0); if(!res) { @@ -2390,7 +2509,17 @@ /* If auto-negotiation timer is running, kill it. */ del_timer(&hp->happy_timer); - free_irq(dev->irq, (void *)dev); + /* On Quattro QFE cards, all hme interrupts are concentrated + * into a single source which we register handling at probe + * time and never unregister. + */ + if((hp->happy_flags & (HFLAG_QUATTRO|HFLAG_PCI)) != HFLAG_QUATTRO) { + free_irq(dev->irq, (void *)dev); + } else { + /* Zap the status register pointer. */ + hp->qfe_parent->irq_status[hp->qfe_ent] = NULL; + } + MOD_DEC_USE_COUNT; return 0; } @@ -2429,10 +2558,23 @@ tx_add_log(hp, TXLOG_ACTION_TXMIT|TXLOG_ACTION_NBUFS, 0); return 1; } +#ifdef __sparc_v9__ + if ((unsigned long)(skb->data + skb->len) >= MAX_DMA_ADDRESS) { + struct sk_buff *new_skb = skb_copy(skb, GFP_DMA | GFP_ATOMIC); + if (!new_skb) + return 1; + dev_kfree_skb(skb); + skb = new_skb; + } +#endif len = skb->len; entry = hp->tx_new; SXD(("SX", len, entry)); +#ifdef NEED_DMA_SYNCHRONIZATION + mmu_sync_dma(kva_to_hva(hp, skb->data), + skb->len, hp->happy_sbus_dev->my_bus); +#endif hp->tx_skbs[entry] = skb; hp->happy_block->happy_meal_txd[entry].tx_addr = kva_to_hva(hp, skb->data); hp->happy_block->happy_meal_txd[entry].tx_flags = @@ -2622,9 +2764,6 @@ return &hp->net_stats; } -#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */ -#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */ - static void happy_meal_set_multicast(struct device *dev) { struct happy_meal *hp = (struct happy_meal *) dev->priv; @@ -2634,10 +2773,6 @@ int i, j, bit, byte; u32 crc, poly = CRC_POLYNOMIAL_LE; - /* Let the transmits drain. */ - while(dev->tbusy) - schedule(); - /* Lock out others. */ set_bit(0, (void *) &dev->tbusy); @@ -2686,13 +2821,262 @@ dev->tbusy = 0; } +/* Ethtool support... */ +static int happy_meal_ioctl(struct device *dev, + struct ifreq *rq, int cmd) +{ + struct happy_meal *hp = (struct happy_meal *) dev->priv; + struct ethtool_cmd *ep_user = (struct ethtool_cmd *) rq->ifr_data; + struct ethtool_cmd ecmd; + + if(cmd != SIOCETHTOOL) + return -EOPNOTSUPP; + if(copy_from_user(&ecmd, ep_user, sizeof(ecmd))) + return -EFAULT; + + if(ecmd.cmd == SPARC_ETH_GSET) { + ecmd.supported = + (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | + SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | + SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII); + + /* XXX hardcoded stuff for now */ + ecmd.port = PORT_TP; /* XXX no MII support */ + ecmd.transceiver = XCVR_INTERNAL; /* XXX no external xcvr support */ + ecmd.phy_address = 0; /* XXX fixed PHYAD */ + + /* Record PHY settings. */ + hp->sw_bmcr = happy_meal_tcvr_read(hp, hp->tcvregs, DP83840_BMCR); + hp->sw_lpa = happy_meal_tcvr_read(hp, hp->tcvregs, DP83840_LPA); + if(hp->sw_bmcr & BMCR_ANENABLE) { + ecmd.autoneg = AUTONEG_ENABLE; + ecmd.speed = + (hp->sw_lpa & (LPA_100HALF | LPA_100FULL)) ? + SPEED_100 : SPEED_10; + if(ecmd.speed == SPEED_100) + ecmd.duplex = + (hp->sw_lpa & (LPA_100FULL)) ? + DUPLEX_FULL : DUPLEX_HALF; + else + ecmd.duplex = + (hp->sw_lpa & (LPA_10FULL)) ? + DUPLEX_FULL : DUPLEX_HALF; + } else { + ecmd.autoneg = AUTONEG_DISABLE; + ecmd.speed = + (hp->sw_bmcr & BMCR_SPEED100) ? + SPEED_100 : SPEED_10; + ecmd.duplex = + (hp->sw_bmcr & BMCR_FULLDPLX) ? + DUPLEX_FULL : DUPLEX_HALF; + } + if(copy_to_user(ep_user, &ecmd, sizeof(ecmd))) + return -EFAULT; + return 0; + } else if(ecmd.cmd == SPARC_ETH_SSET) { + if(!capable(CAP_NET_ADMIN)) + return -EPERM; + + /* Verify the settings we care about. */ + if(ecmd.autoneg != AUTONEG_ENABLE && + ecmd.autoneg != AUTONEG_DISABLE) + return -EINVAL; + if(ecmd.autoneg == AUTONEG_DISABLE && + ((ecmd.speed != SPEED_100 && + ecmd.speed != SPEED_10) || + (ecmd.duplex != DUPLEX_HALF && + ecmd.duplex != DUPLEX_FULL))) + return -EINVAL; + + /* Ok, do it to it. */ + del_timer(&hp->happy_timer); + happy_meal_begin_auto_negotiation(hp, + hp->tcvregs, + &ecmd); + + return 0; + } else + return -EOPNOTSUPP; +} + +void __init quattro_get_ranges(struct quattro *qp) +{ + int err; + + err = prom_getproperty(qp->quattro_sbus_dev->prom_node, + "ranges", + (char *)&qp->ranges[0], + sizeof(qp->ranges)); + if(err == 0 || err == -1) { + qp->nranges = 0; + return; + } + qp->nranges = (err / sizeof(struct linux_prom_ranges)); +} + +static void __init quattro_apply_ranges(struct quattro *qp, struct happy_meal *hp) +{ + struct linux_sbus_device *sdev = hp->happy_sbus_dev; + int rng; + + for(rng = 0; rng < qp->nranges; rng++) { + struct linux_prom_ranges *rngp = &qp->ranges[rng]; + int reg; + + for(reg = 0; reg < 5; reg++) { + if(sdev->reg_addrs[reg].which_io == + rngp->ot_child_space) + break; + } + if(reg == 5) + continue; + + sdev->reg_addrs[reg].which_io = rngp->ot_parent_space; + sdev->reg_addrs[reg].phys_addr += rngp->ot_parent_base; + } +} + +/* Given a happy meal sbus device, find it's quattro parent. + * If none exist, allocate and return a new one. + * + * Return NULL on failure. + */ +static struct quattro * __init quattro_sbus_find(struct linux_sbus_device *goal_sdev) +{ + struct linux_sbus *sbus; + struct linux_sbus_device *sdev; + struct quattro *qp; + + for(qp = qfe_sbus_list; qp != NULL; qp = qp->next) { + for(sdev = qp->quattro_sbus_dev->child; + sdev != NULL; + sdev = sdev->next) { + if(sdev == goal_sdev) + return qp; + } + } + for_each_sbus(sbus) { + for_each_sbusdev(sdev, sbus) { + if(sdev->child != NULL) { + struct linux_sbus_device *p; + + for(p = sdev->child; p != NULL; p = p->next) + if(p == goal_sdev) + goto found; + } + } + } + + /* Cannot find quattro parent, fail. */ + return NULL; + +found: + qp = kmalloc(sizeof(struct quattro), GFP_KERNEL); + if(qp != NULL) { + int i; + + for(i = 0; i < 4; i++) { + qp->irq_status[i] = NULL; + qp->happy_meals[i] = NULL; + } + qp->handler = NULL; + qp->quattro_sbus_dev = sdev; +#ifdef CONFIG_PCI + qp->quattro_pci_dev = NULL; +#endif + qp->next = qfe_sbus_list; + qfe_sbus_list = qp; + quattro_get_ranges(qp); + } + return qp; +} + +#ifdef CONFIG_PCI +static struct quattro * __init quattro_pci_find(struct pci_dev *pdev) +{ + struct pci_dev *bdev = pdev->bus->self; + struct quattro *qp; + + if (!bdev) return NULL; + for(qp = qfe_pci_list; qp != NULL; qp = qp->next) { + if(qp->quattro_pci_dev == bdev) + return qp; + } + qp = kmalloc(sizeof(struct quattro), GFP_KERNEL); + if(qp != NULL) { + int i; + + for(i = 0; i < 4; i++) { + qp->irq_status[i] = NULL; + qp->happy_meals[i] = NULL; + } + qp->handler = NULL; + qp->quattro_sbus_dev = NULL; + qp->quattro_pci_dev = bdev; + qp->next = qfe_pci_list; + qfe_pci_list = qp; + + /* No range tricks necessary on PCI. */ + qp->nranges = 0; + } + return qp; +} +#endif + +/* After all quattro cards have been probed, we call these functions + * to register the IRQ handlers. + */ +static void __init quattro_sbus_register_irqs(void) +{ + struct quattro *qp; + + for(qp = qfe_sbus_list; qp != NULL; qp = qp->next) { + int err; + + /* Set the handler. */ +#ifndef __sparc_v9__ + if(sparc_cpu_model == sun4c) + qp->handler = sun4c_happy_meal_interrupt; + else if(sparc_cpu_model == sun4c) + qp->handler = sun4d_happy_meal_interrupt; + else +#endif +#ifdef CONFIG_PCI + if(qp->quattro_pci_dev != NULL) + panic("QFE: PCI qfe in sbus_register_irqs!"); + else +#endif + qp->handler = happy_meal_interrupt; + + err = request_irq(qp->quattro_sbus_dev->irqs[0], + quattro_sbus_interrupt, + SA_SHIRQ, "Quattro", + qp); + if(err != 0) { + printk("Quattro: Fatal IRQ registery error %d.\n", err); + panic("QFE request irq"); + } + } +} + static unsigned hme_version_printed = 0; -static inline int happy_meal_ether_init(struct device *dev, struct linux_sbus_device *sdev) +static int __init happy_meal_ether_init(struct device *dev, struct linux_sbus_device *sdev, int is_qfe) { + struct quattro *qp = NULL; struct happy_meal *hp; - int i; + int i, qfe_slot = -1; + if(is_qfe) { + qp = quattro_sbus_find(sdev); + if(qp == NULL) + return ENODEV; + for(qfe_slot = 0; qfe_slot < 4; qfe_slot++) + if(qp->happy_meals[qfe_slot] == NULL) + break; + if(qfe_slot == 4) + return ENODEV; + } if(dev == NULL) { dev = init_etherdev(0, sizeof(struct happy_meal)); } else { @@ -2703,9 +3087,16 @@ if(hme_version_printed++ == 0) printk(version); - printk("%s: HAPPY MEAL (SBUS) 10/100baseT Ethernet ", dev->name); + if(qfe_slot != -1) + printk("%s: Quattro HME slot %d (SBUS) 10/100baseT Ethernet", + dev->name, qfe_slot); + else + printk("%s: HAPPY MEAL (SBUS) 10/100baseT Ethernet ", + dev->name); dev->base_addr = (long) sdev; + + /* XXX Check for local-mac-address property on Quattro... -DaveM */ for(i = 0; i < 6; i++) printk("%2.2x%c", dev->dev_addr[i] = idprom->id_ethaddr[i], @@ -2727,6 +3118,13 @@ return ENODEV; } + if(qp != NULL) { + hp->qfe_parent = qp; + hp->qfe_ent = qfe_slot; + qp->happy_meals[qfe_slot] = dev; + quattro_apply_ranges(qp, hp); + } + prom_apply_sbus_ranges(sdev->my_bus, &sdev->reg_addrs[0], sdev->num_registers, sdev); hp->gregs = sparc_alloc_io(sdev->reg_addrs[0].phys_addr, 0, @@ -2784,6 +3182,9 @@ else if(hp->hm_revision != 0xa0) hp->happy_flags = HFLAG_NOT_A0; + if(qp != NULL) + hp->happy_flags |= HFLAG_QUATTRO; + /* Get the supported DVMA burst sizes from our Happy SBUS. */ hp->happy_bursts = prom_getintdefault(hp->happy_sbus_dev->my_bus->prom_node, "burst-sizes", 0x00); @@ -2817,6 +3218,8 @@ */ happy_meal_set_initial_advertisement(hp); + init_timer(&hp->happy_timer); + hp->dev = dev; dev->open = &happy_meal_open; dev->stop = &happy_meal_close; @@ -2830,6 +3233,7 @@ dev->hard_start_xmit = &happy_meal_start_xmit; dev->get_stats = &happy_meal_get_stats; dev->set_multicast_list = &happy_meal_set_multicast; + dev->do_ioctl = &happy_meal_ioctl; dev->irq = sdev->irqs[0]; dev->dma = 0; @@ -2846,14 +3250,35 @@ } #ifdef CONFIG_PCI -__initfunc(int happy_meal_pci_init(struct device *dev, struct pci_dev *pdev)) +static int __init happy_meal_pci_init(struct device *dev, struct pci_dev *pdev) { + struct quattro *qp = NULL; struct pcidev_cookie *pcp; struct happy_meal *hp; unsigned long hpreg_base; unsigned short pci_command; - int i, node; + int i, node, qfe_slot = -1; + char prom_name[64]; + /* Now make sure pci_dev cookie is there. */ + pcp = pdev->sysdata; + if(pcp == NULL || pcp->prom_node == -1) { + printk("happymeal(PCI): Some PCI device info missing\n"); + return ENODEV; + } + node = pcp->prom_node; + + prom_getstring(node, "name", prom_name, sizeof(prom_name)); + if (!strcmp(prom_name, "SUNW,qfe") || !strcmp(prom_name, "qfe")) { + qp = quattro_pci_find(pdev); + if(qp == NULL) + return ENODEV; + for(qfe_slot = 0; qfe_slot < 4; qfe_slot++) + if(qp->happy_meals[qfe_slot] == NULL) + break; + if(qfe_slot == 4) + return ENODEV; + } if(dev == NULL) { dev = init_etherdev(0, sizeof(struct happy_meal)); } else { @@ -2864,15 +3289,28 @@ if(hme_version_printed++ == 0) printk(version); - printk("%s: HAPPY MEAL (PCI/CheerIO) 10/100BaseT Ethernet ", dev->name); + if (!qfe_slot) { + prom_name[0] = 0; + if (!strncmp(dev->name, "eth", 3)) { + int i = simple_strtoul(dev->name + 3, NULL, 10); + sprintf(prom_name, "-%d", i + 3); + } + printk("%s%s: Quattro HME (PCI/CheerIO) 10/100baseT Ethernet ", dev->name, prom_name); + if (qp->quattro_pci_dev->vendor == PCI_VENDOR_ID_DEC && + qp->quattro_pci_dev->device == PCI_DEVICE_ID_DEC_21153) + printk("DEC 21153 PCI Bridge\n"); + else + printk("unknown bridge %04x.%04x\n", + qp->quattro_pci_dev->vendor, qp->quattro_pci_dev->device); + } + if(qfe_slot != -1) + printk("%s: Quattro HME slot %d (PCI/CheerIO) 10/100baseT Ethernet ", + dev->name, qfe_slot); + else + printk("%s: HAPPY MEAL (PCI/CheerIO) 10/100BaseT Ethernet ", + dev->name); dev->base_addr = (long) pdev; - for(i = 0; i < 6; i++) - printk("%2.2x%c", - dev->dev_addr[i] = idprom->id_ethaddr[i], - i == 5 ? ' ' : ':'); - - printk("\n"); hp = (struct happy_meal *)dev->priv; memset(hp, 0, sizeof(*hp)); @@ -2880,6 +3318,12 @@ hp->happy_sbus_dev = NULL; hp->happy_pci_dev = pdev; + if(qp != NULL) { + hp->qfe_parent = qp; + hp->qfe_ent = qfe_slot; + qp->happy_meals[qfe_slot] = dev; + } + hpreg_base = pdev->base_address[0]; if((hpreg_base & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_MEMORY) { printk("happymeal(PCI): Cannot find proper PCI device base address.\n"); @@ -2887,13 +3331,14 @@ } hpreg_base &= PCI_BASE_ADDRESS_MEM_MASK; - /* Now make sure pci_dev cookie is there. */ - pcp = pdev->sysdata; - if(pcp == NULL || pcp->prom_node == -1) { - printk("happymeal(PCI): Some PCI device info missing\n"); - return ENODEV; - } - node = pcp->prom_node; + if (qfe_slot != -1 && prom_getproplen(node, "local-mac-address") == 6) + prom_getproperty(node, "local-mac-address", dev->dev_addr, 6); + else + memcpy(dev->dev_addr, idprom->id_ethaddr, 6); + for(i = 0; i < 6; i++) + printk("%2.2x%c", dev->dev_addr[i], i == 5 ? ' ' : ':'); + + printk("\n"); /* Layout registers. */ hp->gregs = (struct hmeal_gregs *) (hpreg_base + 0x0000); @@ -2912,6 +3357,9 @@ else if(hp->hm_revision != 0xa0) hp->happy_flags = HFLAG_NOT_A0; + if(qp != NULL) + hp->happy_flags |= HFLAG_QUATTRO; + /* And of course, indicate this is PCI. */ hp->happy_flags |= HFLAG_PCI; @@ -2937,29 +3385,32 @@ hp->timer_ticks = 0; happy_meal_set_initial_advertisement(hp); + init_timer(&hp->happy_timer); + hp->dev = dev; dev->open = &happy_meal_open; dev->stop = &happy_meal_close; dev->hard_start_xmit = &pci_happy_meal_start_xmit; dev->get_stats = &happy_meal_get_stats; dev->set_multicast_list = &happy_meal_set_multicast; + dev->do_ioctl = &happy_meal_ioctl; dev->irq = pdev->irq; dev->dma = 0; ether_setup(dev); /* If we don't do this, nothing works. */ - pcibios_read_config_word(pdev->bus->number, - pdev->devfn, - PCI_COMMAND, &pci_command); + pci_read_config_word(pdev, PCI_COMMAND, &pci_command); pci_command |= PCI_COMMAND_MASTER; - pcibios_write_config_word(pdev->bus->number, - pdev->devfn, - PCI_COMMAND, pci_command); - - /* Set the latency timer as well, PROM leaves it at zero. */ - pcibios_write_config_byte(pdev->bus->number, - pdev->devfn, - PCI_LATENCY_TIMER, 240); + pci_write_config_word(pdev, PCI_COMMAND, pci_command); + + /* Set the latency timer and cache line size as well, + * PROM leaves it at zero. + */ + pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 128); +#ifdef __sparc_v9__ + /* NOTE: Cache line size is in 32-bit word units. */ + pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 0x10); +#endif #ifdef MODULE /* We are home free at this point, link us in to the happy @@ -2973,7 +3424,7 @@ } #endif -__initfunc(int happy_meal_probe(struct device *dev)) +int __init happy_meal_probe(struct device *dev) { struct linux_sbus *bus; struct linux_sbus_device *sdev = 0; @@ -2990,11 +3441,18 @@ dev = NULL; if(!strcmp(sdev->prom_name, "SUNW,hme")) { cards++; - if((v = happy_meal_ether_init(dev, sdev))) + if((v = happy_meal_ether_init(dev, sdev, 0))) + return v; + } else if(!strcmp(sdev->prom_name, "qfe") || + !strcmp(sdev->prom_name, "SUNW,qfe")) { + cards++; + if((v = happy_meal_ether_init(dev, sdev, 1))) return v; } } } + if(cards != 0) + quattro_sbus_register_irqs(); #ifdef CONFIG_PCI if(pci_present()) { struct pci_dev *pdev; diff -ur --new-file old/linux/drivers/net/sunhme.h new/linux/drivers/net/sunhme.h --- old/linux/drivers/net/sunhme.h Mon Nov 16 19:37:28 1998 +++ new/linux/drivers/net/sunhme.h Tue Mar 16 01:11:30 1999 @@ -507,6 +507,8 @@ asleep = 3, /* Time inactive. */ }; +struct quattro; + /* Happy happy, joy joy! */ struct happy_meal { struct hmeal_gregs *gregs; /* Happy meal global registers */ @@ -559,6 +561,8 @@ struct pci_dev *happy_pci_dev; #endif struct device *dev; /* Backpointer */ + struct quattro *qfe_parent; /* For Quattro cards */ + int qfe_ent; /* Which instance on quattro */ struct happy_meal *next_module; }; @@ -575,10 +579,28 @@ #define HFLAG_INIT 0x00000200 /* Init called at least once */ #define HFLAG_LINKUP 0x00000400 /* 1 = Link is up */ #define HFLAG_PCI 0x00000800 /* PCI based Happy Meal */ +#define HFLAG_QUATTRO 0x00001000 /* On QFE/Quattro card */ #define HFLAG_20_21 (HFLAG_POLLENABLE | HFLAG_FENABLE) #define HFLAG_NOT_A0 (HFLAG_POLLENABLE | HFLAG_FENABLE | HFLAG_LANCE | HFLAG_RXCV) +/* Support for QFE/Quattro cards. */ +struct quattro { + volatile u32 *irq_status[4]; + struct device *happy_meals[4]; + void (*handler)(int, void *, struct pt_regs *); + + struct linux_sbus_device *quattro_sbus_dev; +#ifdef CONFIG_PCI + struct pci_dev *quattro_pci_dev; +#endif + struct quattro *next; + + /* PROM ranges, if any. */ + struct linux_prom_ranges ranges[8]; + int nranges; +}; + /* We use this to acquire receive skb's that we can DMA directly into. */ #define ALIGNED_RX_SKB_ADDR(addr) \ ((((unsigned long)(addr) + (64 - 1)) & ~(64 - 1)) - (unsigned long)(addr)) @@ -606,7 +628,16 @@ return (u32) virt_to_bus((volatile void *)addr); else #endif - return (u32) ((unsigned long)addr); + { +#ifdef __sparc_v9__ + if (((unsigned long) addr) >= MAX_DMA_ADDRESS) { + printk("sunhme: Bogus DMA buffer address " + "[%016lx]\n", ((unsigned long) addr)); + panic("DMA address too large, tell DaveM"); + } +#endif + return sbus_dvma_addr(addr); + } } extern inline unsigned int hme_read32(struct happy_meal *hp, diff -ur --new-file old/linux/drivers/net/sunlance.c new/linux/drivers/net/sunlance.c --- old/linux/drivers/net/sunlance.c Fri Aug 28 04:33:08 1998 +++ new/linux/drivers/net/sunlance.c Sun Mar 21 16:22:00 1999 @@ -1,4 +1,4 @@ -/* $Id: sunlance.c,v 1.81 1998/08/10 09:08:23 jj Exp $ +/* $Id: sunlance.c,v 1.85 1999/03/21 05:22:05 davem Exp $ * lance.c: Linux/Sparc/Lance driver * * Written 1995, 1996 by Miguel de Icaza @@ -56,12 +56,16 @@ * * 1.11: * 12/27/97: Added sun4d support. (jj@sunsite.mff.cuni.cz) + * + * 1.12: + * 11/3/99: Fixed SMP race in lance_start_xmit found by davem. + * Anton Blanchard (anton@progsoc.uts.edu.au) */ #undef DEBUG_DRIVER static char *version = - "sunlance.c:v1.11 27/Dec/97 Miguel de Icaza (miguel@nuclecu.unam.mx)\n"; + "sunlance.c:v1.12 11/Mar/99 Miguel de Icaza (miguel@nuclecu.unam.mx)\n"; static char *lancestr = "LANCE"; static char *lancedma = "LANCE DMA"; @@ -252,6 +256,7 @@ struct device *dev; /* Backpointer */ struct lance_private *next_module; struct linux_sbus *sbus; + struct timer_list multicast_timer; }; #define TX_BUFFS_AVAIL ((lp->tx_old<=lp->tx_new)?\ @@ -326,8 +331,6 @@ 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 * Note that on the sparc you need to swap the ethernet address. * Note also we want the CPU ptr of the init_block here. @@ -384,10 +387,6 @@ ib->tx_ptr = leptr; if (ZERO) printk ("TX ptr: %8.8x\n", leptr); - - /* Clear the multicast filter */ - ib->filter [0] = 0; - ib->filter [1] = 0; } static int init_restart_lance (struct lance_private *lp) @@ -668,6 +667,7 @@ { struct lance_private *lp = (struct lance_private *)dev->priv; volatile struct lance_regs *ll = lp->ll; + volatile struct lance_init_block *ib = lp->init_block; int status = 0; last_dev = dev; @@ -686,6 +686,16 @@ if (lp->ledma) lp->ledma->regs->dma_test = ((__u32) lp->init_block_dvma) & 0xff000000; + /* Set mode and clear multicast filter only at device open, + so that lance_init_ring() called at any error will not + forget multicast filters. + + BTW it is common bug in all lance drivers! --ANK + */ + ib->mode = 0; + ib->filter [0] = 0; + ib->filter [1] = 0; + lance_init_ring (dev); load_csrs (lp); @@ -742,6 +752,7 @@ dev->start = 0; dev->tbusy = 1; + del_timer(&lp->multicast_timer); /* Stop the card */ ll->rap = LE_CSR0; @@ -791,27 +802,19 @@ volatile unsigned long flush; unsigned long flags; int entry, skblen, len; - int status = 0; - static int outs; - /* Transmitter timeout, serious problems */ - if (dev->tbusy) { + if (test_and_set_bit (0, (void *) &dev->tbusy) != 0) { 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; + if (tickssofar < 100) + return 1; + + printk ("%s: transmit timed out, status %04x, reset\n", + dev->name, ll->rdp); + lp->stats.tx_errors++; + lance_reset (dev); + + return 1; } skblen = skb->len; @@ -820,13 +823,13 @@ if (!TX_BUFFS_AVAIL) { restore_flags(flags); - return -1; + 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) | 0xf000; ib->btx_ring [entry].misc = 0; @@ -842,7 +845,6 @@ 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 */ ll->rdp = LE_C0_INEA | LE_C0_TDMD; dev->trans_start = jiffies; @@ -857,7 +859,7 @@ flush = ll->rdp; restore_flags(flags); - return status; + return 0; } static struct net_device_stats *lance_get_stats (struct device *dev) @@ -879,7 +881,7 @@ u32 crc, poly = CRC_POLYNOMIAL_LE; /* set all multicast bits */ - if (dev->flags & IFF_ALLMULTI){ + if (dev->flags & IFF_ALLMULTI) { ib->filter [0] = 0xffffffff; ib->filter [1] = 0xffffffff; return; @@ -889,31 +891,29 @@ ib->filter [1] = 0; /* Add addresses */ - for (i = 0; i < dev->mc_count; i++){ + 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 (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) { + if (test) crc = crc ^ poly; - } } - + } crc = crc >> 26; mcast_table [crc >> 4] |= 1 << (crc & 0xf); } - return; } static void lance_set_multicast (struct device *dev) @@ -922,12 +922,33 @@ volatile struct lance_init_block *ib = lp->init_block; volatile struct lance_regs *ll = lp->ll; - while (dev->tbusy) - schedule(); + if (!dev->start) + return; + + if (dev->tbusy) { + mod_timer(&lp->multicast_timer, jiffies + 2); + return; + } + /* This CANNOT be correct. Chip is running + and dev->tbusy may change any moment. + It is useless to set it. + + Generally, usage of dev->tbusy in this driver is completely + wrong. + + I protected calls to this function + with start_bh_atomic, so that set_multicast_list + and hard_start_xmit are serialized now by top level. --ANK + + The same is true about a2065. + */ set_bit (0, (void *) &dev->tbusy); - while (lp->tx_old != lp->tx_new) - schedule(); + if (lp->tx_old != lp->tx_new) { + mod_timer(&lp->multicast_timer, jiffies + 4); + dev->tbusy = 0; + return; + } ll->rap = LE_CSR0; ll->rdp = LE_C0_STOP; @@ -942,6 +963,7 @@ load_csrs (lp); init_restart_lance (lp); dev->tbusy = 0; + mark_bh(NET_BH); } __initfunc(static int @@ -1100,6 +1122,16 @@ dev->dma = 0; ether_setup (dev); + + /* We cannot sleep if the chip is busy during a + * multicast list update event, because such events + * can occur from interrupts (ex. IPv6). So we + * use a timer to try again later when necessary. -DaveM + */ + init_timer(&lp->multicast_timer); + lp->multicast_timer.data = (unsigned long) dev; + lp->multicast_timer.function = + (void (*)(unsigned long)) &lance_set_multicast; #ifdef MODULE dev->ifindex = dev_new_index(); diff -ur --new-file old/linux/drivers/net/sunqe.c new/linux/drivers/net/sunqe.c --- old/linux/drivers/net/sunqe.c Mon Jul 27 08:35:56 1998 +++ new/linux/drivers/net/sunqe.c Tue Mar 16 01:11:30 1999 @@ -36,7 +36,6 @@ #include #include #include -#include #include #include @@ -145,7 +144,7 @@ for(i = 0; i < RX_RING_SIZE; i++) { struct sk_buff *skb; - skb = qe_alloc_skb(RX_BUF_ALLOC_SIZE, gfp_flags); + skb = qe_alloc_skb(RX_BUF_ALLOC_SIZE, gfp_flags | GFP_DMA); if(!skb) continue; @@ -155,8 +154,7 @@ skb_put(skb, ETH_FRAME_LEN); skb_reserve(skb, 34); - qb->qe_rxd[i].rx_addr = - (u32) ((unsigned long)skb->data); + qb->qe_rxd[i].rx_addr = sbus_dvma_addr(skb->data); qb->qe_rxd[i].rx_flags = (RXD_OWN | ((RX_BUF_ALLOC_SIZE - 34) & RXD_LENGTH)); } @@ -447,10 +445,6 @@ skb = qep->tx_skbs[elem]; qep->tx_skbs[elem] = NULL; qep->net_stats.tx_bytes+=skb->len; -#ifdef NEED_DMA_SYNCHRONIZATION - mmu_sync_dma(((u32)((unsigned long)skb->data)), - skb->len, qep->qe_sbusdev->my_bus); -#endif dev_kfree_skb(skb); qep->net_stats.tx_packets++; @@ -498,22 +492,28 @@ drop_it: /* Return it to the QE. */ qep->net_stats.rx_dropped++; - this->rx_addr = - (u32) ((unsigned long)qep->rx_skbs[elem]->data); + this->rx_addr = sbus_dvma_addr(qep->rx_skbs[elem]->data); this->rx_flags = (RXD_OWN | (RX_BUF_ALLOC_SIZE & RXD_LENGTH)); goto next; } skb = qep->rx_skbs[elem]; #ifdef NEED_DMA_SYNCHRONIZATION - mmu_sync_dma(((u32)((unsigned long)skb->data)), +#ifdef __sparc_v9__ + if ((unsigned long) (skb->data + skb->len) >= MAX_DMA_ADDRESS) { + printk("sunqe: Bogus DMA buffer address " + "[%016lx]\n", ((unsigned long) skb->data)); + panic("DMA address too large, tell DaveM"); + } +#endif + mmu_sync_dma(sbus_dvma_addr(skb->data), skb->len, qep->qe_sbusdev->my_bus); #endif if(len > RX_COPY_THRESHOLD) { struct sk_buff *new_skb; /* Now refill the entry, if we can. */ - new_skb = qe_alloc_skb(RX_BUF_ALLOC_SIZE, GFP_ATOMIC); + new_skb = qe_alloc_skb(RX_BUF_ALLOC_SIZE, (GFP_DMA|GFP_ATOMIC)); if(!new_skb) { drops++; goto drop_it; @@ -524,8 +524,7 @@ skb_put(new_skb, ETH_FRAME_LEN); skb_reserve(new_skb, 34); - rxbase[elem].rx_addr = - (u32) ((unsigned long)new_skb->data); + rxbase[elem].rx_addr = sbus_dvma_addr(new_skb->data); rxbase[elem].rx_flags = (RXD_OWN | ((RX_BUF_ALLOC_SIZE - 34) & RXD_LENGTH)); @@ -545,8 +544,7 @@ eth_copy_and_sum(copy_skb, (unsigned char *)skb->data, len, 0); /* Reuse original ring buffer. */ - rxbase[elem].rx_addr = - (u32) ((unsigned long)skb->data); + rxbase[elem].rx_addr = sbus_dvma_addr(skb->data); rxbase[elem].rx_flags = (RXD_OWN | ((RX_BUF_ALLOC_SIZE - 34) & RXD_LENGTH)); @@ -741,6 +739,19 @@ if(!TX_BUFFS_AVAIL(qep)) return 1; +#ifdef NEED_DMA_SYNCHRONIZATION +#ifdef __sparc_v9__ + if ((unsigned long) (skb->data + skb->len) >= MAX_DMA_ADDRESS) { + struct sk_buff *new_skb = skb_copy(skb, GFP_DMA | GFP_ATOMIC); + if(!new_skb) + return 1; + dev_kfree_skb(skb); + skb = new_skb; + } +#endif + mmu_sync_dma(sbus_dvma_addr(skb->data), + skb->len, qep->qe_sbusdev->my_bus); +#endif len = skb->len; entry = qep->tx_new; @@ -749,7 +760,7 @@ qep->tx_skbs[entry] = skb; - qep->qe_block->qe_txd[entry].tx_addr = (u32) ((unsigned long) skb->data); + qep->qe_block->qe_txd[entry].tx_addr = sbus_dvma_addr(skb->data); qep->qe_block->qe_txd[entry].tx_flags = (TXD_OWN | TXD_SOP | TXD_EOP | (len & TXD_LENGTH)); qep->tx_new = NEXT_TX(entry); diff -ur --new-file old/linux/drivers/net/syncppp.c new/linux/drivers/net/syncppp.c --- old/linux/drivers/net/syncppp.c Fri Nov 20 17:44:06 1998 +++ new/linux/drivers/net/syncppp.c Fri Apr 16 22:58:46 1999 @@ -51,7 +51,7 @@ #include #include "syncppp.h" -#define MAXALIVECNT 3 /* max. alive packets */ +#define MAXALIVECNT 6 /* max. alive packets */ #define PPP_ALLSTATIONS 0xff /* All-Stations broadcast address */ #define PPP_UI 0x03 /* Unnumbered Information */ @@ -121,6 +121,7 @@ u16 time1; }; #define CISCO_PACKET_LEN 18 +#define CISCO_BIG_PACKET_LEN 20 static struct sppp *spppq; static struct timer_list sppp_keepalive_timer; @@ -380,6 +381,7 @@ if_down (dev); if (! (sp->pp_flags & PP_CISCO)) { /* Shut down the PPP link. */ + sp->lcp.magic = jiffies; sp->lcp.state = LCP_STATE_CLOSED; sp->ipcp.state = IPCP_STATE_CLOSED; sppp_clear_timeout (sp); @@ -648,7 +650,7 @@ struct cisco_packet *h; struct device *dev = sp->pp_if; - if (skb->len != CISCO_PACKET_LEN) { + if (skb->len != CISCO_PACKET_LEN && skb->len != CISCO_BIG_PACKET_LEN) { if (sp->pp_flags & PP_DEBUG) printk (KERN_WARNING "%s: invalid cisco packet length: %d bytes\n", dev->name, skb->len); @@ -841,6 +843,25 @@ } EXPORT_SYMBOL(sppp_open); + +int sppp_reopen (struct device *dev) +{ + struct sppp *sp = &((struct ppp_device *)dev)->sppp; + sppp_close(dev); + dev->flags |= IFF_RUNNING; + if (!(sp->pp_flags & PP_CISCO)) + { + sp->lcp.magic = jiffies; + ++sp->pp_seq; + sp->lcp.state = LCP_STATE_CLOSED; + sp->ipcp.state = IPCP_STATE_CLOSED; + /* Give it a moment for the line to settle then go */ + sppp_set_timeout (sp, 1); + } + return 0; +} + +EXPORT_SYMBOL(sppp_reopen); int sppp_change_mtu(struct device *dev, int new_mtu) { diff -ur --new-file old/linux/drivers/net/syncppp.h new/linux/drivers/net/syncppp.h --- old/linux/drivers/net/syncppp.h Sun Oct 18 00:33:45 1998 +++ new/linux/drivers/net/syncppp.h Sat Feb 6 21:46:21 1999 @@ -80,6 +80,7 @@ int sppp_isempty (struct device *dev); void sppp_flush (struct device *dev); int sppp_open (struct device *dev); +int sppp_reopen (struct device *dev); int sppp_close (struct device *dev); #endif diff -ur --new-file old/linux/drivers/net/tlan.c new/linux/drivers/net/tlan.c --- old/linux/drivers/net/tlan.c Thu Jan 7 17:46:59 1999 +++ new/linux/drivers/net/tlan.c Tue Apr 13 01:18:33 1999 @@ -29,6 +29,8 @@ * * Tigran Aivazian : TLan_PciProbe() now uses * new PCI BIOS interface. + * Alan Cox : Fixed the out of memory + * handling. * ********************************************************************/ @@ -1250,28 +1252,36 @@ netif_rx( skb ); } } else { - skb = (struct sk_buff *) head_list->buffer[9].address; - head_list->buffer[9].address = 0; - skb_trim( skb, head_list->frameSize ); - + struct sk_buff *new_skb; + + /* + * I changed the algorithm here. What we now do + * is allocate the new frame. If this fails we + * simply recycle the frame. + */ + + new_skb = dev_alloc_skb( TLAN_MAX_FRAME_SIZE + 7 ); + if ( new_skb != NULL ) { + /* If this ever happened it would be a problem */ + /* not any more - ac */ + skb = (struct sk_buff *) head_list->buffer[9].address; + head_list->buffer[9].address = 0; + skb_trim( skb, head_list->frameSize ); #if LINUX_KERNEL_VERSION > 0x20100 priv->stats->rx_bytes += head_list->frameSize; #endif - skb->protocol = eth_type_trans( skb, dev ); - netif_rx( skb ); - - skb = dev_alloc_skb( TLAN_MAX_FRAME_SIZE + 7 ); - if ( skb == NULL ) { - printk( "TLAN: Couldn't allocate memory for received data.\n" ); - /* If this ever happened it would be a problem */ - } else { - skb->dev = dev; - skb_reserve( skb, 2 ); - t = (void *) skb_put( skb, TLAN_MAX_FRAME_SIZE ); + skb->protocol = eth_type_trans( skb, dev ); + netif_rx( skb ); + + new_skb->dev = dev; + skb_reserve( new_skb, 2 ); + t = (void *) skb_put( new_skb, TLAN_MAX_FRAME_SIZE ); head_list->buffer[0].address = virt_to_bus( t ); - head_list->buffer[9].address = (u32) skb; + head_list->buffer[9].address = (u32) new_skb; } + else + printk(KERN_WARNING "TLAN: Couldn't allocate memory for received data.\n" ); } head_list->forward = 0; @@ -1867,6 +1877,7 @@ u8 data8; priv->tlanFullDuplex = FALSE; + priv->phyOnline=0; /* 1. Assert reset bit. */ data = inl(dev->base_addr + TLAN_HOST_CMD); diff -ur --new-file old/linux/drivers/net/via-rhine.c new/linux/drivers/net/via-rhine.c --- old/linux/drivers/net/via-rhine.c Mon Dec 28 20:06:11 1998 +++ new/linux/drivers/net/via-rhine.c Mon May 10 22:00:10 1999 @@ -456,9 +456,9 @@ pci_tbl[chip_idx].name, pciaddr, irq); if (pci_tbl[chip_idx].flags & PCI_USES_IO) { - if (check_region(pciaddr, pci_tbl[chip_idx].io_size)) - continue; ioaddr = pciaddr & ~3; + if (check_region(ioaddr, pci_tbl[chip_idx].io_size)) + continue; } else if ((ioaddr = (long)ioremap(pciaddr & ~0xf, pci_tbl[chip_idx].io_size)) == 0) { printk(KERN_INFO "Failed to map PCI address %#lx.\n", @@ -1053,6 +1053,7 @@ 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; diff -ur --new-file old/linux/drivers/net/wavelan.c new/linux/drivers/net/wavelan.c --- old/linux/drivers/net/wavelan.c Thu Oct 8 00:51:45 1998 +++ new/linux/drivers/net/wavelan.c Thu Apr 29 20:53:41 1999 @@ -290,24 +290,26 @@ wv_16_on(ioaddr, hacr); } /* psa_write */ -#ifdef PSA_CRC +#ifdef SET_PSA_CRC /*------------------------------------------------------------------*/ /* - * Calculate the PSA CRC (not tested yet) - * As the WaveLAN drivers don't use the CRC, I won't use it either. - * Thanks to Nico Valster for the code + * Calculate the PSA CRC + * Thanks to Valster, Nico for the code * NOTE: By specifying a length including the CRC position the - * returned value should be zero. (i.e. a correct checksum in the PSA). + * returned value should be zero. (i.e. a correct checksum in the PSA) + * + * The Windows drivers don't use the CRC, but the AP and the PtP tool + * depend on it. */ -static u_short -psa_crc(u_short * psa, /* The PSA */ +static inline u_short +psa_crc(u_char * psa, /* The PSA */ int size) /* Number of short for CRC */ { int byte_cnt; /* Loop on the PSA */ u_short crc_bytes = 0; /* Data in the PSA */ int bit_cnt; /* Loop on the bits of the short */ - for(byte_cnt = 0; byte_cnt <= size; byte_cnt++ ) + for(byte_cnt = 0; byte_cnt < size; byte_cnt++ ) { crc_bytes ^= psa[byte_cnt]; /* Its an xor */ @@ -322,7 +324,49 @@ return crc_bytes; } /* psa_crc */ -#endif /* PSA_CRC */ +#endif /* SET_PSA_CRC */ + +/*------------------------------------------------------------------*/ +/* + * update the checksum field in the Wavelan's PSA + */ +static void +update_psa_checksum(device * dev, + u_long ioaddr, + u_short hacr) +{ +#ifdef SET_PSA_CRC + psa_t psa; + u_short crc; + + /* read the parameter storage area */ + psa_read(ioaddr, hacr, 0, (unsigned char *) &psa, sizeof(psa)); + + /* update the checksum */ + crc = psa_crc((unsigned char *) &psa, + sizeof(psa) - sizeof(psa.psa_crc[0]) - sizeof(psa.psa_crc[1]) + - sizeof(psa.psa_crc_status)); + + psa.psa_crc[0] = crc & 0xFF; + psa.psa_crc[1] = (crc & 0xFF00) >> 8; + + /* Write it ! */ + psa_write(ioaddr, hacr, (char *)&psa.psa_crc - (char *)&psa, + (unsigned char *)&psa.psa_crc, 2); + +#ifdef DEBUG_IOCTL_INFO + printk (KERN_DEBUG "%s: update_psa_checksum(): crc = 0x%02x%02x\n", + dev->name, psa.psa_crc[0], psa.psa_crc[1]); + + /* Check again (luxury !) */ + crc = psa_crc ((unsigned char *) &psa, + sizeof(psa) - sizeof(psa.psa_crc_status)); + + if(crc != 0) + printk(KERN_WARNING "%s: update_psa_checksum(): CRC does not agree with PSA data (even after recalculating)\n", dev->name); +#endif /* DEBUG_IOCTL_INFO */ +#endif /* SET_PSA_CRC */ +} /* update_psa_checksum */ /*------------------------------------------------------------------*/ /* @@ -706,23 +750,23 @@ unsigned short ias_addr; /* Check mc_config command */ - if(status & AC_SFLD_OK != 0) - printk(KERN_INFO "wv_config_complete(): set_multicast_address failed; status = 0x%x\n", - dev->name, str, status); + if((status & AC_SFLD_OK) != AC_SFLD_OK) + printk(KERN_INFO "%s: wv_config_complete(): set_multicast_address failed; status = 0x%x\n", + dev->name, status); /* check ia-config command */ ias_addr = mcs_addr - sizeof(ac_ias_t); obram_read(ioaddr, acoff(ias_addr, ac_status), (unsigned char *)&status, sizeof(status)); - if(status & AC_SFLD_OK != 0) - printk(KERN_INFO "wv_config_complete(): set_MAC_address; status = 0x%x\n", - dev->name, str, status); + if((status & AC_SFLD_OK) != AC_SFLD_OK) + printk(KERN_INFO "%s: wv_config_complete(): set_MAC_address failed; status = 0x%x\n", + dev->name, status); /* Check config command. */ cfg_addr = ias_addr - sizeof(ac_cfg_t); obram_read(ioaddr, acoff(cfg_addr, ac_status), (unsigned char *)&status, sizeof(status)); - if(status & AC_SFLD_OK != 0) - printk(KERN_INFO "wv_config_complete(): configure; status = 0x%x\n", - dev->name, str, status); + if((status & AC_SFLD_OK) != AC_SFLD_OK) + printk(KERN_INFO "%s: wv_config_complete(): configure failed; status = 0x%x\n", + dev->name, status); #endif /* DEBUG_CONFIG_ERROR */ ret = 1; /* Ready to be scrapped */ @@ -758,15 +802,15 @@ /* Read the first transmit buffer */ obram_read(ioaddr, acoff(lp->tx_first_in_use, ac_status), (unsigned char *)&tx_status, sizeof(tx_status)); + /* If not completed -> exit */ + if((tx_status & AC_SFLD_C) == 0) + break; + /* Hack for reconfiguration */ if(tx_status == 0xFFFF) if(!wv_config_complete(dev, ioaddr, lp)) break; /* Not completed */ - /* If not completed -> exit */ - if((tx_status & AC_SFLD_C) == 0) - break; - /* We now remove this buffer */ nreaped++; --lp->tx_n_in_use; @@ -799,7 +843,7 @@ lp->stats.tx_packets++; ncollisions = tx_status & AC_SFLD_MAXCOL; lp->stats.collisions += ncollisions; -#ifdef DEBUG_INTERRUPT_INFO +#ifdef DEBUG_TX_INFO if(ncollisions > 0) printk(KERN_DEBUG "%s: wv_complete(): tx completed after %d collisions.\n", dev->name, ncollisions); @@ -808,53 +852,49 @@ else { lp->stats.tx_errors++; -#ifndef IGNORE_NORMAL_XMIT_ERRS if(tx_status & AC_SFLD_S10) { lp->stats.tx_carrier_errors++; -#ifdef DEBUG_INTERRUPT_ERROR - printk(KERN_INFO "%s: wv_complete(): tx error: no CS.\n", +#ifdef DEBUG_TX_FAIL + printk(KERN_DEBUG "%s: wv_complete(): tx error: no CS.\n", dev->name); #endif } -#endif /* IGNORE_NORMAL_XMIT_ERRS */ if(tx_status & AC_SFLD_S9) { lp->stats.tx_carrier_errors++; -#ifdef DEBUG_INTERRUPT_ERROR - printk(KERN_INFO "%s: wv_complete(): tx error: lost CTS.\n", +#ifdef DEBUG_TX_FAIL + printk(KERN_DEBUG "%s: wv_complete(): tx error: lost CTS.\n", dev->name); #endif } if(tx_status & AC_SFLD_S8) { lp->stats.tx_fifo_errors++; -#ifdef DEBUG_INTERRUPT_ERROR - printk(KERN_INFO "%s: wv_complete(): tx error: slow DMA.\n", +#ifdef DEBUG_TX_FAIL + printk(KERN_DEBUG "%s: wv_complete(): tx error: slow DMA.\n", dev->name); #endif } -#ifndef IGNORE_NORMAL_XMIT_ERRS if(tx_status & AC_SFLD_S6) { lp->stats.tx_heartbeat_errors++; -#ifdef DEBUG_INTERRUPT_ERROR - printk(KERN_INFO "%s: wv_complete(): tx error: heart beat.\n", +#ifdef DEBUG_TX_FAIL + printk(KERN_DEBUG "%s: wv_complete(): tx error: heart beat.\n", dev->name); #endif } if(tx_status & AC_SFLD_S5) { lp->stats.tx_aborted_errors++; -#ifdef DEBUG_INTERRUPT_ERROR - printk(KERN_INFO "%s: wv_complete(): tx error: too many collisions.\n", +#ifdef DEBUG_TX_FAIL + printk(KERN_DEBUG "%s: wv_complete(): tx error: too many collisions.\n", dev->name); #endif } -#endif /* IGNORE_NORMAL_XMIT_ERRS */ } -#ifdef DEBUG_INTERRUPT_INFO +#ifdef DEBUG_TX_INFO printk(KERN_DEBUG "%s: wv_complete(): tx completed, tx_status 0x%04x\n", dev->name, tx_status); #endif @@ -1281,21 +1321,21 @@ char * msg1, /* Name of the device */ char * msg2) /* Name of the function */ { -#ifndef DEBUG_PACKET_DUMP + int i; + int maxi; + printk(KERN_DEBUG "%s: %s(): dest %02X:%02X:%02X:%02X:%02X:%02X, length %d\n", msg1, msg2, p[0], p[1], p[2], p[3], p[4], p[5], length); printk(KERN_DEBUG "%s: %s(): src %02X:%02X:%02X:%02X:%02X:%02X, type 0x%02X%02X\n", msg1, msg2, p[6], p[7], p[8], p[9], p[10], p[11], p[12], p[13]); -#else /* DEBUG_PACKET_DUMP */ - int i; - int maxi; +#ifdef DEBUG_PACKET_DUMP - printk(KERN_DEBUG "%s: %s(): len=%d, data=\"", msg1, msg2, length); + printk(KERN_DEBUG "data=\""); if((maxi = length) > DEBUG_PACKET_DUMP) maxi = DEBUG_PACKET_DUMP; - for(i = 0; i < maxi; i++) + for(i = 14; i < maxi; i++) if(p[i] >= ' ' && p[i] <= '~') printk(" %c", p[i]); else @@ -1522,7 +1562,9 @@ /*------------------------------------------------------------------*/ /* * This function doesn't exist. + * (Note : it was a nice way to test the reconfigure stuff...) */ +#ifdef SET_MAC_ADDRESS static int wavelan_set_mac_address(device * dev, void * addr) @@ -1537,6 +1579,7 @@ return 0; } +#endif /* SET_MAC_ADDRESS */ #ifdef WIRELESS_EXT /* if wireless extensions exist in the kernel */ @@ -1890,6 +1933,8 @@ /* Disable NWID in the mmc (no filtering). */ mmc_out(ioaddr, mmwoff(0, mmw_loopt_sel), MMW_LOOPT_SEL_DIS_NWID); } + /* update the Wavelan checksum */ + update_psa_checksum(dev, ioaddr, lp->hacr); break; case SIOCGIWNWID: @@ -1946,6 +1991,8 @@ psa.psa_thr_pre_set = wrq->u.sensitivity & 0x3F; psa_write(ioaddr, lp->hacr, (char *)&psa.psa_thr_pre_set - (char *)&psa, (unsigned char *) &psa.psa_thr_pre_set, 1); + /* update the Wavelan checksum */ + update_psa_checksum(dev, ioaddr, lp->hacr); mmc_out(ioaddr, mmwoff(0, mmw_thr_pre_set), psa.psa_thr_pre_set); break; @@ -1993,6 +2040,8 @@ mmc_out(ioaddr, mmwoff(0, mmw_encr_enable), 0); } + /* update the Wavelan checksum */ + update_psa_checksum(dev, ioaddr, lp->hacr); break; case SIOCGIWENCODE: @@ -2206,6 +2255,8 @@ psa.psa_quality_thr = *(wrq->u.name) & 0x0F; psa_write(ioaddr, lp->hacr, (char *)&psa.psa_quality_thr - (char *)&psa, (unsigned char *)&psa.psa_quality_thr, 1); + /* update the Wavelan checksum */ + update_psa_checksum(dev, ioaddr, lp->hacr); mmc_out(ioaddr, mmwoff(0, mmw_quality_thr), psa.psa_quality_thr); break; @@ -2316,7 +2367,7 @@ mmc_out(ioaddr, mmwoff(0, mmw_freeze), 0); /* Copy data to wireless stuff. */ - wstats->status = m.mmr_dce_status; + wstats->status = m.mmr_dce_status & MMR_DCE_STATUS; wstats->qual.qual = m.mmr_sgnl_qual & MMR_SGNL_QUAL; wstats->qual.level = m.mmr_signal_lvl & MMR_SIGNAL_LVL; wstats->qual.noise = m.mmr_silence_lvl & MMR_SILENCE_LVL; @@ -2368,7 +2419,7 @@ #ifdef DEBUG_RX_TRACE printk(KERN_DEBUG "%s: ->wv_packet_read(0x%X, %d)\n", - dev->name, fd_p, sksize); + dev->name, buf_off, sksize); #endif /* Allocate buffer for the data */ @@ -2456,6 +2507,8 @@ { u_long ioaddr = dev->base_addr; net_local * lp = (net_local *)dev->priv; + fd_t fd; + rbd_t rbd; int nreaped = 0; #ifdef DEBUG_RX_TRACE @@ -2465,12 +2518,17 @@ /* Loop on each received packet. */ for(;;) { - fd_t fd; - rbd_t rbd; - ushort pkt_len; - obram_read(ioaddr, lp->rx_head, (unsigned char *) &fd, sizeof(fd)); + /* Note about the status : + * It start up to be 0 (the value we set). Then, when the RU + * grab the buffer to prepare for reception, it sets the + * FD_STATUS_B flag. When the RU has finished receiving the + * frame, it clears FD_STATUS_B, set FD_STATUS_C to indicate + * completion and set the other flags to indicate the eventual + * errors. FD_STATUS_OK indicates that the reception was OK. + */ + /* If the current frame is not complete, we have reached the end. */ if((fd.fd_status & FD_STATUS_C) != FD_STATUS_C) break; /* This is how we exit the loop. */ @@ -2478,35 +2536,44 @@ nreaped++; /* Check whether frame was correctly received. */ - if((fd.fd_status & (FD_STATUS_B | FD_STATUS_OK)) != - (FD_STATUS_B | FD_STATUS_OK)) + if((fd.fd_status & FD_STATUS_OK) == FD_STATUS_OK) { - /* - * Not sure about this one -- it does not seem - * to be an error so we will keep quiet about it. - */ -#ifndef IGNORE_NORMAL_XMIT_ERRS -#ifdef DEBUG_RX_ERROR - if((fd.fd_status & FD_STATUS_B) != FD_STATUS_B) - printk(KERN_INFO "%s: wv_receive(): frame not consumed by RU.\n", - dev->name); -#endif -#endif /* IGNORE_NORMAL_XMIT_ERRS */ + /* Does the frame contain a pointer to the data? Let's check. */ + if(fd.fd_rbd_offset != I82586NULL) + { + /* Read the receive buffer descriptor */ + obram_read(ioaddr, fd.fd_rbd_offset, + (unsigned char *) &rbd, sizeof(rbd)); #ifdef DEBUG_RX_ERROR - if((fd.fd_status & FD_STATUS_OK) != FD_STATUS_OK) - printk(KERN_INFO "%s: wv_receive(): frame not received successfully.\n", + if((rbd.rbd_status & RBD_STATUS_EOF) != RBD_STATUS_EOF) + printk(KERN_INFO "%s: wv_receive(): missing EOF flag.\n", + dev->name); + + if((rbd.rbd_status & RBD_STATUS_F) != RBD_STATUS_F) + printk(KERN_INFO "%s: wv_receive(): missing F flag.\n", + dev->name); +#endif /* DEBUG_RX_ERROR */ + + /* Read the packet and transmit to Linux */ + wv_packet_read(dev, rbd.rbd_bufl, + rbd.rbd_status & RBD_STATUS_ACNT); + } +#ifdef DEBUG_RX_ERROR + else /* if frame has no data */ + printk(KERN_INFO "%s: wv_receive(): frame has no data.\n", dev->name); #endif } - - /* Were there problems in processing the frame? Let's check. */ - if((fd.fd_status & (FD_STATUS_S6 | FD_STATUS_S7 | FD_STATUS_S8 | - FD_STATUS_S9 | FD_STATUS_S10 | FD_STATUS_S11)) - != 0) + else /* If reception was no successful */ { lp->stats.rx_errors++; +#ifdef DEBUG_RX_INFO + printk(KERN_DEBUG "%s: wv_receive(): frame not received successfully (%X).\n", + dev->name, fd.fd_status); +#endif + #ifdef DEBUG_RX_ERROR if((fd.fd_status & FD_STATUS_S6) != 0) printk(KERN_INFO "%s: wv_receive(): no EOF flag.\n", dev->name); @@ -2515,8 +2582,8 @@ if((fd.fd_status & FD_STATUS_S7) != 0) { lp->stats.rx_length_errors++; -#ifdef DEBUG_RX_ERROR - printk(KERN_INFO "%s: wv_receive(): frame too short.\n", +#ifdef DEBUG_RX_FAIL + printk(KERN_DEBUG "%s: wv_receive(): frame too short.\n", dev->name); #endif } @@ -2524,8 +2591,8 @@ if((fd.fd_status & FD_STATUS_S8) != 0) { lp->stats.rx_over_errors++; -#ifdef DEBUG_RX_ERROR - printk(KERN_INFO "%s: wv_receive(): rx DMA overrun.\n", +#ifdef DEBUG_RX_FAIL + printk(KERN_DEBUG "%s: wv_receive(): rx DMA overrun.\n", dev->name); #endif } @@ -2533,8 +2600,8 @@ if((fd.fd_status & FD_STATUS_S9) != 0) { lp->stats.rx_fifo_errors++; -#ifdef DEBUG_RX_ERROR - printk(KERN_INFO "%s: wv_receive(): ran out of resources.\n", +#ifdef DEBUG_RX_FAIL + printk(KERN_DEBUG "%s: wv_receive(): ran out of resources.\n", dev->name); #endif } @@ -2542,8 +2609,8 @@ if((fd.fd_status & FD_STATUS_S10) != 0) { lp->stats.rx_frame_errors++; -#ifdef DEBUG_RX_ERROR - printk(KERN_INFO "%s: wv_receive(): alignment error.\n", +#ifdef DEBUG_RX_FAIL + printk(KERN_DEBUG "%s: wv_receive(): alignment error.\n", dev->name); #endif } @@ -2551,38 +2618,12 @@ if((fd.fd_status & FD_STATUS_S11) != 0) { lp->stats.rx_crc_errors++; -#ifdef DEBUG_RX_ERROR - printk(KERN_INFO "%s: wv_receive(): CRC error.\n", dev->name); +#ifdef DEBUG_RX_FAIL + printk(KERN_DEBUG "%s: wv_receive(): CRC error.\n", dev->name); #endif } } - /* Does the frame contain a pointer to the data? Let's check. */ - if(fd.fd_rbd_offset == I82586NULL) -#ifdef DEBUG_RX_ERROR - printk(KERN_INFO "%s: wv_receive(): frame has no data.\n", dev->name); -#endif - else - { - obram_read(ioaddr, fd.fd_rbd_offset, - (unsigned char *) &rbd, sizeof(rbd)); - -#ifdef DEBUG_RX_ERROR - if((rbd.rbd_status & RBD_STATUS_EOF) != RBD_STATUS_EOF) - printk(KERN_INFO "%s: wv_receive(): missing EOF flag.\n", - dev->name); - - if((rbd.rbd_status & RBD_STATUS_F) != RBD_STATUS_F) - printk(KERN_INFO "%s: wv_receive(): missing F flag.\n", - dev->name); -#endif - - pkt_len = rbd.rbd_status & RBD_STATUS_ACNT; - - /* Read the packet and transmit to Linux */ - wv_packet_read(dev, rbd.rbd_bufl, pkt_len); - } /* if frame has data */ - fd.fd_status = 0; obram_write(ioaddr, fdoff(lp->rx_head, fd_status), (unsigned char *) &fd.fd_status, sizeof(fd.fd_status)); @@ -2717,7 +2758,7 @@ /* * Data */ - obram_write(ioaddr, buf_addr, buf, clen); + obram_write(ioaddr, buf_addr, buf, length); /* * Overwrite the predecessor NOP link @@ -2892,6 +2933,8 @@ (unsigned char *)&psa.psa_quality_thr, 1); psa_write(ioaddr, lp->hacr, (char *)&psa.psa_conf_status - (char *)&psa, (unsigned char *)&psa.psa_conf_status, 1); + /* update the Wavelan checksum */ + update_psa_checksum(dev, ioaddr, lp->hacr); #endif } @@ -2918,21 +2961,18 @@ m.mmw_thr_pre_set = psa.psa_thr_pre_set & 0x3F; m.mmw_quality_thr = psa.psa_quality_thr & 0x0F; - /* Encryption stuff is missing. */ - /* * Set default modem control parameters. * See NCR document 407-0024326 Rev. A. */ m.mmw_jabber_enable = 0x01; + m.mmw_freeze = 0; m.mmw_anten_sel = MMW_ANTEN_SEL_ALG_EN; m.mmw_ifs = 0x20; m.mmw_mod_delay = 0x04; m.mmw_jam_time = 0x38; - m.mmw_encr_enable = 0; m.mmw_des_io_invert = 0; - m.mmw_freeze = 0; m.mmw_decay_prm = 0; m.mmw_decay_updat_prm = 0; @@ -3066,7 +3106,7 @@ if(i <= 0) { -#ifdef DEBUG_CONFIG_ERRORS +#ifdef DEBUG_CONFIG_ERROR printk(KERN_INFO "%s: wavelan_ru_start(): board not accepting command.\n", dev->name); #endif @@ -3170,7 +3210,7 @@ if(i <= 0) { -#ifdef DEBUG_CONFIG_ERRORS +#ifdef DEBUG_CONFIG_ERROR printk(KERN_INFO "%s: wavelan_cu_start(): board not accepting command.\n", dev->name); #endif @@ -3257,7 +3297,7 @@ if(i <= 0) { -#ifdef DEBUG_CONFIG_ERRORS +#ifdef DEBUG_CONFIG_ERROR printk(KERN_INFO "%s: wv_82586_start(): iscp_busy timeout.\n", dev->name); #endif @@ -3277,7 +3317,7 @@ if (i <= 0) { -#ifdef DEBUG_CONFIG_ERRORS +#ifdef DEBUG_CONFIG_ERROR printk(KERN_INFO "%s: wv_82586_start(): status: expected 0x%02x, got 0x%02x.\n", dev->name, SCB_ST_CX | SCB_ST_CNA, scb.scb_status); #endif @@ -3298,7 +3338,7 @@ obram_read(ioaddr, OFFSET_CU, (unsigned char *)&cb, sizeof(cb)); if(cb.ac_status & AC_SFLD_FAIL) { -#ifdef DEBUG_CONFIG_ERRORS +#ifdef DEBUG_CONFIG_ERROR printk(KERN_INFO "%s: wv_82586_start(): i82586 Self Test failed.\n", dev->name); #endif @@ -3398,39 +3438,29 @@ /* Create a configure action. */ memset(&cfg, 0x00, sizeof(cfg)); -#if 0 - /* - * The default board configuration - */ - cfg.fifolim_bytecnt = 0x080c; - cfg.addrlen_mode = 0x2600; - cfg.linprio_interframe = 0x7820; /* IFS=120, ACS=2 */ - cfg.slot_time = 0xf00c; /* slottime=12 */ - cfg.hardware = 0x0008; /* tx even without CD */ - cfg.min_frame_len = 0x0040; -#endif /* 0 */ - /* * For Linux we invert AC_CFG_ALOC() so as to conform * to the way that net packets reach us from above. * (See also ac_tx_t.) + * + * Updated from Wavelan Manual WCIN085B */ cfg.cfg_byte_cnt = AC_CFG_BYTE_CNT(sizeof(ac_cfg_t) - sizeof(ach_t)); - cfg.cfg_fifolim = AC_CFG_FIFOLIM(8); - cfg.cfg_byte8 = AC_CFG_SAV_BF(0) | + cfg.cfg_fifolim = AC_CFG_FIFOLIM(4); + cfg.cfg_byte8 = AC_CFG_SAV_BF(1) | AC_CFG_SRDY(0); cfg.cfg_byte9 = AC_CFG_ELPBCK(0) | AC_CFG_ILPBCK(0) | AC_CFG_PRELEN(AC_CFG_PLEN_2) | AC_CFG_ALOC(1) | AC_CFG_ADDRLEN(WAVELAN_ADDR_SIZE); - cfg.cfg_byte10 = AC_CFG_BOFMET(0) | - AC_CFG_ACR(0) | + cfg.cfg_byte10 = AC_CFG_BOFMET(1) | + AC_CFG_ACR(6) | AC_CFG_LINPRIO(0); - cfg.cfg_ifs = 32; - cfg.cfg_slotl = 0; + cfg.cfg_ifs = 0x20; + cfg.cfg_slotl = 0x0C; cfg.cfg_byte13 = AC_CFG_RETRYNUM(15) | - AC_CFG_SLTTMHI(2); + AC_CFG_SLTTMHI(0); cfg.cfg_byte14 = AC_CFG_FLGPAD(0) | AC_CFG_BTSTF(0) | AC_CFG_CRC16(0) | @@ -3589,13 +3619,16 @@ wv_ints_on(dev); /* Start card functions */ - if((wv_ru_start(dev) < 0) || - (wv_cu_start(dev) < 0)) + if(wv_cu_start(dev) < 0) return -1; - /* Finish configuration. */ + /* Setup the controller and parameters */ wv_82586_config(dev); + /* Finish configuration with the receive unit */ + if(wv_ru_start(dev) < 0) + return -1; + #ifdef DEBUG_CONFIG_TRACE printk(KERN_DEBUG "%s: <-wv_hw_reset()\n", dev->name); #endif @@ -3896,7 +3929,7 @@ /* Check irq */ if(dev->irq == 0) { -#ifdef DEBUG_CONFIG_ERRORS +#ifdef DEBUG_CONFIG_ERROR printk(KERN_WARNING "%s: wavelan_open(): no IRQ\n", dev->name); #endif return -ENXIO; @@ -3904,7 +3937,7 @@ if(request_irq(dev->irq, &wavelan_interrupt, 0, "WaveLAN", dev) != 0) { -#ifdef DEBUG_CONFIG_ERRORS +#ifdef DEBUG_CONFIG_ERROR printk(KERN_WARNING "%s: wavelan_open(): invalid IRQ\n", dev->name); #endif return -EAGAIN; @@ -3919,7 +3952,7 @@ else { free_irq(dev->irq, dev); -#ifdef DEBUG_CONFIG_ERRORS +#ifdef DEBUG_CONFIG_ERROR printk(KERN_INFO "%s: wavelan_open(): impossible to start the card\n", dev->name); #endif @@ -4016,6 +4049,8 @@ #endif psa_write(ioaddr, HACR_DEFAULT, psaoff(0, psa_int_req_no), &irq_mask, 1); + /* update the Wavelan checksum */ + update_psa_checksum(dev, ioaddr, HACR_DEFAULT); wv_hacr_reset(ioaddr); } } @@ -4069,7 +4104,9 @@ dev->hard_start_xmit = wavelan_packet_xmit; dev->get_stats = wavelan_get_stats; dev->set_multicast_list = &wavelan_set_multicast_list; +#ifdef SET_MAC_ADDRESS dev->set_mac_address = &wavelan_set_mac_address; +#endif /* SET_MAC_ADDRESS */ #ifdef WIRELESS_EXT /* if wireless extension exists in the kernel */ dev->do_ioctl = wavelan_ioctl; @@ -4123,7 +4160,7 @@ /* Don't probe at all. */ if(base_addr < 0) { -#ifdef DEBUG_CONFIG_ERRORS +#ifdef DEBUG_CONFIG_ERROR printk(KERN_WARNING "%s: wavelan_probe(): invalid base address\n", dev->name); #endif @@ -4196,7 +4233,7 @@ init_module(void) { mac_addr mac; /* MAC address (check WaveLAN existence) */ - int ret = 0; + int ret = -EIO; /* Return error if no cards found */ int i; #ifdef DEBUG_MODULE_TRACE @@ -4206,7 +4243,7 @@ /* If probing is asked */ if(io[0] == 0) { -#ifdef DEBUG_CONFIG_ERRORS +#ifdef DEBUG_CONFIG_ERROR printk(KERN_WARNING "WaveLAN init_module(): doing device probing (bad !)\n"); printk(KERN_WARNING "Specify base addresses while loading module to correct the problem\n"); #endif @@ -4241,12 +4278,16 @@ /* Deallocate everything. */ /* Note: if dev->priv is mallocated, there is no way to fail. */ kfree_s(dev, sizeof(struct device)); - ret = -EIO; + } + else + { + /* If at least one device OK, we do not fail */ + ret = 0; } } /* if there is something at the address */ } /* Loop on all addresses. */ -#ifdef DEBUG_CONFIG_ERRORS +#ifdef DEBUG_CONFIG_ERROR if(wavelan_list == (net_local *) NULL) printk(KERN_WARNING "WaveLAN init_module(): no device found\n"); #endif diff -ur --new-file old/linux/drivers/net/wavelan.h new/linux/drivers/net/wavelan.h --- old/linux/drivers/net/wavelan.h Mon Jul 27 08:35:56 1998 +++ new/linux/drivers/net/wavelan.h Thu Mar 11 01:51:35 1999 @@ -28,6 +28,8 @@ { { 0x08, 0x00, 0x0E }, /* AT&T WaveLAN (standard) & DEC RoamAbout */ { 0x08, 0x00, 0x6A }, /* AT&T WaveLAN (alternate) */ + { 0x00, 0x00, 0xE1 }, /* Hitachi Wavelan */ + { 0x00, 0x60, 0x1D } /* Lucent Wavelan (another one) */ /* Add your card here and send me the patch! */ }; @@ -293,6 +295,7 @@ #define MMR_DCE_STATUS_LOOPT_IND 0x02 /* loop test indicated */ #define MMR_DCE_STATUS_TX_BUSY 0x04 /* transmitter on */ #define MMR_DCE_STATUS_JBR_EXPIRED 0x08 /* jabber timer expired */ +#define MMR_DCE_STATUS 0x0F /* mask to get the bits */ unsigned char mmr_dsp_id; /* DSP ID (AA = Daedalus rev A) */ unsigned char mmr_unused2[2]; /* unused */ unsigned char mmr_correct_nwid_l; /* # of correct NWIDs rxd (low) */ diff -ur --new-file old/linux/drivers/net/wavelan.p.h new/linux/drivers/net/wavelan.p.h --- old/linux/drivers/net/wavelan.p.h Mon Jul 27 08:35:56 1998 +++ new/linux/drivers/net/wavelan.p.h Thu Apr 29 20:53:41 1999 @@ -18,13 +18,7 @@ * This driver provides a Linux interface to the WaveLAN ISA hardware. * The WaveLAN is a product of Lucent (http://www.wavelan.com/). * This division was formerly part of NCR and then AT&T. - * WaveLANs are also distributed by DEC (RoamAbout), Digital Ocean and - * Aironet (Arlan). If you have one of those products, you will need to - * make some changes below. - * - * This driver is still beta software. A lot of bugs have been corrected, - * a lot of functionality is implemented, and the whole appears stable, - * but there is still room for improvement (encryption, performance). + * WaveLANs are also distributed by DEC (RoamAbout DS) and Digital Ocean. * * To learn how to use this driver, read the NET3 HOWTO. * If you want to exploit the many other functionalities, read the comments @@ -35,11 +29,27 @@ /* ------------------------ SPECIFIC NOTES ------------------------ */ /* + * Web page + * -------- + * I try to maintain a web page with the Wireless LAN Howto at : + * http://www-uk.hpl.hp.com/people/jt/Linux/Wavelan.html + * + * Debugging and options + * --------------------- + * You will find below a set of '#define" allowing a very fine control + * on the driver behaviour and the debug messages printed. + * The main options are : + * o SET_PSA_CRC, to have your card correctly recognised by + * an access point and the Point-to-Point diagnostic tool. + * o USE_PSA_CONFIG, to read configuration from the PSA (EEprom) + * (otherwise we always start afresh with some defaults) + * * wavelan.o is too darned big * --------------------------- * That's true! There is a very simple way to reduce the driver * object by 33%! Comment out the following line: * #include + * Other compile options can also reduce the size of it... * * MAC address and hardware detection: * ----------------------------------- @@ -60,23 +70,6 @@ * 3) Compile and verify * 4) Send me the MAC code. I will include it in the next version. * - * "CU Inactive" message at boot up: - * ----------------------------------- - * It seems that there is some weird timing problem with the - * Intel microcontroller. In fact, this message is triggered by a - * bad reading of the onboard RAM the first time we read the - * control block. If you ignore this message, all is OK (but in - * fact, currently, it resets the WaveLAN hardware). - * - * There are two ways to get rid of that problem. The first - * is to add a dummy read of the scb at the end of - * wv_82586_config. The second is to add the timers - * wv_synchronous_cmd and wv_ack (the udelay just after the - * waiting loops--it seems that the controller is not totally ready - * when it says it is). - * - * In the current code, I use the second solution (to be - * consistent with the original solution of Bruce Janson). */ /* --------------------- WIRELESS EXTENSIONS --------------------- */ @@ -273,6 +266,32 @@ * - encryption setting from Brent Elphick (thanks a lot!) * - 'ioaddr' to 'u_long' for the Alpha (thanks to Stanislav Sinyagin) * + * Other changes (not by me) : + * ------------------------- + * - Spelling and gramar "rectification". + * + * Changes made for release in 2.0.37 & 2.2.2 : + * ------------------------------------------ + * - Correct status in /proc/net/wireless + * - Set PSA CRC to make PtP diagnostic tool happy (Bob Gray) + * - Module init code don't fail if we found at least one card in + * the address list (Karlis Peisenieks) + * - Missing parenthesis (Christopher Peterson) + * - Correct i82586 configuration parameters + * - Encryption initialisation bug (Robert McCormack) + * - New mac addresses detected in the probe + * - Increase watchdog for busy environments + * + * Changes made for release in 2.0.38 & 2.2.7 : + * ------------------------------------------ + * - Correct the reception logic to better report errors and avoid + * sending bogus packet up the stack + * - Delay RU config to avoid corrupting first received packet + * - Change config completion code (to actually check something) + * - Avoid reading out of bound in skbuf to transmit + * - Rectify a lot of (useless) debugging code + * - Change the way to `#ifdef SET_PSA_CRC' + * * Wishes & dreams: * ---------------- * - roaming @@ -312,6 +331,24 @@ #include "i82586.h" #include "wavelan.h" +/************************** DRIVER OPTIONS **************************/ +/* + * `#define' or `#undef' the following constant to change the behaviour + * of the driver... + */ +#undef SET_PSA_CRC /* Calculate and set the CRC on PSA (slower) */ +#define USE_PSA_CONFIG /* Use info from the PSA. */ +#undef STRUCT_CHECK /* Verify padding of structures. */ +#undef EEPROM_IS_PROTECTED /* doesn't seem to be necessary */ +#define MULTICAST_AVOID /* Avoid extra multicast (I'm sceptical). */ +#undef SET_MAC_ADDRESS /* Experimental */ + +#ifdef WIRELESS_EXT /* If wireless extensions exist in the kernel */ +/* Warning: this stuff will slow down the driver. */ +#define WIRELESS_SPY /* Enable spying addresses. */ +#undef HISTOGRAM /* Enable histogram of signal level. */ +#endif + /****************************** DEBUG ******************************/ #undef DEBUG_MODULE_TRACE /* module insertion/removal */ @@ -321,14 +358,16 @@ #define DEBUG_INTERRUPT_ERROR /* problems */ #undef DEBUG_CONFIG_TRACE /* Trace the config functions. */ #undef DEBUG_CONFIG_INFO /* what's going on */ -#define DEBUG_CONFIG_ERRORS /* errors on configuration */ +#define DEBUG_CONFIG_ERROR /* errors on configuration */ #undef DEBUG_TX_TRACE /* transmission calls */ #undef DEBUG_TX_INFO /* header of the transmitted packet */ -#define DEBUG_TX_ERROR /* unexpected conditions */ +#undef DEBUG_TX_FAIL /* Normal failure conditions */ +#define DEBUG_TX_ERROR /* Unexpected conditions */ #undef DEBUG_RX_TRACE /* transmission calls */ -#undef DEBUG_RX_INFO /* header of the transmitted packet */ -#define DEBUG_RX_ERROR /* unexpected conditions */ -#undef DEBUG_PACKET_DUMP 16 /* Dump packet on the screen. */ +#undef DEBUG_RX_INFO /* header of the received packet */ +#undef DEBUG_RX_FAIL /* Normal failure conditions */ +#define DEBUG_RX_ERROR /* Unexpected conditions */ +#undef DEBUG_PACKET_DUMP 32 /* Dump packet on the screen. */ #undef DEBUG_IOCTL_TRACE /* misc. call by Linux */ #undef DEBUG_IOCTL_INFO /* various debugging info */ #define DEBUG_IOCTL_ERROR /* what's going wrong */ @@ -340,30 +379,14 @@ #undef DEBUG_I82586_SHOW /* Show i82586 status. */ #undef DEBUG_DEVICE_SHOW /* Show device parameters. */ -/* Options */ -#define USE_PSA_CONFIG /* Use info from the PSA. */ -#define IGNORE_NORMAL_XMIT_ERRS /* Don't bother with normal conditions. */ -#undef STRUCT_CHECK /* Verify padding of structures. */ -#undef PSA_CRC /* Check CRC in PSA. */ -#undef OLDIES /* old code (to redo) */ -#undef RECORD_SNR /* to redo */ -#undef EEPROM_IS_PROTECTED /* doesn't seem to be necessary */ -#define MULTICAST_AVOID /* Avoid extra multicast (I'm sceptical). */ - -#ifdef WIRELESS_EXT /* If wireless extensions exist in the kernel */ -/* Warning: this stuff will slow down the driver. */ -#define WIRELESS_SPY /* Enable spying addresses. */ -#undef HISTOGRAM /* Enable histogram of signal level. */ -#endif - /************************ CONSTANTS & MACROS ************************/ #ifdef DEBUG_VERSION_SHOW -static const char *version = "wavelan.c : v16 (wireless extensions) 17/4/97\n"; +static const char *version = "wavelan.c : v19 (wireless extensions) 20/4/99\n"; #endif /* Watchdog temporisation */ -#define WATCHDOG_JIFFIES 32 /* TODO: express in HZ. */ +#define WATCHDOG_JIFFIES 256 /* TODO: express in HZ. */ /* Macro to get the number of elements in an array */ #define NELS(a) (sizeof(a) / sizeof(a[0])) diff -ur --new-file old/linux/drivers/net/z85230.c new/linux/drivers/net/z85230.c --- old/linux/drivers/net/z85230.c Thu Jan 7 17:46:59 1999 +++ new/linux/drivers/net/z85230.c Sun Apr 25 02:51:48 1999 @@ -48,6 +48,7 @@ #include #include "z85230.h" +#include "syncppp.h" static spinlock_t z8530_buffer_lock = SPIN_LOCK_UNLOCKED; @@ -349,6 +350,7 @@ if(status&TxEOM) { /* printk("%s: Tx underrun.\n", chan->dev->name); */ + chan->stats.tx_fifo_errors++; write_zsctrl(chan, ERR_RES); z8530_tx_done(chan); } @@ -359,6 +361,8 @@ { printk(KERN_INFO "%s: DCD raised\n", chan->dev->name); write_zsreg(chan, R3, chan->regs[3]|RxENABLE); + if(chan->netdevice) + sppp_reopen(chan->netdevice); } else { @@ -413,8 +417,9 @@ static void z8530_dma_tx(struct z8530_channel *chan) { - if(!chan->txdma_on) + if(!chan->dma_tx) { + printk("Hey who turned the DMA off?\n"); z8530_tx(chan); return; } @@ -431,7 +436,7 @@ chan->status=status; - if(chan->txdma_on) + if(chan->dma_tx) { if(status&TxEOM) { @@ -450,6 +455,8 @@ { printk(KERN_INFO "%s: DCD raised\n", chan->dev->name); write_zsreg(chan, R3, chan->regs[3]|RxENABLE); + if(chan->netdevice) + sppp_reopen(chan->netdevice); } else { @@ -614,6 +621,9 @@ z8530_rx_done(c); /* Load the frame ring */ z8530_rx_done(c); /* Load the backup frame */ z8530_rtsdtr(c,1); + c->dma_tx = 0; + c->regs[R1]|=TxINT_ENAB; + write_zsreg(c, R1, c->regs[R1]); write_zsreg(c, R3, c->regs[R3]|RxENABLE); return 0; } @@ -701,6 +711,9 @@ c->regs[R14]|= DTRREQ; write_zsreg(c, R14, c->regs[R14]); + c->regs[R1]&= ~TxINT_ENAB; + write_zsreg(c, R1, c->regs[R1]); + /* * RX DMA via W/Req */ @@ -708,6 +721,7 @@ c->regs[R1]|= WT_FN_RDYFN; c->regs[R1]|= WT_RDY_RT; c->regs[R1]|= INT_ERR_Rx; + c->regs[R1]&= ~TxINT_ENAB; write_zsreg(c, R1, c->regs[R1]); c->regs[R1]|= WT_RDY_ENAB; write_zsreg(c, R1, c->regs[R1]); @@ -967,7 +981,7 @@ dev->name, z8530_type_name[dev->type], mapping, - io, + Z8530_PORT_OF(io), dev->irq); } @@ -986,7 +1000,7 @@ dev->chanB.irqs=&z8530_nop; /* Reset the chip */ write_zsreg(&dev->chanA, R9, 0xC0); - udelay(100); + udelay(200); /* Now check its valid */ write_zsreg(&dev->chanA, R12, 0xAA); if(read_zsreg(&dev->chanA, R12)!=0xAA) @@ -1103,17 +1117,24 @@ if(c->tx_skb==NULL) { /* Idle on */ - if(c->txdma) + if(c->dma_tx) { flags=claim_dma_lock(); disable_dma(c->txdma); + /* + * Check if we crapped out. + */ + if(get_dma_residue(c->txdma)) + { + c->stats.tx_dropped++; + c->stats.tx_fifo_errors++; + } release_dma_lock(flags); } c->txcount=0; } else { - c->tx_ptr=c->tx_next_ptr; c->txcount=c->tx_skb->len; @@ -1128,11 +1149,24 @@ flags=claim_dma_lock(); disable_dma(c->txdma); + + /* + * These two are needed by the 8530/85C30 + * and must be issued when idling. + */ + + if(c->dev->type!=Z85230) + { + write_zsctrl(c, RES_Tx_CRC); + write_zsctrl(c, RES_EOM_L); + } + write_zsreg(c, R10, c->regs[10]&~ABUNDER); clear_dma_ff(c->txdma); set_dma_addr(c->txdma, virt_to_bus(c->tx_ptr)); set_dma_count(c->txdma, c->txcount); enable_dma(c->txdma); release_dma_lock(flags); + write_zsctrl(c, RES_EOM_L); write_zsreg(c, R5, c->regs[R5]|TxENAB); } else @@ -1142,7 +1176,7 @@ /* ABUNDER off */ write_zsreg(c, R10, c->regs[10]); write_zsctrl(c, RES_Tx_CRC); - write_zsctrl(c, RES_EOM_L); +//??? write_zsctrl(c, RES_EOM_L); while(c->txcount && (read_zsreg(c,R0)&Tx_BUF_EMP)) { @@ -1162,17 +1196,18 @@ spin_lock_irqsave(&z8530_buffer_lock, flags); c->netdevice->tbusy=0; - /* Can't happen */ + /* Actually this can happen.*/ if(c->tx_skb==NULL) { spin_unlock_irqrestore(&z8530_buffer_lock, flags); - printk(KERN_WARNING "%s: spurious tx done\n", c->dev->name); return; } skb=c->tx_skb; c->tx_skb=NULL; z8530_tx_begin(c); spin_unlock_irqrestore(&z8530_buffer_lock, flags); + c->stats.tx_packets++; + c->stats.tx_bytes+=skb->len; dev_kfree_skb(skb); } @@ -1255,11 +1290,16 @@ skb=dev_alloc_skb(ct); if(skb==NULL) - printk("%s: Memory squeeze.\n", c->netdevice->name); + { + c->stats.rx_dropped++; + printk(KERN_WARNING "%s: Memory squeeze.\n", c->netdevice->name); + } else { skb_put(skb, ct); memcpy(skb->data, rxb, ct); + c->stats.rx_packets++; + c->stats.rx_bytes+=ct; } c->dma_ready=1; } @@ -1305,6 +1345,9 @@ { skb_put(c->skb2,c->mtu); } + c->stats.rx_packets++; + c->stats.rx_bytes+=ct; + } /* * If we received a frame we must now process it. @@ -1315,7 +1358,10 @@ c->rx_function(c,skb); } else - printk("Lost a frame\n"); + { + c->stats.rx_dropped++; + printk(KERN_ERR "%s: Lost a frame\n", c->netdevice->name); + } } /* diff -ur --new-file old/linux/drivers/pci/oldproc.c new/linux/drivers/pci/oldproc.c --- old/linux/drivers/pci/oldproc.c Fri Jan 15 23:36:21 1999 +++ new/linux/drivers/pci/oldproc.c Wed Apr 21 18:28:49 1999 @@ -101,6 +101,7 @@ DEVICE( DEC, DEC_21052, "DC21052"), DEVICE( DEC, DEC_21150, "DC21150"), DEVICE( DEC, DEC_21152, "DC21152"), + DEVICE( DEC, DEC_21153, "DC21153"), DEVICE( CIRRUS, CIRRUS_7548, "GD 7548"), DEVICE( CIRRUS, CIRRUS_5430, "GD 5430"), DEVICE( CIRRUS, CIRRUS_5434_4, "GD 5434"), @@ -120,6 +121,7 @@ DEVICE( IBM, IBM_82G2675, "82G2675"), DEVICE( IBM, IBM_MCA, "MicroChannel"), DEVICE( IBM, IBM_82351, "82351"), + DEVICE( IBM, IBM_PYTHON, "Python"), DEVICE( IBM, IBM_SERVERAID, "ServeRAID"), DEVICE( IBM, IBM_TR_WAKE, "Wake On LAN Token Ring"), DEVICE( IBM, IBM_MPIC, "MPIC-2 Interrupt Controller"), @@ -431,14 +433,19 @@ DEVICE( RP, RP8M, "RocketModem 8 J"), DEVICE( CYCLADES, CYCLOM_Y_Lo, "Cyclom-Y below 1Mbyte"), DEVICE( CYCLADES, CYCLOM_Y_Hi, "Cyclom-Y above 1Mbyte"), - DEVICE( CYCLADES, CYCLOM_Z_Lo, "Cyclom-Z below 1Mbyte"), - DEVICE( CYCLADES, CYCLOM_Z_Hi, "Cyclom-Z above 1Mbyte"), + DEVICE( CYCLADES, CYCLOM_4Y_Lo, "Cyclom-4Y below 1Mbyte"), + DEVICE( CYCLADES, CYCLOM_4Y_Hi, "Cyclom-4Y above 1Mbyte"), + DEVICE( CYCLADES, CYCLOM_8Y_Lo, "Cyclom-8Y below 1Mbyte"), + DEVICE( CYCLADES, CYCLOM_8Y_Hi, "Cyclom-8Y above 1Mbyte"), + DEVICE( CYCLADES, CYCLOM_Z_Lo, "Cyclades-Z below 1Mbyte"), + DEVICE( CYCLADES, CYCLOM_Z_Hi, "Cyclades-Z above 1Mbyte"), DEVICE( ESSENTIAL, ESSENTIAL_ROADRUNNER,"Roadrunner serial HIPPI"), DEVICE( O2, O2_6832, "6832"), DEVICE( 3DFX, 3DFX_VOODOO, "Voodoo"), DEVICE( 3DFX, 3DFX_VOODOO2, "Voodoo2"), DEVICE( 3DFX, 3DFX_BANSHEE, "Banshee"), DEVICE( SIGMADES, SIGMADES_6425, "REALmagic64/GX"), + DEVICE( AVM, AVM_A1, "A1 (Fritz)"), DEVICE( STALLION, STALLION_ECHPCI832,"EasyConnection 8/32"), DEVICE( STALLION, STALLION_ECHPCI864,"EasyConnection 8/64"), DEVICE( STALLION, STALLION_EIOPCI,"EasyIO"), @@ -778,6 +785,7 @@ case PCI_VENDOR_ID_O2: return "O2 Micro"; case PCI_VENDOR_ID_3DFX: return "3Dfx"; case PCI_VENDOR_ID_SIGMADES: return "Sigma Designs"; + case PCI_VENDOR_ID_AVM: return "AVM"; case PCI_VENDOR_ID_CCUBE: return "C-Cube"; case PCI_VENDOR_ID_DIPIX: return "Dipix"; case PCI_VENDOR_ID_STALLION: return "Stallion Technologies"; diff -ur --new-file old/linux/drivers/pci/pci.c new/linux/drivers/pci/pci.c --- old/linux/drivers/pci/pci.c Wed Jan 20 19:18:53 1999 +++ new/linux/drivers/pci/pci.c Mon Mar 8 00:19:55 1999 @@ -1,12 +1,12 @@ /* - * $Id: pci.c,v 1.90 1998/09/05 12:39:39 mj Exp $ + * $Id: pci.c,v 1.91 1999/01/21 13:34:01 davem Exp $ * * PCI Bus Services, see include/linux/pci.h for further explanation. * * Copyright 1993 -- 1997 Drew Eckhardt, Frederic Potter, * David Mosberger-Tang * - * Copyright 1997 -- 1998 Martin Mares + * Copyright 1997 -- 1999 Martin Mares */ #include @@ -28,9 +28,6 @@ #endif struct pci_bus pci_root; -#ifdef CONFIG_VISWS -struct pci_bus pci_other; -#endif struct pci_dev *pci_devices = NULL; static struct pci_dev **pci_last_dev_p = &pci_devices; static int pci_reverse __initdata = 0; @@ -371,6 +368,18 @@ return max; } +struct pci_bus * __init pci_scan_peer_bridge(int bus) +{ + struct pci_bus *b; + + b = kmalloc(sizeof(*b), GFP_KERNEL); + memset(b, 0, sizeof(*b)); + b->next = pci_root.next; + pci_root.next = b; + b->number = b->secondary = bus; + b->subordinate = pci_scan_bus(b); + return b; +} __initfunc(void pci_init(void)) { @@ -385,11 +394,6 @@ memset(&pci_root, 0, sizeof(pci_root)); pci_root.subordinate = pci_scan_bus(&pci_root); -#ifdef CONFIG_VISWS - pci_other.number = 1; /* XXX unless bridge(s) on pci_root */ - pci_other.subordinate = pci_scan_bus(&pci_other); - pci_root.next = &pci_other; -#endif /* give BIOS a chance to apply platform specific fixes: */ pcibios_fixup(); @@ -402,7 +406,6 @@ pci_proc_init(); #endif } - __initfunc(void pci_setup (char *str, int *ints)) { diff -ur --new-file old/linux/drivers/sbus/audio/audio.c new/linux/drivers/sbus/audio/audio.c --- old/linux/drivers/sbus/audio/audio.c Wed Nov 18 18:06:05 1998 +++ new/linux/drivers/sbus/audio/audio.c Fri Apr 23 04:24:51 1999 @@ -7,6 +7,7 @@ * * Mixer code adapted from code contributed by and * Copyright (C) 1998 Michael Mraka (michael@fi.muni.cz) + * and with fixes from Michael Shuey (shuey@ecn.purdue.edu) * The mixer code cheats; Sparc hardware doesn't generally allow independent * line control, and this fakes it badly. * @@ -136,7 +137,7 @@ drv->output_buffer = kmalloc((drv->output_buffer_size * drv->num_output_buffers), - GFP_KERNEL); + (GFP_DMA | GFP_KERNEL)); if (!drv->output_buffer) goto kmalloc_failed2; /* Allocate the pages for each output buffer. */ @@ -167,7 +168,7 @@ if (duplex == 1) { drv->input_buffer = kmalloc((drv->input_buffer_size * drv->num_input_buffers), - GFP_KERNEL); + (GFP_DMA | GFP_KERNEL)); if (!drv->input_buffer) goto kmalloc_failed4; for (i = 0; i < drv->num_input_buffers; i++) { @@ -628,19 +629,43 @@ #define MONO_DEVICES (SOUND_MASK_SPEAKER | SOUND_MASK_MIC) static int sparcaudio_mixer_ioctl(struct inode * inode, struct file * file, - unsigned int cmd, unsigned long arg) + unsigned int cmd, unsigned int *arg) { struct sparcaudio_driver *drv = drivers[(MINOR(inode->i_rdev) >> SPARCAUDIO_DEVICE_SHIFT)]; - unsigned long i = 0, j = 0, k = 0; + unsigned long i = 0, j = 0; + unsigned int k; - k = (unsigned long) &arg; + if(cmd == SOUND_MIXER_INFO) { + audio_device_t tmp; + mixer_info info; + int retval = -EINVAL; + + if(drv->ops->sunaudio_getdev) { + drv->ops->sunaudio_getdev(drv, &tmp); + memset(&info, 0, sizeof(info)); + strncpy(info.id, tmp.name, sizeof(info.id)); + strncpy(info.name, "Sparc Audio", sizeof(info.name)); + + /* XXX do this right... */ + info.modify_counter = 0; + + if(copy_to_user((char *)arg, &info, sizeof(info))) + retval = -EFAULT; + else + retval = 0; + } + return retval; + } switch (cmd) { case SOUND_MIXER_WRITE_RECLEV: case SOUND_MIXER_WRITE_MIC: case SOUND_MIXER_WRITE_CD: case SOUND_MIXER_WRITE_LINE: + case SOUND_MIXER_WRITE_IMIX: + if(get_user(k, arg)) + return -EFAULT; tprintk(("setting input volume (0x%x)", k)); if (drv->ops->get_input_channels) j = drv->ops->get_input_channels(drv); @@ -670,6 +695,8 @@ case SOUND_MIXER_WRITE_PCM: case SOUND_MIXER_WRITE_VOLUME: case SOUND_MIXER_WRITE_SPEAKER: + if(get_user(k, arg)) + return -EFAULT; tprintk(("setting output volume (0x%x)", k)); if (drv->ops->get_output_channels) j = drv->ops->get_output_channels(drv); @@ -709,10 +736,13 @@ case SOUND_MIXER_WRITE_RECSRC: if (!drv->ops->set_input_port) return -EINVAL; - if (arg & SOUND_MASK_IMIX) j |= AUDIO_ANALOG_LOOPBACK; - if (arg & SOUND_MASK_CD) j |= AUDIO_CD; - if (arg & SOUND_MASK_LINE) j |= AUDIO_LINE_IN; - if (arg & SOUND_MASK_MIC) j |= AUDIO_MICROPHONE; + if(get_user(k, arg)) + return -EFAULT; + /* only one should ever be selected */ + if (k & SOUND_MASK_IMIX) j = AUDIO_ANALOG_LOOPBACK; + if (k & SOUND_MASK_CD) j = AUDIO_CD; + if (k & SOUND_MASK_LINE) j = AUDIO_LINE_IN; + if (k & SOUND_MASK_MIC) j = AUDIO_MICROPHONE; tprintk(("setting inport to %d\n", j)); i = drv->ops->set_input_port(drv, j); @@ -768,11 +798,12 @@ j = drv->ops->get_output_balance(drv); i = b_to_s(i,j); } - return COPY_OUT((int *)arg, i); + return COPY_OUT(arg, i); case SOUND_MIXER_READ_RECLEV: case SOUND_MIXER_READ_MIC: case SOUND_MIXER_READ_CD: case SOUND_MIXER_READ_LINE: + case SOUND_MIXER_READ_IMIX: if (drv->ops->get_input_channels) j = drv->ops->get_input_channels(drv); if (j == 1) { @@ -786,7 +817,7 @@ j = drv->ops->get_input_balance(drv); i = b_to_s(i,j); } - return COPY_OUT((int *)arg, i); + return COPY_OUT(arg, i); default: return -EINVAL; } @@ -840,7 +871,7 @@ switch (minor & 0xf) { case SPARCAUDIO_MIXER_MINOR: - return sparcaudio_mixer_ioctl(inode, file, cmd, arg); + return sparcaudio_mixer_ioctl(inode, file, cmd, (unsigned int *)arg); case SPARCAUDIO_DSP16_MINOR: case SPARCAUDIO_DSP_MINOR: case SPARCAUDIO_AUDIO_MINOR: @@ -1022,12 +1053,14 @@ break; } } else if (k == 16) { + switch (j) { case AUDIO_ENCODING_LINEAR: i = AFMT_S16_BE; break; case AUDIO_ENCODING_LINEARLE: i = AFMT_S16_LE; break; + } } COPY_OUT(arg, i); break; @@ -1872,6 +1905,11 @@ /* A low-level audio driver must exist. */ if (!drv) return -ENODEV; + +#ifdef S_ZERO_WR + /* This is how 2.0 ended up dealing with 0 len writes */ + inode->i_flags |= S_ZERO_WR; +#endif switch (minor & 0xf) { case SPARCAUDIO_AUDIOCTL_MINOR: diff -ur --new-file old/linux/drivers/sbus/audio/cs4215.h new/linux/drivers/sbus/audio/cs4215.h --- old/linux/drivers/sbus/audio/cs4215.h Sun Oct 4 19:22:43 1998 +++ new/linux/drivers/sbus/audio/cs4215.h Tue Mar 16 01:11:30 1999 @@ -13,8 +13,9 @@ __u8 ctrl[4]; /* Ctrl mode: Time slots 1-4 */ __volatile__ struct dbri_mem td; __volatile__ struct dbri_mem rd; - __u8 version; __u8 onboard; + __u32 status; + __u32 version; }; diff -ur --new-file old/linux/drivers/sbus/audio/cs4231.c new/linux/drivers/sbus/audio/cs4231.c --- old/linux/drivers/sbus/audio/cs4231.c Fri Nov 20 20:42:33 1998 +++ new/linux/drivers/sbus/audio/cs4231.c Wed Apr 28 17:47:39 1999 @@ -14,6 +14,7 @@ * The APC DMA controller support unfortunately is not documented. Thanks, Sun */ +#include #include #include #include @@ -24,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -31,6 +33,10 @@ #include #include #include +#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x200ff && defined(CONFIG_PCI) +#define EB4231_SUPPORT +#include +#endif #include #include "cs4231.h" @@ -67,6 +73,7 @@ static int cs4231_recintr(struct sparcaudio_driver *drv); static int cs4231_output_muted(struct sparcaudio_driver *drv, int value); static void cs4231_pollinput(struct sparcaudio_driver *drv); +static void eb4231_pollinput(struct sparcaudio_driver *drv); static int cs4231_length_to_samplecount(struct audio_prinfo *thisdir, unsigned int length); static void cs4231_getsamplecount(struct sparcaudio_driver *drv, @@ -86,8 +93,8 @@ tprintk(("enabling interrupts\n")); save_flags(flags); cli(); - cs4231_chip->regs->iar = 0xa; - cs4231_chip->regs->idr = INTR_ON; + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->iar), 0xa); + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->idr), INTR_ON); restore_flags(flags); cs4231_chip->status |= CS_STATUS_INTS_ON; @@ -105,8 +112,8 @@ tprintk(("disabling interrupts\n")); save_flags(flags); cli(); - cs4231_chip->regs->iar = 0xa; - cs4231_chip->regs->idr = INTR_OFF; + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->iar), 0xa); + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->idr), INTR_OFF); restore_flags(flags); cs4231_chip->status &= ~CS_STATUS_INTS_ON; @@ -120,8 +127,10 @@ tprintk(("enabling play\n")); save_flags(flags); cli(); - cs4231_chip->regs->iar = 0x9; - cs4231_chip->regs->idr |= PEN_ENABLE; + + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->iar), 0x9); + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->idr), + (CS4231_READ8(cs4231_chip, &(cs4231_chip->regs->idr)) | PEN_ENABLE)); restore_flags(flags); } @@ -133,8 +142,9 @@ tprintk(("disabling play\n")); save_flags(flags); cli(); - cs4231_chip->regs->iar = 0x9; - cs4231_chip->regs->idr &= PEN_DISABLE; + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->iar), 0x9); + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->idr), + (CS4231_READ8(cs4231_chip, &(cs4231_chip->regs->idr)) & PEN_DISABLE)); restore_flags(flags); } @@ -146,8 +156,9 @@ tprintk(("enabling rec\n")); save_flags(flags); cli(); - cs4231_chip->regs->iar = 0x9; - cs4231_chip->regs->idr |= CEN_ENABLE; + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->iar), 0x9); + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->idr), + (CS4231_READ8(cs4231_chip, &(cs4231_chip->regs->idr)) | CEN_ENABLE)); restore_flags(flags); } @@ -159,64 +170,68 @@ tprintk(("disabling rec\n")); save_flags(flags); cli(); - cs4231_chip->regs->iar = 0x9; - cs4231_chip->regs->idr &= CEN_DISABLE; + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->iar), 0x9); + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->idr), + (CS4231_READ8(cs4231_chip, &(cs4231_chip->regs->idr)) & CEN_DISABLE)); restore_flags(flags); } +static struct cs4231_rates { + int speed, bits; +} cs4231_rate_table[] = { + { 5512, CS4231_DFR_5512 }, + { 6615, CS4231_DFR_6615 }, + { 8000, CS4231_DFR_8000 }, + { 9600, CS4231_DFR_9600 }, + { 11025, CS4231_DFR_11025 }, + { 16000, CS4231_DFR_16000 }, + { 18900, CS4231_DFR_18900 }, + { 22050, CS4231_DFR_22050 }, + { 27429, CS4231_DFR_27429 }, + { 32000, CS4231_DFR_32000 }, + { 33075, CS4231_DFR_33075 }, + { 37800, CS4231_DFR_37800 }, + { 44100, CS4231_DFR_44100 }, + { 48000, CS4231_DFR_48000 } +}; + +#define NUM_RATES (sizeof(cs4231_rate_table) / sizeof(struct cs4231_rates)) + static int -cs4231_rate_to_bits(struct sparcaudio_driver *drv, int value) +cs4231_rate_to_bits(struct sparcaudio_driver *drv, int *value) { - int set_bits; + struct cs4231_rates *p = &cs4231_rate_table[0]; + int i, wanted = *value; - switch (value) { - case 5512: - set_bits = CS4231_DFR_5512; - break; - case 6615: - set_bits = CS4231_DFR_6615; - break; - case 8000: - set_bits = CS4231_DFR_8000; - break; - case 9600: - set_bits = CS4231_DFR_9600; - break; - case 11025: - set_bits = CS4231_DFR_11025; - break; - case 16000: - set_bits = CS4231_DFR_16000; - break; - case 18900: - set_bits = CS4231_DFR_18900; - break; - case 22050: - set_bits = CS4231_DFR_22050; - break; - case 27429: - set_bits = CS4231_DFR_27429; - break; - case 32000: - set_bits = CS4231_DFR_32000; - break; - case 33075: - set_bits = CS4231_DFR_33075; - break; - case 37800: - set_bits = CS4231_DFR_37800; - break; - case 44100: - set_bits = CS4231_DFR_44100; - break; - case 48000: - set_bits = CS4231_DFR_48000; - break; - default: - set_bits = -(EINVAL); - break; + /* We try to be nice and approximate what the user asks for. */ + if(wanted < 5512) + wanted = 5512; + if(wanted > 48000) + wanted = 48000; + + for(i = 0; i < NUM_RATES; i++, p++) { + /* Exact match? */ + if(wanted == p->speed) + break; + + /* If we're inbetween two entries, and neither is exact, + * pick the closest one. + */ + if(wanted == p[1].speed) + continue; + if(wanted > p->speed && + wanted < p[1].speed) { + int diff1, diff2; + + diff1 = wanted - p->speed; + diff2 = p[1].speed - wanted; + if(diff2 < diff1) + p++; + break; + } } - return set_bits; + *value = p->speed; + return p->bits; } static int @@ -261,14 +276,19 @@ if (value != 0) { set_bits = cs4231_encoding_to_bits(drv, value); if (set_bits >= 0) { - cs4231_chip->regs->iar = IAR_AUTOCAL_BEGIN | 0x8; - tmp_bits = cs4231_chip->regs->idr; - cs4231_chip->regs->idr = CHANGE_ENCODING(tmp_bits, set_bits); + CS4231_READ8(cs4231_chip, &(cs4231_chip->regs->idr)); + CS4231_READ8(cs4231_chip, &(cs4231_chip->regs->idr)); + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->iar), IAR_AUTOCAL_BEGIN | 0x8); + tmp_bits = CS4231_READ8(cs4231_chip, &(cs4231_chip->regs->idr)); + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->idr), + CHANGE_ENCODING(tmp_bits, set_bits)); + CS4231_READ8(cs4231_chip, &(cs4231_chip->regs->idr)); + CS4231_READ8(cs4231_chip, &(cs4231_chip->regs->idr)); - CHIP_READY + CHIP_READY - cs4231_chip->perchip_info.play.encoding = value; - return 0; + cs4231_chip->perchip_info.play.encoding = value; + return 0; } } dprintk(("output enc failed\n")); @@ -291,14 +311,19 @@ if (value != 0) { set_bits = cs4231_encoding_to_bits(drv, value); if (set_bits >= 0) { - cs4231_chip->regs->iar = IAR_AUTOCAL_BEGIN | 0x1c; - tmp_bits = cs4231_chip->regs->idr; - cs4231_chip->regs->idr = CHANGE_ENCODING(tmp_bits, set_bits); + CS4231_READ8(cs4231_chip, &(cs4231_chip->regs->idr)); + CS4231_READ8(cs4231_chip, &(cs4231_chip->regs->idr)); + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->iar), IAR_AUTOCAL_BEGIN | 0x1c); + tmp_bits = CS4231_READ8(cs4231_chip, &(cs4231_chip->regs->idr)); + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->idr), + CHANGE_ENCODING(tmp_bits, set_bits)); + CS4231_READ8(cs4231_chip, &(cs4231_chip->regs->idr)); + CS4231_READ8(cs4231_chip, &(cs4231_chip->regs->idr)); - CHIP_READY + CHIP_READY - cs4231_chip->perchip_info.record.encoding = value; - return 0; + cs4231_chip->perchip_info.record.encoding = value; + return 0; } } dprintk(("input enc failed\n")); @@ -319,16 +344,23 @@ tprintk(("output rate %d\n", value)); if (value != 0) { - set_bits = cs4231_rate_to_bits(drv, value); + set_bits = cs4231_rate_to_bits(drv, &value); if (set_bits >= 0) { - cs4231_chip->regs->iar = IAR_AUTOCAL_BEGIN | 0x8; - tmp_bits = cs4231_chip->regs->idr; - cs4231_chip->regs->idr = CHANGE_DFR(tmp_bits, set_bits); - - CHIP_READY - - cs4231_chip->perchip_info.play.sample_rate = value; - return 0; + CS4231_READ8(cs4231_chip, &(cs4231_chip->regs->idr)); + CS4231_READ8(cs4231_chip, &(cs4231_chip->regs->idr)); + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->iar), IAR_AUTOCAL_BEGIN | 0x8); + tmp_bits = CS4231_READ8(cs4231_chip, &(cs4231_chip->regs->idr)); + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->idr), + CHANGE_DFR(tmp_bits, set_bits)); + CS4231_READ8(cs4231_chip, &(cs4231_chip->regs->idr)); + CS4231_READ8(cs4231_chip, &(cs4231_chip->regs->idr)); + + CHIP_READY + + cs4231_chip->perchip_info.play.sample_rate = value; + tprintk(("tmp_bits[%02x] set_bits[%02x] CHANGE_DFR[%02x]\n", + tmp_bits, set_bits, CHANGE_DFR(tmp_bits, set_bits))); + return 0; } } dprintk(("output rate failed\n")); @@ -349,16 +381,21 @@ tprintk(("input rate %d\n", value)); if (value != 0) { - set_bits = cs4231_rate_to_bits(drv, value); + set_bits = cs4231_rate_to_bits(drv, &value); if (set_bits >= 0) { - cs4231_chip->regs->iar = IAR_AUTOCAL_BEGIN | 0x1c; - tmp_bits = cs4231_chip->regs->idr; - cs4231_chip->regs->idr = CHANGE_DFR(tmp_bits, set_bits); + CS4231_READ8(cs4231_chip, &(cs4231_chip->regs->idr)); + CS4231_READ8(cs4231_chip, &(cs4231_chip->regs->idr)); + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->iar), IAR_AUTOCAL_BEGIN | 0x1c); + tmp_bits = CS4231_READ8(cs4231_chip, &(cs4231_chip->regs->idr)); + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->idr), + CHANGE_DFR(tmp_bits, set_bits)); + CS4231_READ8(cs4231_chip, &(cs4231_chip->regs->idr)); + CS4231_READ8(cs4231_chip, &(cs4231_chip->regs->idr)); - CHIP_READY + CHIP_READY - cs4231_chip->perchip_info.record.sample_rate = value; - return 0; + cs4231_chip->perchip_info.record.sample_rate = value; + return 0; } } dprintk(("input rate failed\n")); @@ -383,14 +420,14 @@ tmp_bits = cs4231_chip->regs->idr; switch (value) { case 1: - cs4231_chip->regs->idr = CS4231_MONO_ON(tmp_bits); - break; + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->idr), CS4231_MONO_ON(tmp_bits)); + break; case 2: - cs4231_chip->regs->idr = CS4231_STEREO_ON(tmp_bits); - break; + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->idr), CS4231_STEREO_ON(tmp_bits)); + break; default: - dprintk(("input chan failed\n")); - return -(EINVAL); + dprintk(("input chan failed\n")); + return -(EINVAL); } CHIP_READY @@ -413,18 +450,18 @@ int tmp_bits; tprintk(("output channels %d\n", value)); - cs4231_chip->regs->iar = IAR_AUTOCAL_BEGIN | 0x8; - tmp_bits = cs4231_chip->regs->idr; + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->iar), IAR_AUTOCAL_BEGIN | 0x8); + tmp_bits = CS4231_READ8(cs4231_chip, &(cs4231_chip->regs->idr)); switch (value) { case 1: - cs4231_chip->regs->idr = CS4231_MONO_ON(tmp_bits); - break; + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->idr), CS4231_MONO_ON(tmp_bits)); + break; case 2: - cs4231_chip->regs->idr = CS4231_STEREO_ON(tmp_bits); - break; + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->idr), CS4231_STEREO_ON(tmp_bits)); + break; default: - dprintk(("output chan failed\n")); - return -(EINVAL); + dprintk(("output chan failed\n")); + return -(EINVAL); } CHIP_READY @@ -476,14 +513,16 @@ struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; unsigned int x = 0; - cs4231_chip->regs->iar = IAR_AUTOCAL_END; - while (cs4231_chip->regs->iar == IAR_NOT_READY && x <= CS_TIMEOUT) { + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->iar), IAR_AUTOCAL_END); + while (CS4231_READ8(cs4231_chip, &(cs4231_chip->regs->idr)) == IAR_NOT_READY && + x <= CS_TIMEOUT) { x++; } x = 0; - cs4231_chip->regs->iar = 0x0b; - while (cs4231_chip->regs->idr == AUTOCAL_IN_PROGRESS && x <= CS_TIMEOUT) { + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->iar), 0x0b); + while (CS4231_READ8(cs4231_chip, &(cs4231_chip->regs->idr)) == AUTOCAL_IN_PROGRESS && + x <= CS_TIMEOUT) { x++; } } @@ -494,17 +533,21 @@ struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; tprintk(("in cs4231_output_muted: %d\n", value)); if (!value) { - cs4231_chip->regs->iar = 0x7; - cs4231_chip->regs->idr &= OUTCR_UNMUTE; - cs4231_chip->regs->iar = 0x6; - cs4231_chip->regs->idr &= OUTCR_UNMUTE; - cs4231_chip->perchip_info.output_muted = 0; + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->iar), 0x7); + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->idr), + (CS4231_READ8(cs4231_chip, &(cs4231_chip->regs->idr)) & OUTCR_UNMUTE)); + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->iar), 0x6); + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->idr), + (CS4231_READ8(cs4231_chip, &(cs4231_chip->regs->idr)) & OUTCR_UNMUTE)); + cs4231_chip->perchip_info.output_muted = 0; } else { - cs4231_chip->regs->iar = 0x7; - cs4231_chip->regs->idr |= OUTCR_MUTE; - cs4231_chip->regs->iar = 0x6; - cs4231_chip->regs->idr |= OUTCR_MUTE; - cs4231_chip->perchip_info.output_muted = 1; + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->iar), 0x7); + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->idr), + (CS4231_READ8(cs4231_chip, &(cs4231_chip->regs->idr)) | OUTCR_MUTE)); + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->iar), 0x6); + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->idr), + (CS4231_READ8(cs4231_chip, &(cs4231_chip->regs->idr)) | OUTCR_MUTE)); + cs4231_chip->perchip_info.output_muted = 1; } return 0; } @@ -548,28 +591,34 @@ /* Aaaaaah! It's all coming so fast! Turn it all off, then selectively * enable things. */ - cs4231_chip->regs->iar = 0x1a; - cs4231_chip->regs->idr |= MONO_IOCR_MUTE; - cs4231_chip->regs->iar = 0x0a; - cs4231_chip->regs->idr |= PINCR_LINE_MUTE; - cs4231_chip->regs->idr |= PINCR_HDPH_MUTE; + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->iar), 0x1a); + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->idr), + (CS4231_READ8(cs4231_chip, &(cs4231_chip->regs->idr)) | MONO_IOCR_MUTE)); + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->iar), 0x0a); + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->idr), + (CS4231_READ8(cs4231_chip, &(cs4231_chip->regs->idr)) | PINCR_LINE_MUTE)); + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->idr), + (CS4231_READ8(cs4231_chip, &(cs4231_chip->regs->idr)) | PINCR_HDPH_MUTE)); if (value & AUDIO_SPEAKER) { - cs4231_chip->regs->iar = 0x1a; - cs4231_chip->regs->idr &= ~MONO_IOCR_MUTE; - retval |= AUDIO_SPEAKER; + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->iar), 0x1a); + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->idr), + (CS4231_READ8(cs4231_chip, &(cs4231_chip->regs->idr)) & ~MONO_IOCR_MUTE)); + retval |= AUDIO_SPEAKER; } if (value & AUDIO_HEADPHONE) { - cs4231_chip->regs->iar = 0x0a; - cs4231_chip->regs->idr &= ~PINCR_HDPH_MUTE; - retval |= AUDIO_HEADPHONE; + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->iar), 0x0a); + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->idr), + (CS4231_READ8(cs4231_chip, &(cs4231_chip->regs->idr)) & ~PINCR_HDPH_MUTE)); + retval |= AUDIO_HEADPHONE; } if (value & AUDIO_LINE_OUT) { - cs4231_chip->regs->iar = 0x0a; - cs4231_chip->regs->idr &= ~PINCR_LINE_MUTE; - retval |= AUDIO_LINE_OUT; + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->iar), 0x0a); + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->idr), + (CS4231_READ8(cs4231_chip, &(cs4231_chip->regs->idr)) & ~PINCR_LINE_MUTE)); + retval |= AUDIO_LINE_OUT; } cs4231_chip->perchip_info.play.port = retval; @@ -598,33 +647,41 @@ /* Ultra systems do not support AUDIO_INTERNAL_CD_IN */ /* This apparently applies only to APC ultras, not ebus ultras */ - if (!cs4231_chip->status & CS_STATUS_IS_ULTRA) { + if (!(cs4231_chip->status & CS_STATUS_IS_ULTRA)) { if (value & AUDIO_INTERNAL_CD_IN) { - cs4231_chip->regs->iar = 0x1; - cs4231_chip->regs->idr = CDROM_ENABLE(cs4231_chip->regs->idr); - cs4231_chip->regs->iar = 0x0; - cs4231_chip->regs->idr = CDROM_ENABLE(cs4231_chip->regs->idr); - retval = AUDIO_INTERNAL_CD_IN; + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->iar), 0x1); + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->idr), + CDROM_ENABLE(CS4231_READ8(cs4231_chip, &(cs4231_chip->regs->idr)))); + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->iar), 0x0); + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->idr), + CDROM_ENABLE(CS4231_READ8(cs4231_chip, &(cs4231_chip->regs->idr)))); + retval = AUDIO_INTERNAL_CD_IN; } } if ((value & AUDIO_LINE_IN)) { - cs4231_chip->regs->iar = 0x1; - cs4231_chip->regs->idr = LINE_ENABLE(cs4231_chip->regs->idr); - cs4231_chip->regs->iar = 0x0; - cs4231_chip->regs->idr = LINE_ENABLE(cs4231_chip->regs->idr); - retval = AUDIO_LINE_IN; + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->iar), 0x1); + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->idr), + LINE_ENABLE(CS4231_READ8(cs4231_chip, &(cs4231_chip->regs->idr)))); + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->iar), 0x0); + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->idr), + LINE_ENABLE(CS4231_READ8(cs4231_chip, &(cs4231_chip->regs->idr)))); + retval = AUDIO_LINE_IN; } else if (value & AUDIO_MICROPHONE) { - cs4231_chip->regs->iar = 0x1; - cs4231_chip->regs->idr = MIC_ENABLE(cs4231_chip->regs->idr); - cs4231_chip->regs->iar = 0x0; - cs4231_chip->regs->idr = MIC_ENABLE(cs4231_chip->regs->idr); - retval = AUDIO_MICROPHONE; + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->iar), 0x1); + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->idr), + MIC_ENABLE(CS4231_READ8(cs4231_chip, &(cs4231_chip->regs->idr)))); + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->iar), 0x0); + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->idr), + MIC_ENABLE(CS4231_READ8(cs4231_chip, &(cs4231_chip->regs->idr)))); + retval = AUDIO_MICROPHONE; } else if (value & AUDIO_ANALOG_LOOPBACK) { - cs4231_chip->regs->iar = 0x1; - cs4231_chip->regs->idr = OUTPUTLOOP_ENABLE(cs4231_chip->regs->idr); - cs4231_chip->regs->iar = 0x0; - cs4231_chip->regs->idr = OUTPUTLOOP_ENABLE(cs4231_chip->regs->idr); - retval = AUDIO_ANALOG_LOOPBACK; + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->iar), 0x1); + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->idr), + OUTPUTLOOP_ENABLE(CS4231_READ8(cs4231_chip, &(cs4231_chip->regs->idr)))); + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->iar), 0x0); + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->idr), + OUTPUTLOOP_ENABLE(CS4231_READ8(cs4231_chip, &(cs4231_chip->regs->idr)))); + retval = AUDIO_ANALOG_LOOPBACK; } cs4231_chip->perchip_info.record.port = retval; @@ -652,18 +709,19 @@ a = CS4231_MON_MAX_ATEN - (value * (CS4231_MON_MAX_ATEN + 1) / (AUDIO_MAX_GAIN + 1)); - cs4231_chip->regs->iar = 0x0d; + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->iar), 0x0d); if (a >= CS4231_MON_MAX_ATEN) - cs4231_chip->regs->idr = LOOPB_OFF; + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->idr), LOOPB_OFF); else - cs4231_chip->regs->idr = ((a << 2) | LOOPB_ON); + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->idr), ((a << 2) | LOOPB_ON)); if (value == AUDIO_MAX_GAIN) - cs4231_chip->perchip_info.monitor_gain = AUDIO_MAX_GAIN; + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->perchip_info.monitor_gain), AUDIO_MAX_GAIN); else - cs4231_chip->perchip_info.monitor_gain = ((CS4231_MAX_DEV_ATEN - a) * - (AUDIO_MAX_GAIN + 1) / - (CS4231_MAX_DEV_ATEN + 1)); + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->perchip_info.monitor_gain), + ((CS4231_MAX_DEV_ATEN - a) * + (AUDIO_MAX_GAIN + 1) / + (CS4231_MAX_DEV_ATEN + 1))); return 0; } @@ -689,6 +747,32 @@ return (int)cs4231_chip->perchip_info.record.error; } +#ifdef EB4231_SUPPORT +static int eb4231_get_output_samples(struct sparcaudio_driver *drv) +{ + struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; + int count = + cs4231_length_to_samplecount(&cs4231_chip->perchip_info.play, + readl(&cs4231_chip->eb2p->dbcr)); + + return (cs4231_chip->perchip_info.play.samples - + ((count > cs4231_chip->perchip_info.play.samples) + ? 0 : count)); +} + +static int eb4231_get_input_samples(struct sparcaudio_driver *drv) +{ + struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; + int count = + cs4231_length_to_samplecount(&cs4231_chip->perchip_info.record, + readl(&cs4231_chip->eb2c->dbcr)); + + return (cs4231_chip->perchip_info.record.samples - + ((count > cs4231_chip->perchip_info.record.samples) ? + 0 : count)); +} +#endif + static int cs4231_get_output_samples(struct sparcaudio_driver *drv) { struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; @@ -819,12 +903,12 @@ l_adj = l * (CS4231_MAX_GAIN + 1) / (AUDIO_MAX_GAIN + 1); r_adj = r * (CS4231_MAX_GAIN + 1) / (AUDIO_MAX_GAIN + 1); - cs4231_chip->regs->iar = 0x0; - old_gain = cs4231_chip->regs->idr; - cs4231_chip->regs->idr = RECGAIN_SET(old_gain, l_adj); - cs4231_chip->regs->iar = 0x1; - old_gain = cs4231_chip->regs->idr; - cs4231_chip->regs->idr = RECGAIN_SET(old_gain, r_adj); + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->iar), 0x0); + old_gain = CS4231_READ8(cs4231_chip, &(cs4231_chip->regs->idr)); + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->idr), RECGAIN_SET(old_gain, l_adj)); + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->iar), 0x1); + old_gain = CS4231_READ8(cs4231_chip, &(cs4231_chip->regs->idr)); + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->idr), RECGAIN_SET(old_gain, r_adj)); if (l == value) { (l == 0) ? (tmp = 0) : (tmp = ((l_adj + 1) * AUDIO_MAX_GAIN) / @@ -861,12 +945,12 @@ (r * (CS4231_MAX_ATEN + 1) / (AUDIO_MAX_GAIN + 1))); - cs4231_chip->regs->iar = 0x6; - old_gain = cs4231_chip->regs->idr; - cs4231_chip->regs->idr = GAIN_SET(old_gain, l_adj); - cs4231_chip->regs->iar = 0x7; - old_gain = cs4231_chip->regs->idr; - cs4231_chip->regs->idr = GAIN_SET(old_gain, r_adj); + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->iar), 0x6); + old_gain = CS4231_READ8(cs4231_chip, &(cs4231_chip->regs->idr)); + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->idr), GAIN_SET(old_gain, l_adj)); + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->iar), 0x7); + old_gain = CS4231_READ8(cs4231_chip, &(cs4231_chip->regs->idr)); + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->idr), GAIN_SET(old_gain, r_adj)); if ((value == 0) || (value == AUDIO_MAX_GAIN)) { tmp = value; @@ -887,22 +971,34 @@ static void cs4231_chip_reset(struct sparcaudio_driver *drv) { struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; + unsigned char vers; tprintk(("in cs4231_chip_reset\n")); - cs4231_chip->regs->dmacsr = CS_CHIP_RESET; - cs4231_chip->regs->dmacsr = 0x00; - cs4231_chip->regs->dmacsr |= CS_CDC_RESET; + if (cs4231_chip->status & CS_STATUS_IS_EBUS) { +#ifdef EB4231_SUPPORT + writel(EBUS_DCSR_RESET, &(cs4231_chip->eb2p->dcsr)); + writel(EBUS_DCSR_RESET, &(cs4231_chip->eb2c->dcsr)); + writel(EBUS_DCSR_BURST_SZ_16, &(cs4231_chip->eb2p->dcsr)); + writel(EBUS_DCSR_BURST_SZ_16, &(cs4231_chip->eb2c->dcsr)); +#endif + } else { + cs4231_chip->regs->dmacsr = APC_CHIP_RESET; + cs4231_chip->regs->dmacsr = 0x00; + cs4231_chip->regs->dmacsr |= APC_CDC_RESET; - udelay(20); + udelay(20); - cs4231_chip->regs->dmacsr &= ~(CS_CDC_RESET); - cs4231_chip->regs->iar |= IAR_AUTOCAL_BEGIN; + cs4231_chip->regs->dmacsr &= ~(APC_CDC_RESET); + } + + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->iar), + (CS4231_READ8(cs4231_chip, &(cs4231_chip->regs->iar)) | IAR_AUTOCAL_BEGIN)); CHIP_READY - cs4231_chip->regs->iar = IAR_AUTOCAL_BEGIN | 0x0c; - cs4231_chip->regs->idr = MISC_IR_MODE2; + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->iar), IAR_AUTOCAL_BEGIN | 0x0c); + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->idr), MISC_IR_MODE2); /* This is the equivalent of DEFAULT_DATA_FMAT */ cs4231_set_input_encoding(drv, AUDIO_ENCODING_ULAW); @@ -915,25 +1011,27 @@ cs4231_set_output_channels(drv, CS4231_CHANNELS); cs4231_set_output_precision(drv, CS4231_PRECISION); - cs4231_chip->regs->iar = 0x19; + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->iar), 0x19); + /* see what we can turn on */ - if (cs4231_chip->regs->idr & CS4231A) { + vers = CS4231_READ8(cs4231_chip, &(cs4231_chip->regs->idr)); + if (vers & CS4231A) { tprintk(("This is a CS4231A\n")); cs4231_chip->status |= CS_STATUS_REV_A; } else cs4231_chip->status &= ~CS_STATUS_REV_A; - cs4231_chip->regs->iar = IAR_AUTOCAL_BEGIN | 0x10; - cs4231_chip->regs->idr = OLB_ENABLE; + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->iar), IAR_AUTOCAL_BEGIN | 0x10); + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->idr), OLB_ENABLE); - cs4231_chip->regs->iar = IAR_AUTOCAL_BEGIN | 0x11; + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->iar), IAR_AUTOCAL_BEGIN | 0x11); if (cs4231_chip->status & CS_STATUS_REV_A) - cs4231_chip->regs->idr = (HPF_ON | XTALE_ON); + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->idr), (HPF_ON | XTALE_ON)); else - cs4231_chip->regs->idr = (HPF_ON); + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->idr), HPF_ON); - cs4231_chip->regs->iar = IAR_AUTOCAL_BEGIN | 0x1a; - cs4231_chip->regs->idr = 0x00; + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->iar), IAR_AUTOCAL_BEGIN | 0x1a); + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->idr), 0x00); /* Now set things up for defaults */ cs4231_set_input_balance(drv, AUDIO_MID_BALANCE); @@ -947,13 +1045,14 @@ cs4231_set_monitor_volume(drv, LOOPB_OFF); - cs4231_chip->regs->iar = IAR_AUTOCAL_END; + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->iar), IAR_AUTOCAL_END); cs4231_ready(drv); - cs4231_chip->regs->iar = IAR_AUTOCAL_BEGIN | 0x09; - cs4231_chip->regs->idr &= ACAL_DISABLE; - cs4231_chip->regs->iar = IAR_AUTOCAL_END; + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->iar), IAR_AUTOCAL_BEGIN | 0x09); + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->idr), + (CS4231_READ8(cs4231_chip, &(cs4231_chip->regs->idr)) & ACAL_DISABLE)); + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->iar), IAR_AUTOCAL_END); cs4231_ready(drv); @@ -990,6 +1089,30 @@ return count; } +#ifdef EB4231_SUPPORT +static void eb4231_getsamplecount(struct sparcaudio_driver *drv, unsigned int length, unsigned int direction) +{ + struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; + struct audio_prinfo *thisdir; + unsigned int count, curcount, nextcount, dbcr; + + if(direction == 1) { + thisdir = &cs4231_chip->perchip_info.record; + dbcr = readl(&(cs4231_chip->eb2c->dbcr)); + nextcount = cs4231_chip->input_next_dma_size; + } else { + thisdir = &cs4231_chip->perchip_info.play; + dbcr = readl(&(cs4231_chip->eb2p->dbcr)); + nextcount = cs4231_chip->output_next_dma_size; + } + curcount = cs4231_length_to_samplecount(thisdir, dbcr); + count = thisdir->samples; + length = cs4231_length_to_samplecount(thisdir, length); + /* normalize for where we are. */ + thisdir->samples = ((count - nextcount) + (length - curcount)); +} +#endif + static void cs4231_getsamplecount(struct sparcaudio_driver *drv, unsigned int length, unsigned int direction) { struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; @@ -1060,14 +1183,16 @@ /* stop capture here or midlevel? */ cs4231_chip->perchip_info.record.open = 0; if (cs4231_chip->input_dma_handle) { - mmu_release_scsi_one((u32)((unsigned long)cs4231_chip->input_dma_handle), - cs4231_chip->input_dma_size, drv->dev->my_bus); + if(!(cs4231_chip->status & CS_STATUS_IS_EBUS)) + mmu_release_scsi_one(cs4231_chip->input_dma_handle, + cs4231_chip->input_dma_size, drv->dev->my_bus); cs4231_chip->input_dma_handle = 0; cs4231_chip->input_dma_size = 0; } if (cs4231_chip->input_next_dma_handle) { - mmu_release_scsi_one((u32) ((unsigned long)cs4231_chip->input_next_dma_handle), - cs4231_chip->input_next_dma_size, drv->dev->my_bus); + if(!(cs4231_chip->status & CS_STATUS_IS_EBUS)) + mmu_release_scsi_one(cs4231_chip->input_next_dma_handle, + cs4231_chip->input_next_dma_size, drv->dev->my_bus); cs4231_chip->input_next_dma_handle = 0; cs4231_chip->input_next_dma_size = 0; } @@ -1077,15 +1202,17 @@ cs4231_chip->perchip_info.play.active = cs4231_chip->perchip_info.play.open = 0; if (cs4231_chip->output_dma_handle) { - mmu_release_scsi_one((u32) ((unsigned long)cs4231_chip->output_dma_handle), - cs4231_chip->output_dma_size, drv->dev->my_bus); + if(!(cs4231_chip->status & CS_STATUS_IS_EBUS)) + mmu_release_scsi_one(cs4231_chip->output_dma_handle, + cs4231_chip->output_dma_size, drv->dev->my_bus); cs4231_chip->output_dma_handle = 0; cs4231_chip->output_dma_size = 0; } if (cs4231_chip->output_next_dma_handle) { - mmu_release_scsi_one((u32) ((unsigned long)cs4231_chip->output_next_dma_handle), - cs4231_chip->output_next_dma_size, - drv->dev->my_bus); + if(!(cs4231_chip->status & CS_STATUS_IS_EBUS)) + mmu_release_scsi_one(cs4231_chip->output_next_dma_handle, + cs4231_chip->output_next_dma_size, + drv->dev->my_bus); cs4231_chip->output_next_dma_handle = 0; cs4231_chip->output_next_dma_size = 0; } @@ -1110,7 +1237,7 @@ cs4231_chip->playlen = cs4231_chip->output_size; if (cs4231_chip->output_dma_handle) { - mmu_release_scsi_one((u32) ((unsigned long)cs4231_chip->output_dma_handle), + mmu_release_scsi_one(cs4231_chip->output_dma_handle, cs4231_chip->output_dma_size, drv->dev->my_bus); cs4231_chip->output_dma_handle = 0; cs4231_chip->output_dma_size = 0; @@ -1126,11 +1253,10 @@ if ((cs4231_chip->output_ptr && cs4231_chip->output_size > 0) && !(cs4231_chip->perchip_info.play.pause)) { - cs4231_chip->output_next_dma_handle = (u32 *) (unsigned long) + cs4231_chip->output_next_dma_handle = mmu_get_scsi_one((char *) cs4231_chip->output_ptr, cs4231_chip->output_size, drv->dev->my_bus); - cs4231_chip->regs->dmapnva = (u32) (unsigned long) - cs4231_chip->output_next_dma_handle; + cs4231_chip->regs->dmapnva = cs4231_chip->output_next_dma_handle; cs4231_chip->output_next_dma_size = cs4231_chip->regs->dmapnc = cs4231_chip->output_size; cs4231_chip->output_size = 0; @@ -1147,6 +1273,47 @@ return; } +#ifdef EB4231_SUPPORT +static void eb4231_playintr(struct sparcaudio_driver *drv) +{ + struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; + int status = 0; + + if (cs4231_chip->playlen == 0 && cs4231_chip->output_size > 0) + cs4231_chip->playlen = cs4231_chip->output_size; + + if (cs4231_chip->output_dma_handle) { + cs4231_chip->output_dma_handle = 0; + cs4231_chip->output_dma_size = 0; + cs4231_chip->playing_count--; + status++; + } + if(cs4231_chip->output_next_dma_handle) { + cs4231_chip->output_dma_handle = cs4231_chip->output_next_dma_handle; + cs4231_chip->output_dma_size = cs4231_chip->output_next_dma_size; + cs4231_chip->output_next_dma_handle = 0; + cs4231_chip->output_next_dma_size = 0; + } + + if ((cs4231_chip->output_ptr && cs4231_chip->output_size > 0) && + !(cs4231_chip->perchip_info.play.pause)) { + cs4231_chip->output_next_dma_handle = virt_to_bus(cs4231_chip->output_ptr); + cs4231_chip->output_next_dma_size = cs4231_chip->output_size; + + writel(cs4231_chip->output_next_dma_size, &(cs4231_chip->eb2p->dbcr)); + writel(cs4231_chip->output_next_dma_handle, &(cs4231_chip->eb2p->dacr)); + cs4231_chip->output_size = 0; + cs4231_chip->output_ptr = NULL; + cs4231_chip->playing_count++; + status += 2; + } + + sparcaudio_output_done(drv, status); + + return; +} +#endif + static void cs4231_recclear(int fmt, char *dmabuf, int length) { switch (fmt) { @@ -1174,7 +1341,7 @@ } if (cs4231_chip->input_dma_handle) { - mmu_release_scsi_one((u32) ((unsigned long)cs4231_chip->input_dma_handle), + mmu_release_scsi_one(cs4231_chip->input_dma_handle, cs4231_chip->input_dma_size, drv->dev->my_bus); cs4231_chip->input_dma_handle = 0; cs4231_chip->input_dma_size = 0; @@ -1192,11 +1359,10 @@ !(cs4231_chip->perchip_info.record.pause)) { cs4231_recclear(cs4231_chip->perchip_info.record.encoding, (char *)cs4231_chip->input_ptr, cs4231_chip->input_size); - cs4231_chip->input_next_dma_handle = (u32*) (unsigned long) + cs4231_chip->input_next_dma_handle = mmu_get_scsi_one((char *) cs4231_chip->input_ptr, cs4231_chip->input_size, drv->dev->my_bus); - cs4231_chip->regs->dmacnva = (u32) (unsigned long) - cs4231_chip->input_next_dma_handle; + cs4231_chip->regs->dmacnva = cs4231_chip->input_next_dma_handle; cs4231_chip->input_next_dma_size = cs4231_chip->regs->dmacnc = cs4231_chip->input_size; cs4231_chip->input_size = 0; @@ -1213,6 +1379,93 @@ return 1; } +#ifdef EB4231_SUPPORT +static int eb4231_recintr(struct sparcaudio_driver *drv) +{ + struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; + int status = 0; + + if (cs4231_chip->perchip_info.record.active == 0) { + dprintk(("going inactive\n")); + eb4231_pollinput(drv); + cs4231_disable_rec(drv); + } + + if (cs4231_chip->input_dma_handle) { + cs4231_chip->input_dma_handle = 0; + cs4231_chip->input_dma_size = 0; + cs4231_chip->recording_count--; + status++; + } + if (cs4231_chip->input_next_dma_handle) { + cs4231_chip->input_dma_handle = cs4231_chip->input_next_dma_handle; + cs4231_chip->input_dma_size = cs4231_chip->input_next_dma_size; + cs4231_chip->input_next_dma_size = 0; + cs4231_chip->input_next_dma_handle = 0; + } + + if ((cs4231_chip->input_ptr && cs4231_chip->input_size > 0) && + !(cs4231_chip->perchip_info.record.pause)) { + cs4231_recclear(cs4231_chip->perchip_info.record.encoding, + (char *)cs4231_chip->input_ptr, cs4231_chip->input_size); + + cs4231_chip->input_next_dma_handle = virt_to_bus(cs4231_chip->input_ptr); + cs4231_chip->input_next_dma_size = cs4231_chip->input_size; + + writel(cs4231_chip->input_next_dma_size, &(cs4231_chip->eb2c->dbcr)); + writel(cs4231_chip->input_next_dma_handle, &(cs4231_chip->eb2c->dacr)); + + cs4231_chip->input_size = 0; + cs4231_chip->input_ptr = NULL; + cs4231_chip->recording_count++; + status += 2; + } + + sparcaudio_input_done(drv, 1); + + return 1; +} +#endif + +#ifdef EB4231_SUPPORT +static void eb4231_start_output(struct sparcaudio_driver *drv, __u8 * buffer, + unsigned long count) +{ + struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; + unsigned int dcsr; + + cs4231_chip->output_ptr = buffer; + cs4231_chip->output_size = count; + + if (cs4231_chip->perchip_info.play.active || + (cs4231_chip->perchip_info.play.pause)) + return; + + cs4231_ready(drv); + + cs4231_chip->perchip_info.play.active = 1; + cs4231_chip->playing_count = 0; + + dcsr = readl(&cs4231_chip->eb2p->dcsr); + if (!(dcsr & EBUS_DCSR_EN_DMA)) { + writel(EBUS_DCSR_RESET, &(cs4231_chip->eb2p->dcsr)); + writel(EBUS_DCSR_BURST_SZ_16, &(cs4231_chip->eb2p->dcsr)); + + eb4231_playintr(drv); + + writel(EBUS_DCSR_BURST_SZ_16 | + (EBUS_DCSR_EN_DMA | EBUS_DCSR_INT_EN | EBUS_DCSR_EN_CNT | EBUS_DCSR_EN_NEXT), + &(cs4231_chip->eb2p->dcsr)); + + cs4231_enable_play(drv); + + cs4231_ready(drv); + } else { + eb4231_playintr(drv); + } +} +#endif + static void cs4231_start_output(struct sparcaudio_driver *drv, __u8 * buffer, unsigned long count) { @@ -1231,14 +1484,14 @@ cs4231_chip->perchip_info.play.active = 1; cs4231_chip->playing_count = 0; - if ((cs4231_chip->regs->dmacsr & CS_PPAUSE) || - !(cs4231_chip->regs->dmacsr & PDMA_READY)) { - cs4231_chip->regs->dmacsr &= ~CS_XINT_PLAY; - cs4231_chip->regs->dmacsr &= ~CS_PPAUSE; + if ((cs4231_chip->regs->dmacsr & APC_PPAUSE) || + !(cs4231_chip->regs->dmacsr & APC_PDMA_READY)) { + cs4231_chip->regs->dmacsr &= ~APC_XINT_PLAY; + cs4231_chip->regs->dmacsr &= ~APC_PPAUSE; cs4231_playintr(drv); - cs4231_chip->regs->dmacsr |= CS_PLAY_SETUP; + cs4231_chip->regs->dmacsr |= APC_PLAY_SETUP; cs4231_enable_play(drv); cs4231_ready(drv); @@ -1246,6 +1499,35 @@ cs4231_playintr(drv); } +#ifdef EB4231_SUPPORT +static void eb4231_stop_output(struct sparcaudio_driver *drv) +{ + struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; + int dcsr; + + dprintk(("eb4231_stop_output: dcsr 0x%x dacr 0x%x dbcr %d\n", + readl(&cs4231_chip->eb2p->dcsr), + readl(&cs4231_chip->eb2p->dacr), + readl(&cs4231_chip->eb2p->dbcr))); + cs4231_chip->output_ptr = NULL; + cs4231_chip->output_size = 0; + if (cs4231_chip->output_dma_handle) { + cs4231_chip->output_dma_handle = 0; + cs4231_chip->output_dma_size = 0; + } + if (cs4231_chip->output_next_dma_handle) { + cs4231_chip->output_next_dma_handle = 0; + cs4231_chip->output_next_dma_size = 0; + } + dcsr = readl(&(cs4231_chip->eb2p->dcsr)); + if(dcsr & EBUS_DCSR_EN_DMA) + writel(dcsr & ~EBUS_DCSR_EN_DMA, &(cs4231_chip->eb2p->dcsr)); + + /* Else subsequent speed setting changes are ignored by the chip. */ + cs4231_disable_play(drv); +} +#endif + static void cs4231_stop_output(struct sparcaudio_driver *drv) { struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; @@ -1254,28 +1536,47 @@ cs4231_chip->output_ptr = NULL; cs4231_chip->output_size = 0; if (cs4231_chip->output_dma_handle) { - mmu_release_scsi_one((u32) ((unsigned long)cs4231_chip->output_dma_handle), + mmu_release_scsi_one(cs4231_chip->output_dma_handle, cs4231_chip->output_dma_size, drv->dev->my_bus); cs4231_chip->output_dma_handle = 0; cs4231_chip->output_dma_size = 0; } if (cs4231_chip->output_next_dma_handle) { - mmu_release_scsi_one((u32) ((unsigned long)cs4231_chip->output_next_dma_handle), + mmu_release_scsi_one(cs4231_chip->output_next_dma_handle, cs4231_chip->output_next_dma_size, drv->dev->my_bus); cs4231_chip->output_next_dma_handle = 0; cs4231_chip->output_next_dma_size = 0; } +#if 0 /* Not safe without shutting off the DMA controller as well. -DaveM */ + /* Else subsequent speed setting changes are ignored by the chip. */ + cs4231_disable_play(drv); +#endif } +#ifdef EB4231_SUPPORT +static void eb4231_pollinput(struct sparcaudio_driver *drv) +{ + struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; + int x = 0, dcsr; + + while (!((dcsr = readl(&(cs4231_chip->eb2c->dcsr))) & EBUS_DCSR_TC) && + x <= CS_TIMEOUT) { + x++; + } + + writel(dcsr | EBUS_DCSR_TC, &(cs4231_chip->eb2c->dcsr)); +} +#endif + static void cs4231_pollinput(struct sparcaudio_driver *drv) { struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; int x = 0; - while (!(cs4231_chip->regs->dmacsr & CS_XINT_COVF) && x <= CS_TIMEOUT) { + while (!(cs4231_chip->regs->dmacsr & APC_XINT_COVF) && x <= CS_TIMEOUT) { x++; } - cs4231_chip->regs->dmacsr |= CS_XINT_CEMP; + cs4231_chip->regs->dmacsr |= APC_XINT_CEMP; } static void cs4231_start_input(struct sparcaudio_driver *drv, __u8 * buffer, @@ -1295,14 +1596,14 @@ cs4231_chip->perchip_info.record.active = 1; cs4231_chip->recording_count = 0; - if ((cs4231_chip->regs->dmacsr & CS_CPAUSE) || - !(cs4231_chip->regs->dmacsr & CDMA_READY)) { - cs4231_chip->regs->dmacsr &= ~CS_XINT_CAPT; - cs4231_chip->regs->dmacsr &= ~CS_CPAUSE; + if ((cs4231_chip->regs->dmacsr & APC_CPAUSE) || + !(cs4231_chip->regs->dmacsr & APC_CDMA_READY)) { + cs4231_chip->regs->dmacsr &= ~APC_XINT_CAPT; + cs4231_chip->regs->dmacsr &= ~APC_CPAUSE; cs4231_recintr(drv); - cs4231_chip->regs->dmacsr |= CS_CAPT_SETUP; + cs4231_chip->regs->dmacsr |= APC_CAPT_SETUP; cs4231_enable_rec(drv); cs4231_ready(drv); @@ -1315,18 +1616,18 @@ struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; cs4231_chip->perchip_info.record.active = 0; - cs4231_chip->regs->dmacsr |= (CS_CPAUSE); + cs4231_chip->regs->dmacsr |= (APC_CPAUSE); cs4231_chip->input_ptr = NULL; cs4231_chip->input_size = 0; if (cs4231_chip->input_dma_handle) { - mmu_release_scsi_one((u32) ((unsigned long)cs4231_chip->input_dma_handle), + mmu_release_scsi_one(cs4231_chip->input_dma_handle, cs4231_chip->input_dma_size, drv->dev->my_bus); cs4231_chip->input_dma_handle = 0; cs4231_chip->input_dma_size = 0; } if (cs4231_chip->input_next_dma_handle) { - mmu_release_scsi_one((u32) ((unsigned long)cs4231_chip->input_next_dma_handle), + mmu_release_scsi_one(cs4231_chip->input_next_dma_handle, cs4231_chip->input_next_dma_size, drv->dev->my_bus); cs4231_chip->input_next_dma_handle = 0; cs4231_chip->input_next_dma_size = 0; @@ -1408,7 +1709,11 @@ struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; strncpy(audinfo->name, "SUNW,CS4231", sizeof(audinfo->name) - 1); - /* versions: SPARCstation 4/5=a, Ultra=b */ + /* versions */ + /* a: SPARCstation 4/5 b: Ultra 1/2 (electron) */ + /* c: Ultra 1/2 PCI? (positron) d: ppc */ + /* e: x86 f: Ultra Enterprise? (tazmo) */ + /* g: Ultra 30? (quark) h: Ultra 5/10? (darwin) */ /* apparently Ultra 1, Ultra 2 don't have internal CD input */ if (cs4231_chip->status & CS_STATUS_IS_ULTRA) strncpy(audinfo->version, "b", sizeof(audinfo->version) - 1); @@ -1427,8 +1732,8 @@ { struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; - cs4231_chip->regs->iar = 0x0d; - cs4231_chip->regs->idr = (value ? LOOPB_ON : 0); + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->iar), 0x0d); + CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->idr), (value ? LOOPB_ON : 0)); } static int cs4231_ioctl(struct inode * inode, struct file * file, @@ -1450,6 +1755,55 @@ return retval; } +#ifdef EB4231_SUPPORT +/* ebus audio capture interrupt handler. */ +void eb4231_cinterrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct sparcaudio_driver *drv = (struct sparcaudio_driver *)dev_id; + struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; + int dummy; + + /* Read status. */ + dummy = readl(&cs4231_chip->eb2c->dcsr); + + cs4231_chip->perchip_info.record.samples += + cs4231_length_to_samplecount(&(cs4231_chip->perchip_info.record), + cs4231_chip->reclen); + eb4231_recintr(drv); +} + +/* ebus audio play interrupt handler. */ +void eb4231_pinterrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct sparcaudio_driver *drv = (struct sparcaudio_driver *)dev_id; + struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; + unsigned int dummy; + + /* Clear the interrupt. Bleh, when not using the next-address + * feature, TC can only be cleared by a reset. + */ + dummy = readl(&(cs4231_chip->eb2p->dcsr)); + writel(dummy, &(cs4231_chip->eb2p->dcsr)); + + /* If we get a terminal count and address loaded condition, + * this means the DNAR was copied into DACR. + */ + if((dummy & EBUS_DCSR_TC) != 0 + /*&& (dummy & EBUS_DCSR_A_LOADED) != 0*/) { + cs4231_chip->perchip_info.play.samples += + cs4231_length_to_samplecount(&(cs4231_chip->perchip_info.play), + cs4231_chip->playlen); + eb4231_playintr(drv); + } + + if((dummy & EBUS_DCSR_A_LOADED) == 0) { + cs4231_chip->perchip_info.play.active = 0; + eb4231_playintr(drv); + + eb4231_getsamplecount(drv, cs4231_chip->playlen, 0); + } +} +#endif /* Audio interrupt handler. */ void cs4231_interrupt(int irq, void *dev_id, struct pt_regs *regs) @@ -1458,7 +1812,7 @@ struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; __u32 dummy; - tprintk(("in cs4231_interrupt\n")); + dprintk(("in cs4231_interrupt\n")); /* Clear the interrupt. */ dummy = cs4231_chip->regs->dmacsr; @@ -1468,8 +1822,8 @@ * if anything since we may be doing shared interrupts */ - if (dummy & CS_PLAY_INT) { - if (dummy & CS_XINT_PNVA) { + if (dummy & APC_PLAY_INT) { + if (dummy & APC_XINT_PNVA) { cs4231_chip->perchip_info.play.samples += cs4231_length_to_samplecount(&(cs4231_chip->perchip_info.play), cs4231_chip->playlen); @@ -1478,8 +1832,8 @@ /* Any other conditions we need worry about? */ } - if (dummy & CS_CAPT_INT) { - if (dummy & CS_XINT_CNVA) { + if (dummy & APC_CAPT_INT) { + if (dummy & APC_XINT_CNVA) { cs4231_chip->perchip_info.record.samples += cs4231_length_to_samplecount(&(cs4231_chip->perchip_info.record), cs4231_chip->reclen); @@ -1489,7 +1843,7 @@ } - if (dummy & CS_XINT_CEMP) { + if (dummy & APC_XINT_CEMP) { if (cs4231_chip->perchip_info.record.active == 0) { /* Fix me */ cs4231_chip->perchip_info.record.active = 0; @@ -1498,9 +1852,9 @@ } } - if (dummy & CS_XINT_EMPT) { + if (dummy & APC_XINT_EMPT) { if (!cs4231_chip->output_next_dma_handle) { - cs4231_chip->regs->dmacsr |= (CS_PPAUSE); + cs4231_chip->regs->dmacsr |= (APC_PPAUSE); cs4231_disable_play(drv); cs4231_chip->perchip_info.play.error = 1; } @@ -1510,7 +1864,7 @@ cs4231_getsamplecount(drv, cs4231_chip->playlen, 0); } - if (dummy & CS_GENL_INT) { + if (dummy & APC_GENL_INT) { /* If we get here we must be sharing an interrupt, but I haven't code to handle this right now */ } @@ -1576,6 +1930,67 @@ cs4231_get_formats, }; +#ifdef EB4231_SUPPORT +static struct sparcaudio_operations eb4231_ops = { + cs4231_open, + cs4231_release, + cs4231_ioctl, + eb4231_start_output, + eb4231_stop_output, + cs4231_start_input, + cs4231_stop_input, + cs4231_audio_getdev, + cs4231_set_output_volume, + cs4231_get_output_volume, + cs4231_set_input_volume, + cs4231_get_input_volume, + cs4231_set_monitor_volume, + cs4231_get_monitor_volume, + cs4231_set_output_balance, + cs4231_get_output_balance, + cs4231_set_input_balance, + cs4231_get_input_balance, + cs4231_set_output_channels, + cs4231_get_output_channels, + cs4231_set_input_channels, + cs4231_get_input_channels, + cs4231_set_output_precision, + cs4231_get_output_precision, + cs4231_set_input_precision, + cs4231_get_input_precision, + cs4231_set_output_port, + cs4231_get_output_port, + cs4231_set_input_port, + cs4231_get_input_port, + cs4231_set_output_encoding, + cs4231_get_output_encoding, + cs4231_set_input_encoding, + cs4231_get_input_encoding, + cs4231_set_output_rate, + cs4231_get_output_rate, + cs4231_set_input_rate, + cs4231_get_input_rate, + cs4231_audio_getdev_sunos, + cs4231_get_output_ports, + cs4231_get_input_ports, + cs4231_output_muted, + cs4231_get_output_muted, + cs4231_set_output_pause, + cs4231_get_output_pause, + cs4231_set_input_pause, + cs4231_get_input_pause, + cs4231_set_output_samples, + eb4231_get_output_samples, + cs4231_set_input_samples, + eb4231_get_input_samples, + cs4231_set_output_error, + cs4231_get_output_error, + cs4231_set_input_error, + cs4231_get_input_error, + cs4231_get_formats, +}; +#endif + /* Attach to an cs4231 chip given its PROM node. */ static int cs4231_attach(struct sparcaudio_driver *drv, struct linux_sbus_device *sdev) @@ -1642,6 +2057,8 @@ enable_irq(cs4231_chip->irq); + cs4231_chip->nirqs = 1; + cs4231_enable_interrupts(drv); /* Reset the audio chip. */ @@ -1676,14 +2093,125 @@ AUDIO_ANALOG_LOOPBACK); /* Announce the hardware to the user. */ - printk(KERN_INFO "audio%d: cs4231%c at 0x%lx irq %d\n", +#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE < 0x20100 + printk(KERN_INFO "audio%d: cs4231%c at 0x%x irq %d\n", drv->index, (cs4231_chip->status & CS_STATUS_REV_A) ? 'a' : ' ', (unsigned long)cs4231_chip->regs, cs4231_chip->irq); +#else + printk(KERN_INFO "audio%d: cs4231%c at %p irq %s\n", + drv->index, (cs4231_chip->status & CS_STATUS_REV_A) ? 'a' : ' ', + cs4231_chip->regs, __irq_itoa(cs4231_chip->irq)); +#endif /* Success! */ return 0; } +#ifdef EB4231_SUPPORT +/* Attach to an cs4231 chip given its PROM node. */ +static int eb4231_attach(struct sparcaudio_driver *drv, + struct linux_ebus_device *edev) +{ + struct cs4231_chip *cs4231_chip; + int len, err, nregs; + struct linux_prom_registers regs[4]; + + /* Allocate our private information structure. */ + drv->private = kmalloc(sizeof(struct cs4231_chip), GFP_KERNEL); + if (!drv->private) + return -ENOMEM; + + /* Point at the information structure and initialize it. */ + drv->ops = &eb4231_ops; + cs4231_chip = (struct cs4231_chip *)drv->private; + cs4231_chip->input_ptr = cs4231_chip->output_ptr = NULL; + cs4231_chip->input_size = cs4231_chip->output_size = 0; + cs4231_chip->status = 0; + + len = prom_getproperty(edev->prom_node, "reg", (void *)regs, sizeof(regs)); + + if ((len % sizeof(regs[0])) != 0) { + printk("eb4231: Strange reg property size %d\n", len); + return -ENODEV; + } + + nregs = len / sizeof(regs[0]); + + cs4231_chip->regs = (struct cs4231_regs *)edev->base_address[0]; + cs4231_chip->eb2p = (struct linux_ebus_dma *)edev->base_address[1]; + cs4231_chip->eb2c = (struct linux_ebus_dma *)edev->base_address[2]; + + request_region((unsigned long)cs4231_chip->regs, + sizeof(struct cs4231_regs), "cs4231 regs"); + request_region((unsigned long)cs4231_chip->eb2c, + sizeof(struct linux_ebus_dma), "4231 capture DMA"); + request_region((unsigned long)cs4231_chip->eb2p, + sizeof(struct linux_ebus_dma), "4231 playback DMA"); + + cs4231_chip->status |= CS_STATUS_IS_EBUS; + + /* Attach the interrupt handler to the audio interrupt. */ + cs4231_chip->irq = edev->irqs[0]; + cs4231_chip->irq2 = edev->irqs[1]; + + if(request_irq(cs4231_chip->irq, eb4231_cinterrupt, SA_SHIRQ, "cs4231", drv) || + request_irq(cs4231_chip->irq2, eb4231_pinterrupt, SA_SHIRQ, "cs4231", drv)) + goto bail; + + cs4231_chip->nirqs = 2; + + cs4231_enable_interrupts(drv); + + /* Reset the audio chip. */ + cs4231_chip_reset(drv); + + /* Register ourselves with the midlevel audio driver. */ + err = register_sparcaudio_driver(drv, 1); + + if (err < 0) { + bail: + printk(KERN_ERR "cs4231: unable to register\n"); + cs4231_disable_interrupts(drv); + disable_irq(cs4231_chip->irq); + free_irq(cs4231_chip->irq, drv); + disable_irq(cs4231_chip->irq2); + free_irq(cs4231_chip->irq2, drv); + + release_region((unsigned long)cs4231_chip->regs, + sizeof(struct cs4231_regs)); + release_region((unsigned long)cs4231_chip->eb2c, + sizeof(struct linux_ebus_dma)); + release_region((unsigned long)cs4231_chip->eb2p, + sizeof(struct linux_ebus_dma)); + kfree(drv->private); + return -EIO; + } + + cs4231_chip->perchip_info.play.active = + cs4231_chip->perchip_info.play.pause = 0; + + cs4231_chip->perchip_info.record.active = + cs4231_chip->perchip_info.record.pause = 0; + + cs4231_chip->perchip_info.play.avail_ports = (AUDIO_HEADPHONE | + AUDIO_SPEAKER | + AUDIO_LINE_OUT); + + cs4231_chip->perchip_info.record.avail_ports = (AUDIO_INTERNAL_CD_IN | + AUDIO_LINE_IN | + AUDIO_MICROPHONE | + AUDIO_ANALOG_LOOPBACK); + + /* Announce the hardware to the user. */ + printk(KERN_INFO "audio%d: cs4231%c(eb2) at %p irq %s\n", + drv->index, (cs4231_chip->status & CS_STATUS_REV_A) ? 'a' : ' ', + cs4231_chip->regs, __irq_itoa(cs4231_chip->irq)); + + /* Success! */ + return 0; +} +#endif + /* Probe for the cs4231 chip and then attach the driver. */ #ifdef MODULE int init_module(void) @@ -1691,13 +2219,17 @@ __initfunc(int cs4231_init(void)) #endif { - struct linux_sbus *bus; + struct linux_sbus *sbus; struct linux_sbus_device *sdev; - +#ifdef EB4231_SUPPORT + struct linux_ebus *ebus; + struct linux_ebus_device *edev; +#endif + num_drivers = 0; /* Probe each SBUS for cs4231 chips. */ - for_all_sbusdev(sdev,bus) { + for_all_sbusdev(sdev,sbus) { if (!strcmp(sdev->prom_name, "SUNW,CS4231")) { /* Don't go over the max number of drivers. */ if (num_drivers >= MAX_DRIVERS) @@ -1708,6 +2240,21 @@ } } +#ifdef EB4231_SUPPORT + for_each_ebus(ebus) { + for_each_ebusdev(edev, ebus) { + if (!strcmp(edev->prom_name, "SUNW,CS4231")) { + /* Don't go over the max number of drivers. */ + if (num_drivers >= MAX_DRIVERS) + continue; + + if (eb4231_attach(&drivers[num_drivers], edev) == 0) + num_drivers++; + } + } + } +#endif + /* Only return success if we found some cs4231 chips. */ return (num_drivers > 0) ? 0 : -EIO; } @@ -1716,13 +2263,23 @@ /* Detach from an cs4231 chip given the device structure. */ static void cs4231_detach(struct sparcaudio_driver *drv) { - struct cs4231_chip *info = (struct cs4231_chip *)drv->private; + struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; cs4231_disable_interrupts(drv); unregister_sparcaudio_driver(drv, 1); - disable_irq(info->irq); - free_irq(info->irq, drv); - sparc_free_io(info->regs, info->regs_size); + disable_irq(cs4231_chip->irq); + free_irq(cs4231_chip->irq, drv); + if (!(cs4231_chip->status & CS_STATUS_IS_EBUS)) { + sparc_free_io(cs4231_chip->regs, cs4231_chip->regs_size); + } else { +#ifdef EB4231_SUPPORT + disable_irq(cs4231_chip->irq2); + free_irq(cs4231_chip->irq2, drv); + release_region((unsigned long)cs4231_chip->regs, sizeof(struct cs4231_regs)); + release_region((unsigned long)cs4231_chip->eb2c, sizeof(struct linux_ebus_dma)); + release_region((unsigned long)cs4231_chip->eb2p, sizeof(struct linux_ebus_dma)); +#endif + } kfree(drv->private); } diff -ur --new-file old/linux/drivers/sbus/audio/cs4231.h new/linux/drivers/sbus/audio/cs4231.h --- old/linux/drivers/sbus/audio/cs4231.h Wed Nov 18 18:06:05 1998 +++ new/linux/drivers/sbus/audio/cs4231.h Fri Apr 23 04:24:51 1999 @@ -37,9 +37,11 @@ struct cs4231_chip { struct cs4231_regs *regs; + struct linux_ebus_dma *eb2c; + struct linux_ebus_dma *eb2p; struct audio_info perchip_info; unsigned int playlen, reclen; - int irq; + int irq, irq2, nirqs; unsigned long regs_size; /* Keep track of various info */ @@ -48,13 +50,13 @@ /* Current buffer that the driver is playing. */ volatile __u8 * output_ptr; volatile unsigned long output_size; - volatile __u32 * output_dma_handle, * output_next_dma_handle; + volatile __u32 output_dma_handle, output_next_dma_handle; volatile unsigned long output_dma_size, output_next_dma_size; /* Current record buffer. */ volatile __u8 * input_ptr; volatile unsigned long input_size; - volatile __u32 * input_dma_handle, * input_next_dma_handle; + volatile __u32 input_dma_handle, input_next_dma_handle; volatile unsigned long input_dma_size, input_next_dma_size; /* Number of buffers in the pipe. */ @@ -62,12 +64,34 @@ volatile unsigned long recording_count; }; +#ifdef EB4231_SUPPORT +#define CS4231_READ32(__C, __REG) \ + (((__C)->status & CS_STATUS_IS_EBUS) ? readl((unsigned long)(__REG)) : (*(__REG))) +#define CS4231_READ8(__C, __REG) \ + (((__C)->status & CS_STATUS_IS_EBUS) ? readb((unsigned long)(__REG)) : (*(__REG))) +#define CS4231_WRITE32(__C, __REG, __VAL) \ + (((__C)->status & CS_STATUS_IS_EBUS) ? \ + writel((__VAL), (unsigned long)(__REG)) : \ + (*(__REG) = (__VAL))) +#define CS4231_WRITE8(__C, __REG, __VAL) \ + (((__C)->status & CS_STATUS_IS_EBUS) ? \ + writeb((__VAL), (unsigned long)(__REG)) : \ + (*(__REG) = (__VAL))) +#else +/* We can assume all is SBUS in this case. */ +#define CS4231_READ32(__C, __REG) (*(__REG)) +#define CS4231_READ8(__C, __REG) (*(__REG)) +#define CS4231_WRITE32(__C, __REG, __VAL) (*(__REG) = (__VAL)) +#define CS4231_WRITE8(__C, __REG, __VAL) (*(__REG) = (__VAL)) +#endif + /* Local status bits */ #define CS_STATUS_NEED_INIT 0x01 #define CS_STATUS_INIT_ON_CLOSE 0x02 #define CS_STATUS_REV_A 0x04 #define CS_STATUS_INTS_ON 0x08 #define CS_STATUS_IS_ULTRA 0x10 +#define CS_STATUS_IS_EBUS 0x20 #define CS_TIMEOUT 9000000 @@ -221,36 +245,43 @@ /* 30 - Capture Upper */ /* 31 - Capture Lower */ -/* Following are CSR register definitions for the Sparc */ +/* Following are APC CSR register definitions for the Sparc */ + +#define APC_INT_PENDING 0x800000 /* Interrupt Pending */ +#define APC_PLAY_INT 0x400000 /* Playback interrupt */ +#define APC_CAPT_INT 0x200000 /* Capture interrupt */ +#define APC_GENL_INT 0x100000 /* General interrupt */ +#define APC_XINT_ENA 0x80000 /* General ext int. enable */ +#define APC_XINT_PLAY 0x40000 /* Playback ext intr */ +#define APC_XINT_CAPT 0x20000 /* Capture ext intr */ +#define APC_XINT_GENL 0x10000 /* Error ext intr */ +#define APC_XINT_EMPT 0x8000 /* Pipe empty interrupt */ +#define APC_XINT_PEMP 0x4000 /* Play pipe empty */ +#define APC_XINT_PNVA 0x2000 /* Playback NVA dirty */ +#define APC_XINT_PENA 0x1000 /* play pipe empty Int enable */ +#define APC_XINT_COVF 0x800 /* Cap data dropped on floor */ +#define APC_XINT_CNVA 0x400 /* Capture NVA dirty */ +#define APC_XINT_CEMP 0x200 /* Capture pipe empty interrupt */ +#define APC_XINT_CENA 0x100 /* Cap. pipe empty int enable */ +#define APC_PPAUSE 0x80 /* Pause the play DMA */ +#define APC_CPAUSE 0x40 /* Pause the capture DMA */ +#define APC_CDC_RESET 0x20 /* CODEC RESET */ +#define APC_PDMA_READY 0x08 /* Play DMA Go */ +#define APC_CDMA_READY 0x04 /* Capture DMA Go */ +#define APC_CHIP_RESET 0x01 /* Reset the chip */ + +#define APC_INIT_SETUP (APC_CDMA_READY | APC_PDMA_READY | APC_XINT_ENA | APC_XINT_PLAY | APC_XINT_GENL | APC_INT_PENDING | APC_PLAY_INT | APC_CAPT_INT | APC_GENL_INT) + +#define APC_PLAY_SETUP (APC_GENL_INT | APC_PLAY_INT | APC_XINT_ENA | APC_XINT_PLAY | APC_XINT_EMPT | APC_XINT_GENL | APC_XINT_PENA | APC_PDMA_READY) -#define CS_INT_PENDING 0x800000 /* Interrupt Pending */ -#define CS_PLAY_INT 0x400000 /* Playback interrupt */ -#define CS_CAPT_INT 0x200000 /* Capture interrupt */ -#define CS_GENL_INT 0x100000 /* General interrupt */ -#define CS_XINT_ENA 0x80000 /* General ext int. enable */ -#define CS_XINT_PLAY 0x40000 /* Playback ext intr */ -#define CS_XINT_CAPT 0x20000 /* Capture ext intr */ -#define CS_XINT_GENL 0x10000 /* Error ext intr */ -#define CS_XINT_EMPT 0x8000 /* Pipe empty interrupt */ -#define CS_XINT_PEMP 0x4000 /* Play pipe empty */ -#define CS_XINT_PNVA 0x2000 /* Playback NVA dirty */ -#define CS_XINT_PENA 0x1000 /* play pipe empty Int enable */ -#define CS_XINT_COVF 0x800 /* Cap data dropped on floor */ -#define CS_XINT_CNVA 0x400 /* Capture NVA dirty */ -#define CS_XINT_CEMP 0x200 /* Capture pipe empty interrupt */ -#define CS_XINT_CENA 0x100 /* Cap. pipe empty int enable */ -#define CS_PPAUSE 0x80 /* Pause the play DMA */ -#define CS_CPAUSE 0x40 /* Pause the capture DMA */ -#define CS_CDC_RESET 0x20 /* CODEC RESET */ -#define PDMA_READY 0x08 /* Play DMA Go */ -#define CDMA_READY 0x04 /* Capture DMA Go */ -#define CS_CHIP_RESET 0x01 /* Reset the chip */ +#define APC_CAPT_SETUP (APC_GENL_INT | APC_CAPT_INT | APC_XINT_ENA | APC_XINT_CAPT | APC_XINT_CEMP | APC_XINT_GENL | APC_CDMA_READY) -#define CS_INIT_SETUP (CDMA_READY | PDMA_READY | CS_XINT_ENA | CS_XINT_PLAY | CS_XINT_GENL | CS_INT_PENDING | CS_PLAY_INT | CS_CAPT_INT | CS_GENL_INT) +/* Following are EB2 CSR register definitions for the Sparc */ -#define CS_PLAY_SETUP (CS_GENL_INT | CS_PLAY_INT | CS_XINT_ENA | CS_XINT_PLAY | CS_XINT_EMPT | CS_XINT_GENL | CS_XINT_PENA | PDMA_READY) +/* asm/ebus.h has the base settings */ -#define CS_CAPT_SETUP (CS_GENL_INT | CS_CAPT_INT | CS_XINT_ENA | CS_XINT_CAPT | CS_XINT_CEMP | CS_XINT_GENL | CDMA_READY) +#define EB2_PLAY_SETUP (EBUS_DCSR_BURST_SZ_8|EBUS_DCSR_INT_EN|EBUS_DCSR_EN_DMA|EBUS_DCSR_EN_CNT|EBUS_DCSR_TC) +#define EB2_CAPT_SETUP (EBUS_DCSR_BURST_SZ_8|EBUS_DCSR_INT_EN|EBUS_DCSR_EN_DMA|EBUS_DCSR_EN_CNT|EBUS_DCSR_TC|EBUS_DCSR_WRITE) #define CS4231_MIN_ATEN (0) #define CS4231_MAX_ATEN (31) diff -ur --new-file old/linux/drivers/sbus/audio/dbri.c new/linux/drivers/sbus/audio/dbri.c --- old/linux/drivers/sbus/audio/dbri.c Wed Nov 18 18:06:05 1998 +++ new/linux/drivers/sbus/audio/dbri.c Tue Mar 16 01:11:30 1999 @@ -2,11 +2,10 @@ * drivers/sbus/audio/dbri.c * * Copyright (C) 1997 Rudolf Koenig (rfkoenig@immd4.informatik.uni-erlangen.de) - * The SparcLinux interface was adopted from the CS4231 driver. + * Copyright (C) 1998, 1999 Brent Baccala (baccala@freesoft.org) * * This is the lowlevel driver for the DBRI & MMCODEC duo used for ISDN & AUDIO * on Sun SPARCstation 10, 20, LX and Voyager models. - * NOTE: This driver only supports audio for now, there is NO SUPPORT for ISDN. * * - DBRI: AT&T T5900FX Dual Basic Rates ISDN Interface. It is a 32 channel * data time multiplexer with ISDN support (aka T7259) @@ -59,6 +58,7 @@ #include #include #include +#include #include #include "dbri.h" @@ -69,7 +69,7 @@ #include "../../isdn/hisax/foreign.h" #endif -/* #define DBRI_DEBUG */ +#define DBRI_DEBUG #ifdef DBRI_DEBUG @@ -80,14 +80,17 @@ #define D_MM (1<<3) #define D_USR (1<<4) -static int dbri_debug = D_GEN|D_INT|D_CMD|D_MM|D_USR; +/* static int dbri_debug = D_GEN|D_INT|D_CMD|D_MM|D_USR; */ +static int dbri_debug = 0; +MODULE_PARM(dbri_debug, "i"); + static char *cmds[] = { "WAIT", "PAUSE", "JUMP", "IIQ", "REX", "SDP", "CDP", "DTS", "SSP", "CHI", "NT", "TE", "CDEC", "TEST", "CDM", "RESRV" }; /* Bit hunting */ -#define dumpcmd {int i; for(i=0; icmd[i]); } +#define dumpcmd {int i; for(i=0; idma->cmd[i]); } #define DBRI_CMD(cmd, intr, value) ((cmd << 28) | (1 << 27) | value) @@ -103,14 +106,16 @@ #define MAX_DRIVERS 2 /* Increase this if need more than 2 DBRI's */ -#define WAIT_INTR1 0xbe -#define WAIT_INTR2 0xbf - static struct sparcaudio_driver drivers[MAX_DRIVERS]; -static char drv_name[] = "DBRI/audio"; -static int num_drivers; +static int num_drivers = 0; + + +/* +**************************************************************************** +************** DBRI initialization and command synchronization ************* +**************************************************************************** +*/ -static void * output_callback_arg; /* * Commands are sent to the DBRI by building a list of them in memory, @@ -137,35 +142,46 @@ * in DBRI register 0. I've tried to implement this in such a way * that might make implementing a more sophisticated scheme easier. * - * Every time a routine wants to write commands to the DBRI, it - * must first call dbri_cmdlock() and get an initial index into dbri->cmd - * (currently always 0) in return. After the commands have been - * write (index incremented after each one), dbri_cmdsend() is called - * with the final index value. + * Every time a routine wants to write commands to the DBRI, it must + * first call dbri_cmdlock() and get an initial pointer into dbri->dma->cmd + * in return. After the commands have been writen, dbri_cmdsend() is + * called with the final pointer value. */ -static int dbri_cmdlock(struct dbri *dbri) +static int dbri_locked = 0; /* XXX not SMP safe! XXX */ + +static volatile int * dbri_cmdlock(struct dbri *dbri) { - return 0; + if (dbri_locked) { + printk("DBRI: Command buffer locked! (bug in driver)\n"); + } + dbri_locked ++; + return dbri->dma->cmd; } -static void dbri_cmdsend(struct dbri *dbri, int n) +static void dbri_cmdsend(struct dbri *dbri, volatile int * cmd) { int maxloops = 1000000; - dbri->cmd[n++] = DBRI_CMD(D_WAIT, 0, WAIT_INTR1); - dbri->regs->reg8 = (int)dbri->cmd; - - while (maxloops > 0 && (dbri->regs->reg0 & D_P)); + dbri_locked --; + if (dbri_locked != 0) { + printk("DBRI: Command buffer improperly locked! (bug in driver)\n"); + } else if ((cmd - dbri->dma->cmd) >= DBRI_NO_CMDS-1) { + printk("DBRI: Command buffer overflow! (bug in driver)\n"); + } else { + *(cmd++) = DBRI_CMD(D_PAUSE, 0, 0); + *(cmd++) = DBRI_CMD(D_WAIT, 0, 0); + dbri->regs->reg8 = (int)dbri->dma_dvma->cmd; + while ((maxloops--) > 0 && (dbri->regs->reg0 & D_P)); + } if (maxloops == 0) { - printk("DBRI: Maxloops exceeded in dbri_cmdsend\n"); + printk("DBRI: Chip never completed command buffer\n"); } } -static void dbri_reset(struct sparcaudio_driver *drv) +static void dbri_reset(struct dbri *dbri) { - struct dbri *dbri = (struct dbri *)drv->private; int i; dprintk(D_GEN, ("DBRI: reset 0:%x 2:%x 8:%x 9:%x\n", @@ -177,75 +193,662 @@ udelay(10); } -static void dbri_detach(struct sparcaudio_driver *drv) +static void dbri_detach(struct dbri *dbri) { - struct dbri *info = (struct dbri *)drv->private; - - dbri_reset(drv); - unregister_sparcaudio_driver(drv, 1); - free_irq(info->irq, drv); - sparc_free_io(info->regs, info->regs_size); - kfree(drv->private); + dbri_reset(dbri); + free_irq(dbri->irq, dbri); + sparc_free_io(dbri->regs, dbri->regs_size); + /* Should we release the DMA structure dbri->dma here? */ + kfree(dbri); } -static void dbri_initialize(struct sparcaudio_driver *drv) +static void dbri_initialize(struct dbri *dbri) { - struct dbri *dbri = (struct dbri *)drv->private; - int n; + int n; + volatile int *cmd; - dbri_reset(drv); - dbri->wait = NULL; + dbri_reset(dbri); dprintk(D_GEN, ("DBRI: init: cmd: %x, int: %x\n", - (int)dbri->cmd, (int)dbri->intr)); + (int)dbri->dma->cmd, (int)dbri->dma->intr)); /* * Initialize the interrupt ringbuffer. */ for(n = 0; n < DBRI_NO_INTS-1; n++) - dbri->intr[n * DBRI_INT_BLK] = - (int)(&dbri->intr[(n+1)*DBRI_INT_BLK]); - dbri->intr[n * DBRI_INT_BLK] = (int)(dbri->intr); + dbri->dma->intr[n * DBRI_INT_BLK] = + (int)(&dbri->dma_dvma->intr[(n+1)*DBRI_INT_BLK]); + dbri->dma->intr[n * DBRI_INT_BLK] = (int)(dbri->dma_dvma->intr); dbri->dbri_irqp = 1; -#ifdef USE_SBUS_BURSTS - /* Enable 4-word, 8-word, and 16-word SBus Bursts */ - dbri->regs->reg0 |= (D_G|D_S|D_E); -#else - /* Disable 4-word, 8-word, and 16-word SBus Bursts */ + /* We should query the openprom to see what burst sizes this + * SBus supports. For now, just disable all SBus bursts */ dbri->regs->reg0 &= ~(D_G|D_S|D_E); -#endif /* * Set up the interrupt queue */ - n = dbri_cmdlock(dbri); + cmd = dbri_cmdlock(dbri); - dbri->cmd[n++] = DBRI_CMD(D_IIQ, 0, 0); - dbri->cmd[n++] = (int)(dbri->intr); + *(cmd++) = DBRI_CMD(D_IIQ, 0, 0); + *(cmd++) = (int)(dbri->dma_dvma->intr); - dbri_cmdsend(dbri, n); + dbri_cmdsend(dbri, cmd); } +/* +**************************************************************************** +*************************** DBRI interrupt handler ************************* +**************************************************************************** +*/ + /* * Short data pipes transmit LSB first. The CS4215 receives MSB first. Grrr. - * So we have to reverse the bits. Note: only 1, 2 or 4 bytes are supported. + * So we have to reverse the bits. Note: not all bit lengths are supported */ static __u32 reverse_bytes(__u32 b, int len) { switch(len) { - case 4: b = ((b & 0xffff0000) >> 16) | ((b & 0x0000ffff) << 16); - case 2: b = ((b & 0xff00ff00) >> 8) | ((b & 0x00ff00ff) << 8); - case 1: b = ((b & 0xf0f0f0f0) >> 4) | ((b & 0x0f0f0f0f) << 4); - b = ((b & 0xcccccccc) >> 2) | ((b & 0x33333333) << 2); - b = ((b & 0xaaaaaaaa) >> 1) | ((b & 0x55555555) << 1); + case 32: + b = ((b & 0xffff0000) >> 16) | ((b & 0x0000ffff) << 16); + case 16: + b = ((b & 0xff00ff00) >> 8) | ((b & 0x00ff00ff) << 8); + case 8: + b = ((b & 0xf0f0f0f0) >> 4) | ((b & 0x0f0f0f0f) << 4); + case 4: + b = ((b & 0xcccccccc) >> 2) | ((b & 0x33333333) << 2); + case 2: + b = ((b & 0xaaaaaaaa) >> 1) | ((b & 0x55555555) << 1); + case 1: + break; + default: + printk("DBRI reverse_bytes: unsupported length\n"); } return b; } +/* transmission_complete_intr() + * + * Called by main interrupt handler when DBRI signals transmission complete + * on a pipe. + * + * Walks through the pipe's list of transmit buffer descriptors, releasing + * each one's DMA buffer (if present) and signaling its callback routine + * (if present), before flaging the descriptor available and proceeding + * to the next one. + * + * Assumes that only the last in a chain of descriptors will have FINT + * sent to signal an interrupt, so that the chain will be completely + * transmitted by the time we get here, and there's no need to save + * any of the descriptors. In particular, use of the DBRI's CDP command + * is precluded, but I've not been able to get CDP working reliably anyway. + */ + +static void transmission_complete_intr(struct dbri *dbri, int pipe) +{ + int td = dbri->pipes[pipe].desc; + int status; + void *buffer; + void (*callback)(void *, int); + + dbri->pipes[pipe].desc = -1; + + for (; td >= 0; td = dbri->descs[td].next) { + + if (td >= DBRI_NO_DESCS) { + printk("DBRI: invalid td on pipe %d\n", pipe); + return; + } + + status = dbri->dma->desc[td].word4; + + buffer = dbri->descs[td].buffer; + if (buffer) { + mmu_release_scsi_one(sbus_dvma_addr(buffer), + dbri->descs[td].len, + dbri->sdev->my_bus); + } + + callback = dbri->descs[td].output_callback; + if (callback != NULL) { + callback(dbri->descs[td].output_callback_arg, + DBRI_TD_STATUS(status) & 0xe); + } + + dbri->descs[td].inuse = 0; + } +} + +static void reception_complete_intr(struct dbri *dbri, int pipe) +{ + int rd = dbri->pipes[pipe].desc; + int status; + void *buffer; + void (*callback)(void *, int, unsigned int); + + if (rd < 0 || rd >= DBRI_NO_DESCS) { + printk("DBRI: invalid rd on pipe %d\n", pipe); + return; + } + + dbri->descs[rd].inuse = 0; + dbri->pipes[pipe].desc = -1; + status = dbri->dma->desc[rd].word1; + + buffer = dbri->descs[rd].buffer; + if (buffer) { + mmu_release_scsi_one(sbus_dvma_addr(buffer), + dbri->descs[rd].len, + dbri->sdev->my_bus); + } + + callback = dbri->descs[rd].input_callback; + if (callback != NULL) { + callback(dbri->descs[rd].input_callback_arg, + DBRI_RD_STATUS(status), + DBRI_RD_CNT(status)-2); + } +} + +static void dbri_intr(int irq, void *opaque, struct pt_regs *regs) +{ + struct dbri *dbri = (struct dbri *)opaque; + int x; + + /* + * Read it, so the interrupt goes away. + */ + x = dbri->regs->reg1; + + if ( x & (D_MRR|D_MLE|D_LBG|D_MBE) ) { + /* + * What should I do here ? + */ + if(x & D_MRR) printk("DBRI: Multiple Error Ack on SBus\n"); + if(x & D_MLE) printk("DBRI: Multiple Late Error on SBus\n"); + if(x & D_LBG) printk("DBRI: Lost Bus Grant on SBus\n"); + if(x & D_MBE) printk("DBRI: Burst Error on SBus\n"); + } + + if (!(x & D_IR)) /* Not for us */ + return; + + x = dbri->dma->intr[dbri->dbri_irqp]; + while (x != 0) { + int val = D_INTR_GETVAL(x); + int channel = D_INTR_GETCHAN(x); + + dbri->dma->intr[dbri->dbri_irqp] = 0; + + if(D_INTR_GETCHAN(x) == D_INTR_CMD) { + dprintk(D_INT,("DBRI: INTR: Command: %-5s Value:%d\n", + cmds[D_INTR_GETCMD(x)], D_INTR_GETVAL(x))); + } else { + dprintk(D_INT,("DBRI: INTR: Chan:%d Code:%d Val:%#x\n", + D_INTR_GETCHAN(x), D_INTR_GETCODE(x), + D_INTR_GETRVAL(x))); + } + + if (D_INTR_GETCODE(x) == D_INTR_SBRI) { + + /* SBRI - BRI status change */ + + int liu_states[] = {1, 0, 8, 3, 4, 5, 6, 7}; + dbri->liu_state = liu_states[val & 0x7]; + if (dbri->liu_callback) + dbri->liu_callback(dbri->liu_callback_arg); + } + + if (D_INTR_GETCODE(x) == D_INTR_BRDY) { + reception_complete_intr(dbri, channel); + } + + if (D_INTR_GETCODE(x) == D_INTR_XCMP) { + transmission_complete_intr(dbri, channel); + } + + if (D_INTR_GETCODE(x) == D_INTR_FXDT) { + + /* FXDT - Fixed data change */ + + if (dbri->pipes[D_INTR_GETCHAN(x)].sdp & D_SDP_MSB) { + val = reverse_bytes(val, dbri->pipes[channel].length); + } + + if (dbri->pipes[D_INTR_GETCHAN(x)].recv_fixed_ptr) { + * dbri->pipes[channel].recv_fixed_ptr = val; + } + } + + + dbri->dbri_irqp++; + if (dbri->dbri_irqp == (DBRI_NO_INTS * DBRI_INT_BLK)) + dbri->dbri_irqp = 1; + else if ((dbri->dbri_irqp & (DBRI_INT_BLK-1)) == 0) + dbri->dbri_irqp++; + x = dbri->dma->intr[dbri->dbri_irqp]; + } +} + + +/* +**************************************************************************** +************************** DBRI data pipe management *********************** +**************************************************************************** +*/ + + +/* reset_pipe(dbri, pipe) + * + * Called on an in-use pipe to clear anything being transmitted or received + */ + +static void reset_pipe(struct dbri *dbri, int pipe) +{ + int sdp; + volatile int *cmd; + + if (pipe < 0 || pipe > 31) { + printk("DBRI: reset_pipe called with illegal pipe number\n"); + return; + } + + sdp = dbri->pipes[pipe].sdp; + if (sdp == 0) { + printk("DBRI: reset_pipe called on uninitialized pipe\n"); + return; + } + + cmd = dbri_cmdlock(dbri); + *(cmd++) = DBRI_CMD(D_SDP, 0, sdp | D_SDP_C | D_SDP_P); + *(cmd++) = 0; + dbri_cmdsend(dbri, cmd); + + dbri->pipes[pipe].desc = -1; +} + +static void setup_pipe(struct dbri *dbri, int pipe, int sdp) +{ + if (pipe < 0 || pipe > 31) { + printk("DBRI: setup_pipe called with illegal pipe number\n"); + return; + } + + if ((sdp & 0xf800) != sdp) { + printk("DBRI: setup_pipe called with strange SDP value\n"); + /* sdp &= 0xf800; */ + } + + sdp |= D_PIPE(pipe); + dbri->pipes[pipe].sdp = sdp; + + reset_pipe(dbri, pipe); +} + +enum master_or_slave { CHImaster, CHIslave }; + +static void reset_chi(struct dbri *dbri, enum master_or_slave master_or_slave, + int bits_per_frame) +{ + volatile int *cmd; + int val; + + cmd = dbri_cmdlock(dbri); + + /* Set CHI Anchor: Pipe 16 */ + + val = D_DTS_VI | D_DTS_VO | D_DTS_INS | + D_DTS_PRVIN(D_P_16) | D_DTS_PRVOUT(D_P_16) | D_PIPE(D_P_16); + *(cmd++) = DBRI_CMD(D_DTS, 0, val); + *(cmd++) = D_TS_ANCHOR | D_TS_NEXT(D_P_16); + *(cmd++) = D_TS_ANCHOR | D_TS_NEXT(D_P_16); + + dbri->pipes[16].sdp = 1; + dbri->pipes[16].nextpipe = 16; + + if (master_or_slave == CHIslave) { + /* Setup DBRI for CHI Slave - receive clock, frame sync (FS) + * + * CHICM = 0 (slave mode, 8 kHz frame rate) + * IR = give immediate CHI status interrupt + * EN = give CHI status interrupt upon change + */ + *(cmd++) = DBRI_CMD(D_CHI, 0, D_CHI_CHICM(0) + | D_CHI_IR | D_CHI_EN); + } else { + /* Setup DBRI for CHI Master - generate clock, FS + * + * BPF = bits per 8 kHz frame + * 12.288 MHz / CHICM_divisor = clock rate + * FD = 1 - drive CHIFS on rising edge of CHICK + */ + + int clockrate = bits_per_frame * 8; + int divisor = 12288 / clockrate; + + if (divisor > 255 || divisor * clockrate != 12288) { + printk("DBRI: illegal bits_per_frame in setup_chi\n"); + } + + *(cmd++) = DBRI_CMD(D_CHI, 0, D_CHI_CHICM(divisor) | D_CHI_FD + | D_CHI_IR | D_CHI_EN + | D_CHI_BPF(bits_per_frame)); + } + + /* CHI Data Mode + * + * RCE = 0 - receive on falling edge of CHICK + * XCE = 1 - transmit on rising edge of CHICK + * XEN = 1 - enable transmitter + * REN = 1 - enable receiver + */ + + *(cmd++) = DBRI_CMD(D_PAUSE, 0, 0); + + *(cmd++) = DBRI_CMD(D_CDM, 0, D_CDM_XCE|D_CDM_XEN|D_CDM_REN); + + dbri_cmdsend(dbri, cmd); +} + +enum in_or_out { PIPEinput, PIPEoutput }; + +static void link_time_slot(struct dbri *dbri, int pipe, + enum in_or_out direction, int prevpipe, + int length, int cycle) +{ + volatile int *cmd; + int val; + int nextpipe; + + if (pipe < 0 || pipe > 31 || prevpipe < 0 || prevpipe > 31) { + printk("DBRI: link_time_slot called with illegal pipe number\n"); + return; + } + + if (dbri->pipes[pipe].sdp == 0 || dbri->pipes[prevpipe].sdp == 0) { + printk("DBRI: link_time_slot called on uninitialized pipe\n"); + return; + } + + if (pipe == prevpipe) { + nextpipe = pipe; + } else { + nextpipe = dbri->pipes[prevpipe].nextpipe; + } + + dbri->pipes[pipe].nextpipe = nextpipe; + dbri->pipes[pipe].cycle = cycle; + dbri->pipes[pipe].length = length; + + cmd = dbri_cmdlock(dbri); + + if (direction == PIPEinput) { + val = D_DTS_VI | D_DTS_INS | D_DTS_PRVIN(prevpipe) | pipe; + *(cmd++) = DBRI_CMD(D_DTS, 0, val); + *(cmd++) = D_TS_LEN(length) | D_TS_CYCLE(cycle) | D_TS_NEXT(nextpipe); + *(cmd++) = 0; + } else { + val = D_DTS_VO | D_DTS_INS | D_DTS_PRVOUT(prevpipe) | pipe; + *(cmd++) = DBRI_CMD(D_DTS, 0, val); + *(cmd++) = 0; + *(cmd++) = D_TS_LEN(length) | D_TS_CYCLE(cycle) | D_TS_NEXT(nextpipe); + } + + dbri_cmdsend(dbri, cmd); +} + +static void xmit_fixed(struct dbri *dbri, int pipe, unsigned int data) +{ + volatile int *cmd; + + if (pipe < 16 || pipe > 31) { + printk("DBRI: xmit_fixed called with illegal pipe number\n"); + return; + } + + if (D_SDP_MODE(dbri->pipes[pipe].sdp) != D_SDP_FIXED) { + printk("DBRI: xmit_fixed called on non-fixed pipe\n"); + return; + } + + if (! dbri->pipes[pipe].sdp & D_SDP_TO_SER) { + printk("DBRI: xmit_fixed called on receive pipe\n"); + return; + } + + /* DBRI short pipes always transmit LSB first */ + + if (dbri->pipes[pipe].sdp & D_SDP_MSB) { + data = reverse_bytes(data, dbri->pipes[pipe].length); + } + + cmd = dbri_cmdlock(dbri); + + *(cmd++) = DBRI_CMD(D_SSP, 0, pipe); + *(cmd++) = data; + + dbri_cmdsend(dbri, cmd); +} + +/* recv_fixed() + * + * Receive data on a "fixed" pipe - i.e, one whose contents are not + * expected to change much, and which we don't need to read constantly + * into a buffer. The DBRI only interrupts us when the data changes. + * Only short pipes (numbers 16-31) can be used in fixed data mode. + * + * Pass this function a pointer to a 32-bit field, no matter how large + * the actual time slot is. The interrupt handler takes care of bit + * ordering and alignment. An 8-bit time slot will always end up + * in the low-order 8 bits, filled either MSB-first or LSB-first, + * depending on the settings passed to setup_pipe() + */ + +static void recv_fixed(struct dbri *dbri, int pipe, __u32 *ptr) +{ + if (pipe < 16 || pipe > 31) { + printk("DBRI: recv_fixed called with illegal pipe number\n"); + return; + } + + if (D_SDP_MODE(dbri->pipes[pipe].sdp) != D_SDP_FIXED) { + printk("DBRI: recv_fixed called on non-fixed pipe\n"); + return; + } + + if (dbri->pipes[pipe].sdp & D_SDP_TO_SER) { + printk("DBRI: recv_fixed called on transmit pipe\n"); + return; + } + + dbri->pipes[pipe].recv_fixed_ptr = ptr; +} + + +static void xmit_on_pipe(struct dbri *dbri, int pipe, + void * buffer, unsigned int len, + void (*callback)(void *, int), void * callback_arg) +{ + volatile int *cmd; + int td = 0; + int first_td = -1; + int last_td; + __u32 dvma_buffer; + + if (pipe < 0 || pipe > 15) { + printk("DBRI: xmit_on_pipe called with illegal pipe number\n"); + return; + } + + if (dbri->pipes[pipe].sdp == 0) { + printk("DBRI: xmit_on_pipe called on uninitialized pipe\n"); + return; + } + + if (! dbri->pipes[pipe].sdp & D_SDP_TO_SER) { + printk("DBRI: xmit_on_pipe called on receive pipe\n"); + return; + } + + /* XXX Fix this XXX + * Should be able to queue multiple buffers to send on a pipe + */ + + if (dbri->pipes[pipe].desc != -1) { + printk("DBRI: xmit_on_pipe called on active pipe\n"); + return; + } + + dvma_buffer = mmu_get_scsi_one(buffer, len, dbri->sdev->my_bus); + + while (len > 0) { + int mylen; + + for (td; td < DBRI_NO_DESCS; td ++) { + if (! dbri->descs[td].inuse) break; + } + if (td == DBRI_NO_DESCS) { + break; + } + + if (len > (1 << 13) - 1) { + mylen = (1 << 13) - 1; + } else { + mylen = len; + } + + dbri->descs[td].inuse = 1; + dbri->descs[td].next = -1; + dbri->descs[td].buffer = NULL; + dbri->descs[td].output_callback = NULL; + dbri->descs[td].input_callback = NULL; + + dbri->dma->desc[td].word1 = DBRI_TD_CNT(mylen); + dbri->dma->desc[td].ba = dvma_buffer; + dbri->dma->desc[td].nda = 0; + dbri->dma->desc[td].word4 = 0; + + if (first_td == -1) { + first_td = td; + } else { + dbri->descs[last_td].next = td; + dbri->dma->desc[last_td].nda = + (int) & dbri->dma_dvma->desc[td]; + } + + last_td = td; + dvma_buffer += mylen; + len -= mylen; + } + + if (first_td == -1) { + printk("xmit_on_pipe: No descriptors available\n"); + return; + } + + if (len > 0) { + printk("xmit_on_pipe: Insufficient descriptors; data truncated\n"); + } + + dbri->dma->desc[last_td].word1 |= DBRI_TD_I | DBRI_TD_F | DBRI_TD_B; + + dbri->descs[last_td].buffer = buffer; + dbri->descs[last_td].len = len; + dbri->descs[last_td].output_callback = callback; + dbri->descs[last_td].output_callback_arg = callback_arg; + + dbri->pipes[pipe].desc = first_td; + + cmd = dbri_cmdlock(dbri); + + *(cmd++) = DBRI_CMD(D_SDP, 0, dbri->pipes[pipe].sdp | D_SDP_P | D_SDP_C); + *(cmd++) = (int) & dbri->dma_dvma->desc[first_td]; + + dbri_cmdsend(dbri, cmd); +} + +static void recv_on_pipe(struct dbri *dbri, int pipe, + void * buffer, unsigned int len, + void (*callback)(void *, int, unsigned int), + void * callback_arg) +{ + volatile int *cmd; + int rd; + + if (pipe < 0 || pipe > 15) { + printk("DBRI: recv_on_pipe called with illegal pipe number\n"); + return; + } + + if (dbri->pipes[pipe].sdp == 0) { + printk("DBRI: recv_on_pipe called on uninitialized pipe\n"); + return; + } + + if (dbri->pipes[pipe].sdp & D_SDP_TO_SER) { + printk("DBRI: recv_on_pipe called on transmit pipe\n"); + return; + } + + /* XXX Fix this XXX + * Should be able to queue multiple buffers to send on a pipe + */ + + if (dbri->pipes[pipe].desc != -1) { + printk("DBRI: recv_on_pipe called on active pipe\n"); + return; + } + + /* XXX Fix this XXX + * Use multiple descriptors, if needed, to fit in all the data + */ + + if (len > (1 << 13) - 1) { + printk("recv_on_pipe called with len=%d; truncated\n", len); + len = (1 << 13) - 1; + } + + /* Make sure buffer size is multiple of four */ + len &= ~3; + + for (rd = 0; rd < DBRI_NO_DESCS; rd ++) { + if (! dbri->descs[rd].inuse) break; + } + if (rd == DBRI_NO_DESCS) { + printk("DBRI xmit_on_pipe: No descriptors available\n"); + return; + } + + dbri->dma->desc[rd].word1 = 0; + dbri->dma->desc[rd].ba = mmu_get_scsi_one(buffer, len, + dbri->sdev->my_bus); + dbri->dma->desc[rd].nda = 0; + dbri->dma->desc[rd].word4 = DBRI_RD_B | DBRI_RD_BCNT(len); + + dbri->descs[rd].buffer = buffer; + dbri->descs[rd].len = len; + dbri->descs[rd].input_callback = callback; + dbri->descs[rd].input_callback_arg = callback_arg; + + dbri->pipes[pipe].desc = rd; + + cmd = dbri_cmdlock(dbri); + + *(cmd++) = DBRI_CMD(D_SDP, 0, dbri->pipes[pipe].sdp | D_SDP_P); + *(cmd++) = (int) & dbri->dma_dvma->desc[rd]; + + dbri_cmdsend(dbri, cmd); +} + + +/* +**************************************************************************** +*********************** CS4215 audio codec management ********************** +**************************************************************************** +*/ static void mmcodec_default(struct cs4215 *mm) @@ -266,7 +869,7 @@ * Control Time Slot 1-4 * 0: Default I/O voltage scale * 1: 8 bit ulaw, 8kHz, mono, high pass filter disabled - * 2: Serial enable, CHI master, 1 CHI device (64bit), clock 1 + * 2: Serial enable, CHI master, 128 bits per frame, clock 1 * 3: Tests disabled */ mm->ctrl[0] = CS4215_RSRVD_1; @@ -278,10 +881,6 @@ static void mmcodec_init_data(struct dbri *dbri) { - int val, n; - - n = dbri_cmdlock(dbri); - /* * Data mode: * Pipe 4: Send timeslots 1-4 (audio data) @@ -295,80 +894,27 @@ * bits. The CS4215, it seems, observes TSIN (the delayed signal) * even if it's the CHI master. Don't ask me... */ - - - /* Pipe 4: SDP */ - val = D_SDP_MEM|D_SDP_TO_SER|D_SDP_C|D_SDP_P|D_SDP_MSB|D_PIPE(D_P_4); - dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val); - dbri->cmd[n++] = 0; - - - /* Pipe 17: SDP */ - val = D_SDP_FIXED|D_SDP_TO_SER|D_SDP_C|D_PIPE(D_P_17); - dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val); - dbri->cmd[n++] = 0; /* Fixed data */ - - /* Pipe 17: SSP */ - dbri->cmd[n++] = DBRI_CMD(D_SSP, 0, D_PIPE(D_P_17)); - dbri->cmd[n++] = reverse_bytes(*(int *)dbri->mm.data, 4); - - - /* Pipe 6: SDP */ - val=D_SDP_MEM|D_SDP_FROM_SER|D_SDP_C|D_SDP_P|D_SDP_MSB|D_PIPE(D_P_6); - dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val); - dbri->cmd[n++] = 0; - - - /* Pipe 20: SDP */ - val = D_SDP_FIXED|D_SDP_FROM_SER|D_SDP_CHANGE|D_SDP_C|D_PIPE(D_P_20); - dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val); - dbri->cmd[n++] = 0; /* Fixed data */ - - dbri->cmd[n++] = DBRI_CMD(D_PAUSE, 0, 0); + /* Switch CS4215 to data mode - set PIO3 to 1 */ + dbri->regs->reg2 = D_ENPIO | D_PIO1 | D_PIO3 | + (dbri->mm.onboard ? D_PIO0 : D_PIO2); + reset_chi(dbri, CHIslave, 0); - /* Pipe 4: DTS */ - val = D_DTS_VO | D_DTS_INS | D_DTS_PRVOUT(D_P_16) | D_PIPE(D_P_4); - dbri->cmd[n++] = DBRI_CMD(D_DTS, 0, val); - dbri->cmd[n++] = 0; -#if 0 - /* Full blown, four time slots, 16 bit stereo */ - dbri->cmd[n++] = D_TS_LEN(32) | D_TS_CYCLE(8)| D_TS_NEXT(D_P_16); -#else - /* Single time slot, 8 bit mono */ - dbri->cmd[n++] = D_TS_LEN(8) | D_TS_CYCLE(8)| D_TS_NEXT(D_P_16); -#endif + setup_pipe(dbri, 4, D_SDP_MEM | D_SDP_TO_SER | D_SDP_MSB); + setup_pipe(dbri, 17, D_SDP_FIXED | D_SDP_TO_SER | D_SDP_MSB); + setup_pipe(dbri, 6, D_SDP_MEM | D_SDP_FROM_SER | D_SDP_MSB); + setup_pipe(dbri, 20, D_SDP_FIXED | D_SDP_FROM_SER | D_SDP_MSB); - /* Pipe 17: DTS */ - val = D_DTS_VO | D_DTS_INS | D_DTS_PRVOUT(D_P_4) | D_PIPE(D_P_17); - dbri->cmd[n++] = DBRI_CMD(D_DTS, 0, val); - dbri->cmd[n++] = 0; - dbri->cmd[n++] = D_TS_LEN(32) | D_TS_CYCLE(40) | D_TS_NEXT(D_P_16); - - /* Pipe 6: DTS */ - val = D_DTS_VI | D_DTS_INS | D_DTS_PRVIN(D_P_16) | D_PIPE(D_P_6); - dbri->cmd[n++] = DBRI_CMD(D_DTS, 0, val); -#if 0 - /* Full blown, four time slots, 16 bit stereo */ - dbri->cmd[n++] = D_TS_LEN(32) | D_TS_CYCLE(8)| D_TS_NEXT(D_P_16); -#else - /* Single time slot, 8 bit mono */ - dbri->cmd[n++] = D_TS_LEN(8) | D_TS_CYCLE(8)| D_TS_NEXT(D_P_16); -#endif - dbri->cmd[n++] = 0; - - /* Pipe 20: DTS */ - val = D_DTS_VI | D_DTS_INS | D_DTS_PRVIN(D_P_6) | D_PIPE(D_P_20); - dbri->cmd[n++] = DBRI_CMD(D_DTS, 0, val); - dbri->cmd[n++] = D_TS_LEN(16) | D_TS_CYCLE(48) | D_TS_NEXT(D_P_16); - dbri->cmd[n++] = 0; + /* Pipes 4 and 6 - Single time slot, 8 bit mono */ - /* CHI: Slave mode; enable interrupts */ - dbri->cmd[n++] = DBRI_CMD(D_CHI, 0, D_CHI_CHICM(0) | D_CHI_IR | D_CHI_EN); + link_time_slot(dbri, 17, PIPEoutput, 16, 32, 32); + link_time_slot(dbri, 4, PIPEoutput, 17, 8, 128); + link_time_slot(dbri, 6, PIPEinput, 16, 8, 0); + link_time_slot(dbri, 20, PIPEinput, 6, 16, 40); - dbri_cmdsend(dbri, n); + xmit_fixed(dbri, 17, *(int *)dbri->mm.data); } @@ -377,7 +923,7 @@ */ static void mmcodec_setctrl(struct dbri *dbri) { - int n, val; + int i, val; /* * Enable Control mode: Set DBRI's PIO3 (4215's D/~C) to 0, then wait @@ -398,15 +944,15 @@ * into Data mode and put the DBRI into slave mode. Various timing * requirements must be observed along the way. * - * Oh, and one more thing - when the DBRI is master (and only when - * the DBRI is master), the addressing of the CS4215's time slots - * is offset by eight bits, so we add eight to all the "cycle" - * values in the Define Time Slot (DTS) commands. This is done in - * hardware by a TI 248 that delays the DBRI->4215 frame sync signal - * by eight clock cycles. Anybody know why? + * Oh, and one more thing, on a SPARCStation 20 (and maybe + * others?), the addressing of the CS4215's time slots is + * offset by eight bits, so we add eight to all the "cycle" + * values in the Define Time Slot (DTS) commands. This is + * done in hardware by a TI 248 that delays the DBRI->4215 + * frame sync signal by eight clock cycles. Anybody know why? */ - n = dbri_cmdlock(dbri); + reset_chi(dbri, CHImaster, 128); /* * Control mode: @@ -415,472 +961,325 @@ * Pipe 19: Receive timeslot 7 (version). */ - /* Set CHI Anchor: Pipe 16. This should take care of the rest. */ - val = D_DTS_VI | D_DTS_VO | D_DTS_INS | - D_DTS_PRVIN(D_P_16) | D_DTS_PRVOUT(D_P_16) | D_PIPE(D_P_16); - dbri->cmd[n++] = DBRI_CMD(D_DTS, 0, val); - dbri->cmd[n++] = D_TS_ANCHOR | D_TS_NEXT(D_P_16); - dbri->cmd[n++] = D_TS_ANCHOR | D_TS_NEXT(D_P_16); - - - /* Setup the pipes first */ - val = D_SDP_FIXED|D_SDP_TO_SER|D_SDP_P|D_SDP_C|D_PIPE(D_P_17); - dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val); - dbri->cmd[n++] = 0; - - val = D_SDP_FIXED|D_SDP_CHANGE|D_SDP_C|D_PIPE(D_P_18); - dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val); - dbri->cmd[n++] = 0; - - val = D_SDP_FIXED|D_SDP_CHANGE|D_SDP_C|D_PIPE(D_P_19); - dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val); - dbri->cmd[n++] = 0; + setup_pipe(dbri, 17, D_SDP_FIXED | D_SDP_TO_SER | D_SDP_MSB); + setup_pipe(dbri, 18, D_SDP_FIXED | D_SDP_CHANGE | D_SDP_MSB); + setup_pipe(dbri, 19, D_SDP_FIXED | D_SDP_CHANGE | D_SDP_MSB); + + link_time_slot(dbri, 17, PIPEoutput, 16, 32, 128); + link_time_slot(dbri, 18, PIPEinput, 16, 8, 0); + link_time_slot(dbri, 19, PIPEinput, 18, 8, 48); + + recv_fixed(dbri, 18, & dbri->mm.status); + recv_fixed(dbri, 19, & dbri->mm.version); + + /* Wait for the chip to echo back CLB (Control Latch Bit) as zero */ - /* Fill in the data to send */ dbri->mm.ctrl[0] &= ~CS4215_CLB; - dbri->cmd[n++] = DBRI_CMD(D_SSP, 0, D_PIPE(D_P_17)); - dbri->cmd[n++] = reverse_bytes(*(int *)dbri->mm.ctrl, 4); + xmit_fixed(dbri, 17, *(int *)dbri->mm.ctrl); - dbri->cmd[n++] = DBRI_CMD(D_PAUSE, 0, 0); + i = 1000000; + while ((! dbri->mm.status & CS4215_CLB) && i--); + if (i == 0) { + printk("CS4215 didn't respond to CLB\n"); + return; + } + /* Terminate CS4215 control mode - data sheet says + * "Set CLB=1 and send two more frames of valid control info" + */ + dbri->mm.ctrl[0] |= CS4215_CLB; + xmit_fixed(dbri, 17, *(int *)dbri->mm.ctrl); - /* Link the timeslots */ + /* Two frames of control info @ 8kHz frame rate = 250 us delay */ + udelay(250); +} - /* Pipe 17 - CS4215 Status, Data Format, Serial Control, Test - output - * time slots 1, 2, 3 and 4 - 32 bits - */ +static int mmcodec_init(struct sparcaudio_driver *drv) +{ + struct dbri *dbri = (struct dbri *)drv->private; + int reg2 = dbri->regs->reg2; - val = D_DTS_VO | D_DTS_INS | D_DTS_PRVOUT(D_P_16) | D_PIPE(D_P_17); - dbri->cmd[n++] = DBRI_CMD(D_DTS, 0, val); - dbri->cmd[n++] = 0; - dbri->cmd[n++] = D_TS_LEN(32) | D_TS_CYCLE(8) | D_TS_NEXT(D_P_16); - /* Pipe 18 - CS4215 Status and Data Format - input - * time slots 1 & 2 - 16 bits - */ + /* Look for the cs4215 chips */ + if(reg2 & D_PIO2) { + dprintk(D_MM, ("DBRI: Onboard CS4215 detected\n")); + dbri->mm.onboard = 1; + } + if(reg2 & D_PIO0) { + dprintk(D_MM, ("DBRI: Speakerbox detected\n")); + dbri->mm.onboard = 0; + } + - val = D_DTS_VI | D_DTS_INS | D_DTS_PRVIN(D_P_16) | D_PIPE(D_P_18); - dbri->cmd[n++] = DBRI_CMD(D_DTS, 0, val); - dbri->cmd[n++] = D_TS_LEN(16) | D_TS_CYCLE(8) | D_TS_NEXT(D_P_16); - dbri->cmd[n++] = 0; + /* Using the Speakerbox, if both are attached. */ + if((reg2 & D_PIO2) && (reg2 & D_PIO0)) { + printk("DBRI: Using speakerbox / ignoring onboard mmcodec.\n"); + dbri->regs->reg2 = D_ENPIO2; + dbri->mm.onboard = 0; + } + if( !(reg2 & (D_PIO0|D_PIO2)) ) { + printk("DBRI: no mmcodec found.\n"); + return -EIO; + } - /* Pipe 19 - CS4215 Revision - time slot 7, eight bits - input - */ - val = D_DTS_VI | D_DTS_INS | D_DTS_PRVIN(D_P_18) | D_PIPE(D_P_19); - dbri->cmd[n++] = DBRI_CMD(D_DTS, 0, val); - dbri->cmd[n++] = D_TS_LEN(8) | D_TS_CYCLE(56) | D_TS_NEXT(D_P_16); - dbri->cmd[n++] = 0; + /* Now talk to our baby */ + dbri->regs->reg0 |= D_C; /* Enable CHI */ + mmcodec_default(&dbri->mm); - /* Setup DBRI for CHI Master - * - * BPF = 128 (128 bits per 8 kHz frame = 1.024 MHz clock rate) - * CHICM = 12 (12.288 MHz / 24 = 1.024 MHz clock rate) - * FD = 1 - drive CHIFS on rising edge of CHICK - * - * RCE = 0 - receive on falling edge of CHICK - * XCE = 1 - transmit on rising edge of CHICK - */ - dbri->cmd[n++] = DBRI_CMD(D_CHI, 0, D_CHI_CHICM(12) | D_CHI_FD | - D_CHI_IR | D_CHI_EN | D_CHI_BPF(128)); - dbri->cmd[n++] = DBRI_CMD(D_CDM, 0, D_CDM_XCE|D_CDM_XEN|D_CDM_REN); - dbri->cmd[n++] = DBRI_CMD(D_PAUSE, 0, 0); + dbri->mm.version = 0xff; + mmcodec_setctrl(dbri); + if(dbri->mm.version == 0xff) + return -EIO; - /* Wait for the command to complete */ - dbri_cmdsend(dbri, n); + mmcodec_init_data(dbri); - /* Switch CS4215 to data mode - data sheet says - * "Set CLB=1 and send two more frames of valid control info" - */ - n = dbri_cmdlock(dbri); + return 0; +} - dbri->mm.ctrl[0] |= CS4215_CLB; - dbri->cmd[n++] = DBRI_CMD(D_SSP, 0, D_PIPE(D_P_17)); - dbri->cmd[n++] = reverse_bytes(*(int *)dbri->mm.ctrl, 4); - dbri_cmdsend(dbri, n); +/* +**************************************************************************** +******************** Interface with sparcaudio midlevel ******************** +**************************************************************************** +*/ - /* Two frames of control info @ 8kHz frame rate = 250 us delay */ - udelay(250); - n = dbri_cmdlock(dbri); +static int dbri_open(struct inode * inode, struct file * file, + struct sparcaudio_driver *drv) +{ + struct dbri *dbri = (struct dbri *)drv->private; - /* Now switch back to data mode */ - /* Reset CHI Anchor: Stop Send/Receive */ - val = D_DTS_VI | D_DTS_VO | D_DTS_INS | - D_DTS_PRVIN(D_P_16) | D_DTS_PRVOUT(D_P_16) | D_PIPE(D_P_16); - dbri->cmd[n++] = DBRI_CMD(D_DTS, 0, val); - dbri->cmd[n++] = D_TS_ANCHOR | D_TS_NEXT(D_P_16); - dbri->cmd[n++] = D_TS_ANCHOR | D_TS_NEXT(D_P_16); + MOD_INC_USE_COUNT; + return 0; +} - /* Setup DBRI for CHI Slave */ - dbri->cmd[n++] = DBRI_CMD(D_CHI, 0, D_CHI_CHICM(0)); - /* dbri->cmd[n++] = DBRI_CMD(D_CHI, 0, D_CHI_CHICM(0) | D_CHI_IR | D_CHI_EN); */ - dbri->cmd[n++] = DBRI_CMD(D_PAUSE, 0, 0x16); +static void dbri_release(struct inode * inode, struct file * file, + struct sparcaudio_driver *drv) +{ + MOD_DEC_USE_COUNT; +} +static int dbri_ioctl(struct inode * inode, struct file * file, + unsigned int x, unsigned long y, + struct sparcaudio_driver *drv) +{ + return 0; +} - /* Wait for command to complete */ - dbri_cmdsend(dbri, n); +static void dbri_audio_output_callback(void * callback_arg, int status) +{ + struct sparcaudio_driver *drv = callback_arg; - /* Switch CS4215 to data mode - set PIO3 to 1 */ - dbri->regs->reg2 = D_ENPIO | D_PIO1 | D_PIO3 | - (dbri->mm.onboard ? D_PIO0 : D_PIO2); + sparcaudio_output_done(drv, 1); } -static int mmcodec_init(struct sparcaudio_driver *drv) +static void dbri_start_output(struct sparcaudio_driver *drv, + __u8 * buffer, unsigned long count) { struct dbri *dbri = (struct dbri *)drv->private; - int reg2 = dbri->regs->reg2; - - /* Look for the cs4215 chips */ - if(reg2 & D_PIO2) { - dprintk(D_MM, ("DBRI: Onboard CS4215 detected\n")); - dbri->mm.onboard = 1; - } - if(reg2 & D_PIO0) { - dprintk(D_MM, ("DBRI: Speakerbox detected\n")); - dbri->mm.onboard = 0; - } - + /* Pipe 4 is audio transmit */ + xmit_on_pipe(dbri, 4, buffer, count, &dbri_audio_output_callback, drv); +} - /* Using the Speakerbox, if both are attached. */ - if((reg2 & D_PIO2) && (reg2 & D_PIO0)) { - printk("DBRI: Using speakerbox / ignoring onboard mmcodec.\n"); - dbri->regs->reg2 = D_ENPIO2; - dbri->mm.onboard = 0; - } - if( !(reg2 & (D_PIO0|D_PIO2)) ) { - printk("DBRI: no mmcodec found.\n"); - return -EIO; - } +static void dbri_stop_output(struct sparcaudio_driver *drv) +{ + struct dbri *dbri = (struct dbri *)drv->private; + reset_pipe(dbri, 4); +} - /* Now talk to our baby */ - dbri->regs->reg0 |= D_C; /* Enable CHI */ +static void dbri_start_input(struct sparcaudio_driver *drv, + __u8 * buffer, unsigned long len) +{ +} - mmcodec_default(&dbri->mm); +static void dbri_stop_input(struct sparcaudio_driver *drv) +{ +} - dbri->mm.version = 0xff; - mmcodec_setctrl(dbri); - if(dbri->mm.version == 0xff) - return -EIO; +static void dbri_audio_getdev(struct sparcaudio_driver *drv, + audio_device_t *devptr) +{ +} - mmcodec_init_data(dbri); +static int dbri_set_output_volume(struct sparcaudio_driver *drv, int volume) +{ + return 0; +} - return 0; +static int dbri_get_output_volume(struct sparcaudio_driver *drv) +{ + return 0; } -void dbri_isdn_init(struct dbri *dbri) +static int dbri_set_input_volume(struct sparcaudio_driver *drv, int volume) { - int n, val; + return 0; +} - /* Pipe 0: Receive D channel - * Pipe 8: Receive B1 channel - * Pipe 9: Receive B2 channel - * Pipe 1: Transmit D channel - * Pipe 10: Transmit B1 channel - * Pipe 11: Transmit B2 channel - */ +static int dbri_get_input_volume(struct sparcaudio_driver *drv) +{ + return 0; +} - n = dbri_cmdlock(dbri); +static int dbri_set_monitor_volume(struct sparcaudio_driver *drv, int volume) +{ + return 0; +} - /* Pipe 0: SDP */ - val = D_SDP_HDLC|D_SDP_FROM_SER|D_SDP_C|D_SDP_P|D_SDP_LSB|D_PIPE(D_P_0); - dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val); - dbri->cmd[n++] = 0; - - /* Pipe 8: SDP */ - val = D_SDP_HDLC|D_SDP_FROM_SER|D_SDP_C|D_SDP_P|D_SDP_LSB|D_PIPE(D_P_8); - dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val); - dbri->cmd[n++] = 0; - - /* Pipe 9: SDP */ - val = D_SDP_HDLC|D_SDP_FROM_SER|D_SDP_C|D_SDP_P|D_SDP_LSB|D_PIPE(D_P_9); - dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val); - dbri->cmd[n++] = 0; - - /* Pipe 1: SDP */ - val = D_SDP_HDLC_D|D_SDP_TO_SER|D_SDP_C|D_SDP_P|D_SDP_LSB|D_PIPE(D_P_1); - dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val); - dbri->cmd[n++] = 0; - - /* Pipe 10: SDP */ - val = D_SDP_HDLC|D_SDP_TO_SER|D_SDP_C|D_SDP_P|D_SDP_LSB|D_PIPE(D_P_10); - dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val); - dbri->cmd[n++] = 0; - - /* Pipe 11: SDP */ - val = D_SDP_HDLC|D_SDP_TO_SER|D_SDP_C|D_SDP_P|D_SDP_LSB|D_PIPE(D_P_11); - dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val); - dbri->cmd[n++] = 0; - - - dbri->cmd[n++] = DBRI_CMD(D_PAUSE, 0, 0); - - /* Pipe 0: DTS */ - val = D_DTS_VI | D_DTS_INS | D_DTS_PRVIN(D_P_0) | D_PIPE(D_P_0); - dbri->cmd[n++] = DBRI_CMD(D_DTS, 0, val); - dbri->cmd[n++] = D_TS_LEN(2) | D_TS_CYCLE(17)| D_TS_NEXT(D_P_0); - dbri->cmd[n++] = 0; - - /* Pipe 8: DTS */ - val = D_DTS_VI | D_DTS_INS | D_DTS_PRVIN(D_P_0) | D_PIPE(D_P_8); - dbri->cmd[n++] = DBRI_CMD(D_DTS, 0, val); - dbri->cmd[n++] = D_TS_LEN(8) | D_TS_CYCLE(0)| D_TS_NEXT(D_P_0); - dbri->cmd[n++] = 0; - - /* Pipe 9: DTS */ - val = D_DTS_VI | D_DTS_INS | D_DTS_PRVIN(D_P_8) | D_PIPE(D_P_9); - dbri->cmd[n++] = DBRI_CMD(D_DTS, 0, val); - dbri->cmd[n++] = D_TS_LEN(8) | D_TS_CYCLE(8)| D_TS_NEXT(D_P_0); - dbri->cmd[n++] = 0; - - /* Pipe 1: DTS */ - val = D_DTS_VO | D_DTS_INS | D_DTS_PRVOUT(D_P_1) | D_PIPE(D_P_1); - dbri->cmd[n++] = DBRI_CMD(D_DTS, 0, val); - dbri->cmd[n++] = 0; - dbri->cmd[n++] = D_TS_LEN(2) | D_TS_CYCLE(17)| D_TS_NEXT(D_P_1); - - /* Pipe 10: DTS */ - val = D_DTS_VO | D_DTS_INS | D_DTS_PRVOUT(D_P_1) | D_PIPE(D_P_10); - dbri->cmd[n++] = DBRI_CMD(D_DTS, 0, val); - dbri->cmd[n++] = 0; - dbri->cmd[n++] = D_TS_LEN(8) | D_TS_CYCLE(0)| D_TS_NEXT(D_P_1); - - /* Pipe 11: DTS */ - val = D_DTS_VO | D_DTS_INS | D_DTS_PRVOUT(D_P_10) | D_PIPE(D_P_11); - dbri->cmd[n++] = DBRI_CMD(D_DTS, 0, val); - dbri->cmd[n++] = 0; - dbri->cmd[n++] = D_TS_LEN(8) | D_TS_CYCLE(8)| D_TS_NEXT(D_P_1); +static int dbri_get_monitor_volume(struct sparcaudio_driver *drv) +{ + return 0; +} +static int dbri_set_output_balance(struct sparcaudio_driver *drv, int balance) +{ + return 0; +} - /* Wait for command to complete */ - dbri_cmdsend(dbri, n); +static int dbri_get_output_balance(struct sparcaudio_driver *drv) +{ + return 0; } -void dbri_intr(int irq, void *dev_id, struct pt_regs *regs) +static int dbri_set_input_balance(struct sparcaudio_driver *drv, int balance) { - struct sparcaudio_driver *drv = (struct sparcaudio_driver *)dev_id; - struct dbri *dbri = (struct dbri *)drv->private; - int x, val; - static int numint = 0; - - /* - * Read it, so the interrupt goes away. - */ - x = dbri->regs->reg1; -#if 0 - if(numint++ > 20) { - dbri->regs->reg0 = D_R; /* Soft Reset */ - numint = 0; - printk("Soft reset\n"); - } -#endif + return 0; +} - if ( x & (D_MRR|D_MLE|D_LBG|D_MBE) ) { - /* - * What should I do here ? - */ - if(x & D_MRR) printk("DBRI: Multiple Error Ack on SBus\n"); - if(x & D_MLE) printk("DBRI: Multiple Late Error on SBus\n"); - if(x & D_LBG) printk("DBRI: Lost Bus Grant on SBus\n"); - if(x & D_MBE) printk("DBRI: Burst Error on SBus\n"); - } +static int dbri_get_input_balance(struct sparcaudio_driver *drv) +{ + return 0; +} - if (!(x & D_IR)) /* Not for us */ - return; +static int dbri_set_output_channels(struct sparcaudio_driver *drv, int chan) +{ + return 0; +} - x = dbri->intr[dbri->dbri_irqp]; - while (x != 0) { - dbri->intr[dbri->dbri_irqp] = 0; +static int dbri_get_output_channels(struct sparcaudio_driver *drv) +{ + return 0; +} - if(D_INTR_GETCHAN(x) == D_INTR_CMD) { - dprintk(D_INT,("DBRI: INTR: Command: %-5s Value:%d\n", - cmds[D_INTR_GETCMD(x)], D_INTR_GETVAL(x))); - } else { - dprintk(D_INT,("DBRI: INTR: Chan:%d Code:%d Val:%#x\n", - D_INTR_GETCHAN(x), D_INTR_GETCODE(x), - D_INTR_GETRVAL(x))); - } +static int dbri_set_input_channels(struct sparcaudio_driver *drv, int chan) +{ + return 0; +} - val = D_INTR_GETVAL(x); +static int dbri_get_input_channels(struct sparcaudio_driver *drv) +{ + return 0; +} - if (D_INTR_GETCODE(x) == D_INTR_SBRI) { - int liu_states[] = {1, 0, 8, 3, 4, 5, 6, 7}; - dbri->liu_state = liu_states[val & 0x7]; - if (dbri->liu_callback) - dbri->liu_callback(dbri->liu_callback_arg); - } +static int dbri_set_output_precision(struct sparcaudio_driver *drv, int prec) +{ + return 8; +} - switch(D_INTR_GETCHAN(x)) { - case D_INTR_CMD: -#if 0 - if(D_INTR_GETCMD(x) == D_WAIT) - if(val == WAIT_INTR1) { - dbri_cmdlocked = 0; - wake_up(&dbri->wait); - } - if(val == WAIT_INTR2) - wake_up(&dbri->int_wait); -#endif - break; +static int dbri_get_output_precision(struct sparcaudio_driver *drv) +{ + return 8; +} - case D_P_0: - /* Pipe 0 - D channel receive */ - if (D_INTR_GETCODE(x) == D_INTR_BRDY && - dbri->D.input_callback) { - dbri->D.input_callback(dbri->D.input_callback_arg, - DBRI_RD_STATUS(dbri->D.rd.flags), - DBRI_RD_CNT(dbri->D.rd.flags)-2); - } - break; - - case D_P_1: - /* Pipe 1 - D channel transmit */ - if (D_INTR_GETCODE(x) == D_INTR_XCMP && - dbri->D.output_callback) { - dbri->D.output_callback(dbri->D.output_callback_arg, - DBRI_TD_STATUS(dbri->D.rd.flags)&0xe); - } - break; - - case D_P_4: - /* Pipe 4 - audio transmit */ - if (D_INTR_GETCODE(x) == D_INTR_XCMP) { - sparcaudio_output_done(output_callback_arg, 1); - } - break; - - case D_P_8: - /* Pipe 8 - B1 channel receive */ - if (D_INTR_GETCODE(x) == D_INTR_BRDY && - dbri->B[0].input_callback) { - dbri->B[0].input_callback(dbri->B[0].input_callback_arg, - DBRI_RD_STATUS(dbri->B[0].rd.flags), - DBRI_RD_CNT(dbri->B[0].rd.flags)-2); - } - break; - - case D_P_9: - /* Pipe 9 - B2 channel receive */ - if (D_INTR_GETCODE(x) == D_INTR_BRDY && - dbri->B[1].input_callback) { - dbri->B[1].input_callback(dbri->B[1].input_callback_arg, - DBRI_RD_STATUS(dbri->B[1].rd.flags), - DBRI_RD_CNT(dbri->B[1].rd.flags)-2); - } - break; - - case D_P_10: - /* Pipe 10 - B1 channel transmit */ - if (D_INTR_GETCODE(x) == D_INTR_XCMP && - dbri->B[0].output_callback) { - dbri->B[0].output_callback(dbri->B[0].output_callback_arg, - DBRI_TD_STATUS(dbri->B[0].rd.flags)&0xfe); - } - break; - - case D_P_11: - /* Pipe 11 - B2 channel transmit */ - if (D_INTR_GETCODE(x) == D_INTR_XCMP && - dbri->B[1].output_callback) { - dbri->B[1].output_callback(dbri->B[1].output_callback_arg, - DBRI_TD_STATUS(dbri->B[1].rd.flags)&0xfe); - } - break; - - case D_P_18: - /* Pipe 18 - receive CS4215 status */ - if(val != 0) { - x = reverse_bytes(val,2)&CS4215_12_MASK; - printk("Comparing int: %x with hi(%x)\n", x, *(int *)dbri->mm.ctrl); - if(x == (*(int *)dbri->mm.ctrl >> 16)) { - printk("Comp ok\n"); - wake_up(&dbri->int_wait); - } - } - break; - case D_P_19: - /* Pipe 19 - receive CS4215 version */ - if(val != 0) { - dbri->mm.version = - reverse_bytes(val, 1) & 0xf; - } - break; - } +static int dbri_set_input_precision(struct sparcaudio_driver *drv, int prec) +{ + return 8; +} - dbri->dbri_irqp++; - if (dbri->dbri_irqp == (DBRI_NO_INTS * DBRI_INT_BLK)) - dbri->dbri_irqp = 1; - else if ((dbri->dbri_irqp & (DBRI_INT_BLK-1)) == 0) - dbri->dbri_irqp++; - x = dbri->intr[dbri->dbri_irqp]; - } +static int dbri_get_input_precision(struct sparcaudio_driver *drv) +{ + return 8; +} + +static int dbri_set_output_port(struct sparcaudio_driver *drv, int port) +{ + return 0; } +static int dbri_get_output_port(struct sparcaudio_driver *drv) +{ + return 0; +} -/* -**************************************************************************** -******************** Interface with sparcaudio midlevel ******************** -**************************************************************************** -*/ +static int dbri_set_input_port(struct sparcaudio_driver *drv, int port) +{ + return 0; +} +static int dbri_get_input_port(struct sparcaudio_driver *drv) +{ + return 0; +} -static void dummy() +static int dbri_set_output_encoding(struct sparcaudio_driver *drv, int enc) { + return 0; } -static int dbri_open(struct inode * inode, struct file * file, - struct sparcaudio_driver *drv) +static int dbri_get_output_encoding(struct sparcaudio_driver *drv) { - struct dbri *dbri = (struct dbri *)drv->private; + return 0; +} - MOD_INC_USE_COUNT; +static int dbri_set_input_encoding(struct sparcaudio_driver *drv, int enc) +{ + return 0; +} - return 0; +static int dbri_get_input_encoding(struct sparcaudio_driver *drv) +{ + return 0; } -static void dbri_release(struct inode * inode, struct file * file, - struct sparcaudio_driver *drv) +static int dbri_set_output_rate(struct sparcaudio_driver *drv, int rate) { - MOD_DEC_USE_COUNT; + return 0; } -static void dbri_start_output(struct sparcaudio_driver *drv, - __u8 * buffer, unsigned long count) +static int dbri_get_output_rate(struct sparcaudio_driver *drv) { - struct dbri *dbri = (struct dbri *)drv->private; - int val, n; + return 0; +} - if (count > (1 << 14) - 1) { - printk("dbri_start_output called with count=%d; truncated", count); - count = (1 << 14) - 1; - } +static int dbri_set_input_rate(struct sparcaudio_driver *drv, int rate) +{ + return 0; +} - n = dbri_cmdlock(dbri); +static int dbri_get_input_rate(struct sparcaudio_driver *drv) +{ + return 0; +} - dbri->mm.td.flags = DBRI_TD_F | DBRI_TD_B | DBRI_TD_D | DBRI_TD_CNT(count); - dbri->mm.td.ba = (__u32) buffer; - dbri->mm.td.nda = 0; - dbri->mm.td.status = 0; +static int dbri_sunaudio_getdev_sunos(struct sparcaudio_driver *drv) +{ + return 0; +} - /* Pipe 4 is audio transmit */ - val = D_SDP_MEM|D_SDP_TO_SER|D_SDP_P|D_SDP_MSB|D_PIPE(D_P_4); - dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val); - dbri->cmd[n++] = (__u32)&dbri->mm.td; +static int dbri_get_output_ports(struct sparcaudio_driver *drv) +{ + return 0; +} - output_callback_arg = drv; +static int dbri_get_input_ports(struct sparcaudio_driver *drv) +{ + return 0; +} - dbri_cmdsend(dbri, n); +static int dbri_set_output_muted(struct sparcaudio_driver *drv, int mute) +{ + return 0; } -static void dbri_stop_output(struct sparcaudio_driver *drv) +static int dbri_get_output_muted(struct sparcaudio_driver *drv) { - struct dbri *dbri = (struct dbri *)drv->private; + return 0; } @@ -888,60 +1287,89 @@ static struct sparcaudio_operations dbri_ops = { dbri_open, dbri_release, - dummy, /* dbri_ioctl, */ + dbri_ioctl, dbri_start_output, dbri_stop_output, - dummy, /* dbri_start_input, */ - dummy, /* dbri_stop_input, */ - dummy, /* dbri_audio_getdev, */ - dummy, /* dbri_set_output_volume, */ - dummy, /* dbri_get_output_volume, */ - dummy, /* dbri_set_input_volume, */ - dummy, /* dbri_get_input_volume, */ - dummy, /* dbri_set_monitor_volume, */ - dummy, /* dbri_get_monitor_volume, */ - dummy, /* dbri_set_output_balance */ - dummy, /* dbri_get_output_balance, */ - dummy, /* dbri_set_input_balance */ - dummy, /* dbri_get_input_balance, */ - dummy, /* dbri_set_output_channels */ - dummy, /* dbri_get_output_channels, */ - dummy, /* dbri_set_input_channels */ - dummy, /* dbri_get_input_channels, */ - dummy, /* dbri_set_output_precision */ - dummy, /* dbri_get_output_precision, */ - dummy, /* dbri_set_input_precision */ - dummy, /* dbri_get_input_precision, */ - dummy, /* dbri_set_output_port */ - dummy, /* dbri_get_output_port, */ - dummy, /* dbri_set_input_port */ - dummy, /* dbri_get_input_port, */ - dummy, /* dbri_set_output_encoding */ - dummy, /* dbri_get_output_encoding, */ - dummy, /* dbri_set_input_encoding */ - dummy, /* dbri_get_input_encoding, */ - dummy, /* dbri_set_output_rate */ - dummy, /* dbri_get_output_rate, */ - dummy, /* dbri_set_input_rate */ - dummy, /* dbri_get_input_rate, */ - dummy, /* dbri_sunaudio_getdev_sunos, */ - dummy, /* dbri_get_output_ports, */ - dummy, /* dbri_get_input_ports, */ - dummy, /* dbri_set_output_muted */ - dummy, /* dbri_get_output_muted, */ + dbri_start_input, + dbri_stop_input, + dbri_audio_getdev, + dbri_set_output_volume, + dbri_get_output_volume, + dbri_set_input_volume, + dbri_get_input_volume, + dbri_set_monitor_volume, + dbri_get_monitor_volume, + dbri_set_output_balance, + dbri_get_output_balance, + dbri_set_input_balance, + dbri_get_input_balance, + dbri_set_output_channels, + dbri_get_output_channels, + dbri_set_input_channels, + dbri_get_input_channels, + dbri_set_output_precision, + dbri_get_output_precision, + dbri_set_input_precision, + dbri_get_input_precision, + dbri_set_output_port, + dbri_get_output_port, + dbri_set_input_port, + dbri_get_input_port, + dbri_set_output_encoding, + dbri_get_output_encoding, + dbri_set_input_encoding, + dbri_get_input_encoding, + dbri_set_output_rate, + dbri_get_output_rate, + dbri_set_input_rate, + dbri_get_input_rate, + dbri_sunaudio_getdev_sunos, + dbri_get_output_ports, + dbri_get_input_ports, + dbri_set_output_muted, + dbri_get_output_muted, }; + /* **************************************************************************** ************************** ISDN (Hisax) Interface ************************** **************************************************************************** */ + +void dbri_isdn_init(struct dbri *dbri) +{ + /* Pipe 0: Receive D channel + * Pipe 8: Receive B1 channel + * Pipe 9: Receive B2 channel + * Pipe 1: Transmit D channel + * Pipe 10: Transmit B1 channel + * Pipe 11: Transmit B2 channel + */ + + setup_pipe(dbri, 0, D_SDP_HDLC | D_SDP_FROM_SER | D_SDP_LSB); + setup_pipe(dbri, 8, D_SDP_HDLC | D_SDP_FROM_SER | D_SDP_LSB); + setup_pipe(dbri, 9, D_SDP_HDLC | D_SDP_FROM_SER | D_SDP_LSB); + + setup_pipe(dbri, 1, D_SDP_HDLC_D | D_SDP_TO_SER | D_SDP_LSB); + setup_pipe(dbri,10, D_SDP_HDLC | D_SDP_TO_SER | D_SDP_LSB); + setup_pipe(dbri,11, D_SDP_HDLC | D_SDP_TO_SER | D_SDP_LSB); + + link_time_slot(dbri, 0, PIPEinput, 0, 2, 17); + link_time_slot(dbri, 8, PIPEinput, 8, 8, 0); + link_time_slot(dbri, 9, PIPEinput, 9, 8, 8); + + link_time_slot(dbri, 1, PIPEoutput, 1, 2, 17); + link_time_slot(dbri, 10, PIPEoutput, 1, 8, 0); + link_time_slot(dbri, 11, PIPEoutput, 10, 8, 8); +} + int dbri_get_irqnum(int dev) { struct dbri *dbri; - if (dev > num_drivers) { + if (dev >= num_drivers) { return(0); } @@ -955,7 +1383,7 @@ { struct dbri *dbri; - if (dev > num_drivers) { + if (dev >= num_drivers) { return(0); } @@ -964,11 +1392,13 @@ return dbri->liu_state; } +void dbri_liu_activate(int dev, int priority); + void dbri_liu_init(int dev, void (*callback)(void *), void *callback_arg) { struct dbri *dbri; - if (dev > num_drivers) { + if (dev >= num_drivers) { return; } @@ -979,26 +1409,28 @@ dbri->liu_callback_arg = callback_arg; dbri_isdn_init(dbri); + dbri_liu_activate(dev, 0); } void dbri_liu_activate(int dev, int priority) { struct dbri *dbri; - int n, val; + int val; + volatile int *cmd; - if (dev > num_drivers) { + if (dev >= num_drivers) { return; } dbri = (struct dbri *) drivers[dev].private; - n = dbri_cmdlock(dbri); + cmd = dbri_cmdlock(dbri); /* Turn on the ISDN TE interface and request activation */ val = D_NT_IRM_IMM | D_NT_IRM_EN | D_NT_ACT; - dbri->cmd[n++] = DBRI_CMD(D_TE, 0, val); + *(cmd++) = DBRI_CMD(D_TE, 0, val); - dbri_cmdsend(dbri, n); + dbri_cmdsend(dbri, cmd); /* Activate the interface */ dbri->regs->reg0 |= D_T; @@ -1008,7 +1440,7 @@ { struct dbri *dbri; - if (dev > num_drivers) { + if (dev >= num_drivers) { return; } @@ -1022,37 +1454,15 @@ void (*callback)(void *, int), void *callback_arg) { struct dbri *dbri; - int n, val; - if (dev > num_drivers) { + if (dev >= num_drivers) { return; } dbri = (struct dbri *) drivers[dev].private; - if (count > (1 << 14) - 1) { - printk("dbri_dxmit called with count=%d; truncated", count); - count = (1 << 14) - 1; - } - - n = dbri_cmdlock(dbri); - - /* XXX - Shouldn't I check to make sure D.td isn't is use? */ - - dbri->D.td.flags = DBRI_TD_F | DBRI_TD_B | DBRI_TD_CNT(count) | DBRI_TD_I; - dbri->D.td.ba = (__u32) buffer; - dbri->D.td.nda = 0; - dbri->D.td.status = 0; - - /* Pipe 1 is D channel transmit */ - val = D_SDP_HDLC_D|D_SDP_TO_SER|D_SDP_C|D_SDP_P|D_SDP_LSB|D_PIPE(D_P_1); - dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val); - dbri->cmd[n++] = (__u32)&dbri->D.td; - - dbri->D.output_callback = callback; - dbri->D.output_callback_arg = callback_arg; - - dbri_cmdsend(dbri, n); + /* Pipe 1 is D channel transmit */ + xmit_on_pipe(dbri, 1, buffer, count, callback, callback_arg); } void dbri_drecv(int dev, __u8 *buffer, unsigned int size, @@ -1060,106 +1470,63 @@ void *callback_arg) { struct dbri *dbri; - int n, val; - if (dev > num_drivers) { + if (dev >= num_drivers) { return; } dbri = (struct dbri *) drivers[dev].private; - if (size > (1 << 14) - 1) { - printk("dbri_drecv called with size=%d; truncated", size); - size = (1 << 14) - 1; - } - - /* Make sure size is a multiple of four */ - size &= ~3; - - n = dbri_cmdlock(dbri); - - /* XXX - Shouldn't I check to make sure D.rd isn't is use? */ - - dbri->D.rd.flags = 0; - dbri->D.rd.ba = (__u32) buffer; - dbri->D.rd.nda = 0; - dbri->D.rd.status = DBRI_RD_B | DBRI_RD_BCNT(size); - - /* Pipe 0 is D channel receive */ - val = D_SDP_HDLC|D_SDP_FROM_SER|D_SDP_C|D_SDP_P|D_SDP_LSB|D_PIPE(D_P_0); - dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val); - dbri->cmd[n++] = (__u32)&dbri->D.rd; - - dbri_cmdsend(dbri, n); - - dbri->D.input_callback = callback; - dbri->D.input_callback_arg = callback_arg; + /* Pipe 0 is D channel receive */ + recv_on_pipe(dbri, 0, buffer, size, callback, callback_arg); } int dbri_bopen(int dev, unsigned int chan, int hdlcmode, u_char xmit_idle_char) { struct dbri *dbri; - int n, val; + int val; - if (dev > num_drivers || chan > 1) { + if (dev >= num_drivers || chan > 1) { return -1; } dbri = (struct dbri *) drivers[dev].private; - if (hdlcmode) { - - return -1; - - /* Pipe 8/9: receive B1/B2 channel */ - dbri->B[chan].recvSDP = D_SDP_HDLC|D_SDP_FROM_SER|D_SDP_P|D_SDP_LSB|D_PIPE(D_P_8+chan); - - /* Pipe 10/11: transmit B1/B2 channel */ - dbri->B[chan].xmitSDP = D_SDP_HDLC|D_SDP_TO_SER|D_SDP_P|D_SDP_LSB|D_PIPE(D_P_10+chan); + if (hdlcmode) { - } else { /* !hdlcmode means transparent */ - - /* Pipe 8/9: receive B1/B2 channel */ - dbri->B[chan].recvSDP = D_SDP_MEM|D_SDP_FROM_SER|D_SDP_P|D_SDP_LSB|D_PIPE(D_P_8+chan); - - /* Pipe 10/11: transmit B1/B2 channel */ - dbri->B[chan].xmitSDP = D_SDP_MEM|D_SDP_TO_SER|D_SDP_P|D_SDP_LSB|D_PIPE(D_P_10+chan); - - } + /* return -1; */ - n = dbri_cmdlock(dbri); + /* Pipe 8/9: receive B1/B2 channel */ + setup_pipe(dbri, 8+chan, D_SDP_HDLC | D_SDP_FROM_SER|D_SDP_LSB); - /* Pipe 8/9: receive B1/B2 channel */ - val = dbri->B[chan].recvSDP | D_SDP_C; - dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val); - dbri->cmd[n++] = 0; + /* Pipe 10/11: transmit B1/B2 channel */ + setup_pipe(dbri,10+chan, D_SDP_HDLC | D_SDP_TO_SER | D_SDP_LSB); - /* Pipe 10/11: transmit B1/B2 channel */ - val = dbri->B[chan].xmitSDP | D_SDP_C; - dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val); - dbri->cmd[n++] = 0; + } else { /* !hdlcmode means transparent */ - dbri->B[chan].output_callback = NULL; - dbri->B[chan].input_callback = NULL; + /* Pipe 8/9: receive B1/B2 channel */ + setup_pipe(dbri, 8+chan, D_SDP_MEM | D_SDP_FROM_SER|D_SDP_LSB); - dbri_cmdsend(dbri, n); + /* Pipe 10/11: transmit B1/B2 channel */ + setup_pipe(dbri,10+chan, D_SDP_MEM | D_SDP_TO_SER | D_SDP_LSB); - return 0; + } + return 0; } void dbri_bclose(int dev, unsigned int chan) { struct dbri *dbri; - if (dev > num_drivers || chan > 1) { + if (dev >= num_drivers || chan > 1) { return; } dbri = (struct dbri *) drivers[dev].private; - dbri->B[chan].output_callback = NULL; - dbri->B[chan].input_callback = NULL; + reset_pipe(dbri, 8+chan); + reset_pipe(dbri, 10+chan); } void dbri_bxmit(int dev, unsigned int chan, @@ -1168,37 +1535,15 @@ void *callback_arg) { struct dbri *dbri; - int n, val; - if (dev > num_drivers || chan > 1) { + if (dev >= num_drivers || chan > 1) { return; } dbri = (struct dbri *) drivers[dev].private; - if (count > (1 << 14) - 1) { - printk("dbri_bxmit called with count=%ld; truncated", count); - count = (1 << 14) - 1; - } - - n = dbri_cmdlock(dbri); - - /* XXX - Shouldn't I check to make sure td isn't is use? */ - - dbri->B[chan].td.flags = DBRI_TD_F | DBRI_TD_B | DBRI_TD_CNT(count); - dbri->B[chan].td.ba = (__u32) buffer; - dbri->B[chan].td.nda = 0; - dbri->B[chan].td.status = 0; - - /* Pipe 10/11 is B1/B2 channel transmit */ - val = dbri->B[chan].xmitSDP; - dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val); - dbri->cmd[n++] = (__u32)&dbri->B[chan].td; - - dbri->B[chan].output_callback = callback; - dbri->B[chan].output_callback_arg = callback_arg; - - dbri_cmdsend(dbri, n); + /* Pipe 10/11 is B1/B2 channel transmit */ + xmit_on_pipe(dbri, 10+chan, buffer, count, callback, callback_arg); } void dbri_brecv(int dev, unsigned int chan, @@ -1207,40 +1552,15 @@ void *callback_arg) { struct dbri *dbri; - int n, val; - if (dev > num_drivers || chan > 1) { + if (dev >= num_drivers || chan > 1) { return; } dbri = (struct dbri *) drivers[dev].private; - if (size > (1 << 14) - 1) { - printk("dbri_brecv called with size=%ld; truncated", size); - size = (1 << 14) - 1; - } - - /* Make sure size is a multiple of four */ - size &= ~3; - - n = dbri_cmdlock(dbri); - - /* XXX - Shouldn't I check to make sure RD isn't is use? */ - - dbri->B[chan].rd.flags = 0; - dbri->B[chan].rd.ba = (__u32) buffer; - dbri->B[chan].rd.nda = 0; - dbri->B[chan].rd.status = DBRI_RD_B | DBRI_RD_BCNT(size); - - /* Pipe 8/9 is B1/B2 channel receive */ - val = dbri->B[chan].recvSDP; - dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val); - dbri->cmd[n++] = (__u32)&dbri->B[chan].rd; - - dbri_cmdsend(dbri, n); - - dbri->B[chan].input_callback = callback; - dbri->B[chan].input_callback_arg = callback_arg; + /* Pipe 8/9 is B1/B2 channel receive */ + recv_on_pipe(dbri, 8+chan, buffer, size, callback, callback_arg); } #if defined(DBRI_ISDN) || defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x200ff @@ -1271,6 +1591,7 @@ { struct dbri *dbri; struct linux_prom_irqs irq; + __u32 dma_dvma; int err; if (sdev->prom_name[9] < 'e') { @@ -1287,7 +1608,13 @@ memset(dbri, 0, sizeof(*dbri)); + /* sparc_dvma_malloc() will halt the kernel if the malloc fails */ + dbri->dma = sparc_dvma_malloc (sizeof (struct dbri_dma), + "DBRI DMA Cmd Block", &dma_dvma); + dbri->dma_dvma = (struct dbri_dma *) dma_dvma; + dbri->dbri_version = sdev->prom_name[9]; + dbri->sdev = sdev; /* Map the registers into memory. */ prom_apply_sbus_ranges(sdev->my_bus, &sdev->reg_addrs[0], @@ -1295,7 +1622,7 @@ dbri->regs_size = sdev->reg_addrs[0].reg_size; dbri->regs = sparc_alloc_io(sdev->reg_addrs[0].phys_addr, 0, sdev->reg_addrs[0].reg_size, - drv_name, sdev->reg_addrs[0].which_io, 0); + "DBRI Registers", sdev->reg_addrs[0].which_io, 0); if (!dbri->regs) { printk(KERN_ERR "DBRI: could not allocate registers\n"); kfree(drv->private); @@ -1305,7 +1632,8 @@ prom_getproperty(sdev->prom_node, "intr", (char *)&irq, sizeof(irq)); dbri->irq = irq.pri; - err = request_irq(dbri->irq, dbri_intr, SA_SHIRQ, "DBRI/audio", drv); + err = request_irq(dbri->irq, dbri_intr, SA_SHIRQ, + "DBRI audio/ISDN", dbri); if (err) { printk(KERN_ERR "DBRI: Can't get irq %d\n", dbri->irq); sparc_free_io(dbri->regs, dbri->regs_size); @@ -1313,23 +1641,20 @@ return err; } + dbri_initialize(dbri); + err = mmcodec_init(drv); + if(err) { + dbri_detach(dbri); + return err; + } + /* Register ourselves with the midlevel audio driver. */ err = register_sparcaudio_driver(drv,1); if (err) { printk(KERN_ERR "DBRI: unable to register audio\n"); - free_irq(dbri->irq, drv); - sparc_free_io(dbri->regs, dbri->regs_size); - kfree(drv->private); - return err; - } - - dbri_initialize(drv); - err = mmcodec_init(drv); - if(err) { - dbri_detach(drv); + dbri_detach(dbri); return err; } - dbri->perchip_info.play.active = dbri->perchip_info.play.pause = 0; dbri->perchip_info.record.active = dbri->perchip_info.record.pause = 0; @@ -1380,7 +1705,8 @@ register int i; for (i = 0; i < num_drivers; i++) { - dbri_detach(&drivers[i]); + dbri_detach((struct dbri *) drivers[i].private); + unregister_sparcaudio_driver(& drivers[i], 1); num_drivers--; } } diff -ur --new-file old/linux/drivers/sbus/audio/dbri.h new/linux/drivers/sbus/audio/dbri.h --- old/linux/drivers/sbus/audio/dbri.h Thu Jan 7 18:21:53 1999 +++ new/linux/drivers/sbus/audio/dbri.h Tue Mar 16 01:11:30 1999 @@ -22,53 +22,77 @@ #define DBRI_NO_CMDS 64 #define DBRI_NO_INTS 2 #define DBRI_INT_BLK 64 +#define DBRI_NO_DESCS 64 #define DBRI_MM_ONB 1 #define DBRI_MM_SB 2 struct dbri_mem { - __u32 flags; + __u32 word1; __u32 ba; /* Transmit/Receive Buffer Address */ __u32 nda; /* Next Descriptor Address */ - __u32 status; + __u32 word4; }; -struct dbri_channel { - struct dbri_mem td; - struct dbri_mem rd; - unsigned int recvSDP; - unsigned int xmitSDP; +#include "cs4215.h" + +/* This structure is in a DMA region where it can accessed by both + * the CPU and the DBRI + */ + +struct dbri_dma { + int cmd[DBRI_NO_CMDS]; /* Place for commands */ + int intr[DBRI_NO_INTS * DBRI_INT_BLK]; /* Interrupt field */ + struct dbri_mem desc[DBRI_NO_DESCS]; /* Xmit/receive descriptors */ +}; + +struct dbri_pipe { + u32 sdp; /* SDP command word */ + int nextpipe; /* Next pipe in linked list */ + int cycle; /* Offset of timeslot (bits) */ + int length; /* Length of timeslot (bits) */ + int desc; /* Index of active descriptor*/ + __u32 *recv_fixed_ptr; /* Ptr to receive fixed data */ +}; + +struct dbri_desc { + int inuse; /* Boolean flag */ + int next; /* Index of next desc, or -1 */ + void *buffer; + unsigned int len; void (*output_callback)(void *, int); void *output_callback_arg; void (*input_callback)(void *, int, unsigned int); void *input_callback_arg; }; -#include "cs4215.h" - /* This structure holds the information for both chips (DBRI & CS4215) */ + struct dbri { int regs_size, irq; /* Needed for unload */ + struct linux_sbus_device *sdev; + + volatile struct dbri_dma *dma; /* Pointer to our DMA block */ + struct dbri_dma *dma_dvma; /* DBRI visible DMA address */ struct dbri_regs *regs; /* dbri HW regs */ int dbri_version; /* 'e' and up is OK */ int dbri_irqp; /* intr queue pointer */ - __volatile__ int cmd[DBRI_NO_CMDS]; /* Place for commands */ - __volatile__ int intr[DBRI_NO_INTS * DBRI_INT_BLK]; /* Interrupt field */ - + + struct dbri_pipe pipes[32]; /* DBRI's 32 data pipes */ + struct dbri_desc descs[DBRI_NO_DESCS]; + struct cs4215 mm; /* mmcodec special info */ - + +#if 0 struct wait_queue *wait, *int_wait; /* Where to sleep if busy */ +#endif struct audio_info perchip_info; /* Track ISDN LIU and notify changes */ int liu_state; void (*liu_callback)(void *); void *liu_callback_arg; - - /* Callback routines and descriptors for ISDN channels */ - struct dbri_channel D; - struct dbri_channel B[2]; }; @@ -145,6 +169,7 @@ #define D_SDP_HDLC_D (3<<13) /* D Channel (prio control)*/ #define D_SDP_SER (4<<13) /* Serial to serial */ #define D_SDP_FIXED (6<<13) /* Short only */ +#define D_SDP_MODE(v) ((v)&(7<<13)) #define D_SDP_TO_SER (1<<12) /* Direction */ #define D_SDP_FROM_SER (0<<12) /* Direction */ @@ -163,8 +188,8 @@ #define D_DTS_PRVOUT(v) ((v)<<5) /* Previous Out Pipe */ /* Time Slot defines */ -#define D_TS_LEN(v) (v<<24) /* Number of bits in this time slot */ -#define D_TS_CYCLE(v) (v<<14) /* Bit Count at start of TS */ +#define D_TS_LEN(v) ((v)<<24) /* Number of bits in this time slot */ +#define D_TS_CYCLE(v) ((v)<<14) /* Bit Count at start of TS */ #define D_TS_DI(v) (1<<13) /* Data Invert */ #define D_TS_1CHANNEL (0<<10) /* Single Channel / Normal mode */ #define D_TS_MONITOR (2<<10) /* Monitor pipe */ @@ -174,13 +199,13 @@ #define D_TS_NEXT(v) ((v)<<0) /* Pipe Nr: 0-15 long, 16-21 short */ /* Concentration Highway Interface Modes */ -#define D_CHI_CHICM(v) (v<<16) /* Clock mode */ +#define D_CHI_CHICM(v) ((v)<<16) /* Clock mode */ #define D_CHI_IR (1<<15) /* Immediate Interrupt Report */ #define D_CHI_EN (1<<14) /* CHIL Interrupt enabled */ #define D_CHI_OD (1<<13) /* Open Drain Enable */ #define D_CHI_FE (1<<12) /* Sample CHIFS on Rising Frame Edge */ #define D_CHI_FD (1<<11) /* Frame Drive */ -#define D_CHI_BPF(v) (v<<0) /* Bits per Frame */ +#define D_CHI_BPF(v) ((v)<<0) /* Bits per Frame */ /* NT: These are here for completeness */ #define D_NT_FBIT (1<<17) /* Frame Bit */ @@ -199,13 +224,13 @@ #define D_NT_ABV (1<<0) /* Activate Bipolar Violation */ /* Codec Setup */ -#define D_CDEC_CK(v) (v<<24) /* Clock Select */ -#define D_CDEC_FED(v) (v<<12) /* FSCOD Falling Edge Delay */ -#define D_CDEC_RED(v) (v<<0) /* FSCOD Rising Edge Delay */ +#define D_CDEC_CK(v) ((v)<<24) /* Clock Select */ +#define D_CDEC_FED(v) ((v)<<12) /* FSCOD Falling Edge Delay */ +#define D_CDEC_RED(v) ((v)<<0) /* FSCOD Rising Edge Delay */ /* Test */ -#define D_TEST_RAM(v) (v<<16) /* RAM Pointer */ -#define D_TEST_SIZE(v) (v<<11) /* */ +#define D_TEST_RAM(v) ((v)<<16) /* RAM Pointer */ +#define D_TEST_SIZE(v) ((v)<<11) /* */ #define D_TEST_ROMONOFF 0x5 /* Toggle ROM opcode monitor on/off */ #define D_TEST_PROC 0x6 /* MicroProcessor test */ #define D_TEST_SER 0x7 /* Serial-Controller test */ @@ -245,11 +270,11 @@ #define D_INTR_CHI 36 #define D_INTR_CMD 38 -#define D_INTR_GETCHAN(v) ((v>>24) & 0x3f) -#define D_INTR_GETCODE(v) ((v>>20) & 0xf) -#define D_INTR_GETCMD(v) ((v>>16) & 0xf) -#define D_INTR_GETVAL(v) (v & 0xffff) -#define D_INTR_GETRVAL(v) (v & 0xfffff) +#define D_INTR_GETCHAN(v) (((v)>>24) & 0x3f) +#define D_INTR_GETCODE(v) (((v)>>20) & 0xf) +#define D_INTR_GETCMD(v) (((v)>>16) & 0xf) +#define D_INTR_GETVAL(v) ((v) & 0xffff) +#define D_INTR_GETRVAL(v) ((v) & 0xfffff) #define D_P_0 0 /* TE receive anchor */ #define D_P_1 1 /* TE transmit anchor */ @@ -288,11 +313,11 @@ /* Transmit descriptor defines */ #define DBRI_TD_F (1<<31) /* End of Frame */ #define DBRI_TD_D (1<<30) /* Do not append CRC */ -#define DBRI_TD_CNT(v) (v<<16) /* Number of valid bytes in the buffer */ +#define DBRI_TD_CNT(v) ((v)<<16) /* Number of valid bytes in the buffer */ #define DBRI_TD_B (1<<15) /* Final interrupt */ #define DBRI_TD_M (1<<14) /* Marker interrupt */ #define DBRI_TD_I (1<<13) /* Transmit Idle Characters */ -#define DBRI_TD_FCNT(v) v /* Flag Count */ +#define DBRI_TD_FCNT(v) (v) /* Flag Count */ #define DBRI_TD_UNR (1<<3) /* Underrun: transmitter is out of data */ #define DBRI_TD_ABT (1<<2) /* Abort: frame aborted */ #define DBRI_TD_TBC (1<<0) /* Transmit buffer Complete */ @@ -303,12 +328,12 @@ #define DBRI_RD_C (1<<30) /* Completed buffer */ #define DBRI_RD_B (1<<15) /* Final interrupt */ #define DBRI_RD_M (1<<14) /* Marker interrupt */ -#define DBRI_RD_BCNT(v) v /* Buffer size */ +#define DBRI_RD_BCNT(v) (v) /* Buffer size */ #define DBRI_RD_CRC (1<<7) /* 0: CRC is correct */ #define DBRI_RD_BBC (1<<6) /* 1: Bad Byte received */ #define DBRI_RD_ABT (1<<5) /* Abort: frame aborted */ #define DBRI_RD_OVRN (1<<3) /* Overrun: data lost */ #define DBRI_RD_STATUS(v) ((v)&0xff) /* Receive status */ -#define DBRI_RD_CNT(v) ((v>>16)&0x1fff) /* Number of valid bytes in the buffer */ +#define DBRI_RD_CNT(v) (((v)>>16)&0x1fff) /* Number of valid bytes in the buffer */ #endif /* _DBRI_H_ */ diff -ur --new-file old/linux/drivers/sbus/audio/dmy.c new/linux/drivers/sbus/audio/dmy.c --- old/linux/drivers/sbus/audio/dmy.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/sbus/audio/dmy.c Fri Apr 16 17:20:23 1999 @@ -0,0 +1,736 @@ +/* + * drivers/sbus/audio/dummy.c + * + * Copyright 1998 Derrick J Brashear (shadow@andrew.cmu.edu) + * + * This is a dummy lowlevel driver. Consider it a distant cousin of + * /proc/audio; It pretends to be a piece of audio hardware, and writes + * to a file instead. (or will shortly) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "dummy.h" + +#define MAX_DRIVERS 1 +static struct sparcaudio_driver drivers[MAX_DRIVERS]; +static int num_drivers; + +static int dummy_play_gain(struct sparcaudio_driver *drv, int value, + unsigned char balance); +static int dummy_record_gain(struct sparcaudio_driver *drv, int value, + unsigned char balance); +static int dummy_output_muted(struct sparcaudio_driver *drv, int value); +static int dummy_attach(struct sparcaudio_driver *drv); + +static int +dummy_set_output_encoding(struct sparcaudio_driver *drv, int value) +{ + struct dummy_chip *dummy_chip = (struct dummy_chip *)drv->private; + if (value != 0) { + dummy_chip->perchip_info.play.encoding = value; + return 0; + } + return -EINVAL; +} + +static int +dummy_set_input_encoding(struct sparcaudio_driver *drv, int value) +{ + struct dummy_chip *dummy_chip = (struct dummy_chip *)drv->private; + if (value != 0) { + dummy_chip->perchip_info.record.encoding = value; + return 0; + } + return -EINVAL; +} + +static int dummy_get_output_encoding(struct sparcaudio_driver *drv) +{ + struct dummy_chip *dummy_chip = (struct dummy_chip *)drv->private; + return dummy_chip->perchip_info.play.encoding; +} + +static int dummy_get_input_encoding(struct sparcaudio_driver *drv) +{ + struct dummy_chip *dummy_chip = (struct dummy_chip *)drv->private; + return dummy_chip->perchip_info.record.encoding; +} + +static int +dummy_set_output_rate(struct sparcaudio_driver *drv, int value) +{ + struct dummy_chip *dummy_chip = (struct dummy_chip *)drv->private; + if (value != 0) { + dummy_chip->perchip_info.play.sample_rate = value; + return 0; + } + return -EINVAL; +} + +static int +dummy_set_input_rate(struct sparcaudio_driver *drv, int value) +{ + struct dummy_chip *dummy_chip = (struct dummy_chip *)drv->private; + if (value != 0) { + dummy_chip->perchip_info.record.sample_rate = value; + return 0; + } + return -EINVAL; +} + +static int dummy_get_output_rate(struct sparcaudio_driver *drv) +{ + struct dummy_chip *dummy_chip = (struct dummy_chip *)drv->private; + return dummy_chip->perchip_info.play.sample_rate; +} + +static int dummy_get_input_rate(struct sparcaudio_driver *drv) +{ + struct dummy_chip *dummy_chip = (struct dummy_chip *)drv->private; + return dummy_chip->perchip_info.record.sample_rate; +} + +/* Generically we support 4 channels. This does 2 */ +static int +dummy_set_output_channels(struct sparcaudio_driver *drv, int value) +{ + struct dummy_chip *dummy_chip = (struct dummy_chip *)drv->private; + switch (value) { + case 1: + case 2: + break; + default: + return -(EINVAL); + } + dummy_chip->perchip_info.play.channels = value; + return 0; +} + +/* Generically we support 4 channels. This does 2 */ +static int +dummy_set_input_channels(struct sparcaudio_driver *drv, int value) +{ + struct dummy_chip *dummy_chip = (struct dummy_chip *)drv->private; + switch (value) { + case 1: + case 2: + break; + default: + return -(EINVAL); + } + dummy_chip->perchip_info.record.channels = value; + return 0; +} + +static int dummy_get_input_channels(struct sparcaudio_driver *drv) +{ + struct dummy_chip *dummy_chip = (struct dummy_chip *)drv->private; + return dummy_chip->perchip_info.record.channels; +} + +static int dummy_get_output_channels(struct sparcaudio_driver *drv) +{ + struct dummy_chip *dummy_chip = (struct dummy_chip *)drv->private; + return dummy_chip->perchip_info.play.channels; +} + +static int dummy_get_output_precision(struct sparcaudio_driver *drv) +{ + struct dummy_chip *dummy_chip = (struct dummy_chip *)drv->private; + return dummy_chip->perchip_info.play.precision; +} + +static int dummy_get_input_precision(struct sparcaudio_driver *drv) +{ + struct dummy_chip *dummy_chip = (struct dummy_chip *)drv->private; + return dummy_chip->perchip_info.record.precision; +} + +static int dummy_set_output_precision(struct sparcaudio_driver *drv, int val) +{ + struct dummy_chip *dummy_chip = (struct dummy_chip *)drv->private; + dummy_chip->perchip_info.play.precision = val; + return dummy_chip->perchip_info.play.precision; +} + +static int dummy_set_input_precision(struct sparcaudio_driver *drv, int val) +{ + struct dummy_chip *dummy_chip = (struct dummy_chip *)drv->private; + dummy_chip->perchip_info.record.precision = val; + return dummy_chip->perchip_info.record.precision; +} + +/* Set output mute */ +static int dummy_output_muted(struct sparcaudio_driver *drv, int value) +{ + struct dummy_chip *dummy_chip = (struct dummy_chip *)drv->private; + if (!value) + dummy_chip->perchip_info.output_muted = 0; + else + dummy_chip->perchip_info.output_muted = 1; + return 0; +} + +static int dummy_get_output_muted(struct sparcaudio_driver *drv) +{ + struct dummy_chip *dummy_chip = (struct dummy_chip *)drv->private; + return dummy_chip->perchip_info.output_muted; +} + +static int dummy_get_formats(struct sparcaudio_driver *drv) +{ + return (AFMT_MU_LAW | AFMT_A_LAW | AFMT_U8 | AFMT_IMA_ADPCM | + AFMT_S16_LE | AFMT_S16_BE); +} + +static int dummy_get_output_ports(struct sparcaudio_driver *drv) +{ + return (AUDIO_LINE_OUT | AUDIO_SPEAKER | AUDIO_HEADPHONE); +} + +static int dummy_get_input_ports(struct sparcaudio_driver *drv) +{ + return (AUDIO_ANALOG_LOOPBACK); +} + +/* Set chip "output" port */ +static int dummy_set_output_port(struct sparcaudio_driver *drv, int value) +{ + struct dummy_chip *dummy_chip = (struct dummy_chip *)drv->private; + dummy_chip->perchip_info.play.port = value; + return (value); +} + +static int dummy_set_input_port(struct sparcaudio_driver *drv, int value) +{ + struct dummy_chip *dummy_chip = (struct dummy_chip *)drv->private; + dummy_chip->perchip_info.record.port = value; + return (value); +} + +static int dummy_get_output_port(struct sparcaudio_driver *drv) +{ + struct dummy_chip *dummy_chip = (struct dummy_chip *)drv->private; + return dummy_chip->perchip_info.play.port; +} + +static int dummy_get_input_port(struct sparcaudio_driver *drv) +{ + struct dummy_chip *dummy_chip = (struct dummy_chip *)drv->private; + return dummy_chip->perchip_info.record.port; +} + +static int dummy_get_output_error(struct sparcaudio_driver *drv) +{ + struct dummy_chip *dummy_chip = (struct dummy_chip *)drv->private; + return (int)dummy_chip->perchip_info.play.error; +} + +static int dummy_get_input_error(struct sparcaudio_driver *drv) +{ + struct dummy_chip *dummy_chip = (struct dummy_chip *)drv->private; + return (int)dummy_chip->perchip_info.record.error; +} + +static int dummy_get_output_samples(struct sparcaudio_driver *drv) +{ + struct dummy_chip *dummy_chip = (struct dummy_chip *)drv->private; + return dummy_chip->perchip_info.play.samples; +} + +static int dummy_get_output_pause(struct sparcaudio_driver *drv) +{ + struct dummy_chip *dummy_chip = (struct dummy_chip *)drv->private; + return (int)dummy_chip->perchip_info.play.pause; +} + +static int dummy_set_output_volume(struct sparcaudio_driver *drv, int value) +{ + struct dummy_chip *dummy_chip = (struct dummy_chip *)drv->private; + dummy_play_gain(drv, value, dummy_chip->perchip_info.play.balance); + return 0; +} + +static int dummy_get_output_volume(struct sparcaudio_driver *drv) +{ + struct dummy_chip *dummy_chip = (struct dummy_chip *)drv->private; + return dummy_chip->perchip_info.play.gain; +} + +static int dummy_set_output_balance(struct sparcaudio_driver *drv, int value) +{ + struct dummy_chip *dummy_chip = (struct dummy_chip *)drv->private; + dummy_chip->perchip_info.play.balance = value; + dummy_play_gain(drv, dummy_chip->perchip_info.play.gain, + dummy_chip->perchip_info.play.balance); + return 0; +} + +static int dummy_get_output_balance(struct sparcaudio_driver *drv) +{ + struct dummy_chip *dummy_chip = (struct dummy_chip *)drv->private; + return (int)dummy_chip->perchip_info.play.balance; +} + +/* Set chip play gain */ +static int dummy_play_gain(struct sparcaudio_driver *drv, int value, unsigned char balance) +{ + struct dummy_chip *dummy_chip = (struct dummy_chip *)drv->private; + int tmp = 0, r, l, r_adj, l_adj; + r = l = value; + if (balance < AUDIO_MID_BALANCE) { + r = (int)(value - ((AUDIO_MID_BALANCE - balance) << AUDIO_BALANCE_SHIFT)); + if (r < 0) r = 0; + } else if (balance > AUDIO_MID_BALANCE) { + l = (int)(value - ((balance - AUDIO_MID_BALANCE) << AUDIO_BALANCE_SHIFT)); + if (l < 0) l = 0; + } + (l == 0) ? (l_adj = DUMMY_MAX_DEV_ATEN) : (l_adj = DUMMY_MAX_ATEN - + (l * (DUMMY_MAX_ATEN + 1) / + (AUDIO_MAX_GAIN + 1))); + (r == 0) ? (r_adj = DUMMY_MAX_DEV_ATEN) : (r_adj = DUMMY_MAX_ATEN - + (r * (DUMMY_MAX_ATEN + 1) / + (AUDIO_MAX_GAIN + 1))); + if ((value == 0) || (value == AUDIO_MAX_GAIN)) { + tmp = value; + } else { + if (value == l) + tmp = ((DUMMY_MAX_ATEN - l_adj) * (AUDIO_MAX_GAIN + 1) / + (DUMMY_MAX_ATEN + 1)); + else if (value == r) + tmp = ((DUMMY_MAX_ATEN - r_adj) * (AUDIO_MAX_GAIN + 1) / + (DUMMY_MAX_ATEN + 1)); + } + dummy_chip->perchip_info.play.gain = tmp; + return 0; +} + +static int dummy_get_input_samples(struct sparcaudio_driver *drv) +{ + struct dummy_chip *dummy_chip = (struct dummy_chip *)drv->private; + return dummy_chip->perchip_info.record.samples; +} + +static int dummy_get_input_pause(struct sparcaudio_driver *drv) +{ + struct dummy_chip *dummy_chip = (struct dummy_chip *)drv->private; + return (int)dummy_chip->perchip_info.record.pause; +} + +static int dummy_set_monitor_volume(struct sparcaudio_driver *drv, int value) +{ + return 0; +} + +static int dummy_get_monitor_volume(struct sparcaudio_driver *drv) +{ + return 0; +} + +static int dummy_set_input_volume(struct sparcaudio_driver *drv, int value) +{ + struct dummy_chip *dummy_chip = (struct dummy_chip *)drv->private; + dummy_record_gain(drv, value, dummy_chip->perchip_info.record.balance); + return 0; +} + +static int dummy_get_input_volume(struct sparcaudio_driver *drv) +{ + struct dummy_chip *dummy_chip = (struct dummy_chip *)drv->private; + return dummy_chip->perchip_info.record.gain; +} + +static int dummy_set_input_balance(struct sparcaudio_driver *drv, int value) +{ + struct dummy_chip *dummy_chip = (struct dummy_chip *)drv->private; + dummy_chip->perchip_info.record.balance = value; + dummy_record_gain(drv, dummy_chip->perchip_info.record.gain, + dummy_chip->perchip_info.play.balance); + return 0; +} + +static int dummy_get_input_balance(struct sparcaudio_driver *drv) +{ + struct dummy_chip *dummy_chip = (struct dummy_chip *)drv->private; + return (int)dummy_chip->perchip_info.record.balance; +} + +static int dummy_record_gain(struct sparcaudio_driver *drv, int value, unsigned char balance) +{ + struct dummy_chip *dummy_chip = (struct dummy_chip *)drv->private; + int tmp = 0, r, l, r_adj, l_adj; + r = l = value; + if (balance < AUDIO_MID_BALANCE) { + r = (int)(value - ((AUDIO_MID_BALANCE - balance) << AUDIO_BALANCE_SHIFT)); + if (r < 0) r = 0; + } else if (balance > AUDIO_MID_BALANCE) { + l = (int)(value - ((balance - AUDIO_MID_BALANCE) << AUDIO_BALANCE_SHIFT)); + if (l < 0) l = 0; + } + (l == 0) ? (l_adj = DUMMY_MAX_DEV_ATEN) : (l_adj = DUMMY_MAX_ATEN - + (l * (DUMMY_MAX_ATEN + 1) / + (AUDIO_MAX_GAIN + 1))); + (r == 0) ? (r_adj = DUMMY_MAX_DEV_ATEN) : (r_adj = DUMMY_MAX_ATEN - + (r * (DUMMY_MAX_ATEN + 1) / + (AUDIO_MAX_GAIN + 1))); + if ((value == 0) || (value == AUDIO_MAX_GAIN)) { + tmp = value; + } else { + if (value == l) + tmp = ((DUMMY_MAX_ATEN - l_adj) * (AUDIO_MAX_GAIN + 1) / + (DUMMY_MAX_ATEN + 1)); + else if (value == r) + tmp = ((DUMMY_MAX_ATEN - r_adj) * (AUDIO_MAX_GAIN + 1) / + (DUMMY_MAX_ATEN + 1)); + } + dummy_chip->perchip_info.record.gain = tmp; + return 0; +} + +/* Reset the audio chip to a sane state. */ +static void dummy_chip_reset(struct sparcaudio_driver *drv) +{ + dummy_set_output_encoding(drv, AUDIO_ENCODING_ULAW); + dummy_set_output_rate(drv, DUMMY_RATE); + dummy_set_output_channels(drv, DUMMY_CHANNELS); + dummy_set_output_precision(drv, DUMMY_PRECISION); + dummy_set_output_balance(drv, AUDIO_MID_BALANCE); + dummy_set_output_volume(drv, DUMMY_DEFAULT_PLAYGAIN); + dummy_set_output_port(drv, AUDIO_SPEAKER); + dummy_output_muted(drv, 0); + dummy_set_input_encoding(drv, AUDIO_ENCODING_ULAW); + dummy_set_input_rate(drv, DUMMY_RATE); + dummy_set_input_channels(drv, DUMMY_CHANNELS); + dummy_set_input_precision(drv, DUMMY_PRECISION); + dummy_set_input_balance(drv, AUDIO_MID_BALANCE); + dummy_set_input_volume(drv, DUMMY_DEFAULT_PLAYGAIN); + dummy_set_input_port(drv, AUDIO_SPEAKER); +} + +static int dummy_open(struct inode * inode, struct file * file, struct sparcaudio_driver *drv) +{ + struct dummy_chip *dummy_chip = (struct dummy_chip *)drv->private; + /* Set the default audio parameters if not already in use. */ + if (file->f_mode & FMODE_WRITE) { + if (!(drv->flags & SDF_OPEN_WRITE) && + (dummy_chip->perchip_info.play.active == 0)) { + dummy_chip->perchip_info.play.open = 1; + dummy_chip->perchip_info.play.samples = + dummy_chip->perchip_info.play.error = 0; + } + } + if (file->f_mode & FMODE_READ) { + if (!(drv->flags & SDF_OPEN_READ) && + (dummy_chip->perchip_info.record.active == 0)) { + dummy_chip->perchip_info.record.open = 1; + dummy_chip->perchip_info.record.samples = + dummy_chip->perchip_info.record.error = 0; + } + } + + MOD_INC_USE_COUNT; + + return 0; +} + +static void dummy_release(struct inode * inode, struct file * file, struct sparcaudio_driver *drv) +{ + struct dummy_chip *dummy_chip = (struct dummy_chip *)drv->private; + if (file->f_mode & FMODE_WRITE) { + dummy_chip->perchip_info.play.active = + dummy_chip->perchip_info.play.open = 0; + } + if (file->f_mode & FMODE_READ) { + dummy_chip->perchip_info.record.active = + dummy_chip->perchip_info.record.open = 0; + } + MOD_DEC_USE_COUNT; +} + +static void dummy_output_done_task(void * arg) +{ + struct sparcaudio_driver *drv = (struct sparcaudio_driver *)arg; + struct dummy_chip *dummy_chip = (struct dummy_chip *)drv->private; + + sparcaudio_output_done(drv, 1); + if (dummy_chip->perchip_info.record.active) + sparcaudio_input_done(drv, 1); +} + +static void dummy_start_output(struct sparcaudio_driver *drv, __u8 * buffer, + unsigned long count) +{ + struct dummy_chip *dummy_chip = (struct dummy_chip *)drv->private; + + if (dummy_chip->perchip_info.play.pause || !count) + return; + + dummy_chip->perchip_info.play.active = 1; + + /* fake an "interrupt" to deal with this block */ + dummy_chip->tqueue.next = NULL; + dummy_chip->tqueue.sync = 0; + dummy_chip->tqueue.routine = dummy_output_done_task; + dummy_chip->tqueue.data = drv; + + queue_task(&dummy_chip->tqueue, &tq_immediate); + mark_bh(IMMEDIATE_BH); +} + +static void dummy_start_input(struct sparcaudio_driver *drv, __u8 * buffer, + unsigned long count) +{ + struct dummy_chip *dummy_chip = (struct dummy_chip *)drv->private; + dummy_chip->perchip_info.record.active = 1; +} + +static void dummy_stop_output(struct sparcaudio_driver *drv) +{ + struct dummy_chip *dummy_chip = (struct dummy_chip *)drv->private; + dummy_chip->perchip_info.play.active = 0; +} + +static void dummy_stop_input(struct sparcaudio_driver *drv) +{ + struct dummy_chip *dummy_chip = (struct dummy_chip *)drv->private; + dummy_chip->perchip_info.record.active = 0; +} + +static int dummy_set_output_pause(struct sparcaudio_driver *drv, int value) +{ + struct dummy_chip *dummy_chip = (struct dummy_chip *)drv->private; + dummy_chip->perchip_info.play.pause = value; + + if (!value) + sparcaudio_output_done(drv, 0); + + return value; +} + +static int dummy_set_input_pause(struct sparcaudio_driver *drv, int value) +{ + struct dummy_chip *dummy_chip = (struct dummy_chip *)drv->private; + dummy_chip->perchip_info.record.pause = value; + + /* This should probably cause play pause. */ + + return value; +} + +static int dummy_set_input_error(struct sparcaudio_driver *drv, int value) +{ + return 0; +} + +static int dummy_set_output_error(struct sparcaudio_driver *drv, int value) +{ + int i; + struct dummy_chip *dummy_chip = (struct dummy_chip *)drv->private; + i = dummy_chip->perchip_info.play.error; + dummy_chip->perchip_info.play.error = value; + return i; +} + +static int dummy_set_output_samples(struct sparcaudio_driver *drv, int value) +{ + int i; + struct dummy_chip *dummy_chip = (struct dummy_chip *)drv->private; + i = dummy_chip->perchip_info.play.samples; + dummy_chip->perchip_info.play.samples = value; + return i; +} + +static int dummy_set_input_samples(struct sparcaudio_driver *drv, int value) +{ + int i; + struct dummy_chip *dummy_chip = (struct dummy_chip *)drv->private; + i = dummy_chip->perchip_info.play.samples; + dummy_chip->perchip_info.record.samples = value; + return i; +} + +/* In order to fake things which care out, play we're a 4231 */ +static void dummy_audio_getdev(struct sparcaudio_driver *drv, + audio_device_t * audinfo) +{ + strncpy(audinfo->name, "SUNW,cs4231", sizeof(audinfo->name) - 1); + strncpy(audinfo->version, "a", sizeof(audinfo->version) - 1); + strncpy(audinfo->config, "onboard1", sizeof(audinfo->config) - 1); +} + + +static int dummy_audio_getdev_sunos(struct sparcaudio_driver *drv) +{ + return (5); +} + +static struct sparcaudio_operations dummy_ops = { + dummy_open, + dummy_release, + NULL, + dummy_start_output, + dummy_stop_output, + dummy_start_input, + dummy_stop_input, + dummy_audio_getdev, + dummy_set_output_volume, + dummy_get_output_volume, + dummy_set_input_volume, + dummy_get_input_volume, + dummy_set_monitor_volume, + dummy_get_monitor_volume, + dummy_set_output_balance, + dummy_get_output_balance, + dummy_set_input_balance, + dummy_get_input_balance, + dummy_set_output_channels, + dummy_get_output_channels, + dummy_set_input_channels, + dummy_get_input_channels, + dummy_set_output_precision, + dummy_get_output_precision, + dummy_set_input_precision, + dummy_get_input_precision, + dummy_set_output_port, + dummy_get_output_port, + dummy_set_input_port, + dummy_get_input_port, + dummy_set_output_encoding, + dummy_get_output_encoding, + dummy_set_input_encoding, + dummy_get_input_encoding, + dummy_set_output_rate, + dummy_get_output_rate, + dummy_set_input_rate, + dummy_get_input_rate, + dummy_audio_getdev_sunos, + dummy_get_output_ports, + dummy_get_input_ports, + dummy_output_muted, + dummy_get_output_muted, + dummy_set_output_pause, + dummy_get_output_pause, + dummy_set_input_pause, + dummy_get_input_pause, + dummy_set_output_samples, + dummy_get_output_samples, + dummy_set_input_samples, + dummy_get_input_samples, + dummy_set_output_error, + dummy_get_output_error, + dummy_set_input_error, + dummy_get_input_error, + dummy_get_formats, +}; + +/* Probe for the dummy chip and then attach the driver. */ +#ifdef MODULE +int init_module(void) +#else +__initfunc(int dummy_init(void)) +#endif +{ + num_drivers = 0; + + /* Add support here for specifying multiple dummies to attach at once. */ + if (dummy_attach(&drivers[num_drivers]) == 0) + num_drivers++; + + /* Only return success if we found some dummy chips. */ + return (num_drivers > 0) ? 0 : -EIO; +} + +/* Attach to an dummy chip given its PROM node. */ +static int dummy_attach(struct sparcaudio_driver *drv) +{ + struct dummy_chip *dummy_chip; + int err; + + /* Allocate our private information structure. */ + drv->private = kmalloc(sizeof(struct dummy_chip), GFP_KERNEL); + if (!drv->private) + return -ENOMEM; + + /* Point at the information structure and initialize it. */ + drv->ops = &dummy_ops; + dummy_chip = (struct dummy_chip *)drv->private; + + /* Reset parameters. */ + dummy_chip_reset(drv); + + /* Register ourselves with the midlevel audio driver. */ + err = register_sparcaudio_driver(drv, 2); + + if (err < 0) { + printk(KERN_ERR "dummy: unable to register\n"); + kfree(drv->private); + return -EIO; + } + + dummy_chip->perchip_info.play.active = + dummy_chip->perchip_info.play.pause = 0; + + dummy_chip->perchip_info.play.avail_ports = (AUDIO_HEADPHONE | + AUDIO_SPEAKER | + AUDIO_LINE_OUT); + + /* Announce the hardware to the user. */ + printk(KERN_INFO "audio%d: dummy at 0x0 irq 0\n", drv->index); + + /* Success! */ + return 0; +} + +#ifdef MODULE +/* Detach from an dummy chip given the device structure. */ +static void dummy_detach(struct sparcaudio_driver *drv) +{ + unregister_sparcaudio_driver(drv, 2); + kfree(drv->private); +} + +void cleanup_module(void) +{ + register int i; + + for (i = 0; i < num_drivers; i++) { + dummy_detach(&drivers[i]); + num_drivers--; + } +} +#endif + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-indent-level: 4 + * c-brace-imaginary-offset: 0 + * c-brace-offset: -4 + * c-argdecl-indent: 4 + * c-label-offset: -4 + * c-continued-statement-offset: 4 + * c-continued-brace-offset: 0 + * indent-tabs-mode: nil + * tab-width: 8 + * End: + */ diff -ur --new-file old/linux/drivers/sbus/audio/dummy.h new/linux/drivers/sbus/audio/dummy.h --- old/linux/drivers/sbus/audio/dummy.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/sbus/audio/dummy.h Tue Mar 16 01:11:30 1999 @@ -0,0 +1,41 @@ +/* + * drivers/sbus/audio/dummy.h + * + * Copyright (C) 1998 Derrick J. Brashear (shadow@dementia.org) + */ + +#ifndef _DUMMY_H_ +#define _DUMMY_H_ + +#include +#include + +#define DUMMY_OUTFILE "/usr/tmp/dummy.au" + +/* Our structure for each chip */ + +struct dummy_chip { + struct audio_info perchip_info; + unsigned int playlen; + struct tq_struct tqueue; +}; + +#define DUMMY_MIN_ATEN (0) +#define DUMMY_MAX_ATEN (31) +#define DUMMY_MAX_DEV_ATEN (63) + +#define DUMMY_MON_MIN_ATEN (0) +#define DUMMY_MON_MAX_ATEN (63) + +#define DUMMY_DEFAULT_PLAYGAIN (132) +#define DUMMY_DEFAULT_RECGAIN (126) + +#define DUMMY_MIN_GAIN (0) +#define DUMMY_MAX_GAIN (15) + +#define DUMMY_PRECISION (8) /* # of bits/sample */ +#define DUMMY_CHANNELS (1) /* channels/sample */ + +#define DUMMY_RATE (8000) /* default sample rate */ + +#endif diff -ur --new-file old/linux/drivers/sbus/char/bpp.c new/linux/drivers/sbus/char/bpp.c --- old/linux/drivers/sbus/char/bpp.c Wed Dec 23 18:44:41 1998 +++ new/linux/drivers/sbus/char/bpp.c Tue Mar 16 01:11:30 1999 @@ -337,7 +337,7 @@ * responds real good. The first while loop guesses an expire * time accounting for possible wraparound of jiffies. */ - while (time_after_eq(jiffies, extime) extime = jiffies + 1; + while (time_after_eq(jiffies, extime)) extime = jiffies + 1; while ( (time_before(jiffies, extime)) && (((pins & set) != set) || ((pins & clr) != 0)) ) { pins = get_pins(minor); @@ -470,13 +470,14 @@ * mode as this is a reasonable place to clean up from messes made by * ioctls, or other mayhem. */ -static void bpp_release(struct inode *inode, struct file *f) +static int bpp_release(struct inode *inode, struct file *f) { unsigned minor = MINOR(inode->i_rdev); instances[minor].opened = 0; if (instances[minor].mode != COMPATIBILITY) terminate(minor); + return 0; } static long read_nibble(unsigned minor, char *c, unsigned long cnt) @@ -624,11 +625,10 @@ return cnt - remaining; } -static long bpp_read(struct inode *inode, struct file *f, - char *c, unsigned long cnt) +static ssize_t bpp_read(struct file *f, char *c, size_t cnt, loff_t * ppos) { long rc; - const unsigned minor = MINOR(inode->i_rdev); + const unsigned minor = MINOR(f->f_dentry->d_inode->i_rdev); if (minor >= BPP_NO) return -ENODEV; if (!instances[minor].present) return -ENODEV; @@ -694,10 +694,12 @@ unsigned long remaining = cnt; + while (remaining > 0) { unsigned char byte; - c += 1; + get_user_ret(byte, c, -EFAULT); + c += 1; rc = wait_for(BPP_GP_nAck, BPP_GP_Busy, TIME_IDLE_LIMIT, minor); if (rc == -1) return -ETIMEDOUT; @@ -774,11 +776,10 @@ * that. Otherwise, terminate and do my writing in compat mode. This * is the safest course as any device can handle it. */ -static long bpp_write(struct inode *inode, struct file *f, - const char *c, unsigned long cnt) +static ssize_t bpp_write(struct file *f, const char *c, size_t cnt, loff_t * ppos) { long errno = 0; - unsigned minor = MINOR(inode->i_rdev); + const unsigned minor = MINOR(f->f_dentry->d_inode->i_rdev); if (minor >= BPP_NO) return -ENODEV; if (!instances[minor].present) return -ENODEV; @@ -861,6 +862,11 @@ bpp_open, NULL, /* flush */ bpp_release, + NULL, /* fsync */ + NULL, /* fasync */ + NULL, /* check media change */ + NULL, /* revalidate */ + NULL, /* lock */ }; #if defined(__i386__) diff -ur --new-file old/linux/drivers/sbus/char/flash.c new/linux/drivers/sbus/char/flash.c --- old/linux/drivers/sbus/char/flash.c Sun Oct 4 19:22:44 1998 +++ new/linux/drivers/sbus/char/flash.c Tue Mar 16 01:11:30 1999 @@ -1,4 +1,4 @@ -/* $Id: flash.c,v 1.10 1998/08/26 10:29:41 davem Exp $ +/* $Id: flash.c,v 1.11 1999/03/09 14:06:45 davem Exp $ * flash.c: Allow mmap access to the OBP Flash, for OBP updates. * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -72,8 +72,6 @@ if (remap_page_range(vma->vm_start, addr, size, vma->vm_page_prot)) return -EAGAIN; - vma->vm_file = file; - file->f_count++; return 0; } diff -ur --new-file old/linux/drivers/sbus/char/pcikbd.c new/linux/drivers/sbus/char/pcikbd.c --- old/linux/drivers/sbus/char/pcikbd.c Mon Nov 16 19:37:28 1998 +++ new/linux/drivers/sbus/char/pcikbd.c Tue May 11 17:24:32 1999 @@ -1,4 +1,4 @@ -/* $Id: pcikbd.c,v 1.24 1998/11/08 11:15:24 davem Exp $ +/* $Id: pcikbd.c,v 1.27 1999/05/09 06:40:47 ecd Exp $ * pcikbd.c: Ultra/AX PC keyboard support. * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -228,8 +228,6 @@ "\r\000/"; /* 0x60 - 0x6f */ #endif -static unsigned int prev_scancode = 0; - int pcikbd_setkeycode(unsigned int scancode, unsigned int keycode) { if(scancode < SC_LIM || scancode > 255 || keycode > 127) @@ -262,29 +260,23 @@ return 0; } } - if(scancode == 0) { - prev_scancode = 0; - return 0; - } return 1; } -int pcikbd_pretranslate(unsigned char scancode, char raw_mode) +int pcikbd_translate(unsigned char scancode, unsigned char *keycode, + char raw_mode) { - if(scancode == 0xff) { - prev_scancode = 0; + static int prev_scancode = 0; + + if (scancode == 0xe0 || scancode == 0xe1) { + prev_scancode = scancode; return 0; } - if(scancode == 0xe0 || scancode == 0xe1) { - prev_scancode = scancode; + if (scancode == 0x00 || scancode == 0xff) { + prev_scancode = 0; return 0; } - return 1; -} - -int pcikbd_translate(unsigned char scancode, unsigned char *keycode, - char raw_mode) -{ + scancode &= 0x7f; if(prev_scancode) { if(prev_scancode != 0xe0) { if(prev_scancode == 0xe1 && scancode == 0x1d) { @@ -338,7 +330,7 @@ break; scancode = pcikbd_inb(pcikbd_iobase + KBD_DATA_REG); if((status & KBD_STAT_OBF) && do_acknowledge(scancode)) - handle_scancode(scancode); + handle_scancode(scancode, !(scancode & 0x80)); status = pcikbd_inb(pcikbd_iobase + KBD_STATUS_REG); } while(status & KBD_STAT_OBF); mark_bh(KEYBOARD_BH); @@ -985,9 +977,11 @@ } queue = (struct aux_queue *) kmalloc(sizeof(*queue), GFP_KERNEL); + if (!queue) { + printk("pcimouse_init: kmalloc(aux_queue) failed.\n"); + return -ENOMEM; + } memset(queue, 0, sizeof(*queue)); - queue->head = queue->tail = 0; - queue->proc_list = NULL; if (request_irq(pcimouse_irq, &pcimouse_interrupt, SA_SHIRQ, "mouse", (void *)pcimouse_iobase)) { diff -ur --new-file old/linux/drivers/sbus/char/sab82532.c new/linux/drivers/sbus/char/sab82532.c --- old/linux/drivers/sbus/char/sab82532.c Wed Dec 23 18:44:41 1998 +++ new/linux/drivers/sbus/char/sab82532.c Thu Mar 25 18:23:34 1999 @@ -1,4 +1,4 @@ -/* $Id: sab82532.c,v 1.27 1998/11/08 11:15:25 davem Exp $ +/* $Id: sab82532.c,v 1.30 1999/03/24 11:34:52 davem Exp $ * sab82532.c: ASYNC Driver for the SIEMENS SAB82532 DUSCC. * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -2136,7 +2136,7 @@ __initfunc(static inline void show_serial_version(void)) { - char *revision = "$Revision: 1.27 $"; + char *revision = "$Revision: 1.30 $"; char *version, *p; version = strchr(revision, ' '); @@ -2359,8 +2359,10 @@ restore_flags(flags); for (i = 0; i < NR_PORTS; i++) { - if (sab82532_table[i].type != PORT_UNKNOWN) - release_region(sab82532_table[i].port, 8); + struct sab82532 *info = (struct sab82532 *)sab82532_table[i]->driver_data; + if (info->type != PORT_UNKNOWN) + release_region((unsigned long)info->regs, + sizeof(union sab82532_async_regs)); } if (tmp_buf) { free_page((unsigned long) tmp_buf); diff -ur --new-file old/linux/drivers/sbus/char/su.c new/linux/drivers/sbus/char/su.c --- old/linux/drivers/sbus/char/su.c Wed Dec 23 18:44:41 1998 +++ new/linux/drivers/sbus/char/su.c Tue Mar 16 01:11:30 1999 @@ -1,4 +1,4 @@ -/* $Id: su.c,v 1.16 1998/11/14 23:02:54 ecd Exp $ +/* $Id: su.c,v 1.18 1999/01/02 16:47:37 davem Exp $ * su.c: Small serial driver for keyboard/mouse interface on sparc32/PCI * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -157,7 +157,7 @@ #define WAKEUP_CHARS 256 static void autoconfig(struct su_struct *info); -static void change_speed(struct su_struct *info); +static void change_speed(struct su_struct *info, struct termios *old); static void su_wait_until_sent(struct tty_struct *tty, int timeout); /* @@ -845,7 +845,7 @@ /* * and set the speed of the serial port */ - change_speed(info); + change_speed(info, 0); info->flags |= ASYNC_INITIALIZED; restore_flags(flags); @@ -948,7 +948,8 @@ * the specified baud rate for a serial port. */ static void -change_speed(struct su_struct *info) +change_speed(struct su_struct *info, + struct termios *old_termios) { int quot = 0, baud; unsigned int cval, fcr = 0; @@ -999,7 +1000,25 @@ else if (baud) quot = info->baud_base / baud; } - /* If the quotient is ever zero, default to 9600 bps */ + /* If the quotient is zero refuse the change */ + if (!quot && old_termios) { + info->tty->termios->c_cflag &= ~CBAUD; + info->tty->termios->c_cflag |= (old_termios->c_cflag & CBAUD); + baud = tty_get_baud_rate(info->tty); + if (!baud) + baud = 9600; + if (baud == 38400 && + ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)) + quot = info->custom_divisor; + else { + if (baud == 134) + /* Special case since 134 is really 134.5 */ + quot = (2*info->baud_base / 269); + else if (baud) + quot = info->baud_base / baud; + } + } + /* As a last resort, if the quotient is zero, default to 9600 bps */ if (!quot) quot = info->baud_base / 9600; info->timeout = ((info->xmit_fifo_size*HZ*bits*quot) / info->baud_base); @@ -1157,7 +1176,7 @@ info->cflag |= 1200; break; } - change_speed(info); + change_speed(info, 0); } static void @@ -1303,6 +1322,9 @@ if (serial_paranoia_check(info, tty->device, "su_send_char")) return; + if (!(info->flags & ASYNC_INITIALIZED)) + return; + info->x_char = ch; if (ch) { /* Make sure transmit interrupts are on */ @@ -1618,7 +1640,7 @@ == RELEVANT_IFLAG(old_termios->c_iflag))) return; - change_speed(info); + change_speed(info, old_termios); /* Handle transition to B0 status */ if ((old_termios->c_cflag & CBAUD) && @@ -2067,13 +2089,13 @@ *tty->termios = info->normal_termios; else *tty->termios = info->callout_termios; - change_speed(info); + change_speed(info, 0); } #ifdef CONFIG_SERIAL_CONSOLE if (sercons.cflag && sercons.index == line) { tty->termios->c_cflag = sercons.cflag; sercons.cflag = 0; - change_speed(info); + change_speed(info, 0); } #endif info->session = current->session; @@ -2193,7 +2215,7 @@ */ __initfunc(static __inline__ void show_su_version(void)) { - char *revision = "$Revision: 1.16 $"; + char *revision = "$Revision: 1.18 $"; char *version, *p; version = strchr(revision, ' '); @@ -2207,8 +2229,8 @@ * This routine is called by su_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. + * whether or not this UART is a 16550A, since this will determine + * whether or not we can use its FIFO features. */ static void autoconfig(struct su_struct *info) diff -ur --new-file old/linux/drivers/sbus/char/sunkbd.c new/linux/drivers/sbus/char/sunkbd.c --- old/linux/drivers/sbus/char/sunkbd.c Sun Oct 4 19:22:44 1998 +++ new/linux/drivers/sbus/char/sunkbd.c Fri Apr 23 04:24:51 1999 @@ -514,8 +514,13 @@ mark_bh(CONSOLE_BH); add_keyboard_randomness(keycode); + tty = ttytab? ttytab[fg_console]: NULL; + if (tty && (!tty->driver_data)) { + /* This is to workaround ugly bug in tty_io.c, which + does not do locking when it should */ + tty = NULL; + } kbd = kbd_table + fg_console; - tty = ttytab[fg_console]; if((raw_mode = (kbd->kbdmode == VC_RAW))) { if (kbd_redirected == fg_console+1) push_kbd (keycode); @@ -1474,7 +1479,7 @@ return 0; if (kbd_redirected) - kbd_table [kbd_opened-1].kbdmode = VC_XLATE; + kbd_table [kbd_redirected-1].kbdmode = VC_XLATE; kbd_redirected = 0; kbd_opened = 0; diff -ur --new-file old/linux/drivers/sbus/char/sunmouse.c new/linux/drivers/sbus/char/sunmouse.c --- old/linux/drivers/sbus/char/sunmouse.c Sun Oct 4 19:22:44 1998 +++ new/linux/drivers/sbus/char/sunmouse.c Fri Apr 23 04:24:51 1999 @@ -94,7 +94,7 @@ #undef SMOUSE_DEBUG -static void +static int push_event (Firm_event *ev) { int next = (sunmouse.head + 1) % EV_SIZE; @@ -102,7 +102,9 @@ if (next != sunmouse.tail){ sunmouse.queue.ev [sunmouse.head] = *ev; sunmouse.head = next; + return 1; } + return 0; } static int @@ -150,7 +152,11 @@ extern void rs_change_mouse_baud(int newbaud); if(mouse_baud == 1200) + mouse_baud = 2400; + else if(mouse_baud == 2400) mouse_baud = 4800; + else if(mouse_baud == 4800) + mouse_baud = 9600; else mouse_baud = 1200; @@ -196,7 +202,7 @@ sun_mouse_inbyte(unsigned char byte) { signed char mvalue; - int d; + int d, pushed = 0; Firm_event ev; add_mouse_randomness (byte); @@ -290,29 +296,31 @@ } ev.time = xtime; ev.value = ev.value ? VKEY_DOWN : VKEY_UP; - push_event (&ev); + pushed += push_event (&ev); } if (sunmouse.delta_x){ ev.id = LOC_X_DELTA; ev.time = xtime; ev.value = sunmouse.delta_x; - push_event (&ev); + pushed += push_event (&ev); sunmouse.delta_x = 0; } if (sunmouse.delta_y){ ev.id = LOC_Y_DELTA; ev.time = xtime; ev.value = sunmouse.delta_y; - push_event (&ev); + pushed += push_event (&ev); } - /* We just completed a transaction, wake up whoever is awaiting - * this event. - */ - sunmouse.ready = 1; - if (sunmouse.fasync) - kill_fasync (sunmouse.fasync, SIGIO); - wake_up_interruptible(&sunmouse.proc_list); + if(pushed != 0) { + /* We just completed a transaction, wake up whoever is awaiting + * this event. + */ + sunmouse.ready = 1; + if (sunmouse.fasync) + kill_fasync (sunmouse.fasync, SIGIO); + wake_up_interruptible(&sunmouse.proc_list); + } return; } diff -ur --new-file old/linux/drivers/sbus/char/sunserial.c new/linux/drivers/sbus/char/sunserial.c --- old/linux/drivers/sbus/char/sunserial.c Tue Oct 27 18:52:21 1998 +++ new/linux/drivers/sbus/char/sunserial.c Tue Mar 16 01:11:30 1999 @@ -1,4 +1,4 @@ -/* $Id: sunserial.c,v 1.67 1998/10/25 03:22:46 jj Exp $ +/* $Id: sunserial.c,v 1.68 1998/12/09 18:53:51 davem Exp $ * serial.c: Serial port driver infrastructure for the Sparc. * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -401,10 +401,10 @@ return memory_start; #ifdef __sparc_v9__ - ret = prom_finddevice("/ssp-serial"); - if (ret && ret != -1) { + { extern int this_is_starfire; /* Hello, Starfire. Pleased to meet you :) */ - return memory_start; + if(this_is_starfire != 0) + return memory_start; } #endif diff -ur --new-file old/linux/drivers/sbus/char/vfc_dev.c new/linux/drivers/sbus/char/vfc_dev.c --- old/linux/drivers/sbus/char/vfc_dev.c Tue Oct 27 18:52:21 1998 +++ new/linux/drivers/sbus/char/vfc_dev.c Sun Mar 7 19:43:40 1999 @@ -582,8 +582,6 @@ if(ret) return -EAGAIN; - vma->vm_file = file; - file->f_count++; return 0; } diff -ur --new-file old/linux/drivers/sbus/char/zs.c new/linux/drivers/sbus/char/zs.c --- old/linux/drivers/sbus/char/zs.c Mon Nov 16 19:37:28 1998 +++ new/linux/drivers/sbus/char/zs.c Fri Apr 23 04:24:51 1999 @@ -1,4 +1,4 @@ -/* $Id: zs.c,v 1.32 1998/11/08 11:15:29 davem Exp $ +/* $Id: zs.c,v 1.41 1999/04/16 16:22:27 jj Exp $ * zs.c: Zilog serial port driver for the Sparc. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -53,6 +53,22 @@ #define KEYBOARD_LINE 0x2 #define MOUSE_LINE 0x3 +/* On 32-bit sparcs we need to delay after register accesses + * to accomodate sun4 systems, but we do not need to flush writes. + * On 64-bit sparc we only need to flush single writes to ensure + * completion. + */ +#ifndef __sparc_v9__ +#define ZSDELAY() udelay(5) +#define ZSDELAY_LONG() udelay(20) +#define ZS_WSYNC(channel) do { } while(0) +#else +#define ZSDELAY() +#define ZSDELAY_LONG() +#define ZS_WSYNC(channel) \ + ((void) *((volatile unsigned char *)(&((channel)->control)))) +#endif + struct sun_zslayout **zs_chips; struct sun_zschannel **zs_channels; struct sun_zschannel *zs_mousechan; @@ -200,9 +216,9 @@ unsigned char retval; channel->control = reg; - udelay(5); + ZSDELAY(); retval = channel->control; - udelay(5); + ZSDELAY(); return retval; } @@ -210,9 +226,9 @@ unsigned char reg, unsigned char value) { channel->control = reg; - udelay(5); + ZSDELAY(); channel->control = value; - udelay(5); + ZSDELAY(); } static inline void load_zsregs(struct sun_serial *info, unsigned char *regs) @@ -239,7 +255,7 @@ write_zsreg(channel, R9, CHRA); else write_zsreg(channel, R9, CHRB); - udelay(20); /* wait for some old sun4's */ + ZSDELAY_LONG(); write_zsreg(channel, R4, regs[R4]); write_zsreg(channel, R3, regs[R3] & ~RxENAB); write_zsreg(channel, R5, regs[R5] & ~TxENAB); @@ -267,10 +283,16 @@ { int loops = ZS_PUT_CHAR_MAX_DELAY; + /* Do not change this to use ZSDELAY as this is + * a timed polling loop and on sparc64 ZSDELAY + * is a nop. -DaveM + */ while((channel->control & Tx_BUF_EMP) == 0 && --loops) udelay(5); + channel->data = ch; - udelay(5); + ZSDELAY(); + ZS_WSYNC(channel); } /* Sets or clears DTR/RTS on the requested line */ @@ -420,7 +442,7 @@ do { ch = (info->zs_channel->data) & info->parity_mask; - udelay(5); + ZSDELAY(); /* If this is the console keyboard, we need to handle * L1-A's here. @@ -482,7 +504,7 @@ /* Check if we have another character... */ stat = info->zs_channel->control; - udelay(5); + ZSDELAY(); if (!(stat & Rx_CH_AV)) break; @@ -507,7 +529,8 @@ if((info->xmit_cnt <= 0) || (tty != 0 && tty->stopped)) { /* That's peculiar... */ info->zs_channel->control = RES_Tx_P; - udelay(5); + ZSDELAY(); + ZS_WSYNC(info->zs_channel); return; } @@ -521,7 +544,8 @@ if(info->xmit_cnt <= 0) { info->zs_channel->control = RES_Tx_P; - udelay(5); + ZSDELAY(); + ZS_WSYNC(info->zs_channel); } } @@ -531,10 +555,11 @@ /* Get status from Read Register 0 */ status = info->zs_channel->control; - udelay(5); + ZSDELAY(); /* Clear status condition... */ info->zs_channel->control = RES_EXT_INT; - udelay(5); + ZSDELAY(); + ZS_WSYNC(info->zs_channel); #if 0 if(status & DCD) { @@ -571,7 +596,7 @@ stat = read_zsreg(info->zs_channel, R1); if (stat & (PAR_ERR | Rx_OVR | CRC_ERR)) { ch = info->zs_channel->data; - udelay(5); + ZSDELAY(); } if (!tty) @@ -592,7 +617,8 @@ queue_task(&tty->flip.tqueue, &tq_timer); clear: info->zs_channel->control = ERR_RES; - udelay(5); + ZSDELAY(); + ZS_WSYNC(info->zs_channel); } @@ -772,9 +798,12 @@ * Clear the interrupt registers. */ info->zs_channel->control = ERR_RES; - udelay(5); + ZSDELAY(); + ZS_WSYNC(info->zs_channel); + info->zs_channel->control = RES_H_IUS; - udelay(5); + ZSDELAY(); + ZS_WSYNC(info->zs_channel); /* * Now, initialize the Zilog @@ -798,9 +827,12 @@ * And clear the interrupt registers again for luck. */ info->zs_channel->control = ERR_RES; - udelay(5); + ZSDELAY(); + ZS_WSYNC(info->zs_channel); + info->zs_channel->control = RES_H_IUS; - udelay(5); + ZSDELAY(); + ZS_WSYNC(info->zs_channel); if (info->tty) clear_bit(TTY_IO_ERROR, &info->tty->flags); @@ -1006,6 +1038,7 @@ while((chan->control & Tx_BUF_EMP)==0) udelay(5); chan->data = kgdb_char; + ZS_WSYNC(chan); } char getDebugChar(void) @@ -1013,7 +1046,7 @@ struct sun_zschannel *chan = zs_kgdbchan; while((chan->control & Rx_CH_AV)==0) - barrier(); + udelay(5); return chan->data; } @@ -1254,6 +1287,9 @@ goto check_and_exit; } + if(new_serial.baud_base < 9600) + return -EINVAL; + if (info->count > 1) return -EBUSY; @@ -1291,6 +1327,7 @@ cli(); status = info->zs_channel->control; + ZSDELAY(); sti(); put_user_ret(status,value, -EFAULT); return 0; @@ -1303,6 +1340,7 @@ cli(); status = info->zs_channel->control; + ZSDELAY(); sti(); result = ((info->curregs[5] & RTS) ? TIOCM_RTS : 0) | ((info->curregs[5] & DTR) ? TIOCM_DTR : 0) @@ -1806,7 +1844,7 @@ static void show_serial_version(void) { - char *revision = "$Revision: 1.32 $"; + char *revision = "$Revision: 1.41 $"; char *version, *p; version = strchr(revision, ' '); @@ -1853,8 +1891,8 @@ int len = prom_getproperty(zsnode, "address", (void *) vaddr, sizeof(vaddr)); - if(len == -1) { - struct linux_sbus *sbus; + if(len == -1 || central_bus != NULL) { + struct linux_sbus *sbus = NULL; struct linux_sbus_device *sdev = NULL; /* "address" property is not guarenteed, @@ -1862,20 +1900,40 @@ * anyways by our clever TLB miss handling * scheme, so don't fail here. -DaveM */ - for_each_sbus(sbus) { - for_each_sbusdev(sdev, sbus) { - if (sdev->prom_node == zsnode) - goto found; + if (central_bus == NULL) { + for_each_sbus(sbus) { + for_each_sbusdev(sdev, sbus) { + if (sdev->prom_node == zsnode) + goto found; + } } } found: - if (sdev == NULL) + if (sdev == NULL && central_bus == NULL) prom_halt(); - prom_apply_sbus_ranges(sbus, sdev->reg_addrs, 1, sdev); - mapped_addr = (unsigned long) - sparc_alloc_io(sdev->reg_addrs[0].phys_addr, 0, - PAGE_SIZE, "Zilog Registers", - sdev->reg_addrs[0].which_io, 0x0); + if (central_bus == NULL) { + prom_apply_sbus_ranges(sbus, sdev->reg_addrs, 1, sdev); + mapped_addr = (unsigned long) + sparc_alloc_io(sdev->reg_addrs[0].phys_addr, 0, + PAGE_SIZE, "Zilog Registers", + sdev->reg_addrs[0].which_io, 0x0); + } else { + struct linux_prom_registers zsregs[1]; + int err; + + err = prom_getproperty(zsnode, "reg", + (char *)&zsregs[0], + sizeof(zsregs)); + if (err == -1) { + prom_printf("ZS: Cannot map Zilog regs.\n"); + prom_halt(); + } + prom_apply_fhc_ranges(central_bus->child, &zsregs[0], 1); + prom_apply_central_ranges(central_bus, &zsregs[0], 1); + mapped_addr = (unsigned long) + __va((((unsigned long)zsregs[0].which_io)<<32) | + (((unsigned long)zsregs[0].phys_addr))); + } } else if(len % sizeof(unsigned int)) { prom_printf("WHOOPS: proplen for %s " "was %d, need multiple of " @@ -1954,25 +2012,27 @@ /* Can use the prom for other machine types */ zsnode = prom_getchild(prom_root_node); if (sparc_cpu_model == sun4d) { - int board, node; + int node; + int no = 0; tmpnode = zsnode; + zsnode = 0; + bbnode = 0; while (tmpnode && (tmpnode = prom_searchsiblings(tmpnode, "cpu-unit"))) { - board = prom_getintdefault (tmpnode, "board#", -1); - if (board == (chip >> 1)) { - node = prom_getchild(tmpnode); - if (node && (node = prom_searchsiblings(node, "bootbus"))) { + bbnode = prom_getchild(tmpnode); + if (bbnode && (bbnode = prom_searchsiblings(bbnode, "bootbus"))) { + if (no == (chip >> 1)) { cpunode = tmpnode; - bbnode = node; - zsnode = prom_getchild(node); + zsnode = prom_getchild(bbnode); chipid = (chip & 1); break; } + no++; } tmpnode = prom_getsibling(tmpnode); } if (!tmpnode) - panic ("get_zs: couldn't find board%d's bootbus\n", chip >> 1); + panic ("get_zs: couldn't find %dth bootbus\n", chip >> 1); } else { tmpnode = prom_searchsiblings(zsnode, "obio"); if(tmpnode) @@ -2066,13 +2126,12 @@ node = prom_getchild(prom_root_node); if (sparc_cpu_model == sun4d) { - node = prom_searchsiblings(node, "boards"); - if (!node) - panic ("Cannot find out count of boards"); - else - node = prom_getchild(node); - while (node && (node = prom_searchsiblings(node, "bif"))) { - NUM_SERIAL += 2; + int bbnode; + + while (node && (node = prom_searchsiblings(node, "cpu-unit"))) { + bbnode = prom_getchild(node); + if (bbnode && prom_searchsiblings(bbnode, "bootbus")) + NUM_SERIAL += 2; node = prom_getsibling(node); } goto no_probe; @@ -2082,7 +2141,7 @@ int central_node; /* Central bus zilogs must be checked for first, - * since Enterprise boxes have SBUS as well. + * since Enterprise boxes might have SBUSes as well. */ central_node = prom_finddevice("/central"); if(central_node != 0 && central_node != -1) @@ -2219,11 +2278,6 @@ return 0; #endif -#ifdef CONFIG_PCI - if (pci_present()) - return 0; -#endif - /* Setup base handler, and timer table. */ init_bh(SERIAL_BH, do_serial_bh); timer_table[RS_TIMER].fn = zs_timer; @@ -2290,13 +2344,21 @@ /* Initialize Softinfo */ zs_prepare(); + /* Grab IRQ line before poking the chips so we do + * not lose any interrupts. + */ + if (request_irq(zilog_irq, zs_interrupt, + (SA_INTERRUPT | SA_STATIC_ALLOC), + "Zilog8530", zs_chain)) + panic("Unable to attach zs intr\n"); + /* Initialize Hardware */ for(channel = 0; channel < NUM_CHANNELS; channel++) { /* Hardware reset each chip */ if (!(channel & 1)) { write_zsreg(zs_soft[channel].zs_channel, R9, FHWRES); - udelay(20); /* wait for some old sun4's */ + ZSDELAY_LONG(); dummy = read_zsreg(zs_soft[channel].zs_channel, R0); } @@ -2462,10 +2524,6 @@ printk(" is a Zilog8530\n"); } - if (request_irq(zilog_irq, zs_interrupt, - (SA_INTERRUPT | SA_STATIC_ALLOC), - "Zilog8530", zs_chain)) - panic("Unable to attach zs intr\n"); restore_flags(flags); keyboard_zsinit(kbd_put_char); @@ -2549,7 +2607,7 @@ /* Last character is being transmitted now (hopefully). */ info->zs_channel->control = RES_Tx_P; - udelay(5); + ZSDELAY(); restore_flags(flags); return; diff -ur --new-file old/linux/drivers/sbus/sbus.c new/linux/drivers/sbus/sbus.c --- old/linux/drivers/sbus/sbus.c Tue Oct 27 18:52:21 1998 +++ new/linux/drivers/sbus/sbus.c Tue Mar 16 01:11:30 1999 @@ -1,4 +1,4 @@ -/* $Id: sbus.c,v 1.73 1998/10/07 11:35:50 jj Exp $ +/* $Id: sbus.c,v 1.76 1998/12/17 11:11:26 davem Exp $ * sbus.c: SBus support routines. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -71,7 +71,7 @@ base = (unsigned long) sbus_dev->reg_addrs[0].phys_addr; if(base>=SUN_SBUS_BVADDR || (sparc_cpu_model != sun4c && - sparc_cpu_model != sun4)) { + sparc_cpu_model != sun4)) { /* Ahh, we can determine the slot and offset */ if(sparc_cpu_model == sun4u) { /* A bit tricky on the SYSIO. */ @@ -261,6 +261,11 @@ if (!pcibios_present()) { prom_printf("Neither SBUS nor PCI found.\n"); prom_halt(); + } else { +#ifdef __sparc_v9__ + extern void firetruck_init(void); + firetruck_init(); +#endif } return; #else @@ -296,6 +301,7 @@ */ sbus = SBus_chain = kmalloc(sizeof(struct linux_sbus), GFP_ATOMIC); sbus->next = 0; + sbus->prom_node = nd; this_sbus=nd; if(iommund && sparc_cpu_model != sun4u && sparc_cpu_model != sun4d) @@ -319,7 +325,6 @@ prom_getstring(this_sbus, "name", lbuf, sizeof(lbuf)); lbuf[sizeof(sbus->prom_name) - 1] = 0; - sbus->prom_node = this_sbus; strcpy(sbus->prom_name, lbuf); sbus->clock_freq = sbus_clock; #ifndef __sparc_v9__ @@ -406,6 +411,7 @@ sbus->next = kmalloc(sizeof(struct linux_sbus), GFP_ATOMIC); sbus = sbus->next; sbus->next = 0; + sbus->prom_node = this_sbus; } else { break; } @@ -415,6 +421,13 @@ sun4d_init_sbi_irq(); } +#ifdef __sparc_v9__ + if (sparc_cpu_model == sun4u) { + extern void firetruck_init(void); + + firetruck_init(); + } +#endif #ifdef CONFIG_SUN_OPENPROMIO openprom_init(); #endif diff -ur --new-file old/linux/drivers/scsi/ChangeLog.ncr53c8xx new/linux/drivers/scsi/ChangeLog.ncr53c8xx --- old/linux/drivers/scsi/ChangeLog.ncr53c8xx Sun Jan 17 01:57:16 1999 +++ new/linux/drivers/scsi/ChangeLog.ncr53c8xx Mon Apr 12 18:51:04 1999 @@ -1,4 +1,38 @@ -Sat Jan 16 17:30 1998 Gerard Roudier (groudier@club-internet.fr) +Thu Mar 11 23:00 1999 Gerard Roudier (groudier@club-internet.fr) + * revision 3.2 (8xx-896 driver bundle) + - Only define the host template in ncr53c8xx.h and include the + sym53c8xx_defs.h file. + - Declare static all symbols that donnot need to be visible from + outside the driver code. + - Add 'excl' boot command option that allows to pass to the driver + io address of devices not to attach. + - Add info() function called from the host template to print + driver/host information. + - Minor documentation additions. + +Sat Mar 6 11:00 1999 Gerard Roudier (groudier@club-internet.fr) + * revision 3.1h + - Fix some oooold bug that hangs the bus if a device rejects a + negotiation. Btw, the corresponding stuff also needed some cleanup + and thus the change is a bit larger than it could have been. + - Still some typo that made compilation fail for 64 bit (trivial fix). + +Sun Feb 14:00 1999 Gerard Roudier (groudier@club-internet.fr) + * revision 3.1g + - Deal correctly with 64 bit PCI address registers on Linux 2.2. + Pointed out by Leonard Zubkoff. + - Allow to tune request_irq() flags from the boot command line using + ncr53c8xx=irqm:??, as follows: + a) If bit 0x10 is set in irqm, SA_SHIRQ flag is not used. + b) If bit 0x20 is set in irqm, SA_INTERRUPT flag is not used. + By default the driver uses both SA_SHIRQ and SA_INTERRUPT. + Option 'ncr53c8xx=irqm:0x20' may be used when an IRQ is shared by + a 53C8XX adapter and a network board. + - Tiny mispelling fixed (ABORT instead of ABRT). Was fortunately + harmless. + - Negotiate SYNC data transfers with CCS devices. + +Sat Jan 16 17:30 1999 Gerard Roudier (groudier@club-internet.fr) * revision 3.1f - Some PCI fix-ups not needed any more for PPC (from Cort). - Cache line size set to 16 DWORDS for Sparc (from DSM). diff -ur --new-file old/linux/drivers/scsi/ChangeLog.sym53c8xx new/linux/drivers/scsi/ChangeLog.sym53c8xx --- old/linux/drivers/scsi/ChangeLog.sym53c8xx Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/scsi/ChangeLog.sym53c8xx Mon Apr 12 18:51:04 1999 @@ -0,0 +1,219 @@ +Sat Mar 20 21:00 1999 Gerard Roudier (groudier@club-internet.fr) + * version sym53c8xx-1.3b + - Add support for NCR PQS PDS. + James Bottomley + - Allow value 0 for host ID. + - Support more than 8 controllers (> 40 in fact :-) ) + - Add 'excl=#ioaddr' boot option: exclude controller. + (Version 1.3a driver) + +Thu Mar 11 23:00 1999 Gerard Roudier (groudier@club-internet.fr) + * version sym53c8xx-1.3 (8xx-896 driver bundle) + - Equivalent changes as ncr53c8xx-3.2 due to the driver bundle. + (See Changelog.ncr53c8xx) + - Do a normal soft reset as first chip reset, since aborting current + operation may raise an interrupt we are not able to handle since + the interrupt handler is not yet established. + +Sat Mar 6 11:00 1999 Gerard Roudier (groudier@club-internet.fr) + * version sym53c8xx-1.2b + - Fix some oooold bug that hangs the bus if a device rejects a + negotiation. Btw, the corresponding stuff also needed some cleanup + and thus the change is a bit larger than it could have been. + - Still some typo that made compilation fail for 64 bit (trivial fix). + +Sun Feb 21 20:00 1999 Gerard Roudier (groudier@club-internet.fr) + * version sym53c8xx-1.2a + - The rewrite of the interrupt handling broke the SBMC interrupt + handling due to a 1 bit mask tiny error. Hopefully fixed. + - If INQUIRY came from a scatter list, the driver looked into + the scatterlist instead of the data.:) Since this should never + happen, we just discard the data if use_sg is not zero. + +Fri Feb 12 23:00 1999 Gerard Roudier (groudier@club-internet.fr) + * version sym53c8xx-1.2 + - Major rewrite of the interrupt handling and recovery stuff for + the support of non compliant SCSI removal, insertion and all + kinds of screw-up that may happen on the SCSI BUS. + Hopefully, the driver is now unbreakable or may-be, it is just + quite brocken. :-) + Many thanks to Johnson Russel (Symbios) for having responded to + my questions and for his interesting advices and comments about + support of SCSI hot-plug. + - Add 'recovery' option to driver set-up. + - Negotiate SYNC data transfers with CCS devices. + - Deal correctly with 64 bit PCI address registers on Linux 2.2. + Pointed out by Leonard Zubkoff. + +Sun Jan 31 18:00 1999 Gerard Roudier (groudier@club-internet.fr) + * version sym53c8xx-1.1a + - Some 896 chip revisions (all for now :-)), may hang-up if the + soft reset bit is set at the wrong time while SCRIPTS are running. + We need to first abort the current SCRIPTS operation prior to + resetting the chip. This fix has been sent to me by SYMBIOS/LSI + and I just translated it into ncr53c8xx syntax. + Must be considered 100 % trustable, unless I did some mistake + when translating it. :-) + +Sun Jan 24 18:00 1999 Gerard Roudier (groudier@club-internet.fr) + * version sym53c8xx-1.1 + - Major rewrite of the SCSI parity error handling. + The informations contained in the data manuals are incomplete about + this feature. + I asked SYMBIOS about and got in reply the explanations that are + _indeed_ missing in the data manuals. + - Allow to tune request_irq() flags from the boot command line using + ncr53c8xx=irqm:??, as follows: + a) If bit 0x10 is set in irqm, SA_SHIRQ flag is not used. + b) If bit 0x20 is set in irqm, SA_INTERRUPT flag is not used. + By default the driver uses both SA_SHIRQ and SA_INTERRUPT. + Option 'ncr53c8xx=irqm:0x20' may be used when an IRQ is shared by + a 53C8XX adapter and a network board. + - Fix for 64 bit PCI address register calculation. (Lance Robinson) + - Fix for big-endian in phase mismatch handling. (Michal Jaegermann) + +Fri Jan 1 20:00 1999 Gerard Roudier (groudier@club-internet.fr) + * version sym53c8xx-1.0a + - Waiting list look-up didn't work for the first command of the list. + Hopefully fixed, but tested on paper only. ;) + - Remove the most part of PPC specific code for Linux-2.2. + Thanks to Cort. + - Some other minors changes. + +Sat Dec 19 21:00 1998 Gerard Roudier (groudier@club-internet.fr) + * version sym53c8xx-1.0 + - Define some new IO registers for the 896 (istat1, mbox0, mbox1) + - Revamp slighly the Symbios NVRAM lay-out based on the excerpt of + the header file I received from Symbios. + - Check the PCI bus number for the boot order (Using a fast + PCI controller behing a PCI-PCI bridge seems sub-optimal). + - Disable overlapped PCI arbitration for the 896 revision 1. + - Reduce a bit the number of IO register reads for phase mismatch + by reading DWORDS at a time instead of BYTES. + +Thu Dec 3 24:00 1998 Gerard Roudier (groudier@club-internet.fr) + * version pre-sym53c8xx-0.18 + - I received this afternoon a 896 from SYMBIOS and started testing + the driver with this beast. After having fixed 3 buglets, it worked + with all features enabled including the phase mismatch handling + from SCRIPTS. Since this feature is not yet tested enough, the + boot option 'ncr53c8xx=specf:1' is still required to enable the + driver to handle PM from SCRIPTS. + +Sun Nov 29 18:00 1998 Gerard Roudier (groudier@club-internet.fr) + * version pre-sym53c8xx-0.17 + - The SISL RAID change requires now remap_pci_mem() stuff to be + compiled for __i386__ when normal IOs are used. + - The PCI memory read from SCRIPTS that should ensure ordering + was in fact misplaced. BTW, this may explain why broken PCI + device drivers regarding ordering are working so well. ;-) + - Rewrite ncr53c8xx_setup (boot command line options) since the + binary code was a bit too bloated in my opinion. + - Make the code simpler in the wakeup_done routine. + +Tue Nov 24 23:00 1998 Gerard Roudier (groudier@club-internet.fr) + * version pre-sym53c8xx-0.16 + - Add SCSI_NCR_OPTIMIZE_896_1 compile option and 'optim' boot option. + When set, the driver unconditionnaly assumes that the interrupt + handler is called for command completion, then clears INTF, scans + the done queue and returns if some completed CCB is found. If no + completed CCB are found, interrupt handling will proceed normally. + With a 896 that handles MA from SCRIPTS, this can be a great win, + since the driver will never performs PCI read transactions, but + only PCI write transactions that may be posted. + If the driver haven't to also raise the SIGP this would be perfect. + Even with this penalty, I think that this will work great. + Obviously this optimization makes sense only if the IRQ is not + shared with another device. + - Still a buglet in the tags initial settings that needed to be fixed. + It was not possible to disable TGQ at system startup for devices + that claim TGQ support. The driver used at least 2 for the queue + depth but did'nt keep track of user settings for tags depth lower + than 2. + +Thu Nov 19 23:00 1998 Gerard Roudier (groudier@club-internet.fr) + * version pre-sym53c8xx-0.15 + - Add support for hardware LED control of the 896. + - Ignore chips that are driven by SISL RAID (DAC 960). + Change sent by Leonard Zubkoff and slightly reworked. + - Prevent 810A rev 11 and 860 rev 1 from using cache line based + transactions since those early chip revisions may use such on + LOAD/STORE instructions (work-around). + - Remove some useless and bloat code from the pci init stuff. + - Donnot use the readX()/writeX() kernel functions for __i386__, + since they perform useless masking operations in order to deal + with broken driver in 2.1.X kernel. + +Wed Nov 11 10:00 1998 Gerard Roudier (groudier@club-internet.fr) + * version pre-sym53c8xx-0.14 + - The driver was unhappy when configured with default_tags > MAX_TAGS + Hopefully doubly-fixed. + - Set PCI_PARITY in PCI_COMMAND register in not set (PCI fix-up). + - Print out some message if phase mismatch is handled from SCRIPTS. + +Sun Nov 1 14H00 1998 Gerard Roudier (groudier@club-internet.fr) + * version pre-sym53c8xx-0.13 + - Some rewrite of the device detection code. This code had been + patched too much and needed to be face-lifted a bit. + Remove all platform dependant fix-ups that was not needed or + conflicted with some other driver code as work-arounds. + Reread the NVRAM before the calling of ncr_attach(). This spares + stack space and so allows to handle more boards. + Handle 64 bit base addresses under linux-2.0.X. + Set MASTER bit in PCI COMMAND register if not set. + +Wed Oct 30 22H00 1998 Gerard Roudier (groudier@club-internet.fr) + * version pre-sym53c8xx-0.12 + - Damned! I just broke the driver for Alpha by leaving a stale + instruction in the source code. Hopefully fixed. + - Donnot set PFEN when it is useless. Doing so we are sure that BOF + will be active, since the manual appears to be very unclear on what + feature is actually used by the chip when both PFEN and BOF are + set. + +Sat Oct 24 16H00 1998 Gerard Roudier (groudier@club-internet.fr) + * version pre-sym53c8xx-0.11 + - LOAD/STORE instructions were miscompiled for register offsets + beyond 0x7f. This broke accesses to 896' new registers. + - Disable by default Phase Mismatch handling from SCRIPTS, since + current 896 rev.1 seems not to operate safely with the driver + when this feature is enabled (and above LOAD/STORE fix applied). + I will change the default to 'enabled' when this problem will be + solved. + Using boot option 'ncr53c8xx=specf:1' enables this feature. + - Implement a work-around (DEL 472 - ITEM 5) that should allow the + driver to safely enable hardware phase mismatch with 896 rev. 1. + +Tue Oct 20 22H00 1998 Gerard Roudier (groudier@club-internet.fr) + * version pre-sym53c8xx-0.10 + - Add the 53c876 description to the chip table. This is only useful + for printing the right name of the controller. + - Add additionnal checking of INQUIRY data: + Check INQUIRY data received length is at least 7. Byte 7 of + inquiry data contains device features bits and the driver might + be confused by garbage. Also check peripheral qualifier. + - Use a 1,3,5,...MAXTAGS*2+1 tag numbering. Previous driver could + use any tag number from 1 to 253 and some non conformant devices + might have problems with large tag numbers. + - Use NAME53C and NAME53C8XX for chip name prefix chip family name. + Just give a try using "sym53c" and "sym53c8xx" instead of "ncr53c" + and "ncr53c8xx". :-) + +Sun Oct 11 17H00 1998 Gerard Roudier (groudier@club-internet.fr) + * version pre-sym53c8xx-0.9 + - DEL-441 Item 2 work-around for the 53c876 rev <= 5 (0x15). + - Break ncr_scatter() into 2 functions in order to guarantee best + possible code optimization for the case we get a scatter list. + - Add the code intended to support up to 1 tera-byte for 64 bit systems. + It is probably too early, but I wanted to complete the thing. + +Sat Oct 3 14H00 1998 Gerard Roudier (groudier@club-internet.fr) + * version pre-sym53c8xx-0.8 + - Do some testing with io_mapped and fix what needed to be so. + - Wait for SCSI selection to complete or time-out immediately after + the chip won arbitration, since executing SCRIPTS while the SCSI + core is performing SCSI selection breaks the selection procedure + at least for some chip revisions. + - Interrupt the SCRIPTS if a device does not go to MSG OUT phase after + having been selected with ATN. Such a situation is not recoverable, + better to fail when we are stuck. diff -ur --new-file old/linux/drivers/scsi/Config.in new/linux/drivers/scsi/Config.in --- old/linux/drivers/scsi/Config.in Sat Jan 2 19:21:06 1999 +++ new/linux/drivers/scsi/Config.in Thu Apr 29 20:53:41 1999 @@ -36,6 +36,9 @@ dep_tristate 'Always IN2000 SCSI support' CONFIG_SCSI_IN2000 $CONFIG_SCSI dep_tristate 'AM53/79C974 PCI SCSI support' CONFIG_SCSI_AM53C974 $CONFIG_SCSI dep_tristate 'AMI MegaRAID support' CONFIG_SCSI_MEGARAID $CONFIG_SCSI +if [ "$CONFIG_SCSI_MEGARAID" != "n" ]; then + bool ' Concurrent IO commands on MegaRAID' CONFIG_MEGARAID_MULTI_IO +fi dep_tristate 'BusLogic SCSI support' CONFIG_SCSI_BUSLOGIC $CONFIG_SCSI if [ "$CONFIG_SCSI_BUSLOGIC" != "n" ]; then @@ -52,9 +55,7 @@ dep_tristate 'EATA-PIO (old DPT PM2001, PM2012A) support' CONFIG_SCSI_EATA_PIO $CONFIG_SCSI dep_tristate 'Future Domain 16xx SCSI/AHA-2920A support' CONFIG_SCSI_FUTURE_DOMAIN $CONFIG_SCSI if [ "$CONFIG_MCA" = "y" ]; then - if [ "$CONFIG_SCSI" = "y" ]; then - bool 'Future Domain MCS-600/700 SCSI support' CONFIG_SCSI_FD_MCS - fi + dep_tristate 'Future Domain MCS-600/700 SCSI support' CONFIG_SCSI_FD_MCS $CONFIG_SCSI fi dep_tristate 'GDT SCSI Disk Array Controller support' CONFIG_SCSI_GDTH $CONFIG_SCSI dep_tristate 'Generic NCR5380/53c400 SCSI support' CONFIG_SCSI_GENERIC_NCR5380 $CONFIG_SCSI @@ -66,6 +67,7 @@ fi if [ "$CONFIG_PCI" = "y" ]; then dep_tristate 'Initio 9100U(W) support' CONFIG_SCSI_INITIO $CONFIG_SCSI + dep_tristate 'Initio INI-A100U2W support' CONFIG_SCSI_INIA100 $CONFIG_SCSI fi if [ "$CONFIG_PARPORT" != "n" ]; then dep_tristate 'IOMEGA parallel port (ppa - older drives)' CONFIG_SCSI_PPA $CONFIG_SCSI $CONFIG_PARPORT @@ -76,6 +78,7 @@ fi fi dep_tristate 'NCR53c406a SCSI support' CONFIG_SCSI_NCR53C406A $CONFIG_SCSI +dep_tristate 'symbios 53c416 SCSI support' CONFIG_SCSI_SYM53C416 $CONFIG_SCSI if [ "$CONFIG_PCI" = "y" ]; then dep_tristate 'NCR53c7,8xx SCSI support' CONFIG_SCSI_NCR53C7xx $CONFIG_SCSI if [ "$CONFIG_SCSI_NCR53C7xx" != "n" ]; then @@ -86,12 +89,16 @@ fi if [ "$CONFIG_PCI" = "y" -a "$CONFIG_SCSI_NCR53C7xx" != "y" ]; then dep_tristate 'NCR53C8XX SCSI support' CONFIG_SCSI_NCR53C8XX $CONFIG_SCSI - if [ "$CONFIG_SCSI_NCR53C8XX" != "n" ]; then + dep_tristate 'SYM53C8XX SCSI support' CONFIG_SCSI_SYM53C8XX $CONFIG_SCSI + if [ "$CONFIG_SCSI_NCR53C8XX" != "n" -o "$CONFIG_SCSI_SYM53C8XX" != "n" ]; then int ' default tagged command queue depth' CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS 8 int ' maximum number of queued commands' CONFIG_SCSI_NCR53C8XX_MAX_TAGS 32 int ' synchronous transfers frequency in MHz' CONFIG_SCSI_NCR53C8XX_SYNC 20 bool ' enable profiling' CONFIG_SCSI_NCR53C8XX_PROFILE bool ' use normal IO' CONFIG_SCSI_NCR53C8XX_IOMAPPED + if [ "$CONFIG_SCSI_SYM53C8XX" != "n" ]; then + bool ' include support for the NCR PQS/PDS SCSI card' CONFIG_SCSI_NCR53C8XX_PQS_PDS + fi if [ "$CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS" = "0" ]; then bool ' not allow targets to disconnect' CONFIG_SCSI_NCR53C8XX_NO_DISCONNECT fi @@ -117,7 +124,7 @@ dep_tristate 'Qlogic FAS SCSI support' CONFIG_SCSI_QLOGIC_FAS $CONFIG_SCSI if [ "$CONFIG_PCI" = "y" ]; then dep_tristate 'Qlogic ISP SCSI support' CONFIG_SCSI_QLOGIC_ISP $CONFIG_SCSI -# dep_tristate 'Qlogic ISP FC SCSI support' CONFIG_SCSI_QLOGIC_FC $CONFIG_SCSI + dep_tristate 'Qlogic ISP FC SCSI support' CONFIG_SCSI_QLOGIC_FC $CONFIG_SCSI fi dep_tristate 'Seagate ST-02 and Future Domain TMC-8xx SCSI support' CONFIG_SCSI_SEAGATE $CONFIG_SCSI if [ "$CONFIG_PCI" = "y" ]; then diff -ur --new-file old/linux/drivers/scsi/Makefile new/linux/drivers/scsi/Makefile --- old/linux/drivers/scsi/Makefile Sun Jan 3 02:55:05 1999 +++ new/linux/drivers/scsi/Makefile Thu Apr 29 20:53:41 1999 @@ -298,6 +298,14 @@ endif endif +ifeq ($(CONFIG_SCSI_INIA100),y) +L_OBJS += a100u2w.o +else + ifeq ($(CONFIG_SCSI_INIA100),m) + M_OBJS += a100u2w.o + endif +endif + ifeq ($(CONFIG_SCSI_QLOGIC_FC),y) L_OBJS += qlogicfc.o else @@ -474,6 +482,14 @@ endif endif +ifeq ($(CONFIG_SCSI_SYM53C8XX),y) +L_OBJS += sym53c8xx.o +else + ifeq ($(CONFIG_SCSI_SYM53C8XX),m) + M_OBJS += sym53c8xx.o + endif +endif + ifeq ($(CONFIG_SCSI_PAS16),y) L_OBJS += pas16.o else @@ -517,9 +533,12 @@ ifeq ($(CONFIG_SCSI_FD_MCS),y) L_OBJS += fd_mcs.o +else + ifeq ($(CONFIG_SCSI_FD_MCS),m) + M_OBJS += fd_mcs.o + endif endif - ifeq ($(CONFIG_SCSI_T128),y) L_OBJS += t128.o else @@ -552,6 +571,14 @@ endif endif +ifeq ($(CONFIG_SCSI_FCAL),y) +L_OBJS += fcal.o +else + ifeq ($(CONFIG_SCSI_FCAL),m) + M_OBJS += fcal.o + endif +endif + ifeq ($(CONFIG_SCSI_EATA),y) L_OBJS += eata.o else @@ -576,6 +603,14 @@ endif endif +ifeq ($(CONFIG_SCSI_SYM53C416),y) +L_OBJS += sym53c416.o +else + ifeq ($(CONFIG_SCSI_SYM53C416),m) + M_OBJS += sym53c416.o + endif +endif + ifeq ($(CONFIG_BLK_DEV_IDESCSI),y) L_OBJS += ide-scsi.o else @@ -616,6 +651,9 @@ $(CC) $(CFLAGS) -c i91uscsi.c -o i91uscsi.o $(LD) -r -o initio.o ini9100u.o i91uscsi.o rm -f ini9100u.o i91uscsi.o + +a100u2w.o: inia100.o i60uscsi.o + $(LD) -r -o a100u2w.o inia100.o i60uscsi.o megaraid.o: megaraid.c $(CC) $(CFLAGS) -c megaraid.c diff -ur --new-file old/linux/drivers/scsi/NCR5380.c new/linux/drivers/scsi/NCR5380.c --- old/linux/drivers/scsi/NCR5380.c Fri Dec 18 18:47:38 1998 +++ new/linux/drivers/scsi/NCR5380.c Thu Apr 15 14:45:12 1999 @@ -569,10 +569,6 @@ if (!main_running) { main_running = 1; NCR5380_main(); - /* - * main_running is cleared in NCR5380_main once it can't do - * more work, and NCR5380_main exits with interrupts disabled. - */ } restore_flags(flags); } @@ -702,7 +698,9 @@ } restore_flags(flags); + spin_lock_irqsave(&io_request_lock, flags); run_main(); + spin_unlock_irqrestore(&io_request_lock, flags); } #endif /* def USLEEP */ @@ -1266,6 +1264,7 @@ struct Scsi_Host *instance; struct NCR5380_hostdata *hostdata; int done; + unsigned long flags; /* * We run (with interrupts disabled) until we're sure that none of @@ -1279,14 +1278,16 @@ * this should prevent any race conditions. */ + spin_unlock_irq(&io_request_lock); + + save_flags(flags); + do { cli(); /* Freeze request queues */ done = 1; for (instance = first_instance; instance && instance->hostt == the_template; instance = instance->next) { - unsigned long flags; hostdata = (struct NCR5380_hostdata *) instance->hostdata; - save_flags(flags); cli(); #ifdef USLEEP if (!hostdata->connected && !hostdata->selecting) { @@ -1365,8 +1366,6 @@ TAG_NEXT)) { break; } else { - unsigned long flags; - save_flags(flags); cli(); LIST(tmp, hostdata->issue_queue); tmp->host_scribble = (unsigned char *) @@ -1393,14 +1392,12 @@ } else { - unsigned long flags; /* RvC: device failed, so we wait a long time this is needed for Mustek scanners, that do not respond to commands immediately after a scan */ printk(KERN_DEBUG "scsi%d: device %d did not respond in time\n", instance->host_no, tmp->target); - save_flags(flags); cli(); LIST(tmp, hostdata->issue_queue); tmp->host_scribble = (unsigned char *) hostdata->issue_queue; @@ -1434,7 +1431,8 @@ break; } /* for instance */ } while (!done); - cli(); + spin_lock_irq(&io_request_lock); + /* cli();*/ main_running = 0; } diff -ur --new-file old/linux/drivers/scsi/README.ibmmca new/linux/drivers/scsi/README.ibmmca --- old/linux/drivers/scsi/README.ibmmca Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/scsi/README.ibmmca Mon May 10 22:00:10 1999 @@ -0,0 +1,979 @@ + + + -=< The IBM Microchannel SCSI-Subsystem >=- + + for the IBM PS/2 series + + Low Level Software-Driver for Linux + + Copyright (c) 1995 Strom Systems, Inc. under the terms of the GNU + General Public License. Originally written by Martin Kolinek, December 1995. + Officially maintained by Michael Lang since January 1999. + + Version 3.1e + + + Last update: 20 February 1999 + + + Authors of this Driver + ---------------------- + - Chris Beauregard (improvement of the SCSI-device mapping by the driver) + - Martin Kolinek (origin, first release of this driver) + - Klaus Kudielka (multiple SCSI-host management/detection, adaption to + Linux Kernel 2.1.x, module support) + - Michael Lang (assigning original pun,lun mapping, dynamical ldn + assignment, this file, patch, official driver maintenance) + + Table of Contents + ----------------- + 1 Abstract + 2 Driver Description + 2.1 IBM SCSI-Subsystem Detection + 2.2 Physical Units, Logical Units, and Logical Devices + 2.3 SCSI-Device Recognition and dynamical ldn Assignment + 2.4 SCSI-Device Order + 2.5 Regular SCSI-Command-Processing + 2.6 Abort & Reset Commands + 2.7 Disk Geometry + 2.8 Kernel Boot Option + 2.9 Driver Module Support + 2.10 Multiple Hostadapter Support + 2.11 /proc/scsi-Filesystem Information + 2.12 /proc/mca-Filesystem Information + 2.13 Supported IBM SCSI-Subsystems + 2.14 Linux Kernel Versions + 3 Code History + 4 To do + 5 Users' Manual + 5.1 Commandline Parameters + 5.2 Troubleshooting + 5.3 Bugreports + 5.4 Support WWW-page + 6 References + 7 Trademarks + + * * * + + 1 Abstract + ---------- + This README-file describes the IBM SCSI-subsystem low level driver for + Linux. The descriptions which were formerly kept in the source-code have + been taken out to this file to easify the codes' readability. The driver + description has been updated, as most of the former description was already + quite outdated. The history of the driver development is also kept inside + here. Multiple historical developments have been summarized to shorten the + textsize a bit. At the end of this file you can find a small manual for + this driver and hints to get it running even on your machine (hopefully). + + 2 Driver Description + -------------------- + 2.1 IBM SCSI-Subsystem Detection + -------------------------------- + This is done in the ibmmca_detect() function. It first checks, if the + Microchannel-bus support is enabled, as the IBM SCSI-subsystem needs the + Microchannel. In a next step, a free interrupt is chosen and the main + interrupt handler is connected to it to handle answers of the SCSI- + subsystem(s). In a further step, it is checked, wether there was a forced + detection of the adapter via the kernel commandline, where the I/O port + and the SCSI-subsystem id can be specified. The next step checks if there + is an integrated SCSI-subsystem installed. This register area is fixed + through all IBM PS/2 MCA-machines and appears as something like a virtual + slot 10 of the MCA-bus. If POS-register 2 is not 0xff, there must be a SCSI- + subsystem present and it will be registered as IBM Integrated SCSI- + Subsystem. The next step checks, if there is a slot-adapter installed on + the MCA-bus. To get this, the first two POS-registers, that represent the + adapter ID are checked. If they fit to one of the ids, stored in the + adapter list, a SCSI-subsystem is assumed to be found and will be + registered. This check is done through all possible MCA-bus slots to allow + more than one SCSI-adapter to be present in the PS/2-system and this is + already the first point of problems. Looking into the technical reference + manual for the IBM PS/2 common interfaces, the POS2 register must have + different interpretation of its single bits. While one can assume, that the + integrated subsystem has a fix I/O-address at 0x3540 - 0x3547, further + installed IBM SCSI-adapters must use a different I/O-address. This is + expressed by bit 1 to 3 of POS2 (multiplied by 8 + 0x3540). Bits 2 and 3 + are reserved for the integrated subsystem, but not for the adapters! The + following list shows, how the bits of POS2 and POS3 should be interpreted. + + The POS2-register of all PS/2 models' integrated SCSI-subsystems has the + following interpretation of bits: + Bit 7 - 4 : Chip Revision ID (Release) + Bit 3 - 2 : Reserved + Bit 1 : 8k NVRAM Disabled + Bit 0 : Chip Enable (EN-Signal) + The POS3-register is interpreted as follows (for ALL IBM SCSI-subsys.): + Bit 7 - 5 : SCSI ID + Bit 4 - 0 : Reserved = 0 + (taken from "IBM, PS/2 Hardware Interface Technical Reference, Common + Interfaces (1991)"). + In short words, this means, that IBM PS/2 machines only support 1 single + subsystem by default. But (additional) slot-adapters must have another + configuration on pos2 in order to be enabled to use more than one IBM SCSI- + subsystem, e.g. for a network server. From tests with the IBM SCSI Adapter + w/cache, the POS2-register for slot adapters should be interpreted in the + following way: + Bit 7 - 4 : Chip Revision ID (Release) + Bit 3 - 1 : port offset factor ( * 8 + 0x3540 ) + Bit 0 : Chip Enable (EN-Signal) + + One day I found a patch in ibmmca_detect(), forcing the I/O-address to be + 0x3540 for integrated SCSI-subsystems, there was a remark placed, that on + integrated IBM SCSI-subsystems of model 56, the POS2 register was showing 5. + This means, that really for these models, POS2 has to be interpreted + sticking to the technical reference guide. In this case, the bit 2 (4) is + a reserved bit and may not be interpreted. These differences between the + adapters and the integrated controllers are taken into account by the + detection routine of the driver on from version >3.0g. + + Every time, a SCSI-subsystem is discovered, the ibmmca_register() function + is called. This function checks first, if the requested area for the I/O- + address of this SCSI-subsystem is still available and assigns this I/O- + area to the SCSI-subsystem. There are always 8 sequential I/O-addresses + taken for each individual SCSI-subsystem found, which are: + + Offset Type Permissions + 0 Command Interface Register 1 Read/Write + 1 Command Interface Register 2 Read/Write + 2 Command Interface Register 3 Read/Write + 3 Command Interface Register 4 Read/Write + 4 Attention Register Read/Write + 5 Basic Control Register Read/Write + 6 Interrupt Status Register Read + 7 Basic Status Register Read + + After the I/O-address range is assigned, the host-adapter is assigned + to a local structure which keeps all adapter information needed for the + driver itself and the mid- and higher-level SCSI-drivers. The SCSI pun/lun + and the adapters' ldn tables are initialized and get probed afterwards by + the check_devices() function. If no further adapters are found, + ibmmca_detect() quits. + + 2.2 Physical Units, Logical Units, and Logical Devices + ------------------------------------------------------ + There can be up to 56 devices on the SCSI bus (besides the adapter): + there are up to 7 "physical units" (each identified by physical unit + number or pun, also called the scsi id, this is the number you select + with hardware jumpers), and each physical unit can have up to 8 + "logical units" (each identified by logical unit number, or lun, + between 0 and 7). + + Typically the adapter has pun=7, so puns of other physical units + are between 0 and 6. Almost all physical units have only one + logical unit, with lun=0. A CD-ROM jukebox would be an example of + a physical unit with more than one logical unit. + + The embedded microprocessor of the IBM SCSI-subsystem hides the complex + two-dimensional (pun,lun) organization from the operating system. + When the machine is powered-up (or rebooted), the embedded microprocessor + checks, on its own, all 56 possible (pun,lun) combinations, and the first + 15 devices found are assigned into a one-dimensional array of so-called + "logical devices", identified by "logical device numbers" or ldn. The last + ldn=15 is reserved for the subsystem itself. + + 2.3 SCSI-Device Recognition and dynamical ldn Assignment + -------------------------------------------------------- + One consequence of information hiding is that the real (pun,lun) + numbers are also hidden. The two possibilities to get around this problem + is to offer fake pun/lun combinations to the operating system or to + delete the whole mapping of the adapter and to reassign the ldns, using + the immediate assign command of the SCSI-subsystem. At the beginning of the + development of this driver, the following approach was used: + First, the driver checked the ldn's (0 to 6) to find out which ldn's + have devices assigned. This was done by the functions check_devices() and + device_exists(). The interrupt handler has a special paragraph of code + (see local_checking_phase_flag) to assist in the checking. Assume, for + example, that three logical devices were found assigned at ldn 0, 1, 2. + These are presented to the upper layer of Linux SCSI driver + as devices with bogus (pun, lun) equal to (0,0), (1,0), (2,0). + On the other hand, if the upper layer issues a command to device + say (4,0), this driver returns DID_NO_CONNECT error. + + In a second step of the driver development, the following improvement has + been applied: The first approach limited the number of devices to 7, far + fewer than the 15 that it could usem then it just maped ldn -> + (ldn/8,ldn%8) for pun,lun. We ended up with a real mishmash of puns + and luns, but it all seemed to work. + + The latest development, which is implemented from the driver version 3.0 + and later, realizes the device recognition in the following way: + The physical SCSI-devices on the SCSI-bus are probed via immediate_assign- + and device_inquiry-commands, that is all implemented in a completely new + made check_devices() subroutine. This delivers a exact map of the physical + SCSI-world that is now stored in the get_scsi[][]-array. This means, + that the once hidden pun,lun assignment is now known to this driver. + It no longer believes in default-settings of the subsystem and maps all + ldns to existing pun,lun "by foot". This assures full control of the ldn + mapping and allows dynamical remapping of ldns to different pun,lun, if + there are more SCSI-devices installed than ldns available (n>15). The + ldns from 0 to 6 get 'hardwired' by this driver to puns 0 to 7 at lun=0, + excluding the pun of the subsystem. This assures, that at least simple + SCSI-installations have optimum access-speed and are not touched by + dynamical remapping. The ldns 7 to 14 are put to existing devices with + lun>0 or to non-existing devices, in order to satisfy the subsystem, if + there are less than 15 SCSI-devices connected. In the case of more than 15 + devices, the dynamical mapping goes active. If the get_scsi[][] reports a + device to be existant, but it has no ldn assigned, it gets a ldn out of 7 + to 14. The numbers are assigned in cyclic order. Therefore it takes 8 + dynamical reassignments on the SCSI-devices, until a certain device + looses its ldn again. This assures, that dynamical remapping is avoided + during intense I/O between up to 15 SCSI-devices (means pun,lun + combinations). A further advantage of this method is, that people who + build their kernel without probing on all luns will get what they expect, + because the driver just won't assign everything with lun>0 when + multpile lun probing is inactive. + + 2.4 SCSI-Device Order + --------------------- + Because of the now correct recognition of physical pun,lun, and + their report to mid-level- and higher-level-drivers, the new reported puns + can be different from the old, faked puns. Therefore, Linux will eventually + change /dev/sdXXX assignments and prompt you for corrupted superblock + repair on boottime. In this case DO NOT PANIC, YOUR DISKS ARE STILL OK!!! + You have to reboot (CTRL-D) with a old kernel and set the /etc/fstab-file + entries right. After that, the system should come up as errorfree as before. + If your boot-partition is not coming up, also edit the /etc/lilo.conf-file + in a Linux session booted on old kernel and run lilo before reboot. Check + lilo.conf anyway to get boot on other partitions with foreign OSes right + again. But there exists a feature of this driver that allows you to change + the assignment order of the SCSI-devices by flipping the PUN-assignment. + See the next paragraph for a description. + + The problem for this is, that Linux does not assign the SCSI-devices in the + way as described in the ANSI-SCSI-standard. Linux assigns /dev/sda to + the device with at minimum id 0. But the first drive should be at id 6, + because for historical reasons, drive at id 6 has, by hardware, the highest + priority and a drive at id 0 the lowest. IBM was one of the rare producers, + where the BIOS assigns drives belonging to the ANSI-SCSI-standard. Most + other producers' BIOS does not (I think even Adaptec-BIOS). The + IBMMCA_SCSI_ORDER_STANDARD flag, which you set while configuring the + kernel enables to choose the preferred way of SCSI-device-assignment. + Defining this flag would result in Linux determining the devices in the + same order as DOS and OS/2 does on your MCA-machine. This is also standard + on most industrial computers and OSes, like e.g. OS-9. Leaving this flag + undefined will get your devices ordered in the default way of Linux. See + also the remarks of Chris Beauregard from Dec 15, 1997 and the followups + in section 3. + + 2.5 Regular SCSI-Command-Processing + ----------------------------------- + Only three functions get involved: ibmmca_queuecommand(), issue_cmd(), + and interrupt_handler(). + + The upper layer issues a scsi command by calling function + ibmmca_queuecommand(). This function fills a "subsystem control block" + (scb) and calls a local function issue_cmd(), which writes a scb + command into subsystem I/O ports. Once the scb command is carried out, + the interrupt_handler() is invoked. If a device is determined to be + existant and it has not assigned any ldn, it gets one dynamically. + For this, the whole stuff is done in ibmmca_queuecommand(). + + 2.6 Abort & Reset Commands + -------------------------- + These are implemented with busy waiting for interrupt to arrive. + ibmmca_reset() and ibmmca_abort() do not work sufficently well + up to now and need still a lot of development work. But, this seems + to be even a problem with other SCSI-low level drivers, too. However, + this should be no excuse. + + 2.7 Disk Geometry + ----------------- + The ibmmca_biosparams() function should return the same disk geometry + as the bios. This is needed for fdisk, etc. The returned geometry is + certainly correct for disks smaller than 1 gigabyte. In the meantime, + it has been proved, that this works fine even with disks larger than + 1 gigabyte. + + 2.8 Kernel Boot Option + ---------------------- + The function ibmmca_scsi_setup() is called if option ibmmcascsi=n + is passed to the kernel. See file linux/init/main.c for details. + + 2.9 Driver Module Support + ------------------------- + Is implemented and tested by K. Kudielka. This could probably not work + on kernels <2.1.0. + + 2.10 Multiple Hostadapter Support + --------------------------------- + This driver supports up to eight interfaces of type IBM-SCSI-Subsystem. + Integrated-, and MCA-adapters are automatically recognized. Unrecognizable + IBM-SCSI-Subsystem interfaces can be specified as kernel-parameters. + + 2.11 /proc/scsi-Filesystem Information + -------------------------------------- + Information about the driver condition is given in + /proc/scsi/ibmmca/. ibmmca_proc_info() provides this information. + + This table is quite informative for interested users. It shows the load + of commands on the subsystem and wether you are running the bypassed + (software) or integrated (hardware) SCSI-command set (see below). The + amount of accesses is shown. Read, write, modeselect is shown seperately + in order to help debugging problems with CD-ROMs or tapedrives. + + The following table shows the list of 15 logical device numbers, that are + used by the SCSI-subsystem. The load on each ldn is shown in the table, + again, read and write commands are split. The last column shows the amount + of reassignments, that have been applied to the ldns, if you have more than + 15 pun/lun combinations available on the SCSI-bus. + + The last two tables show the pun/lun map and the positions of the ldns + on this pun/lun map. This may change during operation, when a ldn is + reassigned to another pun/lun combination. If the necessity for dynamical + assignments is set to 'no', the ldn structure keeps static. + + 2.12 /proc/mca-Filesystem Information + ------------------------------------- + The slot-file contains all default entries and in addition chip and I/O- + address information of the SCSI-subsystem. This information is provided + by ibmmca_getinfo(). + + 2.13 Supported IBM SCSI-Subsystems + ---------------------------------- + The following IBM SCSI-subsystems are supported by this driver: + + - IBM Fast SCSI-2 Adapter + - IBM 7568 Industrial Computer SCSI Adapter w/cache + - IBM Expansion Unit SCSI Controller + - IBM SCSI Adapter w/Cache + - IBM SCSI Adapter + - IBM Integrated SCSI Controller + + 2.14 Linux Kernel Versions + -------------------------- + The IBM SCSI-subsystem low level driver is prepared to be used with + all versions of Linux between 2.0.x and 2.2.x. The compatibility checks + are fully implemented up from version 3.1e of the driver. This means, that + you just need the latest ibmmca.h and ibmmca.c file and copy it in the + linux/drivers/scsi directory. The code is automatically adapted during + kernel compilation. + + 3 Code History + -------------- + Jan 15 1996: First public release. + - Martin Kolinek + + Jan 23 1996: Scrapped code which reassigned scsi devices to logical + device numbers. Instead, the existing assignment (created + when the machine is powered-up or rebooted) is used. + A side effect is that the upper layer of Linux SCSI + device driver gets bogus scsi ids (this is benign), + and also the hard disks are ordered under Linux the + same way as they are under dos (i.e., C: disk is sda, + D: disk is sdb, etc.). + - Martin Kolinek + + I think that the CD-ROM is now detected only if a CD is + inside CD_ROM while Linux boots. This can be fixed later, + once the driver works on all types of PS/2's. + - Martin Kolinek + + Feb 7 1996: Modified biosparam function. Fixed the CD-ROM detection. + For now, devices other than harddisk and CD_ROM are + ignored. Temporarily modified abort() function + to behave like reset(). + - Martin Kolinek + + Mar 31 1996: The integrated scsi subsystem is correctly found + in PS/2 models 56,57, but not in model 76. Therefore + the ibmmca_scsi_setup() function has been added today. + This function allows the user to force detection of + scsi subsystem. The kernel option has format + ibmmcascsi=n + where n is the scsi_id (pun) of the subsystem. Most likely, n is 7. + - Martin Kolinek + + Aug 21 1996: Modified the code which maps ldns to (pun,0). It was + insufficient for those of us with CD-ROM changers. + - Chris Beauregard + + Dec 14 1996: More improvements to the ldn mapping. See check_devices + for details. Did more fiddling with the integrated SCSI detection, + but I think it's ultimately hopeless without actually testing the + model of the machine. The 56, 57, 76 and 95 (ultimedia) all have + different integrated SCSI register configurations. However, the 56 + and 57 are the only ones that have problems with forced detection. + - Chris Beauregard + + Mar 8-16 1997: Modified driver to run as a module and to support + multiple adapters. A structure, called ibmmca_hostdata, is now + present, containing all the variables, that were once only + available for one single adapter. The find_subsystem-routine has vanished. + The hardware recognition is now done in ibmmca_detect directly. + This routine checks for presence of MCA-bus, checks the interrupt + level and continues with checking the installed hardware. + Certain PS/2-models do not recognize a SCSI-subsystem automatically. + Hence, the setup defined by command-line-parameters is checked first. + Thereafter, the routine probes for an integrated SCSI-subsystem. + Finally, adapters are checked. This method has the advantage to cover all + possible combinations of multiple SCSI-subsystems on one MCA-board. Up to + eight SCSI-subsystems can be recognized and announced to the upper-level + drivers with this improvement. A set of defines made changes to other + routines as small as possible. + - Klaus Kudielka + + May 30 1997: (v1.5b) + 1) SCSI-command capability enlarged by the recognition of MODE_SELECT. + This needs the RD-Bit to be disabled on IM_OTHER_SCSI_CMD_CMD which + allows data to be written from the system to the device. It is a + necessary step to be allowed to set blocksize of SCSI-tape-drives and + the tape-speed, whithout confusing the SCSI-Subsystem. + 2) The recognition of a tape is included in the check_devices routine. + This is done by checking for TYPE_TAPE, that is already defined in + the kernel-scsi-environment. The markup of a tape is done in the + global ldn_is_tape[] array. If the entry on index ldn + is 1, there is a tapedrive connected. + 3) The ldn_is_tape[] array is necessary to distinguish between tape- and + other devices. Fixed blocklength devices should not cause a problem + with the SCB-command for read and write in the ibmmca_queuecommand + subroutine. Therefore, I only derivate the READ_XX, WRITE_XX for + the tape-devices, as recommended by IBM in this Technical Reference, + mentioned below. (IBM recommends to avoid using the read/write of the + subsystem, but the fact was, that read/write causes a command error from + the subsystem and this causes kernel-panic.) + 4) In addition, I propose to use the ldn instead of a fix char for the + display of PS2_DISK_LED_ON(). On 95, one can distinguish between the + devices that are accessed. It shows activity and easyfies debugging. + The tape-support has been tested with a SONY SDT-5200 and a HP DDS-2 + (I do not know yet the type). Optimization and CD-ROM audio-support, + I am working on ... + - Michael Lang + + June 19 1997: (v1.6b) + 1) Submitting the extra-array ldn_is_tape[] -> to the local ld[] + device-array. + 2) CD-ROM Audio-Play seems to work now. + 3) When using DDS-2 (120M) DAT-Tapes, mtst shows still density-code + 0x13 for ordinary DDS (61000 BPM) instead 0x24 for DDS-2. This appears + also on Adaptec 2940 adaptor in a PCI-System. Therefore, I assume that + the problem is independent of the low-level-driver/bus-architecture. + 4) Hexadecimal ldn on PS/2-95 LED-display. + 5) Fixing of the PS/2-LED on/off that it works right with tapedrives and + does not confuse the disk_rw_in_progress counter. + - Michael Lang + + June 21 1997: (v1.7b) + 1) Adding of a proc_info routine to inform in /proc/scsi/ibmmca/ the + outer-world about operational load statistics on the different ldns, + seen by the driver. Everybody that has more than one IBM-SCSI should + test this, because I only have one and cannot see what happens with more + than one IBM-SCSI hosts. + 2) Definition of a driver version-number to have a better recognition of + the source when there are existing too much releases that may confuse + the user, when reading about release-specific problems. Up to know, + I calculated the version-number to be 1.7. Because we are in BETA-test + yet, it is today 1.7b. + 3) Sorry for the heavy bug I programmed on June 19 1997! After that, the + CD-ROM did not work any more! The C7-command was a fake impression + I got while programming. Now, the READ and WRITE commands for CD-ROM are + no longer running over the subsystem, but just over + IM_OTHER_SCSI_CMD_CMD. On my observations (PS/2-95), now CD-ROM mounts + much faster(!) and hopefully all fancy multimedia-functions, like direct + digital recording from audio-CDs also work. (I tried it with cdda2wav + from the cdwtools-package and it filled up the harddisk immediately :-).) + To easify boolean logics, a further local device-type in ld[], called + is_cdrom has been included. + 4) If one uses a SCSI-device of unsupported type/commands, one + immediately runs into a kernel-panic caused by Command Error. To better + understand which SCSI-command caused the problem, I extended this + specific panic-message slightly. + - Michael Lang + + June 25 1997: (v1.8b) + 1) Some cosmetical changes for the handling of SCSI-device-types. + Now, also CD-Burners / WORMs and SCSI-scanners should work. For + MO-drives I have no experience, therefore not yet supported. + In logical_devices I changed from different type-variables to one + called 'device_type' where the values, corresponding to scsi.h, + of a SCSI-device are stored. + 2) There existed a small bug, that maps a device, coming after a SCSI-tape + wrong. Therefore, e.g. a CD-ROM changer would have been mapped wrong + -> problem removed. + 3) Extension of the logical_device structure. Now it contains also device, + vendor and revision-level of a SCSI-device for internal usage. + - Michael Lang + + June 26-29 1997: (v2.0b) + 1) The release number 2.0b is necessary because of the completely new done + recognition and handling of SCSI-devices with the adapter. As I got + from Chris the hint, that the subsystem can reassign ldns dynamically, + I remembered this immediate_assign-command, I found once in the handbook. + Now, the driver first kills all ldn assignments that are set by default + on the SCSI-subsystem. After that, it probes on all puns and luns for + devices by going through all combinations with immediate_assign and + probing for devices, using device_inquiry. The found physical(!) pun,lun + structure is stored in get_scsi[][] as device types. This is followed + by the assignment of all ldns to existing SCSI-devices. If more ldns + than devices are available, they are assigned to non existing pun,lun + combinations to satisfy the adapter. With this, the dynamical mapping + was possible to implement. (For further info see the text in the + source-code and in the description below. Read the description + below BEFORE installing this driver on your system!) + 2) Changed the name IBMMCA_DRIVER_VERSION to IBMMCA_SCSI_DRIVER_VERSION. + 3) The LED-display shows on PS/2-95 no longer the ldn, but the SCSI-ID + (pun) of the accessed SCSI-device. This is now senseful, because the + pun known within the driver is exactly the pun of the physical device + and no longer a fake one. + 4) The /proc/scsi/ibmmca/ consists now of the first part, where + hit-statistics of ldns is shown and a second part, where the maps of + physical and logical SCSI-devices are displayed. This could be very + interesting, when one is using more than 15 SCSI-devices in order to + follow the dynamical remapping of ldns. + - Michael Lang + + June 26-29 1997: (v2.0b-1) + 1) I forgot to switch the local_checking_phase_flag to 1 and back to 0 + in the dynamical remapping part in ibmmca_queuecommand for the + device_exist routine. Sorry. + - Michael Lang + + July 1-13 1997: (v3.0b,c) + 1) Merging of the driver-developments of Klaus Kudielka and Michael Lang + in order to get a optimum and unified driver-release for the + IBM-SCSI-Subsystem-Adapter(s). + For people, using the Kernel-release >=2.1.0, module-support should + be no problem. For users, running under <2.1.0, module-support may not + work, because the methods have changed between 2.0.x and 2.1.x. + 2) Added some more effective statistics for /proc-output. + 3) Change typecasting at necessary points from (unsigned long) to + virt_to_bus(). + 4) Included #if... at special points to have specific adaption of the + driver to kernel 2.0.x and 2.1.x. It should therefore also run with + later releases. + 5) Magneto-Optical drives and medium-changers are also recognized, now. + Therefore, we have a completely gapfree recognition of all SCSI- + device-types, that are known by Linux up to kernel 2.1.31. + 6) The flag SCSI_IBMMCA_DEV_RESET has been inserted. If it is set within + the configuration, each connected SCSI-device will get a reset command + during boottime. This can be necessary for some special SCSI-devices. + This flag should be included in Config.in. + (See also the new Config.in file.) + Probable next improvement: bad disk handler. + - Michael Lang + + Sept 14 1997: (v3.0c) + 1) Some debugging and speed optimization applied. + - Michael Lang + + Dec 15, 1997 + - chrisb@truespectra.com + - made the front panel display thingy optional, specified from the + command-line via ibmmcascsi=display. Along the lines of the /LED + option for the OS/2 driver. + - fixed small bug in the LED display that would hang some machines. + - reversed ordering of the drives (using the + IBMMCA_SCSI_ORDER_STANDARD define). This is necessary for two main + reasons: + - users who've already installed Linux won't be screwed. Keep + in mind that not everyone is a kernel hacker. + - be consistent with the BIOS ordering of the drives. In the + BIOS, id 6 is C:, id 0 might be D:. With this scheme, they'd be + backwards. This confuses the crap out of those heathens who've + got a impure Linux installation (which, , I'm one of). + This whole problem arises because IBM is actually non-standard with + the id to BIOS mappings. You'll find, in fdomain.c, a similar + comment about a few FD BIOS revisions. The Linux (and apparently + industry) standard is that C: maps to scsi id (0,0). Let's stick + with that standard. + - Since this is technically a branch of my own, I changed the + version number to 3.0e-cpb. + + Jan 17, 1998: (v3.0f) + 1) Addition of some statistical info for /proc in proc_info. + 2) Taking care of the SCSI-assignment problem, dealed by Chris at Dec 15 + 1997. In fact, IBM is right, concerning the assignment of SCSI-devices + to driveletters. It is conform to the ANSI-definition of the SCSI- + standard to assign drive C: to SCSI-id 6, because it is the highest + hardware priority after the hostadapter (that has still today by + default everywhere id 7). Also realtime-operating systems that I use, + like LynxOS and OS9, which are quite industrial systems use top-down + numbering of the harddisks, that is also starting at id 6. Now, one + sits a bit between two chairs. On one hand side, using the define + IBMMCA_SCSI_ORDER_STANDARD makes Linux assigning disks conform to + the IBM- and ANSI-SCSI-standard and keeps this driver downward + compatible to older releases, on the other hand side, people is quite + habituated in believing that C: is assigned to (0,0) and much other + SCSI-BIOS do so. Therefore, I moved the IBMMCA_SCSI_ORDER_STANDARD + define out of the driver and put it into Config.in as subitem of + 'IBM SCSI support'. A help, added to Documentation/Configure.help + explains the differences between saying 'y' or 'n' to the user, when + IBMMCA_SCSI_ORDER_STANDARD prompts, so the ordinary user is enabled to + choose the way of assignment, depending on his own situation and gusto. + 3) Adapted SCSI_IBMMCA_DEV_RESET to the local naming convention, so it is + now called IBMMCA_SCSI_DEV_RESET. + 4) Optimization of proc_info and its subroutines. + 5) Added more in-source-comments and extended the driver description by + some explanation about the SCSI-device-assignment problem. + - Michael Lang + + Jan 18, 1998: (v3.0g) + 1) Correcting names to be absolutely conform to the later 2.1.x releases. + This is necessary for + IBMMCA_SCSI_DEV_RESET -> CONFIG_IBMMCA_SCSI_DEV_RESET + IBMMCA_SCSI_ORDER_STANDARD -> CONFIG_IBMMCA_SCSI_ORDER_STANDARD + - Michael Lang + + Jan 18, 1999: (v3.1 MCA-team internal) + 1) The multiple hosts structure is accessed from every subroutine, so there + is no longer the address of the device structure passed from function + to function, but only the hostindex. A call by value, nothing more. This + should really be understood by the compiler and the subsystem should get + the right values and addresses. + 2) The SCSI-subsystem detection was not complete and quite hugely buggy up + to now, compared to the technical manual. The interpretation of the pos2 + register is not as assumed by people before, therefore, I dropped a note + in the ibmmca_detect function to show the registers' interpretation. + The pos-registers of integrated SCSI-subsystems do not contain any + information concerning the IO-port offset, really. Instead, they contain + some info about the adapter, the chip, the NVRAM .... The I/O-port is + fixed to 0x3540 - 0x3547. There can be more than one adapters in the + slots and they get an offset for the I/O area in order to get their own + I/O-address area. See chapter 2 for detailed description. At least, the + detection should now work right, even on models other than 95. The 95ers + came happily around the bug, as their pos2 register contains always 0 + in the critical area. Reserved bits are not allowed to be interpreted, + therefore, IBM is allowed to set those bits as they like and they may + really vary between different PS/2 models. So, now, no interpretation + of reserved bits - hopefully no trouble here anymore. + 3) The command error, which you may get on models 55, 56, 57, 70, 77 and + P70 may have been caused by the fact, that adapters of older design do + not like sending commands to non-existing SCSI-devices and will react + with a command error as a sign of protest. While this error is not + present on IBM SCSI Adapter w/cache, it appears on IBM Integrated SCSI + Adapters. Therefore, I implemented a workarround to forgive those + adapters their protests, but it is marked up in the statisctis, so + after a successful boot, you can see in /proc/scsi/ibmmca/ + how often the command errors have been forgiven to the SCSI-subsystem. + If the number is bigger than 0, you have a SCSI subsystem of older + design, what should no longer matter. + 4) ibmmca_getinfo() has been adapted very carefully, so it shows in the + slotn file really, what is senseful to be presented. + 5) ibmmca_register() has been extended in its parameter list in order to + pass the right name of the SCSI-adapter to Linux. + - Michael Lang + + Feb 6, 1999: (v3.1) + 1) Finally, after some 3.1Beta-releases, the 3.1 release. Sorry, for + the delayed release, but it was not finished with the release of + Kernel 2.2.0. + - Michael Lang + + Feb 10, 1999 (v3.1) + 1) Added a new commandline parameter called 'bypass' in order to bypass + every integrated subsystem SCSI-command consequently in case of + troubles. + 2) Concatenated read_capacity requests to the harddisks. It gave a lot + of troubles with some controllers and after I wanted to apply some + extensions, it jumped out in the same situation, on my w/cache, as like + on D. Weinehalls' Model 56, having integrated SCSI. This gave me the + descissive hint to move the code-part out and declare it global. Now, + it seems to work by far much better an more stable. Let us see, what + the world thinks of it... + 3) By the way, only Sony DAT-drives seem to show density code 0x13. A + test with a HP drive gave right results, so the problem is vendor- + specific and not a problem of the OS or the driver. + - Michael Lang + + Feb 18, 1999 (v3.1d) + 1) The abort command and the reset function have been checked for + inconsistencies. From the logical point of thinking, they work + at their optimum, now, but as the subsystem does not answer with an + interrupt, abort never finishes, sigh... + 2) Everything, that is accessed by a busmaster request from the adapter + is now declared as global variable, even the return-buffer in the + local checking phase. This assures, that no accesses to undefined memory + areas are performed. + 3) In ibmmca.h, the line unchecked_isa_dma is added with 1 in order to + avoid memory-pointers for the areas higher than 16MByte in order to + be sure, it also works on 16-Bit Microchannel bus systems. + 4) A lot of small things have been found, but nothing that endangered the + driver operations. Just it should be more stable, now. + - Michael Lang + + Feb 20, 1999 (v3.1e) + 1) I took the warning from the Linux Kernel Hackers Guide serious and + checked the cmd->result return value to the done-function very carefuly. + It is obvious, that the IBM SCSI only delivers the tsb.dev_status, if + some error appeared, else it is undefined. Now, this is fixed. Before + any SCB command gets queued, the tsb.dev_status is set to 0, so the + cmd->result won't screw up Linux higher level drivers. + 2) The reset-function has slightly improved. This is still planed for + abort. During the abort and the reset function, no interrupts are + allowed. This is however quite hard to cope with, so the INT-status + register is read. When the interrupt gets queued, one can find its + status immediately on that register and is enabled to continue in the + reset function. I had no chance to test this really, only in a bogus + situation, I got this function running, but the situation was too much + worse for Linux :-(, so tests will continue. + 3) Buffers got now consistent. No open address mapping, as before and + therefore no further troubles with the unassigned memory segmentation + faults that scrambled probes on 95XX series and even on 85XX series, + when the kernel is done in a not so perfectly fitting way. + 4) Spontaneous interrupts from the subsystem, appearing without any + command previously queued are answered with a DID_BAD_INTR result. + 5) Taken into account ZP Gus' proposals to reverse the SCSI-device + scan order. As it does not work on Kernel 2.1.x or 2.2.x, as proposed + by him, I implemented it in a slightly derived way, which offers in + addition more flexibility. + - Michael Lang + + 4 To do + ------- + - It seems that the handling of bad disks is really bad - + non-existent, in fact. + - More testing of the full driver-controlled dynamical ldn + (re)mapping for up to 56 SCSI-devices. + - Support more of the SCSI-command set. + - Support some of the caching abilities, particularly Read Prefetch. + This fetches data into the cache, which later gets hit by the + regular Read Data. (<--- This is coming soon!!!!) + - Abort and Reset functions still slightly buggy or better say, + it is the new episode, called SCREAM III. + + 5 Users' Manual + --------------- + 5.1 Commandline Parameters + -------------------------- + There exist several features for the IBM SCSI-subsystem driver. + The commandline parameter format is: + + ibmmcascsi=,,,... + + where commandN can be one of the following: + + display Owners of a model 95 or other PS/2 systems with an + alphanumeric LED display may set this to have their + display showing the following output of the 8 digits: + + ------DA + + where '-' stays dark, 'D' shows the SCSI-device id + and 'A' shows the SCSI hostindex, beeing currently + accessed. + adisplay This works like display, but gives more optical overview + of the activities on the SCSI-bus. The display will have + the following output: + + 6543210A + + where the numbers 0 to 6 light up at the shown position, + when the SCSI-device is accessed. A shows again the SCSI + hostindex. If display nor adisplay is set, the internal + PS/2 harddisk LED is used for media-activities. So, if + you really do not have a system with a LED-display, you + should not set display or adisplay. + bypass This commandline parameter forces the driver never to use + SCSI-subsystems' integrated SCSI-command set. Except of + the immediate assign, which is of vital importance for + every IBM SCSI-subsystem to set its ldns right. Instead, + the ordinary ANSI-SCSI-commands are used and passed by the + controller to the SCSI-devices, therefore 'bypass'. The + effort, done by the subsystem is quite bogus and at a + minimum and therefore it should work everywhere. This + could maybe solve troubles with old or integrated SCSI- + controllers and nasty harddisks. Keep in mind, that using + this flag will slow-down SCSI-accesses slightly, as the + software generated commands are always slower than the + hardware. Non-harddisk devices always get read/write- + commands in bypass mode. + normal This is the parameter, introduced on the 2.0.x development + rail by ZP Gu. This parameter defines the SCSI-device + scan order in the new industry standard. This means, that + the first SCSI-device is the one with the lowest pun. + E.g. harddisk at pun=0 is scanned before harddisk at + pun=6, which means, that harddisk at pun=0 gets sda + and the one at pun=6 gets sdb. + ansi The ANSI-standard for the right scan order, as done by + IBM, Microware and Microsoft, scans SCSI-devices starting + at the highest pun, which means, that e.g. harddisk at + pun=6 gets sda and a harddisk at pun=0 gets sdb. If you + like to have the same SCSI-device order, as in DOS, OS-9 + or OS/2, just use this parameter. + + A further option is that you can force the SCSI-driver to accept a SCSI- + subsystem at a certain I/O-address with a predefined adapter PUN. This + is done by entering + + commandN = I/O-base + commandN+1 = adapter PUN + + e.g. ibmmcascsi=0x3540,7 will force the driver to detect a SCSI-subsystem + at I/O-address 0x3540 with adapter PUN 7. + + Examples: + + ibmmcascsi=adisplay,bypass + + This will use the advanced display mode for the model 95 LED display and + every SCSI-command passed to a attached device will get bypassed in order + not to use any of the subsystem built-in commands. + + ibmmcascsi=display,0x3558,7 + + This will activate the default display mode for the model 95 LED display + and will force the driver to accept a SCSI-subsystem at I/O-base 0x3558 + with adapter PUN 7. + + 5.2 Troubleshooting + ------------------- + The following FAQs should help you to solve some major problems with this + driver. + + Q: "Reset SCSI-devices at boottime" halts the system at boottime, why? + A: This is only tested with the IBM SCSI Adapter w/cache. It is not + yet prooved to run on other adapters, however you may be lucky. + In version 3.1d this has been hugely improved and should work better, + now. Normally you really won't need to activate this flag in the + kernel configuration, as all post 1989 SCSI-devices should accept + the reset-signal, when the computer is switched on. The SCSI- + subsystem generates this reset while beeing initialized. This flag + is really reserved for users with very old, very strange or self-made + SCSI-devices. + Q: Why is the SCSI-order of my drives mirrored to the device-order + seen from OS/2 or DOS ? + A: It depends on the operating system, if it looks at the devices in + ANSI-SCSI-standard (starting from pun 6 and going down to pun 0) or + if it just starts at pun 0 and counts up. If you want to be conform + with OS/2 and DOS, you have to activate this flag in the kernel + configuration or you should set 'ansi' as parameter for the kernel. + The parameter 'normal' sets the new industry standard, starting + from pun 0, scaning up to pun 6. This allows you to change your + opinion still after having already compiled the kernel. + Q: Why can I not find the IBM MCA SCSI support in the config menue? + A: You have to activate MCA bus support, first. + Q: Where can I find the latest info about this driver? + A: See the file MAINTAINERS for the current WWW-address, which offers + updates, info and Q/A lists. At this files' origin, the webaddress + was: http://www.uni-mainz.de/~langm000/linux.html + Q: My SCSI-adapter is not recognized by the driver, what can I do? + A: Just force it to be recognized by kernel parameters. See section 5.1. + Q: The driver screws up, if it starts to probe SCSI-devices, is there + some way out of it? + A: This is based on some problems with the driver. In such cases, send + e-mail to the maintainer. If you are owner of a model with the serial + number 95XX, just send as subject NOTIFY 95XX PROBLEM and the + maintainer immediately knows about your problem. But please: + Check your hardware and only if it works fine with other operating + systems, send E-Mail to me to notify the troubles. See the homepage + for how to send bug-reports or please read the next Q/A, here: + Q: I get a message: panic IBM MCA SCSI: command error .... , what can + I do against this? + A: Previously, I followed the way by ignoring command errors by using + ibmmcascsi=forgiveall, but this command no longer exists and is + obsolete. If such a problem appears, it is caused by some segmentation + fault of the driver, which maps to some unallowed area. The latest + version of the driver should be ok, as most bugs have been solved. + Q: There are still kernel panics, even after having set + ibmmcascsi=forgiveall. Are there other possibilities to prevent + such panics? + A: No, get just the latest release of the driver and it should work + better and better with increasing version number. Forget this + ibmmcascsi=forgiveall, as also ignorecmd are obsolete. + Q: Linux panics or stops without any comment, but it is probable, that my + harddisk(s) have bad blocks. + A: Sorry, the bad-block handling is still a feeble point of this driver, + but is on the schedule for development in the near future. + Q: Linux panics while dynamically assigning SCSI-ids or ldns. + A: If you disconnect a SCSI-device from the machine, while Linux is up + and the driver uses dynamical reassignment of logical device numbers + (ldn), it really gets "angry" if it won't find devices, that were still + present at boottime and stops Linux. + Q: The system does not recover after an abort-command has been generated. + A: This is regrettably true, as it is not yet understood, why the + SCSI-adapter does really NOT generate any interrupt at the end of + the abort-command. As no interrupt is generated, the abort command + cannot get finished and the system hangs, sorry, but checks are + running to hunt down this problem. If there is a real pending command, + the interrupt MUST get generated after abort. In this case, it + should finish well. + Q: The system gets in bad shape after a SCSI-reset, is this known? + A: Yes, as there are a lot of prescriptions (see the Linux Hackers' + Guide) what has to be done for reset, we still share the bad shape of + the reset functions with all other low level SCSI-drivers. + Astonishingly, reset works in most cases quite ok, but the harddisks + won't run in synchonous mode anymore after a reset, until you reboot. + Q: Why does my XXX w/Cache adapter not use read-prefetch? + A: w/Cache technical manuals are incoming here, so if I understood the + command of read-prefetch, it should be an easy thing to get harddisks + read in read-prefetch with w/Cache controllers. Some weeks or months, + still ahead and a lot of work still to do, sigh ... + + 5.3 Bugreports + -------------- + If you really find bugs in the sourcecode or the driver will successfully + refuse to work on your machine, you should send a bug report to me. The + best for this is to follow the instructions on the WWW-page for this + driver. Fill out the bug-report form, placed on the WWW-page and ship it, + so the bugs can be taken into account with maximum efforts. But, please + do not send bug reports about this driver to Linus Torvalds or Leonard + Zubkoff, as Linus is burried in E-Mail and Leonard is supervising all + SCSI-drivers and won't have the time left to look inside every single + driver to fix a bug and especially DO NOT send modified code to Linus + Torvalds, which has not been checked here!!! Recently, I got a lot of + bugreports for errors in the ibmmca.c code, which I could not imagine, but + a look inside some Linux-distribution showed me quite often some modified + code, which did no longer work on most other machines than the one of the + modifier. Ok, so now that there is maintenance service available for this + driver, please use this address first in order to keep the level of + confusion low. Thank you! + + When you get a SCSI-error message that panics your system, a list of + register-entries of the SCSI-subsystem is shown (from Version 3.1d). With + this list, it is very easy for the maintainer to localize the problem in + the driver or in the configuration of the user. Please write down all the + values from this report and send them to the maintainer. This would really + help a lot and makes life easier concerning misunderstandings. + + Use the bug-report form (see 5.4 for its address) to send all the bug- + stuff to the maintainer or write e-mail with the values from the table. + + 5.4 Support WWW-page + -------------------- + The address of the IBM SCSI-subsystem supporting WWW-page is: + + http://www.uni-mainz.de/~langm000/linux.html + + Here you can find info about the background of this driver, patches, + news and a bugreport form. + + 6 References + ------------ + The source of information is "Update for the PS/2 Hardware + Interface Technical Reference, Common Interfaces", September 1991, + part number 04G3281, available in the U.S. for $21.75 at + 1-800-IBM-PCTB, elsewhere call your local friendly IBM + representative. E.g. in Germany, "Hallo IBM" works really great. + In addition to SCSI subsystem, this update contains fairly detailed + (at hardware register level) sections on diskette controller, + keyboard controller, serial port controller, VGA, and XGA. + + Additional information from "Personal System/2 Micro Channel SCSI + Adapter with Cache Technical Reference", March 1990, PN 68X2365, + probably available from the same source (or possibly found buried + in officemates desk). + + Friedhelm Schmidt, "SCSI-Bus und IDE-Schnittstelle - Moderne Peripherie- + Schnittstellen: Hardware, Protokollbeschreibung und Anwendung", 2. Aufl. + Addison Wesley, 1996. + + Michael K. Johnson, "The Linux Kernel Hackers' Guide", Version 0.6, Chapel + Hill - North Carolina, 1995 + + Andreas Kaiser, "SCSI TAPE BACKUP for OS/2 2.0", Version 2.12, Stuttgart + 1993 + + Helmut Rompel, "IBM Computerwelt GUIDE", What is what bei IBM., Systeme * + Programme * Begriffe, IWT-Verlag GmbH - Muenchen, 1988 + + 7 Trademarks + ------------ + IBM, PS/2, OS/2, Microchannel are registered trademarks of International + Business Machines Corp. + + MS-DOS is a registered trademark of Microsoft Corporation + + OS-9 is a registered trademark of Microware Systems + +------ +Michael Lang +(langa2@kph.uni-mainz.de) diff -ur --new-file old/linux/drivers/scsi/README.ncr53c8xx new/linux/drivers/scsi/README.ncr53c8xx --- old/linux/drivers/scsi/README.ncr53c8xx Thu Jan 7 18:21:53 1999 +++ new/linux/drivers/scsi/README.ncr53c8xx Mon Apr 12 18:51:04 1999 @@ -4,12 +4,14 @@ 21 Rue Carnot 95170 DEUIL LA BARRE - FRANCE -22 November 1998 +10 March 1999 =============================================================================== 1. Introduction 2. Supported chips and SCSI features -3. Summary of other supported features +3. Advantages of the enhanced 896 driver + 3.1 Optimized SCSI SCRIPTS + 3.2 New features of the SYM53C896 (64 bit PCI dual LVD SCSI controller) 4. Memory mapped I/O versus normal I/O 5. Tagged command queueing 6. Parity checking @@ -39,6 +41,7 @@ 14.2 Device names change when another controller is added 14.3 Using only 8 bit devices with a WIDE SCSI controller. 14.4 Possible data corruption during a Memory Write and Invalidate + 14.5 IRQ sharing problems 15. SCSI problem troubleshooting 16. Synchonous transfer negotiation tables 16.1 Synchronous timings for 53C875 and 53C860 Ultra-SCSI controllers @@ -55,21 +58,30 @@ 1. Introduction -This driver has been ported from FreeBSD to Linux and is currently -maintained by: +The initial Linux ncr53c8xx driver has been a port of the ncr driver from +FreeBSD that has been achieved in November 1995 by: Gerard Roudier The original driver has been written for 386bsd and FreeBSD by: Wolfgang Stanglmeier Stefan Esser +It is now available as a bundle of 2 drivers: + +- ncr53c8xx generic driver that supports all the SYM53C8XX family including + the ealiest 810 rev. 1 and the latest 896 2 channels LVD SCSI controller. +- sym53c8xx enhanced driver (a.k.a. 896 drivers) that drops support of oldest + chips in order to gain advantage of new features, as LOAD/STORE intructions + available since the 810A and hardware phase mismatch available with the + latest 896. + You can find technical information about the NCR 8xx family in the PCI-HOWTO written by Michael Will and in the SCSI-HOWTO written by Drew Eckhardt. -Information about new chips is available at SYMBIOS web server: +Information about new chips is available at LSILOGIC web server: - http://www.symbios.com/ + http://www.lsilogic.com/ SCSI standard documentations are available at SYMBIOS ftp server: @@ -108,34 +120,65 @@ Master parity checking "Wide negotiation" is supported for chips that allow it. The -following table shows some characteristics of NCR 8xx family chips: - - On board Supported by -Chip SDMS BIOS Wide SCSI std. Max. sync the driver ----- --------- ---- --------- ---------- ------------ -810 N N FAST10 10 MB/s Y -810A N N FAST10 10 MB/s Y -815 Y N FAST10 10 MB/s Y -825 Y Y FAST10 20 MB/s Y -825A Y Y FAST10 20 MB/s Y -860 N N FAST20 20 MB/s Y -875 Y Y FAST20 40 MB/s Y -876 Y Y FAST20 40 MB/s Y -895 Y Y FAST40 80 MB/s Y - - -3. Summary of other supported features. - - Module: allow to load the driver - Memory mapped I/O: increases performance - Profiling information: read operations from the proc SCSI file system - Control commands: write operations to the proc SCSI file system - Debugging information: written to syslog (expert only) - Scatter / gather - Shared interrupt - Boot setup commands - Serial NVRAM: Symbios and Tekram formats +following table shows some characteristics of NCR 8xx family chips +and what drivers support them. + Supported by Supported by + On board the generic the enhanced +Chip SDMS BIOS Wide SCSI std. Max. sync driver driver +---- --------- ---- --------- ---------- ------------ ------------- +810 N N FAST10 10 MB/s Y N +810A N N FAST10 10 MB/s Y Y +815 Y N FAST10 10 MB/s Y N +825 Y Y FAST10 20 MB/s Y N +825A Y Y FAST10 20 MB/s Y Y +860 N N FAST20 20 MB/s Y Y +875 Y Y FAST20 40 MB/s Y Y +876 Y Y FAST20 40 MB/s Y Y +895 Y Y FAST40 80 MB/s Y Y +896 Y Y FAST40 80 MB/s Y Y + + +Summary of other supported features: + +Module: allow to load the driver +Memory mapped I/O: increases performance +Profiling information: read operations from the proc SCSI file system +Control commands: write operations to the proc SCSI file system +Debugging information: written to syslog (expert only) +Scatter / gather +Shared interrupt +Boot setup commands +Serial NVRAM: Symbios and Tekram formats + + +3. Advantages of the enhanced 896 driver + +3.1 Optimized SCSI SCRIPTS. + +The 810A, 825A, 875, 895 and newest 896 support new SCSI SCRIPTS instructions +named LOAD and STORE that allow to move 1 DWORD from/to an IO register to/from +memory much faster that the MOVE MEMORY instruction that is supported by the +53c7xx and 53c8xx family. The LOAD/STORE instructions support absolute and +DSA relative addressing modes. The SCSI SCRIPTS had been entirely rewritten +using LOAD/STORE instead of MOVE MEMORY instructions. + +3.2 New features of the SYM53C896 (64 bit PCI dual LVD SCSI controller) + +The 896 allows to handle the phase mismatch context saving from SCRIPTS +(avoids the phase mismatch interrupt that stops the SCSI processor +until the C code has saved the context of the transfer). +Implementing this without using LOAD/STORE instructions would be painfull +and I did'nt even try it. This chip also supports 64 bit PCI transactions +and addressing. The SCRIPTS processor is not true 64 bit, but uses segment +registers for bit 32-63. Another interesting feature is that LOAD/STORE +instructions that address the on-chip RAM (8k) remain internal to the chip. + +Due to the use of LOAD/STORE SCRIPTS instructions, this driver does not +support the following chips: +- SYM53C810 revision < 0x10 (16) +- SYM53C815 all revisions +- SYM53C825 revision < 0x10 (16) 4. Memory mapped I/O versus normal I/O @@ -669,6 +712,10 @@ irqm:0 always open drain irqm:1 same as initial settings (assumed BIOS settings) irqm:2 always totem pole + irqm:0x10 driver will not use SA_SHIRQ flag when requesting irq + irqm:0x20 driver will not use SA_INTERRUPT flag when requesting irq + + (Bits 0x10 and 0x20 can be combined with hardware irq mode option) Reverse probe revprob:n probe chip ids from the PCI configuration in this order: @@ -698,6 +745,13 @@ 0x1: Check and donnot attach the controller on error. 0x2: Check and just warn on error. +Exclude hosts from being attached + excl= + + Prevent host at a given io address from being attached. + For example 'ncr53c8xx=excl:0xb400,excl:0xc000' indicate to the + ncr53c8xx driver not to attach hosts at address 0xb400 and 0xc000. + Boot fail safe safe:y load the following assumed fail safe initial setup @@ -1027,7 +1081,30 @@ may only be needed under Linux when a scatter/gather list is not used and when the SCSI DATA IN phase is reentered after a phase mismatch. - +14.5 IRQ sharing problems + +When an IRQ is shared by devices that are handled by different drivers, it +may happen that one driver complains about the request of the IRQ having +failed. Inder Linux-2.0, this may be due to one driver having requested the +IRQ using the SA_INTERRUPT flag but some other having requested the same IRQ +without this flag. Under both Linux-2.0 and linux-2.2, this may be caused by +one driver not having requested the IRQ with the SA_SHIRQ flag. + +By default, the ncr53c8xx and sym53c8xx drivers request IRQs with both the +SA_INTERRUPT and the SA_SHIRQ flag under Linux-2.0 and with only the SA_SHIRQ +flag under Linux-2.2. + +Under Linux-2.0, you can disable use of SA_INTERRUPT flag from the boot +command line by using the following option: + + ncr53c8xx=irqm:0x20 (for the generic ncr53c8xx driver) + sym53c8xx=irqm:0x20 (for the sym53c8xx driver) + +If this does not fix the problem, then you may want to check how all other +drivers are requesting the IRQ and report the problem. Note that if at least +a single driver does not request the IRQ with the SA_SHIRQ flag (share IRQ), +then the request of the IRQ obviously will not succeed for all the drivers. + 15. SCSI problem troubleshooting Most SCSI problems are due to a non conformant SCSI bus or to buggy diff -ur --new-file old/linux/drivers/scsi/README.st new/linux/drivers/scsi/README.st --- old/linux/drivers/scsi/README.st Sun Sep 6 18:48:30 1998 +++ new/linux/drivers/scsi/README.st Mon Mar 8 00:20:26 1999 @@ -2,7 +2,7 @@ The driver is currently maintained by Kai M{kisara (email Kai.Makisara@metla.fi) -Last modified: Sun Sep 6 10:03:47 1998 by makisara@home +Last modified: Sun Jan 17 10:57:41 1999 by makisara@home BASICS @@ -60,10 +60,19 @@ alternative is to make a small script that uses mt to set the defaults tailored to the system. - The driver supports fixed and variable block size (within buffer limits). Both the auto-rewind (minor equals device number) and non-rewind devices (minor is 128 + device number) are implemented. + +In variable block mode, the byte count in write() determines the size +of the physical block on tape. When reading, the drive reads the next +tape block and returns to the user the data if the read() byte count +is at least the block size. Otherwise the data is truncated. + +In fixed block mode, the data transfer between the drive and the +driver is in multiples of the block size. The write() byte count must +be a multiple of the block size. This is not required when reading but +may be advisable for portability. Support is provided for changing the tape partition and partitioning of the tape with one or two partitions. By default support for diff -ur --new-file old/linux/drivers/scsi/aha152x.c new/linux/drivers/scsi/aha152x.c --- old/linux/drivers/scsi/aha152x.c Tue Jan 19 20:01:04 1999 +++ new/linux/drivers/scsi/aha152x.c Wed May 12 22:19:32 1999 @@ -343,6 +343,7 @@ #include #include #include +#include #include "aha152x.h" #include @@ -413,8 +414,13 @@ #define P_PARITY 2 /* possible irq range */ +#ifdef PCMCIA +#define IRQ_MIN 0 +#define IRQ_MAX 16 +#else #define IRQ_MIN 9 #define IRQ_MAX 12 +#endif #define IRQS IRQ_MAX-IRQ_MIN+1 enum { @@ -489,6 +495,7 @@ int ext_trans; int swint; + int service; unsigned char syncrate[8]; @@ -500,7 +507,7 @@ #endif }; -void aha152x_intr(int irq, void *dev_id, struct pt_regs *); +static void aha152x_intr(int irq, void *dev_id, struct pt_regs *); void aha152x_done(struct Scsi_Host *shpnt, int error); void aha152x_setup(char *str, int *ints); int aha152x_checksetup(struct aha152x_setup *setup); @@ -744,7 +751,7 @@ if(!aha152x_porttest(setup->io_port)) return 0; - if(setup->irqirq>IRQ_MAX) + if((setup->irqirq>IRQ_MAX)) return 0; if((setup->scsiid < 0) || (setup->scsiid > 7)) @@ -1550,38 +1557,72 @@ aha152x_panic(shpnt, "done() called outside of command"); } + +static void aha152x_complete(struct Scsi_Host *); + +static struct tq_struct aha152x_tq; + /* - * Interrupts handler (main routine of the driver) + * Run service completions on the card with interrupts enabled. */ -void aha152x_intr(int irqno, void *dev_id, struct pt_regs * regs) + +static void aha152x_run(void) { - struct Scsi_Host *shpnt = aha152x_host[irqno-IRQ_MIN]; - unsigned int flags; - int done=0, phase; + int i; + for(i=0;iservice) + { + HOSTDATA(shpnt)->service=0; + aha152x_complete(shpnt); + } + } +} + +/* + * Interrupts handler (main routine of the driver) + */ + +static void aha152x_intr(int irqno, void *dev_id, struct pt_regs * regs) +{ + struct Scsi_Host *shpnt = aha152x_host[irqno-IRQ_MIN]; #if defined(DEBUG_RACE) - enter_driver("intr"); + enter_driver("intr"); #else #if defined(DEBUG_INTR) - if(HOSTDATA(shpnt)->debug & debug_intr) - printk("\naha152x: intr(), "); + if(HOSTDATA(shpnt)->debug & debug_intr) + printk("\naha152x: intr(), "); #endif #endif - if(!shpnt) - panic("aha152x: catched interrupt for unknown controller.\n"); + if(!shpnt) + panic("aha152x: catched interrupt for unknown controller.\n"); + + /* no more interrupts from the controller, while we're busy. + INTEN is restored by the BH handler */ + + CLRBITS(DMACNTRL0, INTEN); + + /* Poke the BH handler */ + + HOSTDATA(shpnt)->service=1; + aha152x_tq.routine = (void *)aha152x_run; + queue_task(&aha152x_tq, &tq_immediate); + mark_bh(IMMEDIATE_BH); +} + +static void aha152x_complete(struct Scsi_Host *shpnt) +{ + unsigned int flags; + int done=0, phase; - /* no more interrupts from the controller, while we're busy. - INTEN has to be restored, when we're ready to leave - intr(). To avoid race conditions, we have to return - immediately afterwards. */ - CLRBITS(DMACNTRL0, INTEN); - /* sti(); FIXME!!! Yes, sti() really needs to be here if we want to lock up */ - - /* disconnected target is trying to reconnect. - Only possible, if we have disconnected nexuses and - nothing is occupying the bus. - */ + /* 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)) ) { diff -ur --new-file old/linux/drivers/scsi/atp870u.c new/linux/drivers/scsi/atp870u.c --- old/linux/drivers/scsi/atp870u.c Fri Dec 18 18:48:05 1998 +++ new/linux/drivers/scsi/atp870u.c Thu Feb 25 01:27:54 1999 @@ -1684,7 +1684,7 @@ struct Scsi_Host * shpnt = NULL; int count = 0; static unsigned short devid[7]={0x8002,0x8010,0x8020,0x8030,0x8040,0x8050,0}; - static struct pci_dev *pdev = NULL; + static struct pci_dev *pdev = NULL, *acard_pdev[3]; printk("aec671x_detect: \n"); if (!pci_present()) @@ -1720,8 +1720,8 @@ h=0; while ( devid[h] != 0 ) { - pci_find_device(0x1191,devid[h],pdev); - if (pdev == NULL); { + pdev = pci_find_device(0x1191,devid[h],pdev); + if (pdev == NULL) { h++; index=0; continue; @@ -1729,6 +1729,7 @@ chip_ver[2]=0; /* To avoid messing with the things below... */ + acard_pdev[2] = pdev; pci_device_fn[2] = pdev->devfn; pci_bus[2] = pdev->bus->number; @@ -1746,15 +1747,18 @@ } if ( pci_device_fn[2] < pci_device_fn[0] ) { + acard_pdev[1]=acard_pdev[0]; pci_bus[1]=pci_bus[0]; pci_device_fn[1]=pci_device_fn[0]; chip_ver[1]=chip_ver[0]; + acard_pdev[0]=acard_pdev[2]; pci_bus[0]=pci_bus[2]; pci_device_fn[0]=pci_device_fn[2]; chip_ver[0]=chip_ver[2]; } else if ( pci_device_fn[2] < pci_device_fn[1] ) { + acard_pdev[1]=acard_pdev[2]; pci_bus[1]=pci_bus[2]; pci_device_fn[1]=pci_device_fn[2]; chip_ver[1]=chip_ver[2]; @@ -1774,6 +1778,7 @@ return count; } + pdev = acard_pdev[h]; pdev->devfn = pci_device_fn[h]; pdev->bus->number = pci_bus[h]; diff -ur --new-file old/linux/drivers/scsi/esp.c new/linux/drivers/scsi/esp.c --- old/linux/drivers/scsi/esp.c Mon Nov 16 19:37:28 1998 +++ new/linux/drivers/scsi/esp.c Tue Mar 16 01:11:31 1999 @@ -1,6 +1,6 @@ /* esp.c: EnhancedScsiProcessor Sun SCSI driver code. * - * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1995, 1998 David S. Miller (davem@caip.rutgers.edu) */ /* TODO: @@ -162,6 +162,17 @@ in_tgterror = 0x84, /* Target did something stupid */ }; +enum { + /* Zero has special meaning, see skipahead[12]. */ +/*0*/ do_never, + +/*1*/ do_phase_determine, +/*2*/ do_reset_bus, +/*3*/ do_reset_complete, +/*4*/ do_work_bus, +/*5*/ do_intr_end +}; + struct proc_dir_entry proc_scsi_esp = { PROC_SCSI_ESP, 3, "esp", S_IFDIR | S_IRUGO | S_IXUGO, 2 @@ -354,24 +365,30 @@ }; } +#ifdef DEBUG_STATE_MACHINE static inline void esp_advance_phase(Scsi_Cmnd *s, int newphase) { -#ifdef DEBUG_STATE_MACHINE ESPLOG(("<%s>", phase_string(newphase))); -#endif s->SCp.sent_command = s->SCp.phase; s->SCp.phase = newphase; } +#else +#define esp_advance_phase(__s, __newphase) \ + (__s)->SCp.sent_command = (__s)->SCp.phase; \ + (__s)->SCp.phase = (__newphase); +#endif +#ifdef DEBUG_ESP_CMDS extern inline void esp_cmd(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs, unchar cmd) { -#ifdef DEBUG_ESP_CMDS esp->espcmdlog[esp->espcmdent] = cmd; esp->espcmdent = (esp->espcmdent + 1) & 31; -#endif eregs->esp_cmd = cmd; } +#else +#define esp_cmd(__esp, __eregs, __cmd) (__eregs)->esp_cmd = (__cmd) +#endif /* How we use the various Linux SCSI data structures for operation. * @@ -442,14 +459,23 @@ } /* Resetting various pieces of the ESP scsi driver chipset/buses. */ -static inline void esp_reset_dma(struct Sparc_ESP *esp) +static void esp_reset_dma(struct Sparc_ESP *esp) { struct sparc_dma_registers *dregs = esp->dregs; - unsigned long tmp, flags; - int can_do_burst16, can_do_burst32; + unsigned long flags; + int can_do_burst16, can_do_burst32, can_do_burst64; + int can_do_sbus64; can_do_burst16 = esp->bursts & DMA_BURST16; can_do_burst32 = esp->bursts & DMA_BURST32; + can_do_burst64 = 0; + can_do_sbus64 = 0; +#ifdef __sparc_v9__ + /* XXX Can sun4d do these too? */ + can_do_burst64 = esp->bursts & DMA_BURST64; + can_do_sbus64 = 1; + mmu_set_sbus64(esp->edev, esp->bursts); +#endif /* Punt the DVMA into a known state. */ if(esp->dma->revision != dvmahme) { @@ -462,14 +488,19 @@ save_flags(flags); cli(); /* I really hate this chip. */ - dregs->cond_reg = 0x08000000; /* Reset interface to FAS */ - dregs->cond_reg = DMA_RST_SCSI; /* Reset DVMA itself */ + dregs->cond_reg = DMA_RESET_FAS366; /* Reset interface to FAS */ + dregs->cond_reg = DMA_RST_SCSI; /* Reset DVMA itself */ - tmp = (DMA_PARITY_OFF|DMA_2CLKS|DMA_SCSI_DISAB|DMA_INT_ENAB); - tmp &= ~(DMA_ENABLE|DMA_ST_WRITE|DMA_BRST_SZ); + esp->prev_hme_dmacsr = (DMA_PARITY_OFF|DMA_2CLKS|DMA_SCSI_DISAB|DMA_INT_ENAB); + esp->prev_hme_dmacsr &= ~(DMA_ENABLE|DMA_ST_WRITE|DMA_BRST_SZ); if(can_do_burst32) - tmp |= DMA_BRST32; + esp->prev_hme_dmacsr |= DMA_BRST32; + else if(can_do_burst64) + esp->prev_hme_dmacsr |= DMA_BRST64; + + if(can_do_sbus64) + esp->prev_hme_dmacsr |= DMA_SCSI_SBUS64; /* This chip is horrible. */ while(dregs->cond_reg & DMA_PEND_READ) @@ -477,8 +508,14 @@ dregs->cond_reg = 0; - dregs->cond_reg = tmp; /* bite me */ - restore_flags(flags); /* ugh... */ + dregs->cond_reg = esp->prev_hme_dmacsr; + + /* This is necessary to avoid having the SCSI channel + * engine lock up on us. + */ + dregs->st_addr = 0; + + restore_flags(flags); break; case dvmarev2: /* This is the gate array found in the sun4m @@ -512,7 +549,7 @@ } /* Reset the ESP chip, _not_ the SCSI bus. */ -static inline void esp_reset_esp(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs) +static void esp_reset_esp(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs) { int family_code, version, i; volatile int trash; @@ -524,8 +561,8 @@ /* Reload the configuration registers */ eregs->esp_cfact = esp->cfact; - eregs->esp_stp = 0; - eregs->esp_soff = 0; + eregs->esp_stp = esp->prev_stp = 0; + eregs->esp_soff = esp->prev_soff = 0; eregs->esp_timeo = esp->neg_defp; /* This is the only point at which it is reliable to read @@ -541,11 +578,11 @@ esp->erev = fashme; /* Version is usually '5'. */ else esp->erev = fas100a; - printk("esp%d: FAST chip is %s (family=%d, version=%d)\n", - esp->esp_id, - (esp->erev == fas236) ? "fas236" : - ((esp->erev == fas100a) ? "fas100a" : - "fasHME"), family_code, (version & 7)); + ESPMISC(("esp%d: FAST chip is %s (family=%d, version=%d)\n", + esp->esp_id, + (esp->erev == fas236) ? "fas236" : + ((esp->erev == fas100a) ? "fas100a" : + "fasHME"), family_code, (version & 7))); esp->min_period = ((4 * esp->ccycle) / 1000); } else { @@ -565,7 +602,7 @@ case esp236: /* Slow 236 */ eregs->esp_cfg2 = esp->config2; - eregs->esp_cfg3 = esp->config3[0]; + eregs->esp_cfg3 = esp->prev_cfg3 = esp->config3[0]; break; case fashme: esp->config2 |= (ESP_CONFIG2_HME32 | ESP_CONFIG2_HMEFENAB); @@ -574,13 +611,18 @@ /* Fast 236 or HME */ eregs->esp_cfg2 = esp->config2; for(i=0; i<8; i++) { - if(esp->erev == fashme) - esp->config3[i] |= - (ESP_CONFIG3_FCLOCK | ESP_CONFIG3_BIGID | ESP_CONFIG3_OBPUSH); - else + if(esp->erev == fashme) { + unsigned char cfg3; + + cfg3 = ESP_CONFIG3_FCLOCK | ESP_CONFIG3_OBPUSH; + if (esp->scsi_id >= 8) + cfg3 |= ESP_CONFIG3_IDBIT3; + esp->config3[i] |= cfg3; + } else { esp->config3[i] |= ESP_CONFIG3_FCLK; + } } - eregs->esp_cfg3 = esp->config3[0]; + eregs->esp_cfg3 = esp->prev_cfg3 = esp->config3[0]; if(esp->erev == fashme) { esp->radelay = 80; } else { @@ -595,7 +637,7 @@ eregs->esp_cfg2 = esp->config2; for(i=0; i<8; i++) esp->config3[i] |= ESP_CONFIG3_FCLOCK; - eregs->esp_cfg3 = esp->config3[0]; + eregs->esp_cfg3 = esp->prev_cfg3 = esp->config3[0]; esp->radelay = 32; break; default: @@ -609,7 +651,7 @@ } /* This places the ESP into a known state at boot time. */ -static inline void esp_bootup_reset(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs) +static void esp_bootup_reset(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs) { volatile unchar trash; @@ -654,6 +696,10 @@ esp->edev = esp_dev; esp->esp_id = id; +#ifdef __sparc_v9__ + esp_host->unchecked_isa_dma = 1; +#endif + /* Put into the chain of esp chips detected */ if(espchain) { elink = espchain; @@ -877,7 +923,7 @@ esp->ctick = ESP_TICK(ccf, esp->ccycle); esp->neg_defp = ESP_NEG_DEFP(fmhz, ccf); esp->sync_defp = SYNC_DEFP_SLOW; - printk("SCSI ID %d Clock %d MHz CCF=%d Time-Out %d ", + printk("SCSI ID %d Clk %dMHz CCF=%d TOut %d ", esp->scsi_id, (fmhz / 1000000), ccf, (int) esp->neg_defp); @@ -910,28 +956,28 @@ eregs->esp_cfg2 = esp->config2; if((eregs->esp_cfg2 & ~(ESP_CONFIG2_MAGIC)) != (ESP_CONFIG2_SCSI2ENAB | ESP_CONFIG2_REGPARITY)) { - printk("NCR53C90(esp100) detected\n"); + printk("NCR53C90(esp100)\n"); esp->erev = esp100; } else { eregs->esp_cfg2 = esp->config2 = 0; eregs->esp_cfg3 = 0; - eregs->esp_cfg3 = esp->config3[0] = 5; + eregs->esp_cfg3 = esp->prev_cfg3 = esp->config3[0] = 5; if(eregs->esp_cfg3 != 5) { - printk("NCR53C90A(esp100a) detected\n"); + printk("NCR53C90A(esp100a)\n"); esp->erev = esp100a; } else { int target; for(target=0; target<8; target++) esp->config3[target] = 0; - eregs->esp_cfg3 = 0; + eregs->esp_cfg3 = esp->prev_cfg3 = 0; if(ccf > ESP_CCF_F5) { - printk("NCR53C9XF(espfast) detected\n"); + printk("NCR53C9XF(espfast)\n"); esp->erev = fast; eregs->esp_cfg2 = esp->config2 = 0; esp->sync_defp = SYNC_DEFP_FAST; } else { - printk("NCR53C9x(esp236) detected\n"); + printk("NCR53C9x(esp236)\n"); esp->erev = esp236; eregs->esp_cfg2 = esp->config2 = 0; } @@ -958,6 +1004,10 @@ esp->prevmsgout = esp->prevmsgin = 0; esp->msgout_len = esp->msgin_len = 0; + /* Clear the one behind caches to hold unmatchable values. */ + esp->prev_soff = esp->prev_stp = esp->prev_cfg3 = 0xff; + esp->prev_hme_dmacsr = 0xffffffff; + /* Reset the thing before we try anything... */ esp_bootup_reset(esp, eregs); @@ -1238,6 +1288,59 @@ return esp_host_info(esp, buffer, offset, length); } +static void esp_get_dmabufs(struct Sparc_ESP *esp, Scsi_Cmnd *sp) +{ + if(sp->use_sg == 0) { + sp->SCp.this_residual = sp->request_bufflen; + sp->SCp.buffer = (struct scatterlist *) sp->request_buffer; + sp->SCp.buffers_residual = 0; + sp->SCp.have_data_in = mmu_get_scsi_one((char *)sp->SCp.buffer, + sp->SCp.this_residual, + esp->edev->my_bus); + sp->SCp.ptr = (char *) ((unsigned long)sp->SCp.have_data_in); + } else { + sp->SCp.buffer = (struct scatterlist *) sp->buffer; + sp->SCp.buffers_residual = sp->use_sg - 1; + sp->SCp.this_residual = sp->SCp.buffer->length; + mmu_get_scsi_sgl((struct mmu_sglist *) sp->SCp.buffer, + sp->SCp.buffers_residual, + esp->edev->my_bus); + sp->SCp.ptr = (char *) ((unsigned long)sp->SCp.buffer->dvma_address); + } +} + +static void esp_release_dmabufs(struct Sparc_ESP *esp, Scsi_Cmnd *sp) +{ + if(sp->use_sg == 0) + mmu_release_scsi_one(sp->SCp.have_data_in, + sp->request_bufflen, + esp->edev->my_bus); + else + mmu_release_scsi_sgl((struct mmu_sglist *) + sp->buffer, sp->use_sg - 1, + esp->edev->my_bus); +} + +static void esp_restore_pointers(struct Sparc_ESP *esp, Scsi_Cmnd *sp) +{ + struct esp_pointers *ep = &esp->data_pointers[sp->target]; + + sp->SCp.ptr = ep->saved_ptr; + sp->SCp.buffer = ep->saved_buffer; + sp->SCp.this_residual = ep->saved_this_residual; + sp->SCp.buffers_residual = ep->saved_buffers_residual; +} + +static void esp_save_pointers(struct Sparc_ESP *esp, Scsi_Cmnd *sp) +{ + struct esp_pointers *ep = &esp->data_pointers[sp->target]; + + ep->saved_ptr = sp->SCp.ptr; + ep->saved_buffer = sp->SCp.buffer; + ep->saved_this_residual = sp->SCp.this_residual; + ep->saved_buffers_residual = sp->SCp.buffers_residual; +} + /* Some rules: * * 1) Never ever panic while something is live on the bus. @@ -1307,7 +1410,7 @@ esp->msgout_len = 4; } -static inline void esp_exec_cmd(struct Sparc_ESP *esp) +static void esp_exec_cmd(struct Sparc_ESP *esp) { struct sparc_dma_registers *dregs = esp->dregs; struct Sparc_ESP_regs *eregs = esp->eregs; @@ -1318,15 +1421,18 @@ int lun, target; int i; - /* Hold off if we've been reselected or an IRQ is showing... */ - if(esp->disconnected_SC || DMA_IRQ_P(dregs)) + /* Hold off if we have disconnected commands and + * an IRQ is showing... + */ + if(esp->disconnected_SC && DMA_IRQ_P(dregs)) return; /* Grab first member of the issue queue. */ SCptr = esp->current_SC = remove_first_SC(&esp->issue_SC); /* Safe to panic here because current_SC is null. */ - if(!SCptr) panic("esp: esp_exec_cmd and issue queue is NULL"); + if(!SCptr) + panic("esp: esp_exec_cmd and issue queue is NULL"); SDptr = SCptr->device; lun = SCptr->lun; @@ -1402,7 +1508,10 @@ SDptr->sync_max_offset = 0; SDptr->sync_min_period = 0; } else { - int toshiba_cdrom_hwbug_wkaround = 0; + /* Sorry, I have had way too many problems with + * various CDROM devices on ESP. -DaveM + */ + int cdrom_hwbug_wkaround = 0; /* Never allow disconnects or synchronous transfers on * SparcStation1 and SparcStation1+. Allowing those @@ -1429,8 +1538,7 @@ */ if(esp->erev == fashme && !SDptr->wide) { if(!SDptr->borken && - (SDptr->type != TYPE_ROM || - strncmp(SDptr->vendor, "TOSHIBA", 7))) { + SDptr->type != TYPE_ROM) { build_wide_nego_msg(esp, 16); SDptr->wide = 1; esp->wnip = 1; @@ -1442,12 +1550,11 @@ } if(!SDptr->borken) { - if((SDptr->type == TYPE_ROM) && - (!strncmp(SDptr->vendor, "TOSHIBA", 7))) { + if((SDptr->type == TYPE_ROM)) { /* Nice try sucker... */ - printk(KERN_INFO "esp%d: Disabling sync for buggy " - "Toshiba CDROM.\n", esp->esp_id); - toshiba_cdrom_hwbug_wkaround = 1; + ESPMISC(("esp%d: Disabling sync for buggy " + "CDROM.\n", esp->esp_id)); + cdrom_hwbug_wkaround = 1; build_sync_nego_msg(esp, 0, 0); } else { build_sync_nego_msg(esp, esp->sync_defp, 15); @@ -1483,13 +1590,9 @@ * thank you very much. ;-) */ if(((SDptr->scsi_level < 3) && (SDptr->type != TYPE_TAPE)) || -#if 1 /* Until I find out why HME barfs with disconnects enabled... */ - toshiba_cdrom_hwbug_wkaround || SDptr->borken || esp->erev == fashme) { -#else - toshiba_cdrom_hwbug_wkaround || SDptr->borken) { -#endif - printk(KERN_INFO "esp%d: Disabling DISCONNECT for target %d " - "lun %d\n", esp->esp_id, SCptr->target, SCptr->lun); + cdrom_hwbug_wkaround || SDptr->borken) { + ESPMISC((KERN_INFO "esp%d: Disabling DISCONNECT for target %d " + "lun %d\n", esp->esp_id, SCptr->target, SCptr->lun)); SDptr->disconnect = 0; *cmdp++ = IDENTIFY(0, lun); } else { @@ -1517,16 +1620,20 @@ (ESP_BUSID_RESELID | ESP_BUSID_CTR32BIT); else eregs->esp_busid = (target & 7); - eregs->esp_soff = SDptr->sync_max_offset; - eregs->esp_stp = SDptr->sync_min_period; - if(esp->erev > esp100a) - eregs->esp_cfg3 = esp->config3[target]; - + if (esp->prev_soff != SDptr->sync_max_offset || + esp->prev_stp != SDptr->sync_min_period || + (esp->erev > esp100a && + esp->prev_cfg3 != esp->config3[target])) { + eregs->esp_soff = esp->prev_soff = SDptr->sync_max_offset; + eregs->esp_stp = esp->prev_stp = SDptr->sync_min_period; + if(esp->erev > esp100a) + eregs->esp_cfg3 = + esp->prev_cfg3 = + esp->config3[target]; + } i = (cmdp - esp->esp_command); if(esp->erev == fashme) { - unsigned long tmp; - esp_cmd(esp, eregs, ESP_CMD_FLUSH); /* Grrr! */ /* Set up the DMA and HME counters */ @@ -1537,12 +1644,12 @@ esp_cmd(esp, eregs, the_esp_command); /* Talk about touchy hardware... */ - tmp = dregs->cond_reg; - tmp |= (DMA_SCSI_DISAB | DMA_ENABLE); - tmp &= ~(DMA_ST_WRITE); + esp->prev_hme_dmacsr = ((esp->prev_hme_dmacsr | + (DMA_SCSI_DISAB | DMA_ENABLE)) & + ~(DMA_ST_WRITE)); dregs->cnt = 16; dregs->st_addr = esp->esp_command_dvma; - dregs->cond_reg = tmp; + dregs->cond_reg = esp->prev_hme_dmacsr; } else { /* Set up the DMA and ESP counters */ eregs->esp_tclow = i; @@ -1575,35 +1682,10 @@ /* We use the scratch area. */ ESPQUEUE(("esp_queue: target=%d lun=%d ", SCpnt->target, SCpnt->lun)); ESPDISC(("N<%02x,%02x>", SCpnt->target, SCpnt->lun)); - if(!SCpnt->use_sg) { - ESPQUEUE(("!use_sg\n")); - SCpnt->SCp.this_residual = SCpnt->request_bufflen; - SCpnt->SCp.buffer = - (struct scatterlist *) SCpnt->request_buffer; - SCpnt->SCp.buffers_residual = 0; - /* Sneaky. */ - SCpnt->SCp.have_data_in = mmu_get_scsi_one((char *)SCpnt->SCp.buffer, - SCpnt->SCp.this_residual, - esp->edev->my_bus); - /* XXX The casts are extremely gross, but with 64-bit kernel - * XXX and 32-bit SBUS what am I to do? -DaveM - */ - SCpnt->SCp.ptr = (char *)((unsigned long)SCpnt->SCp.have_data_in); - } else { - ESPQUEUE(("use_sg ")); -#ifdef DEBUG_ESP_SG - printk("esp%d: sglist at %p with %d buffers\n", - esp->esp_id, SCpnt->buffer, SCpnt->use_sg); -#endif - SCpnt->SCp.buffer = (struct scatterlist *) SCpnt->buffer; - SCpnt->SCp.buffers_residual = SCpnt->use_sg - 1; - SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length; - mmu_get_scsi_sgl((struct mmu_sglist *) SCpnt->SCp.buffer, - SCpnt->SCp.buffers_residual, - esp->edev->my_bus); - /* XXX Again these casts are sick... -DaveM */ - SCpnt->SCp.ptr=(char *)((unsigned long)SCpnt->SCp.buffer->dvma_address); - } + + esp_get_dmabufs(esp, SCpnt); + esp_save_pointers(esp, SCpnt); /* FIXME for tag queueing */ + SCpnt->SCp.Status = CHECK_CONDITION; SCpnt->SCp.Message = 0xff; SCpnt->SCp.sent_command = 0; @@ -1634,7 +1716,7 @@ } /* Dump driver state. */ -static inline void esp_dump_cmd(Scsi_Cmnd *SCptr) +static void esp_dump_cmd(Scsi_Cmnd *SCptr) { ESPLOG(("[tgt<%02x> lun<%02x> " "pphase<%s> cphase<%s>]", @@ -1643,8 +1725,8 @@ phase_string(SCptr->SCp.phase))); } -static inline void esp_dump_state(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs, - struct sparc_dma_registers *dregs) +static void esp_dump_state(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs, + struct sparc_dma_registers *dregs) { Scsi_Cmnd *SCptr = esp->current_SC; #ifdef DEBUG_ESP_CMDS @@ -1735,6 +1817,7 @@ if(this == SCptr) { *prev = (Scsi_Cmnd *) this->host_scribble; this->host_scribble = NULL; + esp_release_dmabufs(esp, this); this->result = DID_ABORT << 16; this->done(this); if(don) @@ -1749,8 +1832,11 @@ * on the bus at this time. So, we let the SCSI code wait * a little bit and try again later. */ - if(esp->current_SC) + if(esp->current_SC) { + if(don) + DMA_INTSON(dregs); return SCSI_ABORT_BUSY; + } /* It's disconnected, we have to reconnect to re-establish * the nexus and tell the device to abort. However, we really @@ -1759,20 +1845,70 @@ * happens, we are really hung so reset the bus. */ + if(don) + DMA_INTSON(dregs); return SCSI_ABORT_SNOOZE; } +/* We've sent ESP_CMD_RS to the ESP, the interrupt had just + * arrived indicating the end of the SCSI bus reset. Our job + * is to clean out the command queues and begin re-execution + * of SCSI commands once more. + */ +static int esp_finish_reset(struct Sparc_ESP *esp, + struct Sparc_ESP_regs *eregs, + struct sparc_dma_registers *dregs) +{ + Scsi_Cmnd *sp = esp->current_SC; + + /* Clean up currently executing command, if any. */ + if (sp != NULL) { + esp_release_dmabufs(esp, sp); + sp->result = (DID_RESET << 16); + sp->scsi_done(sp); + esp->current_SC = NULL; + } + + /* Clean up disconnected queue, they have been invalidated + * by the bus reset. + */ + if (esp->disconnected_SC) { + while((sp = remove_first_SC(&esp->disconnected_SC)) != NULL) { + esp_release_dmabufs(esp, sp); + sp->result = (DID_RESET << 16); + sp->scsi_done(sp); + } + } + + /* SCSI bus reset is complete. */ + esp->resetting_bus = 0; + + /* Ok, now it is safe to get commands going once more. */ + if(esp->issue_SC) + esp_exec_cmd(esp); + + return do_intr_end; +} + +static int esp_do_resetbus(struct Sparc_ESP *esp, + struct Sparc_ESP_regs *eregs, + struct sparc_dma_registers *dregs) +{ + ESPLOG(("esp%d: Resetting scsi bus\n", esp->esp_id)); + esp->resetting_bus = 1; + esp_cmd(esp, eregs, ESP_CMD_RS); + + return do_intr_end; +} + /* Reset ESP chip, reset hanging bus, then kill active and * disconnected commands for targets without soft reset. */ int esp_reset(Scsi_Cmnd *SCptr, unsigned int how) { struct Sparc_ESP *esp = (struct Sparc_ESP *) SCptr->host->hostdata; - struct Sparc_ESP_regs *eregs = esp->eregs; - ESPLOG(("esp%d: Resetting scsi bus\n", esp->esp_id)); - esp->resetting_bus = 1; - esp_cmd(esp, eregs, ESP_CMD_RS); + (void) esp_do_resetbus(esp, esp->eregs, esp->dregs); return SCSI_RESET_PENDING; } @@ -1784,25 +1920,7 @@ if(esp->current_SC) { done_SC = esp->current_SC; esp->current_SC = NULL; - - /* Free dvma entry. */ - if(!done_SC->use_sg) { - /* Sneaky. */ - mmu_release_scsi_one(done_SC->SCp.have_data_in, - done_SC->request_bufflen, - esp->edev->my_bus); - } else { -#ifdef DEBUG_ESP_SG - printk("esp%d: unmapping sg ", esp->esp_id); -#endif - mmu_release_scsi_sgl((struct mmu_sglist *) done_SC->buffer, - done_SC->use_sg - 1, - esp->edev->my_bus); -#ifdef DEBUG_ESP_SG - printk("done.\n"); -#endif - } - + esp_release_dmabufs(esp, done_SC); done_SC->result = error; done_SC->scsi_done(done_SC); @@ -1820,11 +1938,6 @@ /* Wheee, ESP interrupt engine. */ -enum { - do_phase_determine, do_reset_bus, do_reset_complete, - do_work_bus, do_intr_end, -}; - /* Forward declarations. */ static int esp_do_phase_determine(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs, struct sparc_dma_registers *dregs); @@ -1843,29 +1956,29 @@ static int esp_do_cmdbegin(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs, struct sparc_dma_registers *dregs); -static inline int sreg_datainp(unchar sreg) -{ - return (sreg & ESP_STAT_PMASK) == ESP_DIP; -} - -static inline int sreg_dataoutp(unchar sreg) -{ - return (sreg & ESP_STAT_PMASK) == ESP_DOP; -} +#define sreg_datainp(__sreg) (((__sreg) & ESP_STAT_PMASK) == ESP_DIP) +#define sreg_dataoutp(__sreg) (((__sreg) & ESP_STAT_PMASK) == ESP_DOP) -/* Did they drop these fabs on the floor or what?!?!! */ -static inline void hme_fifo_hwbug_workaround(struct Sparc_ESP *esp, - struct Sparc_ESP_regs *eregs) +/* Read any bytes found in the FAS366 fifo, storing them into + * the ESP driver software state structure. + */ +static void hme_fifo_read(struct Sparc_ESP *esp, + struct Sparc_ESP_regs *eregs) { + unsigned long count = 0; unchar status = esp->sreg; - /* Cannot safely frob the fifo for these following cases. */ - if(sreg_datainp(status) || sreg_dataoutp(status) || - (esp->current_SC && esp->current_SC->SCp.phase == in_data_done)) { + /* Cannot safely frob the fifo for these following cases, but + * we must always read the fifo when the reselect interrupt + * is pending. + */ + if(((esp->ireg & ESP_INTR_RSEL) == 0) && + (sreg_datainp(status) || + sreg_dataoutp(status) || + (esp->current_SC && + esp->current_SC->SCp.phase == in_data_done))) { ESPHME(("")); - return; } else { - unsigned long count = 0; unsigned long fcnt = eregs->esp_fflags & ESP_FF_FBYTES; /* The HME stores bytes in multiples of 2 in the fifo. */ @@ -1886,9 +1999,9 @@ } else { ESPHME(("no_xtra_byte")); } - esp->hme_fifo_workaround_count = count; - ESPHME(("wkarnd_cnt=%d]", (int)count)); } + ESPHME(("wkarnd_cnt=%d]", (int)count)); + esp->hme_fifo_workaround_count = count; } static inline void hme_fifo_push(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs, @@ -1913,7 +2026,10 @@ return 0; if(DMA_IRQ_P(dregs)) { /* Yes, we are able to save an interrupt. */ - esp->sreg = eregs->esp_status; + if (esp->erev == fashme) + esp->sreg2 = eregs->esp_status2; + esp->sreg = (eregs->esp_status & ~(ESP_STAT_INTR)); + esp->ireg = eregs->esp_intrpt; if(esp->erev == fashme) { /* This chip is really losing. */ ESPHME(("HME[")); @@ -1923,10 +2039,10 @@ * Happy Meal indeed.... */ ESPHME(("fifo_workaround]")); - hme_fifo_hwbug_workaround(esp, eregs); + if(!(esp->sreg2 & ESP_STAT2_FEMPTY) || + (esp->sreg2 & ESP_STAT2_F1BYTE)) + hme_fifo_read(esp, eregs); } - esp->ireg = eregs->esp_intrpt; - esp->sreg &= ~(ESP_STAT_INTR); if(!(esp->ireg & ESP_INTR_SR)) return 0; else @@ -1947,7 +2063,10 @@ return 0; if(DMA_IRQ_P(dregs)) { /* Yes, we are able to save an interrupt. */ - esp->sreg = eregs->esp_status; + if (esp->erev == fashme) + esp->sreg2 = eregs->esp_status2; + esp->sreg = (eregs->esp_status & ~(ESP_STAT_INTR)); + esp->ireg = eregs->esp_intrpt; if(esp->erev == fashme) { /* This chip is really losing. */ ESPHME(("HME[")); @@ -1958,10 +2077,10 @@ * Happy Meal indeed.... */ ESPHME(("fifo_workaround]")); - hme_fifo_hwbug_workaround(esp, eregs); + if(!(esp->sreg2 & ESP_STAT2_FEMPTY) || + (esp->sreg2 & ESP_STAT2_F1BYTE)) + hme_fifo_read(esp, eregs); } - esp->ireg = eregs->esp_intrpt; - esp->sreg &= ~(ESP_STAT_INTR); if(!(esp->ireg & ESP_INTR_SR)) return 0; else @@ -2012,21 +2131,27 @@ } } -static inline void dma_invalidate(struct sparc_dma_registers *dregs, enum dvma_rev drev) +static inline void dma_invalidate(struct Sparc_ESP *esp, + struct sparc_dma_registers *dregs, + enum dvma_rev drev) { unsigned int tmp; if(drev == dvmahme) { - /* SMCC can bite me. */ - tmp = dregs->cond_reg; dregs->cond_reg = DMA_RST_SCSI; - /* This would explain a lot. */ - tmp |= (DMA_PARITY_OFF|DMA_2CLKS|DMA_SCSI_DISAB); + esp->prev_hme_dmacsr = ((esp->prev_hme_dmacsr | + (DMA_PARITY_OFF | DMA_2CLKS | + DMA_SCSI_DISAB | DMA_INT_ENAB)) & + ~(DMA_ST_WRITE | DMA_ENABLE)); - tmp &= ~(DMA_ENABLE|DMA_ST_WRITE); dregs->cond_reg = 0; - dregs->cond_reg = tmp; + dregs->cond_reg = esp->prev_hme_dmacsr; + + /* This is necessary to avoid having the SCSI channel + * engine lock up on us. + */ + dregs->st_addr = 0; } else { while(dregs->cond_reg & DMA_PEND_READ) udelay(1); @@ -2039,10 +2164,12 @@ } } -static inline void dma_flashclear(struct sparc_dma_registers *dregs, enum dvma_rev drev) +static inline void dma_flashclear(struct Sparc_ESP *esp, + struct sparc_dma_registers *dregs, + enum dvma_rev drev) { dma_drain(dregs, drev); - dma_invalidate(dregs, drev); + dma_invalidate(esp, dregs, drev); } static inline int dma_can_transfer(Scsi_Cmnd *sp, enum dvma_rev drev) @@ -2064,56 +2191,38 @@ return sz; } -/* Misc. esp helper routines. */ -static inline void esp_setcount(struct Sparc_ESP_regs *eregs, int cnt, int hme) -{ - eregs->esp_tclow = (cnt & 0xff); - eregs->esp_tcmed = ((cnt >> 8) & 0xff); - if(hme) { - eregs->fas_rlo = 0; - eregs->fas_rhi = 0; - } -} - -static inline int esp_getcount(struct Sparc_ESP_regs *eregs) -{ - return (((eregs->esp_tclow)&0xff) | - (((eregs->esp_tcmed)&0xff) << 8)); -} - -static inline int fcount(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs) -{ - if(esp->erev == fashme) - return esp->hme_fifo_workaround_count; - else - return eregs->esp_fflags & ESP_FF_FBYTES; -} - -static inline int fnzero(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs) -{ - if(esp->erev == fashme) - return 0; - else - return eregs->esp_fflags & ESP_FF_ONOTZERO; -} +/* Misc. esp helper macros. */ +#define esp_setcount(__eregs, __cnt, __hme) \ + (__eregs)->esp_tclow = ((__cnt) & 0xff); \ + (__eregs)->esp_tcmed = (((__cnt) >> 8) & 0xff); \ + if(__hme) { \ + (__eregs)->fas_rlo = 0; \ + (__eregs)->fas_rhi = 0; \ + } + +#define esp_getcount(__eregs) \ + ((((__eregs)->esp_tclow)&0xff) | \ + ((((__eregs)->esp_tcmed)&0xff) << 8)) + +#define fcount(__esp, __eregs) \ + (((__esp)->erev == fashme) ? \ + (__esp)->hme_fifo_workaround_count : \ + (__eregs)->esp_fflags & ESP_FF_FBYTES) + +#define fnzero(__esp, __eregs) \ + (((__esp)->erev == fashme) ? 0 : \ + (__eregs)->esp_fflags & ESP_FF_ONOTZERO) /* XXX speculative nops unnecessary when continuing amidst a data phase * XXX even on esp100!!! another case of flooding the bus with I/O reg * XXX writes... */ -static inline void esp_maybe_nop(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs) -{ - if(esp->erev == esp100) - esp_cmd(esp, eregs, ESP_CMD_NULL); -} +#define esp_maybe_nop(__esp, __eregs) \ + if((__esp)->erev == esp100) \ + esp_cmd((__esp), (__eregs), ESP_CMD_NULL) -static inline int sreg_to_dataphase(unchar sreg) -{ - if((sreg & ESP_STAT_PMASK) == ESP_DOP) - return in_dataout; - else - return in_datain; -} +#define sreg_to_dataphase(__sreg) \ + ((((__sreg) & ESP_STAT_PMASK) == ESP_DOP) ? in_dataout : in_datain) /* The ESP100 when in synchronous data phase, can mistake a long final * REQ pulse from the target as an extra byte, it places whatever is on @@ -2205,10 +2314,19 @@ lun = esp->hme_fifo_workaround_buffer[1]; else lun = eregs->esp_fdata; + + /* Yes, you read this correctly. We report lun of zero + * if we see parity error. ESP reports parity error for + * the lun byte, and this is the only way to hope to recover + * because the target is connected. + */ if(esp->sreg & ESP_STAT_PERR) return 0; + + /* Check for illegal bits being set in the lun. */ if((lun & 0x40) || !(lun & 0x80)) return -1; + return lun & 7; } @@ -2219,13 +2337,18 @@ Scsi_Cmnd *sp) { Scsi_Device *dp = sp->device; - eregs->esp_soff = dp->sync_max_offset; - eregs->esp_stp = dp->sync_min_period; - if(esp->erev > esp100a) - eregs->esp_cfg3 = esp->config3[sp->target]; - if(esp->erev == fashme) - eregs->esp_busid = (sp->target & 0xf) | - (ESP_BUSID_RESELID | ESP_BUSID_CTR32BIT); + + if(esp->prev_soff != dp->sync_max_offset || + esp->prev_stp != dp->sync_min_period || + (esp->erev > esp100a && + esp->prev_cfg3 != esp->config3[sp->target])) { + eregs->esp_soff = esp->prev_soff = dp->sync_max_offset; + eregs->esp_stp = esp->prev_stp = dp->sync_min_period; + if(esp->erev > esp100a) + eregs->esp_cfg3 = + esp->prev_cfg3 = + esp->config3[sp->target]; + } esp->current_SC = sp; } @@ -2235,8 +2358,8 @@ static inline void esp_reconnect(struct Sparc_ESP *esp, Scsi_Cmnd *sp) { if(!esp->disconnected_SC) - printk("esp%d: Weird, being reselected but disconnected " - "command queue is empty.\n", esp->esp_id); + ESPLOG(("esp%d: Weird, being reselected but disconnected " + "command queue is empty.\n", esp->esp_id)); esp->snip = 0; esp->current_SC = 0; sp->SCp.phase = not_issued; @@ -2244,8 +2367,8 @@ } /* Begin message in phase. */ -static inline int esp_do_msgin(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs, - struct sparc_dma_registers *dregs) +static int esp_do_msgin(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs, + struct sparc_dma_registers *dregs) { /* Must be very careful with the fifo on the HME */ if((esp->erev != fashme) || !(eregs->esp_status2 & ESP_STAT2_FEMPTY)) @@ -2298,8 +2421,8 @@ * within a buffer or sub-buffer should not upset us at all no matter * how bad the target and/or ESP fucks things up. */ -static inline int esp_do_data(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs, - struct sparc_dma_registers *dregs) +static int esp_do_data(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs, + struct sparc_dma_registers *dregs) { Scsi_Cmnd *SCptr = esp->current_SC; int thisphase, hmuch; @@ -2313,19 +2436,28 @@ ESPDATA(("hmuch<%d> ", hmuch)); esp->current_transfer_size = hmuch; if(esp->erev == fashme) { - unsigned long tmp = dregs->cond_reg; + unsigned long tmp = esp->prev_hme_dmacsr; - /* Touchy chip, this stupid HME scsi adapter... */ + /* Always set the ESP count registers first. */ esp_setcount(eregs, hmuch, 1); - esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_TI); - dregs->cnt = hmuch; + + /* Get the DMA csr computed. */ tmp |= (DMA_SCSI_DISAB | DMA_ENABLE); - if(thisphase == in_datain) + if (thisphase == in_datain) tmp |= DMA_ST_WRITE; else tmp &= ~(DMA_ST_WRITE); + esp->prev_hme_dmacsr = tmp; + + if (thisphase == in_datain) { + dregs->cnt = hmuch; + esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_TI); + } else { + esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_TI); + dregs->cnt = hmuch; + } dregs->st_addr = ((__u32)((unsigned long)SCptr->SCp.ptr)); - dregs->cond_reg = tmp; + dregs->cond_reg = esp->prev_hme_dmacsr; } else { esp_setcount(eregs, hmuch, 0); dma_setup(dregs, esp->dma->revision, @@ -2338,9 +2470,9 @@ } /* See how successful the data transfer was. */ -static inline int esp_do_data_finale(struct Sparc_ESP *esp, - struct Sparc_ESP_regs *eregs, - struct sparc_dma_registers *dregs) +static int esp_do_data_finale(struct Sparc_ESP *esp, + struct Sparc_ESP_regs *eregs, + struct sparc_dma_registers *dregs) { Scsi_Cmnd *SCptr = esp->current_SC; int bogus_data = 0, bytes_sent = 0, fifocnt, ecount = 0; @@ -2361,7 +2493,7 @@ } dma_drain(dregs, esp->dma->revision); } - dma_invalidate(dregs, esp->dma->revision); + dma_invalidate(esp, dregs, esp->dma->revision); /* This could happen for the above parity error case. */ if(!(esp->ireg == ESP_INTR_BSERV)) { @@ -2387,26 +2519,43 @@ ecount = esp_getcount(eregs); bytes_sent = esp->current_transfer_size; - /* Uhhh, might not want both of these conditionals to run - * at once on HME due to the fifo problems it has. Consider - * changing it to: - * - * if(!(esp->sreg & ESP_STAT_TCNT)) { - * bytes_sent -= ecount; - * } else if(SCptr->SCp.phase == in_dataout) { - * bytes_sent -= fifocnt; - * } - * - * But only for the HME case, leave the current code alone - * for all other ESP revisions as we know the existing code - * works just fine for them. - */ ESPDATA(("trans_sz=%d, ", bytes_sent)); if(esp->erev == fashme) { if(!(esp->sreg & ESP_STAT_TCNT)) { - bytes_sent -= esp_getcount(eregs); - } else if(SCptr->SCp.phase == in_dataout) { + ecount = esp_getcount(eregs); + bytes_sent -= ecount; + } + + /* Always subtract any cruft remaining in the FIFO. */ + if(esp->prev_cfg3 & ESP_CONFIG3_EWIDE) + fifocnt <<= 1; + if(SCptr->SCp.phase == in_dataout) bytes_sent -= fifocnt; + + /* I have an IBM disk which exhibits the following + * behavior during writes to it. It disconnects in + * the middle of a partial transfer, the current sglist + * buffer is 1024 bytes, the disk stops data transfer + * at 512 bytes. + * + * However the FAS366 reports that 32 more bytes were + * transferred than really were. This is precisely + * the size of a fully loaded FIFO in wide scsi mode. + * The FIFO state recorded indicates that it is empty. + * + * I have no idea if this is a bug in the FAS366 chip + * or a bug in the firmware on this IBM disk. In any + * event the following seems to be a good workaround. -DaveM + */ + if (bytes_sent != esp->current_transfer_size && + SCptr->SCp.phase == in_dataout) { + int mask = (64 - 1); + + if((esp->prev_cfg3 & ESP_CONFIG3_EWIDE) == 0) + mask >>= 1; + + if (bytes_sent & mask) + bytes_sent -= (bytes_sent & mask); } } else { if(!(esp->sreg & ESP_STAT_TCNT)) @@ -2442,6 +2591,8 @@ * driver. No idea why it happened, but allowing * this value to be negative caused things to * lock up. This allows greater chance of recovery. + * In fact every time I've seen this, it has been + * a driver bug without question. */ ESPLOG(("esp%d: yieee, bytes_sent < 0!\n", esp->esp_id)); ESPLOG(("esp%d: csz=%d fifocount=%d ecount=%d\n", @@ -2462,7 +2613,7 @@ SCptr->SCp.this_residual -= bytes_sent; if(SCptr->SCp.this_residual < 0) { /* shit */ - printk("esp%d: Data transfer overrun.\n", esp->esp_id); + ESPLOG(("esp%d: Data transfer overrun.\n", esp->esp_id)); SCptr->SCp.this_residual = 0; } @@ -2493,11 +2644,49 @@ return do_intr_end; } +/* We received a non-good status return at the end of + * running a SCSI command. This is used to decide if + * we should clear our synchronous transfer state for + * such a device when that happens. + * + * The idea is that when spinning up a disk or rewinding + * a tape, we don't want to go into a loop re-negotiating + * synchronous capabilities over and over. + */ +static int esp_should_clear_sync(Scsi_Cmnd *sp) +{ + unchar cmd1 = sp->cmnd[0]; + unchar cmd2 = sp->data_cmnd[0]; + + /* These cases are for spinning up a disk and + * waiting for that spinup to complete. + */ + if(cmd1 == START_STOP || + cmd2 == START_STOP) + return 0; + + if(cmd1 == TEST_UNIT_READY || + cmd2 == TEST_UNIT_READY) + return 0; + + /* One more special case for SCSI tape drives, + * this is what is used to probe the device for + * completion of a rewind or tape load operation. + */ + if(sp->device->type == TYPE_TAPE) { + if(cmd1 == MODE_SENSE || + cmd2 == MODE_SENSE) + return 0; + } + + return 1; +} + /* Either a command is completing or a target is dropping off the bus * to continue the command in the background so we can do other work. */ -static inline int esp_do_freebus(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs, - struct sparc_dma_registers *dregs) +static int esp_do_freebus(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs, + struct sparc_dma_registers *dregs) { Scsi_Cmnd *SCptr = esp->current_SC; int rval; @@ -2516,9 +2705,11 @@ if(esp->disconnected_SC || (esp->erev == fashme)) esp_cmd(esp, eregs, ESP_CMD_ESEL); - if(SCptr->SCp.Status != GOOD && SCptr->SCp.Status != CONDITION_GOOD && + if(SCptr->SCp.Status != GOOD && + SCptr->SCp.Status != CONDITION_GOOD && ((1<target) & esp->targets_present) && - SCptr->device->sync && SCptr->device->sync_max_offset) { + SCptr->device->sync && + SCptr->device->sync_max_offset) { /* SCSI standard says that the synchronous capabilities * should be renegotiated at this point. Most likely * we are about to request sense from this target @@ -2535,15 +2726,7 @@ * can report not ready many times right after * loading up a tape. */ - if(SCptr->cmnd[0] != START_STOP && - SCptr->data_cmnd[0] != START_STOP && - SCptr->cmnd[0] != TEST_UNIT_READY && - SCptr->data_cmnd[0] != TEST_UNIT_READY && - !(SCptr->device->type == TYPE_TAPE && - (SCptr->cmnd[0] == TEST_UNIT_READY || - SCptr->data_cmnd[0] == TEST_UNIT_READY || - SCptr->cmnd[0] == MODE_SENSE || - SCptr->data_cmnd[0] == MODE_SENSE))) + if(esp_should_clear_sync(SCptr) != 0) SCptr->device->sync = 0; } ESPDISC(("F<%02x,%02x>", SCptr->target, SCptr->lun)); @@ -2570,9 +2753,43 @@ return do_intr_end; } +/* When a reselect occurs, and we cannot find the command to + * reconnect to in our queues, we do this. + */ +static int esp_bad_reconnect(struct Sparc_ESP *esp) +{ + Scsi_Cmnd *sp; + + ESPLOG(("esp%d: Eieeee, reconnecting unknown command!\n", + esp->esp_id)); + ESPLOG(("QUEUE DUMP\n")); + sp = esp->issue_SC; + ESPLOG(("esp%d: issue_SC[", esp->esp_id)); + while(sp) { + ESPLOG(("<%02x,%02x>", sp->target, sp->lun)); + sp = (Scsi_Cmnd *) sp->host_scribble; + } + ESPLOG(("]\n")); + sp = esp->current_SC; + ESPLOG(("esp%d: current_SC[", esp->esp_id)); + while(sp) { + ESPLOG(("<%02x,%02x>", sp->target, sp->lun)); + sp = (Scsi_Cmnd *) sp->host_scribble; + } + ESPLOG(("]\n")); + sp = esp->disconnected_SC; + ESPLOG(("esp%d: disconnected_SC[", esp->esp_id)); + while(sp) { + ESPLOG(("<%02x,%02x>", sp->target, sp->lun)); + sp = (Scsi_Cmnd *) sp->host_scribble; + } + ESPLOG(("]\n")); + return do_reset_bus; +} + /* Do the needy when a target tries to reconnect to us. */ -static inline int esp_do_reconnect(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs, - struct sparc_dma_registers *dregs) +static int esp_do_reconnect(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs, + struct sparc_dma_registers *dregs) { int lun, target; Scsi_Cmnd *SCptr; @@ -2592,12 +2809,8 @@ /* Things look ok... */ ESPDISC(("R<%02x,%02x>", target, lun)); - /* Must flush both FIFO and the DVMA on HME. */ - if(esp->erev == fashme) { - /* XXX this still doesn't fix the problem... */ - esp_cmd(esp, eregs, ESP_CMD_FLUSH); - dma_invalidate(esp->dregs, dvmahme); - } else { + /* Must not flush FIFO or DVMA on HME. */ + if(esp->erev != fashme) { esp_cmd(esp, eregs, ESP_CMD_FLUSH); if(esp100_reconnect_hwbug(esp, eregs)) return do_reset_bus; @@ -2605,39 +2818,19 @@ } SCptr = remove_SC(&esp->disconnected_SC, (unchar) target, (unchar) lun); - if(!SCptr) { - Scsi_Cmnd *sp; + if(!SCptr) + return esp_bad_reconnect(esp); - ESPLOG(("esp%d: Eieeee, reconnecting unknown command!\n", - esp->esp_id)); - ESPLOG(("QUEUE DUMP\n")); - sp = esp->issue_SC; - ESPLOG(("esp%d: issue_SC[", esp->esp_id)); - while(sp) { - ESPLOG(("<%02x,%02x>", sp->target, sp->lun)); - sp = (Scsi_Cmnd *) sp->host_scribble; - } - ESPLOG(("]\n")); - sp = esp->current_SC; - ESPLOG(("esp%d: current_SC[", esp->esp_id)); - while(sp) { - ESPLOG(("<%02x,%02x>", sp->target, sp->lun)); - sp = (Scsi_Cmnd *) sp->host_scribble; - } - ESPLOG(("]\n")); - sp = esp->disconnected_SC; - ESPLOG(("esp%d: disconnected_SC[", esp->esp_id)); - while(sp) { - ESPLOG(("<%02x,%02x>", sp->target, sp->lun)); - sp = (Scsi_Cmnd *) sp->host_scribble; - } - ESPLOG(("]\n")); - return do_reset_bus; - } esp_connect(esp, eregs, SCptr); esp_cmd(esp, eregs, ESP_CMD_MOK); - /* No need for explicit restore pointers operation. */ + if(esp->erev == fashme) + eregs->esp_busid = (SCptr->target & 0xf) | + (ESP_BUSID_RESELID | ESP_BUSID_CTR32BIT); + + /* Reconnect implies a restore pointers operation. */ + esp_restore_pointers(esp, SCptr); + esp->snip = 0; esp_advance_phase(SCptr, in_the_dark); return do_intr_end; @@ -2665,7 +2858,7 @@ esp_cmd(esp, eregs, ESP_CMD_MOK); if(esp->erev != fashme) { - dma_flashclear(dregs, esp->dma->revision); + dma_flashclear(esp, dregs, esp->dma->revision); /* Wait till the first bits settle. */ while(esp->esp_command[0] == 0xff) @@ -2767,112 +2960,135 @@ } } -/* The target has control of the bus and we have to see where it has - * taken us. - */ -static int esp_do_phase_determine(struct Sparc_ESP *esp, - struct Sparc_ESP_regs *eregs, - struct sparc_dma_registers *dregs) +static int esp_enter_status(struct Sparc_ESP *esp, + struct Sparc_ESP_regs *eregs, + struct sparc_dma_registers *dregs) { - Scsi_Cmnd *SCptr = esp->current_SC; + unchar thecmd = ESP_CMD_ICCSEQ; - ESPPHASE(("esp_do_phase_determine: ")); - if(!(esp->ireg & ESP_INTR_DC)) { - switch(esp->sreg & ESP_STAT_PMASK) { - case ESP_DOP: - case ESP_DIP: - ESPPHASE(("to data phase\n")); - return esp_do_data(esp, eregs, dregs); + esp_cmd(esp, eregs, ESP_CMD_FLUSH); + if(esp->erev != fashme) { + esp->esp_command[0] = esp->esp_command[1] = 0xff; + eregs->esp_tclow = 2; + eregs->esp_tcmed = 0; + dregs->cond_reg |= (DMA_ST_WRITE | DMA_ENABLE); + if(esp->dma->revision == dvmaesc1) + dregs->cnt = 0x100; + dregs->st_addr = esp->esp_command_dvma; + thecmd |= ESP_CMD_DMA; + } + esp_cmd(esp, eregs, thecmd); + esp_advance_phase(esp->current_SC, in_status); - case ESP_STATP: - /* Whee, status phase, finish up the command. */ - ESPPHASE(("to status phase\n")); - esp_cmd(esp, eregs, ESP_CMD_FLUSH); - if(esp->erev != fashme) { - esp->esp_command[0] = 0xff; - esp->esp_command[1] = 0xff; - eregs->esp_tclow = 2; - eregs->esp_tcmed = 0; - dregs->cond_reg |= (DMA_ST_WRITE | DMA_ENABLE); - if(esp->dma->revision == dvmaesc1) - dregs->cnt = 0x1000; - dregs->st_addr = esp->esp_command_dvma; - esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_ICCSEQ); - } else { - /* Using DVMA for status/message bytes is - * unreliable on HME, nice job QLogic. - * Happy Meal indeed.... - */ - esp_cmd(esp, eregs, ESP_CMD_ICCSEQ); - } - esp_advance_phase(SCptr, in_status); - return esp_do_status(esp, eregs, dregs); + return esp_do_status(esp, eregs, dregs); +} - case ESP_MOP: - ESPPHASE(("to msgout phase\n")); - esp_advance_phase(SCptr, in_msgout); - return esp_do_msgout(esp, eregs, dregs); - - case ESP_MIP: - ESPPHASE(("to msgin phase\n")); - esp_advance_phase(SCptr, in_msgin); - return esp_do_msgin(esp, eregs, dregs); - - case ESP_CMDP: - /* Ugh, we're running a non-standard command the - * ESP doesn't understand, one byte at a time. - */ - ESPPHASE(("to cmd phase\n")); - esp_advance_phase(SCptr, in_cmdbegin); - return esp_do_cmdbegin(esp, eregs, dregs); - }; - } else { - Scsi_Device *dp = SCptr->device; +static int esp_disconnect_amidst_phases(struct Sparc_ESP *esp, + struct Sparc_ESP_regs *eregs, + struct sparc_dma_registers *dregs) +{ + Scsi_Cmnd *sp = esp->current_SC; + Scsi_Device *dp = sp->device; - /* This means real problems if we see this - * here. Unless we were actually trying - * to force the device to abort/reset. - */ - ESPLOG(("esp%d Disconnect amidst phases, ", esp->esp_id)); - ESPLOG(("pphase<%s> cphase<%s>, ", - phase_string(SCptr->SCp.phase), - phase_string(SCptr->SCp.sent_command))); - if(esp->disconnected_SC || (esp->erev == fashme)) - esp_cmd(esp, eregs, ESP_CMD_ESEL); + /* This means real problems if we see this + * here. Unless we were actually trying + * to force the device to abort/reset. + */ + ESPLOG(("esp%d Disconnect amidst phases, ", esp->esp_id)); + ESPLOG(("pphase<%s> cphase<%s>, ", + phase_string(sp->SCp.phase), + phase_string(sp->SCp.sent_command))); - switch(esp->cur_msgout[0]) { - default: - /* We didn't expect this to happen at all. */ - ESPLOG(("device is bolixed\n")); - esp_advance_phase(SCptr, in_tgterror); - esp_done(esp, (DID_ERROR << 16)); - break; + if(esp->disconnected_SC || (esp->erev == fashme)) + esp_cmd(esp, eregs, ESP_CMD_ESEL); - case BUS_DEVICE_RESET: - ESPLOG(("device reset successful\n")); - dp->sync_max_offset = 0; - dp->sync_min_period = 0; - dp->sync = 0; - esp_advance_phase(SCptr, in_resetdev); - esp_done(esp, (DID_RESET << 16)); - break; + switch(esp->cur_msgout[0]) { + default: + /* We didn't expect this to happen at all. */ + ESPLOG(("device is bolixed\n")); + esp_advance_phase(sp, in_tgterror); + esp_done(esp, (DID_ERROR << 16)); + break; - case ABORT: - ESPLOG(("device abort successful\n")); - esp_advance_phase(SCptr, in_abortone); - esp_done(esp, (DID_ABORT << 16)); - break; + case BUS_DEVICE_RESET: + ESPLOG(("device reset successful\n")); + dp->sync_max_offset = 0; + dp->sync_min_period = 0; + dp->sync = 0; + esp_advance_phase(sp, in_resetdev); + esp_done(esp, (DID_RESET << 16)); + break; - }; - return do_intr_end; - } + case ABORT: + ESPLOG(("device abort successful\n")); + esp_advance_phase(sp, in_abortone); + esp_done(esp, (DID_ABORT << 16)); + break; + + }; + return do_intr_end; +} + +static int esp_enter_msgout(struct Sparc_ESP *esp, + struct Sparc_ESP_regs *eregs, + struct sparc_dma_registers *dregs) +{ + esp_advance_phase(esp->current_SC, in_msgout); + return esp_do_msgout(esp, eregs, dregs); +} + +static int esp_enter_msgin(struct Sparc_ESP *esp, + struct Sparc_ESP_regs *eregs, + struct sparc_dma_registers *dregs) +{ + esp_advance_phase(esp->current_SC, in_msgin); + return esp_do_msgin(esp, eregs, dregs); +} - ESPLOG(("esp%d: to unknown phase\n", esp->esp_id)); - printk("esp%d: Bizarre bus phase %2x.\n", esp->esp_id, - esp->sreg & ESP_STAT_PMASK); +static int esp_enter_cmd(struct Sparc_ESP *esp, + struct Sparc_ESP_regs *eregs, + struct sparc_dma_registers *dregs) +{ + esp_advance_phase(esp->current_SC, in_cmdbegin); + return esp_do_cmdbegin(esp, eregs, dregs); +} + +static int esp_enter_badphase(struct Sparc_ESP *esp, + struct Sparc_ESP_regs *eregs, + struct sparc_dma_registers *dregs) +{ + ESPLOG(("esp%d: Bizarre bus phase %2x.\n", esp->esp_id, + esp->sreg & ESP_STAT_PMASK)); return do_reset_bus; } +typedef int (*espfunc_t)(struct Sparc_ESP *, + struct Sparc_ESP_regs *, + struct sparc_dma_registers *); + +static espfunc_t phase_vector[] = { + esp_do_data, /* ESP_DOP */ + esp_do_data, /* ESP_DIP */ + esp_enter_cmd, /* ESP_CMDP */ + esp_enter_status, /* ESP_STATP */ + esp_enter_badphase, /* ESP_STAT_PMSG */ + esp_enter_badphase, /* ESP_STAT_PMSG | ESP_STAT_PIO */ + esp_enter_msgout, /* ESP_MOP */ + esp_enter_msgin, /* ESP_MIP */ +}; + +/* The target has control of the bus and we have to see where it has + * taken us. + */ +static int esp_do_phase_determine(struct Sparc_ESP *esp, + struct Sparc_ESP_regs *eregs, + struct sparc_dma_registers *dregs) +{ + if ((esp->ireg & ESP_INTR_DC) != 0) + return esp_disconnect_amidst_phases(esp, eregs, dregs); + return phase_vector[esp->sreg & ESP_STAT_PMASK](esp, eregs, dregs); +} + /* First interrupt after exec'ing a cmd comes here. */ static int esp_select_complete(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs, struct sparc_dma_registers *dregs) @@ -2888,7 +3104,7 @@ else fcnt = (eregs->esp_fflags & ESP_FF_FBYTES); cmd_bytes_sent = esp_bytes_sent(esp, dregs, fcnt); - dma_invalidate(dregs, esp->dma->revision); + dma_invalidate(esp, dregs, esp->dma->revision); /* Let's check to see if a reselect happened * while we we're trying to select. This must @@ -3061,9 +3277,8 @@ SCptr->SCp.phase == in_slct_stop)) { /* shit */ esp->snip = 0; - printk("esp%d: Failed synchronous negotiation for target %d " - "lun %d\n", - esp->esp_id, SCptr->target, SCptr->lun); + ESPLOG(("esp%d: Failed synchronous negotiation for target %d " + "lun %d\n", esp->esp_id, SCptr->target, SCptr->lun)); SDptr->sync_max_offset = 0; SDptr->sync_min_period = 0; SDptr->sync = 1; /* so we don't negotiate again */ @@ -3090,8 +3305,8 @@ * But first make sure that is really what is happening. */ if(((1<target) & esp->targets_present)) { - printk("esp%d: Warning, live target %d not responding to " - "selection.\n", esp->esp_id, SCptr->target); + ESPLOG(("esp%d: Warning, live target %d not responding to " + "selection.\n", esp->esp_id, SCptr->target)); /* This _CAN_ happen. The SCSI standard states that * the target is to _not_ respond to selection if @@ -3154,15 +3369,15 @@ * have miscoded something..... so, try to * recover as best we can. */ - printk("esp%d: message in mis-carriage.\n", esp->esp_id); + ESPLOG(("esp%d: message in mis-carriage.\n", esp->esp_id)); } esp_advance_phase(esp->current_SC, in_the_dark); return do_phase_determine; } -static inline int check_singlebyte_msg(struct Sparc_ESP *esp, - struct Sparc_ESP_regs *eregs, - struct sparc_dma_registers *dregs) +static int check_singlebyte_msg(struct Sparc_ESP *esp, + struct Sparc_ESP_regs *eregs, + struct sparc_dma_registers *dregs) { esp->prevmsgin = esp->cur_msgin[0]; if(esp->cur_msgin[0] & 0x80) { @@ -3191,8 +3406,20 @@ return 0; case RESTORE_POINTERS: + /* In this case we might also have to backup the + * "slow command" pointer. It is rare to get such + * a save/restore pointer sequence so early in the + * bus transition sequences, but cover it. + */ + if(esp->esp_slowcmd) { + esp->esp_scmdleft = esp->current_SC->cmd_len; + esp->esp_scmdp = &esp->current_SC->cmnd[0]; + } + esp_restore_pointers(esp, esp->current_SC); + return 0; + case SAVE_POINTERS: - /* We handle this all automatically. */ + esp_save_pointers(esp, esp->current_SC); return 0; case COMMAND_COMPLETE: @@ -3227,9 +3454,9 @@ * the SCSI2 standard specifically recommends against targets doing * this because so many initiators cannot cope with this occuring. */ -static inline int target_with_ants_in_pants(struct Sparc_ESP *esp, - Scsi_Cmnd *SCptr, - Scsi_Device *SDptr) +static int target_with_ants_in_pants(struct Sparc_ESP *esp, + Scsi_Cmnd *SCptr, + Scsi_Device *SDptr) { if(SDptr->sync || SDptr->borken) { /* sorry, no can do */ @@ -3246,7 +3473,7 @@ return 0; } -static inline void sync_report(struct Sparc_ESP *esp) +static void sync_report(struct Sparc_ESP *esp) { int msg3, msg4; char *type; @@ -3267,21 +3494,27 @@ } else { type = "synchronous"; } - printk(KERN_INFO "esp%d: target %d [period %dns offset %d %d.%02dMHz %s SCSI%s]\n", - esp->esp_id, esp->current_SC->target, - (int) msg3 * 4, - (int) msg4, - integer, fraction, type, - (((msg3 * 4) < 200) ? "-II" : "")); + + /* Do not transform this back into one big printk + * again, it triggers a bug in our sparc64-gcc272 + * sibling call optimization. -DaveM + */ + ESPLOG((KERN_INFO "esp%d: target %d ", + esp->esp_id, esp->current_SC->target)); + ESPLOG(("[period %dns offset %d %d.%02dMHz ", + (int) msg3 * 4, (int) msg4, + integer, fraction)); + ESPLOG(("%s SCSI%s]\n", type, + (((msg3 * 4) < 200) ? "-II" : ""))); } else { - printk(KERN_INFO "esp%d: target %d asynchronous\n", - esp->esp_id, esp->current_SC->target); + ESPLOG((KERN_INFO "esp%d: target %d asynchronous\n", + esp->esp_id, esp->current_SC->target)); } } -static inline int check_multibyte_msg(struct Sparc_ESP *esp, - struct Sparc_ESP_regs *eregs, - struct sparc_dma_registers *dregs) +static int check_multibyte_msg(struct Sparc_ESP *esp, + struct Sparc_ESP_regs *eregs, + struct sparc_dma_registers *dregs) { Scsi_Cmnd *SCptr = esp->current_SC; Scsi_Device *SDptr = SCptr->device; @@ -3358,10 +3591,10 @@ esp->config3[SCptr->target] |= bit; else esp->config3[SCptr->target] &= ~bit; - eregs->esp_cfg3 = esp->config3[SCptr->target]; + eregs->esp_cfg3 = esp->prev_cfg3 = esp->config3[SCptr->target]; } - eregs->esp_soff = SDptr->sync_min_period; - eregs->esp_stp = SDptr->sync_max_offset; + eregs->esp_soff = esp->prev_soff = SDptr->sync_min_period; + eregs->esp_stp = esp->prev_stp = SDptr->sync_max_offset; ESPSDTR(("soff=%2x stp=%2x cfg3=%2x\n", SDptr->sync_max_offset, @@ -3376,15 +3609,15 @@ ESPSDTR(("unaccaptable sync nego, forcing async\n")); SDptr->sync_max_offset = 0; SDptr->sync_min_period = 0; - eregs->esp_soff = 0; - eregs->esp_stp = 0; + eregs->esp_soff = esp->prev_soff = 0; + eregs->esp_stp = esp->prev_stp = 0; if((esp->erev == fas100a || esp->erev == fas236 || esp->erev == fashme)) { if((esp->erev == fas100a) || (esp->erev == fashme)) bit = ESP_CONFIG3_FAST; else bit = ESP_CONFIG3_FSCSI; esp->config3[SCptr->target] &= ~bit; - eregs->esp_cfg3 = esp->config3[SCptr->target]; + eregs->esp_cfg3 = esp->prev_cfg3 = esp->config3[SCptr->target]; } } @@ -3409,32 +3642,30 @@ esp->wnip = 0; if(esp->erev != fashme) { - printk("esp%d: AIEEE wide msg received and not HME.\n", - esp->esp_id); + ESPLOG(("esp%d: AIEEE wide msg received and not HME.\n", + esp->esp_id)); message_out = MESSAGE_REJECT; } else if(size > 16) { - printk("esp%d: AIEEE wide transfer for %d size not supported.\n", - esp->esp_id, size); + ESPLOG(("esp%d: AIEEE wide transfer for %d size " + "not supported.\n", esp->esp_id, size)); message_out = MESSAGE_REJECT; } else { /* Things look good; let's see what we got. */ if(size == 16) { /* Set config 3 register for this target. */ - printk("esp%d: 16 byte WIDE transfers enabled for target %d.\n", - esp->esp_id, SCptr->target); esp->config3[SCptr->target] |= ESP_CONFIG3_EWIDE; } else { /* Just make sure it was one byte sized. */ if(size != 8) { - printk("esp%d: Aieee, wide nego of %d size.\n", - esp->esp_id, size); + ESPLOG(("esp%d: Aieee, wide nego of %d size.\n", + esp->esp_id, size)); message_out = MESSAGE_REJECT; goto finish; } /* Pure paranoia. */ esp->config3[SCptr->target] &= ~(ESP_CONFIG3_EWIDE); } - eregs->esp_cfg3 = esp->config3[SCptr->target]; + eregs->esp_cfg3 = esp->prev_cfg3 = esp->config3[SCptr->target]; /* Regardless, next try for sync transfers. */ build_sync_nego_msg(esp, esp->sync_defp, 15); @@ -3566,11 +3797,11 @@ return do_intr_end; } -static inline int esp_do_cmddone(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs, - struct sparc_dma_registers *dregs) +static int esp_do_cmddone(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs, + struct sparc_dma_registers *dregs) { if(esp->erev == fashme) - dma_invalidate(dregs, dvmahme); + dma_invalidate(esp, dregs, dvmahme); else esp_cmd(esp, eregs, ESP_CMD_NULL); if(esp->ireg & ESP_INTR_BSERV) { @@ -3583,7 +3814,7 @@ } static int esp_do_msgout(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs, - struct sparc_dma_registers *dregs) + struct sparc_dma_registers *dregs) { esp_cmd(esp, eregs, ESP_CMD_FLUSH); switch(esp->msgout_len) { @@ -3661,8 +3892,8 @@ return do_intr_end; } -static inline int esp_do_msgoutdone(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs, - struct sparc_dma_registers *dregs) +static int esp_do_msgoutdone(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs, + struct sparc_dma_registers *dregs) { if(esp->msgout_len > 1) { /* XXX HME/FAS ATN deassert workaround required, @@ -3673,7 +3904,7 @@ while(dregs->cond_reg & DMA_PEND_READ) udelay(1); dregs->cond_reg &= ~(DMA_ENABLE); - dma_invalidate(dregs, esp->dma->revision); + dma_invalidate(esp, dregs, esp->dma->revision); } else { esp_cmd(esp, eregs, ESP_CMD_FLUSH); } @@ -3722,81 +3953,65 @@ return esp_do_phase_determine(esp, eregs, dregs); } +static int esp_bus_unexpected(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs, + struct sparc_dma_registers *dregs) +{ + ESPLOG(("esp%d: command in weird state %2x\n", + esp->esp_id, esp->current_SC->SCp.phase)); + return do_reset_bus; +} + +static espfunc_t bus_vector[] = { + esp_do_data_finale, + esp_do_data_finale, + esp_bus_unexpected, + esp_do_msgin, + esp_do_msgincont, + esp_do_msgindone, + esp_do_msgout, + esp_do_msgoutdone, + esp_do_cmdbegin, + esp_do_cmddone, + esp_do_status, + esp_do_freebus, + esp_do_phase_determine, + esp_bus_unexpected, + esp_bus_unexpected, + esp_bus_unexpected, +}; + /* This is the second tier in our dual-level SCSI state machine. */ -static inline int esp_work_bus(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs, - struct sparc_dma_registers *dregs) +static int esp_work_bus(struct Sparc_ESP *esp, + struct Sparc_ESP_regs *eregs, + struct sparc_dma_registers *dregs) { Scsi_Cmnd *SCptr = esp->current_SC; + unsigned int phase; ESPBUS(("esp_work_bus: ")); if(!SCptr) { ESPBUS(("reconnect\n")); return esp_do_reconnect(esp, eregs, dregs); } - - switch(SCptr->SCp.phase) { - case in_the_dark: - ESPBUS(("in the dark\n")); - return esp_do_phase_determine(esp, eregs, dregs); - - case in_slct_norm: - case in_slct_stop: - case in_slct_msg: - case in_slct_tag: - case in_slct_sneg: - ESPBUS(("finish selection\n")); + phase = SCptr->SCp.phase; + if ((phase & 0xf0) == in_phases_mask) + return bus_vector[(phase & 0x0f)](esp, eregs, dregs); + else if((phase & 0xf0) == in_slct_mask) return esp_select_complete(esp, eregs, dregs); - - case in_datain: - case in_dataout: - ESPBUS(("finish data\n")); - return esp_do_data_finale(esp, eregs, dregs); - - case in_msgout: - ESPBUS(("message out ")); - return esp_do_msgout(esp, eregs, dregs); - - case in_msgoutdone: - ESPBUS(("finish message out ")); - return esp_do_msgoutdone(esp, eregs, dregs); - - case in_msgin: - ESPBUS(("message in ")); - return esp_do_msgin(esp, eregs, dregs); - - case in_msgincont: - ESPBUS(("continue message in ")); - return esp_do_msgincont(esp, eregs, dregs); - - case in_msgindone: - ESPBUS(("finish message in ")); - return esp_do_msgindone(esp, eregs, dregs); - - case in_status: - ESPBUS(("status phase ")); - return esp_do_status(esp, eregs, dregs); - - case in_freeing: - ESPBUS(("freeing the bus ")); - return esp_do_freebus(esp, eregs, dregs); - - case in_cmdbegin: - ESPBUS(("begin slow cmd ")); - return esp_do_cmdbegin(esp, eregs, dregs); - - case in_cmdend: - ESPBUS(("end slow cmd ")); - return esp_do_cmddone(esp, eregs, dregs); - - default: - printk("esp%d: command in weird state %2x\n", - esp->esp_id, esp->current_SC->SCp.phase); - return do_reset_bus; - }; + else + return esp_bus_unexpected(esp, eregs, dregs); } +static espfunc_t isvc_vector[] = { + 0, + esp_do_phase_determine, + esp_do_resetbus, + esp_finish_reset, + esp_work_bus +}; + /* Main interrupt handler for an esp adapter. */ -static inline void esp_handle(struct Sparc_ESP *esp) +static void esp_handle(struct Sparc_ESP *esp) { struct sparc_dma_registers *dregs; struct Sparc_ESP_regs *eregs; @@ -3841,7 +4056,7 @@ ESPLOG(("esp%d: No current cmd during gross error, " "resetting bus\n", esp->esp_id)); what_next = do_reset_bus; - goto again; + goto state_machine; } } @@ -3862,9 +4077,11 @@ esp_reset_dma(esp); what_next = do_reset_bus; - goto again; + goto state_machine; } + esp->ireg = eregs->esp_intrpt; /* Unlatch intr and stat regs */ + if(esp->erev == fashme) { /* This chip is really losing. */ ESPHME(("HME[")); @@ -3877,17 +4094,12 @@ if(!(esp->sreg2 & ESP_STAT2_FEMPTY) || (esp->sreg2 & ESP_STAT2_F1BYTE)) { ESPHME(("fifo_workaround]")); - hme_fifo_hwbug_workaround(esp, eregs); + hme_fifo_read(esp, eregs); } else { ESPHME(("no_fifo_workaround]")); } } - esp->ireg = eregs->esp_intrpt; /* Unlatch intr and stat regs */ - - /* This cannot be done until this very moment. -DaveM */ - synchronize_irq(); - /* No current cmd is only valid at this point when there are * commands off the bus or we are trying a reset. */ @@ -3926,10 +4138,7 @@ } what_next = do_reset_bus; - goto again; - } - - if(!(esp->ireg & ~(ESP_INTR_FDONE | ESP_INTR_BSERV | ESP_INTR_DC))) { + } else if(!(esp->ireg & ~(ESP_INTR_FDONE | ESP_INTR_BSERV | ESP_INTR_DC))) { int phase; if(SCptr) { @@ -3941,13 +4150,12 @@ } else { ESPLOG(("esp%d: interrupt for no good reason...\n", esp->esp_id)); - goto esp_handle_done; + what_next = do_intr_end; } } else { ESPLOG(("esp%d: BSERV or FDONE or DC while SCptr==NULL\n", esp->esp_id)); what_next = do_reset_bus; - goto again; } } else if(esp->ireg & ESP_INTR_SR) { ESPLOG(("esp%d: SCSI bus reset interrupt\n", esp->esp_id)); @@ -3956,7 +4164,6 @@ ESPLOG(("esp%d: AIEEE we have been selected by another initiator!\n", esp->esp_id)); what_next = do_reset_bus; - goto again; } else if(esp->ireg & ESP_INTR_RSEL) { if(!SCptr) { /* This is ok. */ @@ -3971,95 +4178,22 @@ ESPLOG(("esp%d: Reselected while bus is busy\n", esp->esp_id)); what_next = do_reset_bus; - goto again; } } - /* We're trying to fight stack problems, and inline as much as - * possible without making this driver a mess. hate hate hate - * This is tier-one in our dual level SCSI state machine. - */ -again: - switch(what_next) { - case do_intr_end: - goto esp_handle_done; - - case do_work_bus: - what_next = esp_work_bus(esp, eregs, dregs); - break; - - case do_phase_determine: - what_next = esp_do_phase_determine(esp, eregs, dregs); - break; - - case do_reset_bus: - ESPLOG(("esp%d: resetting bus...\n", esp->esp_id)); - esp->resetting_bus = 1; - esp_cmd(esp, eregs, ESP_CMD_RS); - goto esp_handle_done; - - case do_reset_complete: - /* Tricky, we don't want to cause any more commands to - * go out until we clear all the live cmds by hand. - */ - if(esp->current_SC) { - Scsi_Cmnd *SCptr = esp->current_SC; - if(!SCptr->use_sg) - mmu_release_scsi_one(SCptr->SCp.have_data_in, - SCptr->request_bufflen, - esp->edev->my_bus); - else - mmu_release_scsi_sgl((struct mmu_sglist *) - SCptr->buffer, - SCptr->use_sg - 1, - esp->edev->my_bus); - SCptr->result = (DID_RESET << 16); - - SCptr->scsi_done(SCptr); - } - esp->current_SC = NULL; - if(esp->disconnected_SC) { - Scsi_Cmnd *SCptr; - while((SCptr = remove_first_SC(&esp->disconnected_SC))) { - if(!SCptr->use_sg) - mmu_release_scsi_one(SCptr->SCp.have_data_in, - SCptr->request_bufflen, - esp->edev->my_bus); - else - mmu_release_scsi_sgl((struct mmu_sglist *) - SCptr->buffer, - SCptr->use_sg - 1, - esp->edev->my_bus); - SCptr->result = (DID_RESET << 16); - - SCptr->scsi_done(SCptr); - } - } - esp->resetting_bus = 0; - - if(esp->current_SC) { - printk("esp%d: weird weird weird, current_SC not NULL after " - "SCSI bus reset.\n", esp->esp_id); - goto esp_handle_done; + /* This is tier-one in our dual level SCSI state machine. */ +state_machine: + while(what_next != do_intr_end) { + if (what_next >= do_phase_determine && + what_next < do_intr_end) + what_next = isvc_vector[what_next](esp, eregs, dregs); + else { + /* state is completely lost ;-( */ + ESPLOG(("esp%d: interrupt engine loses state, resetting bus\n", + esp->esp_id)); + what_next = do_reset_bus; } - - /* Now it is safe to execute more things. */ - if(esp->issue_SC) - esp_exec_cmd(esp); - goto esp_handle_done; - - default: - /* state is completely lost ;-( */ - ESPLOG(("esp%d: interrupt engine loses state, resetting bus\n", - esp->esp_id)); - what_next = do_reset_bus; - break; - - }; - goto again; - -esp_handle_done: - return; + } } #ifndef __sparc_v9__ diff -ur --new-file old/linux/drivers/scsi/esp.h new/linux/drivers/scsi/esp.h --- old/linux/drivers/scsi/esp.h Thu Jan 28 21:42:10 1999 +++ new/linux/drivers/scsi/esp.h Tue May 11 19:36:36 1999 @@ -123,10 +123,31 @@ unchar seqreg; /* The ESP sequence register */ unchar sreg2; /* Copy of HME status2 register */ + /* To save register writes to the ESP, which can be expensive, we + * keep track of the previous value that various registers had for + * the last target we connected to. If they are the same for the + * current target, we skip the register writes as they are not needed. + */ + unchar prev_soff, prev_stp, prev_cfg3, __cache_pad; + + /* We also keep a cache of the previous FAS/HME DMA CSR register value. */ + unsigned int prev_hme_dmacsr; + /* The HME is the biggest piece of shit I have ever seen. */ unchar hme_fifo_workaround_buffer[16 * 2]; /* 16-bit/entry fifo for wide scsi */ unchar hme_fifo_workaround_count; + /* For each target we keep track of save/restore data + * pointer information. This needs to be updated majorly + * when we add support for tagged queueing. -DaveM + */ + struct esp_pointers { + char *saved_ptr; + struct scatterlist *saved_buffer; + int saved_this_residual; + int saved_buffers_residual; + } data_pointers[16] /*XXX [MAX_TAGS_PER_TARGET]*/; + /* Clock periods, frequencies, synchronization, etc. */ unsigned int cfreq; /* Clock frequency in HZ */ unsigned int cfact; /* Clock conversion factor */ @@ -217,7 +238,7 @@ #define ESP_CONFIG3_IDMSG 0x10 /* ID message checking (esp100a/hme) */ #define ESP_CONFIG3_FSCSI 0x10 /* Enable FAST SCSI (esp/fas236) */ #define ESP_CONFIG3_GTM 0x20 /* group2 SCSI2 support (esp/fas236) */ -#define ESP_CONFIG3_BIGID 0x20 /* SCSI-ID's are 4bits (hme) */ +#define ESP_CONFIG3_IDBIT3 0x20 /* Bit 3 of HME SCSI-ID (hme) */ #define ESP_CONFIG3_TBMS 0x40 /* Three-byte msg's ok (esp/fas236) */ #define ESP_CONFIG3_EWIDE 0x40 /* Enable Wide-SCSI (hme) */ #define ESP_CONFIG3_IMS 0x80 /* ID msg chk'ng (esp/fas236) */ diff -ur --new-file old/linux/drivers/scsi/fcal.c new/linux/drivers/scsi/fcal.c --- old/linux/drivers/scsi/fcal.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/scsi/fcal.c Tue Mar 16 01:11:31 1999 @@ -0,0 +1,307 @@ +/* fcal.c: Fibre Channel Arbitrated Loop SCSI host adapter driver. + * + * Copyright (C) 1998,1999 Jakub Jelinek (jj@ultra.linux.cz) + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_KMOD +#include +#endif + +#include + +#include "scsi.h" +#include "hosts.h" +#include "../fc4/fcp_impl.h" +#include "fcal.h" + +#include + +/* #define FCAL_DEBUG */ + +#define fcal_printk printk ("FCAL %s: ", fc->name); printk + +#ifdef FCAL_DEBUG +#define FCALD(x) fcal_printk x; +#define FCALND(x) printk ("FCAL: "); printk x; +#else +#define FCALD(x) +#define FCALND(x) +#endif + +static unsigned char alpa2target[] = { +0x7e, 0x7d, 0x7c, 0xff, 0x7b, 0xff, 0xff, 0xff, 0x7a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x79, +0x78, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x77, 0x76, 0xff, 0xff, 0x75, 0xff, 0x74, 0x73, 0x72, +0xff, 0xff, 0xff, 0x71, 0xff, 0x70, 0x6f, 0x6e, 0xff, 0x6d, 0x6c, 0x6b, 0x6a, 0x69, 0x68, 0xff, +0xff, 0x67, 0x66, 0x65, 0x64, 0x63, 0x62, 0xff, 0xff, 0x61, 0x60, 0xff, 0x5f, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0x5e, 0xff, 0x5d, 0x5c, 0x5b, 0xff, 0x5a, 0x59, 0x58, 0x57, 0x56, 0x55, 0xff, +0xff, 0x54, 0x53, 0x52, 0x51, 0x50, 0x4f, 0xff, 0xff, 0x4e, 0x4d, 0xff, 0x4c, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0x4b, 0xff, 0x4a, 0x49, 0x48, 0xff, 0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0xff, +0xff, 0x41, 0x40, 0x3f, 0x3e, 0x3d, 0x3c, 0xff, 0xff, 0x3b, 0x3a, 0xff, 0x39, 0xff, 0xff, 0xff, +0x38, 0x37, 0x36, 0xff, 0x35, 0xff, 0xff, 0xff, 0x34, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x33, +0x32, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x31, 0x30, 0xff, 0xff, 0x2f, 0xff, 0x2e, 0x2d, 0x2c, +0xff, 0xff, 0xff, 0x2b, 0xff, 0x2a, 0x29, 0x28, 0xff, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0xff, +0xff, 0x21, 0x20, 0x1f, 0x1e, 0x1d, 0x1c, 0xff, 0xff, 0x1b, 0x1a, 0xff, 0x19, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0x18, 0xff, 0x17, 0x16, 0x15, 0xff, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0f, 0xff, +0xff, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0xff, 0xff, 0x08, 0x07, 0xff, 0x06, 0xff, 0xff, 0xff, +0x05, 0x04, 0x03, 0xff, 0x02, 0xff, 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 +}; + +static unsigned char target2alpa[] = { +0xef, 0xe8, 0xe4, 0xe2, 0xe1, 0xe0, 0xdc, 0xda, 0xd9, 0xd6, 0xd5, 0xd4, 0xd3, 0xd2, 0xd1, 0xce, +0xcd, 0xcc, 0xcb, 0xca, 0xc9, 0xc7, 0xc6, 0xc5, 0xc3, 0xbc, 0xba, 0xb9, 0xb6, 0xb5, 0xb4, 0xb3, +0xb2, 0xb1, 0xae, 0xad, 0xac, 0xab, 0xaa, 0xa9, 0xa7, 0xa6, 0xa5, 0xa3, 0x9f, 0x9e, 0x9d, 0x9b, +0x98, 0x97, 0x90, 0x8f, 0x88, 0x84, 0x82, 0x81, 0x80, 0x7c, 0x7a, 0x79, 0x76, 0x75, 0x74, 0x73, +0x72, 0x71, 0x6e, 0x6d, 0x6c, 0x6b, 0x6a, 0x69, 0x67, 0x66, 0x65, 0x63, 0x5c, 0x5a, 0x59, 0x56, +0x55, 0x54, 0x53, 0x52, 0x51, 0x4e, 0x4d, 0x4c, 0x4b, 0x4a, 0x49, 0x47, 0x46, 0x45, 0x43, 0x3c, +0x3a, 0x39, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x27, 0x26, +0x25, 0x23, 0x1f, 0x1e, 0x1d, 0x1b, 0x18, 0x17, 0x10, 0x0f, 0x08, 0x04, 0x02, 0x01, 0x00 +}; + +struct proc_dir_entry proc_scsi_fcal = { + PROC_SCSI_FCAL, 4, "fcal", + S_IFDIR | S_IRUGO | S_IXUGO, 2 +}; + +static int fcal_encode_addr(Scsi_Cmnd *SCpnt, u16 *addr, fc_channel *fc, fcp_cmnd *fcmd); + +static void fcal_select_queue_depths(struct Scsi_Host *host, Scsi_Device *devlist) +{ + Scsi_Device *device; + + for (device = devlist; device; device = device->next) { + if (device->host != host) continue; + if (device->tagged_supported) + device->queue_depth = /* 254 */ 8; + else + device->queue_depth = 2; + } +} + +/* Detect all FC Arbitrated Loops attached to the machine. + fc4 module has done all the work for us... */ +__initfunc(int fcal_detect(Scsi_Host_Template *tpnt)) +{ + int nfcals = 0; + fc_channel *fc; + int fcalcount; + int i; + + tpnt->proc_dir = &proc_scsi_fcal; + fcalcount = 0; + for_each_online_fc_channel(fc) + if (fc->posmap) + fcalcount++; + FCALND(("%d channels online\n", fcalcount)) + if (!fcalcount) { +#if defined(MODULE) && defined(CONFIG_FC4_SOCAL_MODULE) && defined(CONFIG_KMOD) + request_module("socal"); + + for_each_online_fc_channel(fc) + if (fc->posmap) + fcalcount++; + if (!fcalcount) +#endif + return 0; + } + for_each_online_fc_channel(fc) { + struct Scsi_Host *host; + long *ages; + struct fcal *fcal; + + if (!fc->posmap) continue; + + /* Strange, this is already registered to some other SCSI host, then it cannot be fcal */ + if (fc->scsi_name[0]) continue; + memcpy (fc->scsi_name, "FCAL", 4); + + fc->can_queue = FCAL_CAN_QUEUE; + fc->rsp_size = 64; + fc->encode_addr = fcal_encode_addr; + + ages = kmalloc (128 * sizeof(long), GFP_KERNEL); + if (!ages) continue; + + host = scsi_register (tpnt, sizeof (struct fcal)); + if (!host) panic ("Cannot register FCAL host\n"); + + nfcals++; + + if (fc->module) __MOD_INC_USE_COUNT(fc->module); + + fcal = (struct fcal *)host->hostdata; + + fc->fcp_register(fc, TYPE_SCSI_FCP, 0); + + for (i = 0; i < fc->posmap->len; i++) { + int status, target, alpa; + + alpa = fc->posmap->list[i]; + FCALD(("Sending PLOGI to %02x\n", alpa)) + target = alpa2target[alpa]; + status = fc_do_plogi(fc, alpa, fcal->node_wwn + target, + fcal->nport_wwn + target); + FCALD(("PLOGI returned with status %d\n", status)) + if (status != FC_STATUS_OK) + continue; + FCALD(("Sending PRLI to %02x\n", alpa)) + status = fc_do_prli(fc, alpa); + FCALD(("PRLI returned with status %d\n", status)) + if (status == FC_STATUS_OK) + fcal->map[target] = 1; + } + + host->max_id = 127; + host->irq = fc->irq; +#ifdef __sparc_v9__ + host->unchecked_isa_dma = 1; +#endif + host->select_queue_depths = fcal_select_queue_depths; + + fc->channels = 1; + fc->targets = 127; + fc->ages = ages; + memset (ages, 0, 128 * sizeof(long)); + + fcal->fc = fc; + + FCALD(("Found FCAL\n")) + } + if (nfcals) +#ifdef __sparc__ + printk ("FCAL: Total of %d Sun Enterprise Network Array (A5000 or EX500) channels found\n", nfcals); +#else + printk ("FCAL: Total of %d Fibre Channel Arbitrated Loops found\n", nfcals); +#endif + return nfcals; +} + +int fcal_release(struct Scsi_Host *host) +{ + struct fcal *fcal = (struct fcal *)host->hostdata; + fc_channel *fc = fcal->fc; + + if (fc->module) __MOD_DEC_USE_COUNT(fc->module); + + fc->fcp_register(fc, TYPE_SCSI_FCP, 1); + FCALND((" releasing fcal.\n")); + kfree (fc->ages); + FCALND(("released fcal!\n")); + return 0; +} + +#undef SPRINTF +#define SPRINTF(args...) { if (pos < (buffer + length)) pos += sprintf (pos, ## args); } + +int fcal_proc_info (char *buffer, char **start, off_t offset, int length, int hostno, int inout) +{ + struct Scsi_Host *host = NULL; + struct fcal *fcal; + fc_channel *fc; + char *pos = buffer; + int i, j; + + for (host=scsi_hostlist; host; host=host->next) + if (host->host_no == hostno) + break; + + if (!host) return -ESRCH; + + if (inout) return length; + + fcal = (struct fcal *)host->hostdata; + fc = fcal->fc; + +#ifdef __sparc__ + SPRINTF ("Sun Enterprise Network Array (A5000 or E?500) on %s\n", fc->name); +#else + SPRINTF ("Fibre Channel Arbitrated Loop on %s\n", fc->name); +#endif + SPRINTF ("Initiator AL-PA: %02x\n", fc->sid); + + SPRINTF ("\nAttached devices: %s\n", host->host_queue ? "" : "none"); + + for (i = 0; i < fc->posmap->len; i++) { + unsigned char alpa = fc->posmap->list[i]; + unsigned char target; + u32 *u1, *u2; + + target = alpa2target[alpa]; + u1 = (u32 *)&fcal->nport_wwn[target]; + u2 = (u32 *)&fcal->node_wwn[target]; + if (!u1[0] && !u1[1]) { + SPRINTF (" [AL-PA: %02x] Not responded to PLOGI\n", alpa); + } else if (!fcal->map[target]) { + SPRINTF (" [AL-PA: %02x, Port WWN: %08x%08x, Node WWN: %08x%08x] Not responded to PRLI\n", + alpa, u1[0], u1[1], u2[0], u2[1]); + } else { + Scsi_Device *scd; + for (scd = host->host_queue ; scd; scd = scd->next) + if (scd->host->host_no == hostno && scd->id == target) { + SPRINTF (" [AL-PA: %02x, Id: %02d, Port WWN: %08x%08x, Node WWN: %08x%08x] ", + alpa, target, u1[0], u1[1], u2[0], u2[1]); + SPRINTF ("%s ", (scd->type < MAX_SCSI_DEVICE_CODE) ? + scsi_device_types[(short) scd->type] : "Unknown device"); + + for (j = 0; (j < 8) && (scd->vendor[j] >= 0x20); j++) + SPRINTF ("%c", scd->vendor[j]); + SPRINTF (" "); + + for (j = 0; (j < 16) && (scd->model[j] >= 0x20); j++) + SPRINTF ("%c", scd->model[j]); + + SPRINTF ("\n"); + } + } + } + SPRINTF ("\n"); + + *start = buffer + offset; + + if ((pos - buffer) < offset) + return 0; + else if (pos - buffer - offset < length) + return pos - buffer - offset; + else + return length; +} + +/* + For FC-AL, we use a simple addressing: we have just one channel 0, + and all AL-PAs are mapped to targets 0..0x7e + */ +static int fcal_encode_addr(Scsi_Cmnd *SCpnt, u16 *addr, fc_channel *fc, fcp_cmnd *fcmd) +{ + struct fcal *f; + + /* We don't support LUNs yet - I'm not sure if LUN should be in SCSI fcp_cdb, or in second byte of addr[0] */ + if (SCpnt->cmnd[1] & 0xe0) return -EINVAL; + /* FC-PLDA tells us... */ + memset(addr, 0, 8); + f = (struct fcal *)SCpnt->host->hostdata; + if (!f->map[SCpnt->target]) return -EINVAL; + /* Now, determine DID: It will be Native Identifier, so we zero upper + 2 bytes of the 3 byte DID, lowest byte will be AL-PA */ + fcmd->did = target2alpa[SCpnt->target]; + FCALD(("trying DID %06x\n", fcmd->did)) + return 0; +} + +#ifdef MODULE + +Scsi_Host_Template driver_template = FCAL; + +#include "scsi_module.c" + +EXPORT_NO_SYMBOLS; +#endif /* MODULE */ diff -ur --new-file old/linux/drivers/scsi/fcal.h new/linux/drivers/scsi/fcal.h --- old/linux/drivers/scsi/fcal.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/scsi/fcal.h Tue Mar 16 01:11:31 1999 @@ -0,0 +1,46 @@ +/* fcal.h: Generic Fibre Channel Arbitrated Loop SCSI host adapter driver definitions. + * + * Copyright (C) 1998,1999 Jakub Jelinek (jj@ultra.linux.cz) + */ + +#ifndef _FCAL_H +#define _FCAL_H + +#include "../fc4/fcp_impl.h" + +struct fcal { + /* fc must be first */ + fc_channel *fc; + unsigned char map[128]; + fc_wwn nport_wwn[128]; + fc_wwn node_wwn[128]; +}; + +/* Arbitrary constant. Cannot be too large, as fc4 layer has limitations + for a particular channel */ +#define FCAL_CAN_QUEUE 512 + +int fcal_detect(Scsi_Host_Template *); +int fcal_release(struct Scsi_Host *); +int fcal_proc_info (char *, char **, off_t, int, int, int); + +#define FCAL { \ + name: "Fibre Channel Arbitrated Loop",\ + detect: fcal_detect, \ + release: fcal_release, \ + proc_info: fcal_proc_info, \ + queuecommand: fcp_scsi_queuecommand, \ + can_queue: FCAL_CAN_QUEUE, \ + this_id: -1, \ + sg_tablesize: 1, \ + cmd_per_lun: 1, \ + use_clustering: ENABLE_CLUSTERING, \ + use_new_eh_code: FCP_SCSI_USE_NEW_EH_CODE, \ + abort: fcp_old_abort, \ + eh_abort_handler: fcp_scsi_abort, \ + eh_device_reset_handler:fcp_scsi_dev_reset, \ + eh_bus_reset_handler: fcp_scsi_bus_reset, \ + eh_host_reset_handler: fcp_scsi_host_reset, \ +} + +#endif /* !(_FCAL_H) */ diff -ur --new-file old/linux/drivers/scsi/gdth.c new/linux/drivers/scsi/gdth.c --- old/linux/drivers/scsi/gdth.c Mon Jan 11 19:17:20 1999 +++ new/linux/drivers/scsi/gdth.c Mon Apr 12 18:56:16 1999 @@ -2,7 +2,7 @@ * GDT ISA/EISA/PCI Disk Array Controller driver for Linux * * * * gdth.c * - * Copyright (C) 1995-98 ICP vortex Computersysteme GmbH, Achim Leubner * + * Copyright (C) 1995-99 ICP vortex Computersysteme GmbH, Achim Leubner * * * * * * * @@ -20,9 +20,34 @@ * along with this kernel; if not, write to the Free Software * * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * * - * Tested with Linux 1.2.13, ..., 2.1.131 * + * Tested with Linux 1.2.13, ..., 2.2.4 * * * * $Log: gdth.c,v $ + * Revision 1.23 1999/03/26 09:12:31 achim + * Default value for hdr_channel set to 0 + * + * Revision 1.22 1999/03/22 16:27:16 achim + * Bugfix: gdth_store_event() must not be locked with GDTH_LOCK_HA() + * + * Revision 1.21 1999/03/16 13:40:34 achim + * Problems with reserved drives solved + * gdth_eh_bus_reset() implemented + * + * Revision 1.20 1999/03/10 09:08:13 achim + * Bugfix: Corrections in gdth_direction_tab[] made + * Bugfix: Increase command timeout (gdth_update_timeout()) NOT in gdth_putq() + * + * Revision 1.19 1999/03/05 14:38:16 achim + * Bugfix: Heads/Sectors mapping for reserved devices possibly wrong + * -> gdth_eval_mapping() implemented, changes in gdth_bios_param() + * INIT_RETRIES set to 100s to avoid DEINIT-Timeout for controllers + * with BIOS disabled and memory test set to Intensive + * Enhanced /proc support + * + * Revision 1.18 1999/02/24 09:54:33 achim + * Command line parameter hdr_channel implemented + * Bugfix for EISA controllers + Linux 2.2.x + * * Revision 1.17 1998/12/17 15:58:11 achim * Command line parameters implemented * Changes for Alpha platforms @@ -95,7 +120,7 @@ * Initial revision * ************************************************************************/ -#ident "$Id: gdth.c,v 1.17 1998/12/17 15:58:11 achim Exp $" +#ident "$Id: gdth.c,v 1.23 1999/03/26 09:12:31 achim Exp $" /* All GDT Disk Array Controllers are fully supported by this driver. * This includes the PCI/EISA/ISA SCSI Disk Array Controllers and the @@ -122,9 +147,10 @@ * max_ids:x x - target ID count per channel (1..MAXID) * rescan:Y rescan all channels/IDs * rescan:N use all devices found until now + * hdr_channel:x x - number of virtual bus for host drives * * The default value is: "gdth=disable:N,reserve_mode:1,reverse_scan:N, - * max_ids:127,rescan:N". + * max_ids:127,rescan:N,hdr_channel:0". * Here is another example: "gdth=reserve_list:0,1,2,0,0,1,3,0,rescan:Y". * * When loading the gdth driver as a module, the same options are available. @@ -134,7 +160,7 @@ * '1' in place of 'Y' and '0' in place of 'N'. * * Default: "modprobe gdth disable=0 reserve_mode=1 reverse_scan=0 - * max_ids=127 rescan=0" + * max_ids=127 rescan=0 hdr_channel=0" * The other example: "modprobe gdth reserve_list=0,1,2,0,0,1,3,0 rescan=1". */ @@ -179,6 +205,8 @@ #include "gdth.h" +static void gdth_delay(int milliseconds); +static void gdth_eval_mapping(ulong32 size, int *cyls, int *heads, int *secs); #if LINUX_VERSION_CODE >= 0x010346 static void gdth_interrupt(int irq,void *dev_id,struct pt_regs *regs); #else @@ -186,7 +214,7 @@ #endif static int gdth_sync_event(int hanum,int service,unchar index,Scsi_Cmnd *scp); static int gdth_async_event(int hanum,int service); -static void gdth_log_event(gdth_evt_data *dvr); +static void gdth_log_event(gdth_evt_data *dvr, char *buffer); static void gdth_putq(int hanum,Scsi_Cmnd *scp,unchar priority); static void gdth_next(int hanum); @@ -226,6 +254,7 @@ static const char *gdth_ctr_name(int hanum); +#if LINUX_VERSION_CODE >= 0x010300 static void gdth_flush(int hanum); #if LINUX_VERSION_CODE >= 0x020100 static int gdth_halt(struct notifier_block *nb, ulong event, void *buf); @@ -233,6 +262,7 @@ static int halt_called = FALSE; void gdth_halt(void); #endif +#endif #ifdef DEBUG_GDTH static unchar DebugState = DEBUG_GDTH; @@ -331,6 +361,7 @@ #define HADATA(a) (&((gdth_ext_str *)((a)->hostdata))->haext) #define CMDDATA(a) (&((gdth_ext_str *)((a)->hostdata))->cmdext) +#define BUS_L2P(a,b) ((b)>(a)->virt_bus ? (b-1):(b)) #if LINUX_VERSION_CODE < 0x010300 static void *gdth_mmap(ulong paddr, ulong size) @@ -429,16 +460,16 @@ static unchar gdth_direction_tab[0x100] = { DNO,DNO,DIN,DIN,DOU,DIN,DIN,DOU,DIN,DUN,DOU,DOU,DUN,DUN,DUN,DIN, DNO,DIN,DIN,DOU,DIN,DOU,DNO,DNO,DOU,DNO,DIN,DNO,DIN,DOU,DNO,DUN, - DIN,DUN,DIN,DUN,DOU,DIN,DUN,DUN,DIN,DIN,DIN,DUN,DUN,DIN,DIN,DIN, - DIN,DIN,DIN,DNO,DIN,DNO,DNO,DIN,DIN,DIN,DIN,DIN,DIN,DIN,DIN,DIN, - DIN,DIN,DIN,DIN,DIN,DNO,DUN,DNO,DNO,DNO,DUN,DNO,DIN,DIN,DUN,DUN, - DUN,DUN,DUN,DUN,DUN,DIN,DUN,DUN,DUN,DUN,DIN,DUN,DUN,DUN,DUN,DUN, + DIN,DUN,DIN,DUN,DOU,DIN,DUN,DUN,DIN,DIN,DOU,DNO,DUN,DIN,DOU,DOU, + DOU,DOU,DOU,DNO,DIN,DNO,DNO,DIN,DOU,DOU,DOU,DOU,DIN,DOU,DIN,DOU, + DOU,DOU,DIN,DIN,DIN,DNO,DUN,DNO,DNO,DNO,DUN,DNO,DOU,DIN,DUN,DUN, + DUN,DUN,DUN,DUN,DUN,DOU,DUN,DUN,DUN,DUN,DIN,DUN,DUN,DUN,DUN,DUN, DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN, DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN, DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN, DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN, - DUN,DUN,DUN,DUN,DUN,DNO,DNO,DUN,DIN,DNO,DIN,DUN,DNO,DUN,DIN,DIN, - DIN,DIN,DIN,DNO,DUN,DIN,DIN,DIN,DIN,DUN,DUN,DUN,DUN,DUN,DUN,DUN, + DUN,DUN,DUN,DUN,DUN,DNO,DNO,DUN,DIN,DNO,DOU,DUN,DNO,DUN,DOU,DOU, + DOU,DOU,DOU,DNO,DUN,DIN,DOU,DIN,DIN,DUN,DUN,DUN,DUN,DUN,DUN,DUN, DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN, DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN, DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DOU,DUN,DUN,DUN,DUN,DUN, @@ -474,25 +505,6 @@ #define GDTH_UNLOCK_SCSI_DOCMD() do {} while (0) #endif -/* /proc support */ -#if LINUX_VERSION_CODE >= 0x010300 -#include -struct proc_dir_entry proc_scsi_gdth = { - PROC_SCSI_GDTH, 4, "gdth", - S_IFDIR | S_IRUGO | S_IXUGO, 2 -}; -#include "gdth_proc.h" -#include "gdth_proc.c" -#endif - -#if LINUX_VERSION_CODE >= 0x020100 -/* notifier block to get a notify on system shutdown/halt/reboot */ -static struct notifier_block gdth_notifier = { - gdth_halt, NULL, 0 -}; -#endif - - /* LILO and modprobe/insmod parameters */ /* IRQ list for GDT3000/3020 EISA controllers */ static int irq[MAXHA] __initdata = @@ -501,14 +513,16 @@ /* disable driver flag */ static int disable __initdata = 0; /* reserve flag */ -static int reserve_mode __initdata = 1; +static int reserve_mode = 1; /* reserve list */ -static int reserve_list[MAX_RES_ARGS] __initdata = +static int reserve_list[MAX_RES_ARGS] = {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,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}; /* scan order for PCI controllers */ -static int reverse_scan __initdata = 0; +static int reverse_scan = 0; +/* virtual channel for the host drives */ +static int hdr_channel = 0; /* max. IDs per channel */ static int max_ids = MAXID; /* rescan all IDs */ @@ -522,12 +536,31 @@ MODULE_PARM(reserve_mode, "i"); MODULE_PARM(reserve_list, "4-" __MODULE_STRING(MAX_RES_ARGS) "i"); MODULE_PARM(reverse_scan, "i"); +MODULE_PARM(hdr_channel, "i"); MODULE_PARM(max_ids, "i"); MODULE_PARM(rescan, "i"); MODULE_AUTHOR("Achim Leubner"); #endif #endif +/* /proc support */ +#if LINUX_VERSION_CODE >= 0x010300 +#include +struct proc_dir_entry proc_scsi_gdth = { + PROC_SCSI_GDTH, 4, "gdth", + S_IFDIR | S_IRUGO | S_IXUGO, 2 +}; +#include "gdth_proc.h" +#include "gdth_proc.c" +#endif + +#if LINUX_VERSION_CODE >= 0x020100 +/* notifier block to get a notify on system shutdown/halt/reboot */ +static struct notifier_block gdth_notifier = { + gdth_halt, NULL, 0 +}; +#endif + static void gdth_delay(int milliseconds) { @@ -544,6 +577,25 @@ } } +static void gdth_eval_mapping(ulong32 size, int *cyls, int *heads, int *secs) +{ + *cyls = size /HEADS/SECS; + if (*cyls <= MAXCYLS) { + *heads = HEADS; + *secs = SECS; + } else { /* too high for 64*32 */ + *cyls = size /MEDHEADS/MEDSECS; + if (*cyls <= MAXCYLS) { + *heads = MEDHEADS; + *secs = MEDSECS; + } else { /* too high for 127*63 */ + *cyls = size /BIGHEADS/BIGSECS; + *heads = BIGHEADS; + *secs = BIGSECS; + } + } +} + /* controller search and initialization functions */ __initfunc (static int gdth_search_eisa(ushort eisa_adr)) @@ -1413,9 +1465,9 @@ ha->pccb->Service |= 0x80; if (ha->type == GDT_EISA) { - outb(ha->pccb->Service, ha->bmic + LDOORREG); if (ha->pccb->OpCode == GDT_INIT) /* store DMA buffer */ - outl((ulong)ha->pccb, ha->bmic + MAILBOXREG); + outl(virt_to_bus(ha->pccb), ha->bmic + MAILBOXREG); + outb(ha->pccb->Service, ha->bmic + LDOORREG); } else if (ha->type == GDT_ISA) { gdth_writeb(0, &((gdt2_dpram_str *)ha->brd)->io.event); } else if (ha->type == GDT_PCI) { @@ -1526,11 +1578,15 @@ { register gdth_ha_str *ha; ushort cdev_cnt, i; - ulong32 drv_cyls, drv_hds, drv_secs; + int drv_cyls, drv_hds, drv_secs; ulong32 bus_no; + ulong32 drv_cnt, drv_no, j; gdth_getch_str *chn; + gdth_drlist_str *drl; gdth_iochan_str *ioc; - + gdth_raw_iochan_str *iocr; + gdth_arraylist_str *alst; + TRACE(("gdth_search_drives() hanum %d\n",hanum)); ha = HADATA(gdth_ctr_tab[hanum]); @@ -1565,19 +1621,19 @@ cdev_cnt = (ushort)ha->info; /* detect number of buses - try new IOCTL */ - ioc = (gdth_iochan_str *)ha->pscratch; - ioc->version = 0xffffffff; - ioc->list_entries = MAXBUS; - ioc->first_chan = 0; - ioc->last_chan = MAXBUS-1; - ioc->list_offset = GDTOFFSOF(gdth_iochan_str, list[0]); - if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,GET_IOCHAN_DESC, - INVALID_CHANNEL,sizeof(gdth_iochan_str))) { - TRACE2(("GET_IOCHAN_DESC supported!\n")); - ha->bus_cnt = ioc->chan_count; + iocr = (gdth_raw_iochan_str *)ha->pscratch; + iocr->hdr.version = 0xffffffff; + iocr->hdr.list_entries = MAXBUS; + iocr->hdr.first_chan = 0; + iocr->hdr.last_chan = MAXBUS-1; + iocr->hdr.list_offset = GDTOFFSOF(gdth_raw_iochan_str, list[0]); + if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,IOCHAN_RAW_DESC, + INVALID_CHANNEL,sizeof(gdth_raw_iochan_str))) { + TRACE2(("IOCHAN_RAW_DESC supported!\n")); + ha->bus_cnt = iocr->hdr.chan_count; for (bus_no = 0; bus_no < ha->bus_cnt; ++bus_no) { - if (ioc->list[bus_no].proc_id < MAXID) - ha->bus_id[bus_no] = ioc->list[bus_no].proc_id; + if (iocr->list[bus_no].proc_id < MAXID) + ha->bus_id[bus_no] = iocr->list[bus_no].proc_id; else ha->bus_id[bus_no] = 0xff; } @@ -1618,16 +1674,100 @@ ha->cpar.version,ha->cpar.state,ha->cpar.strategy, ha->cpar.write_back,ha->cpar.block_size)); - /* read board info, fill ctr_name[] */ + /* read board info and features */ + ha->more_proc = FALSE; if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,BOARD_INFO, INVALID_CHANNEL,sizeof(gdth_binfo_str))) { - TRACE2(("BOARD_INFO supported!\n")); - strcpy(ha->ctr_name, ((gdth_binfo_str *)ha->pscratch)->type_string); + ha->binfo = *(gdth_binfo_str *)ha->pscratch; + if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,BOARD_FEATURES, + INVALID_CHANNEL,sizeof(gdth_bfeat_str))) { + TRACE2(("BOARD_INFO/BOARD_FEATURES supported\n")); + ha->bfeat = *(gdth_bfeat_str *)ha->pscratch; + ha->more_proc = TRUE; + } } else { - strcpy(ha->ctr_name, gdth_ctr_name(hanum)); + TRACE2(("BOARD_INFO requires firmware >= 1.10/2.08\n")); + strcpy(ha->binfo.type_string, gdth_ctr_name(hanum)); } - TRACE2(("Controller name: %s\n",ha->ctr_name)); + TRACE2(("Controller name: %s\n",ha->binfo.type_string)); + /* read more informations */ + if (ha->more_proc) { + /* physical drives, channel addresses */ + ioc = (gdth_iochan_str *)ha->pscratch; + ioc->hdr.version = 0xffffffff; + ioc->hdr.list_entries = MAXBUS; + ioc->hdr.first_chan = 0; + ioc->hdr.last_chan = MAXBUS-1; + ioc->hdr.list_offset = GDTOFFSOF(gdth_iochan_str, list[0]); + if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,IOCHAN_DESC, + INVALID_CHANNEL,sizeof(gdth_iochan_str))) { + for (bus_no = 0; bus_no < ha->bus_cnt; ++bus_no) { + ha->raw[bus_no].address = ioc->list[bus_no].address; + ha->raw[bus_no].local_no = ioc->list[bus_no].local_no; + } + } else { + for (bus_no = 0; bus_no < ha->bus_cnt; ++bus_no) { + ha->raw[bus_no].address = IO_CHANNEL; + ha->raw[bus_no].local_no = bus_no; + } + } + for (bus_no = 0; bus_no < ha->bus_cnt; ++bus_no) { + chn = (gdth_getch_str *)ha->pscratch; + chn->channel_no = ha->raw[bus_no].local_no; + if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL, + SCSI_CHAN_CNT | L_CTRL_PATTERN, + ha->raw[bus_no].address | INVALID_CHANNEL, + sizeof(gdth_getch_str))) { + ha->raw[bus_no].pdev_cnt = chn->drive_cnt; + TRACE2(("Channel %d: %d phys. drives\n", + bus_no,chn->drive_cnt)); + } + if (ha->raw[bus_no].pdev_cnt > 0) { + drl = (gdth_drlist_str *)ha->pscratch; + drl->sc_no = ha->raw[bus_no].local_no; + drl->sc_cnt = ha->raw[bus_no].pdev_cnt; + if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL, + SCSI_DR_LIST | L_CTRL_PATTERN, + ha->raw[bus_no].address | INVALID_CHANNEL, + sizeof(gdth_drlist_str))) { + for (j = 0; j < ha->raw[bus_no].pdev_cnt; ++j) + ha->raw[bus_no].id_list[j] = drl->sc_list[j]; + } else { + ha->raw[bus_no].pdev_cnt = 0; + } + } + } + + /* logical drives */ + if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,CACHE_DRV_CNT, + INVALID_CHANNEL,sizeof(ulong32))) { + drv_cnt = *(ulong32 *)ha->pscratch; + if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,CACHE_DRV_LIST, + INVALID_CHANNEL,drv_cnt * sizeof(ulong32))) { + for (j = 0; j < drv_cnt; ++j) { + drv_no = ((ulong32 *)ha->pscratch)[j]; + if (drv_no < MAX_HDRIVES) { + ha->hdr[drv_no].is_logdrv = TRUE; + TRACE2(("Drive %d is log. drive\n",drv_no)); + } + } + } + if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL, + ARRAY_DRV_LIST | LA_CTRL_PATTERN, + 0, 35 * sizeof(gdth_arraylist_str))) { + for (j = 0; j < 35; ++j) { + alst = &((gdth_arraylist_str *)ha->pscratch)[j]; + ha->hdr[j].is_arraydrv = alst->is_arrayd; + ha->hdr[j].is_master = alst->is_master; + ha->hdr[j].is_parity = alst->is_parity; + ha->hdr[j].is_hotfix = alst->is_hotfix; + ha->hdr[j].master_no = alst->cd_handle; + } + } + } + } + /* initialize raw service */ if (!gdth_internal_cmd(hanum,SCSIRAWSERVICE,GDT_INIT,0,0,0)) { printk("GDT: Initialization error raw service (code %d)\n", @@ -1695,21 +1835,7 @@ /* evaluate mapping (sectors per head, heads per cylinder) */ ha->hdr[i].size &= ~SECS32; if (ha->info2 == 0) { - drv_cyls = ha->hdr[i].size /HEADS/SECS; - if (drv_cyls <= MAXCYLS) { - drv_hds = HEADS; - drv_secs= SECS; - } else { /* too high for 64*32 */ - drv_cyls = ha->hdr[i].size /MEDHEADS/MEDSECS; - if (drv_cyls <= MAXCYLS) { - drv_hds = MEDHEADS; - drv_secs= MEDSECS; - } else { /* too high for 127*63 */ - drv_cyls = ha->hdr[i].size /BIGHEADS/BIGSECS; - drv_hds = BIGHEADS; - drv_secs= BIGSECS; - } - } + gdth_eval_mapping(ha->hdr[i].size,&drv_cyls,&drv_hds,&drv_secs); } else { drv_hds = ha->info2 & 0xff; drv_secs = (ha->info2 >> 8) & 0xff; @@ -1752,7 +1878,6 @@ GDTH_LOCK_HA(ha, flags); scp->SCp.this_residual = (int)priority; - gdth_update_timeout(hanum, scp, scp->timeout_per_command * 6); #if LINUX_VERSION_CODE >= 0x020000 b = scp->channel; #else @@ -1761,8 +1886,8 @@ t = scp->target; #if LINUX_VERSION_CODE >= 0x010300 if (priority >= DEFAULT_PRI) { - if ((b < ha->bus_cnt && ha->raw[b].lock) || - (b == ha->bus_cnt && ha->hdr[t].lock)) { + if ((b != ha->virt_bus && ha->raw[BUS_L2P(ha,b)].lock) || + (b == ha->virt_bus && t < MAX_HDRIVES && ha->hdr[t].lock)) { TRACE2(("gdth_putq(): locked IO -> update_timeout()\n")); scp->SCp.buffers_residual = gdth_update_timeout(hanum, scp, 0); } @@ -1825,8 +1950,8 @@ #endif t = nscp->target; if (nscp->SCp.this_residual >= DEFAULT_PRI) { - if ((b < ha->bus_cnt && ha->raw[b].lock) || - (b == ha->bus_cnt && ha->hdr[t].lock)) + if ((b != ha->virt_bus && ha->raw[BUS_L2P(ha,b)].lock) || + (b == ha->virt_bus && t < MAX_HDRIVES && ha->hdr[t].lock)) continue; } @@ -1843,22 +1968,24 @@ firsttime = FALSE; } +#if LINUX_VERSION_CODE >= 0x010300 + if (nscp->done != gdth_scsi_done) +#endif + { if (nscp->SCp.phase == -1) { nscp->SCp.phase = SCSIRAWSERVICE; /* default: raw svc. */ if (nscp->cmnd[0] == TEST_UNIT_READY) { - TRACE2(("TEST_UNIT_READY Bus %d Id %d LUN %d\n", - nscp->channel, nscp->target, nscp->lun)); + TRACE2(("TEST_UNIT_READY Bus %d Id %d LUN %d\n", + b, t, nscp->lun)); /* TEST_UNIT_READY -> set scan mode */ if ((ha->scan_mode & 0x0f) == 0) { - if (nscp->channel == 0 && nscp->target == 0 && - nscp->lun == 0) { + if (b == 0 && t == 0 && nscp->lun == 0) { ha->scan_mode |= 1; TRACE2(("Scan mode: 0x%x\n", ha->scan_mode)); } } else if ((ha->scan_mode & 0x0f) == 1) { - if (nscp->channel == 0 && - ((nscp->target == 0 && nscp->lun == 1) || - (nscp->target == 1 && nscp->lun == 0))) { + if (b == 0 && ((t == 0 && nscp->lun == 1) || + (t == 1 && nscp->lun == 0))) { nscp->SCp.Status = GDT_SCAN_START; nscp->SCp.phase |= ((ha->scan_mode & 0x10 ? 1:0) << 8); ha->scan_mode = 0x12; @@ -1869,7 +1996,7 @@ TRACE2(("Scan mode: 0x%x\n", ha->scan_mode)); } } else if (ha->scan_mode == 0x12) { - if (b == ha->bus_cnt) { + if (b == ha->bus_cnt && t == ha->tid_cnt-1) { nscp->SCp.Status = GDT_SCAN_END; ha->scan_mode &= 0x10; TRACE2(("Scan mode: 0x%x (SCAN_END)\n", @@ -1878,10 +2005,12 @@ } } } + } if (nscp->SCp.Status != -1) { if ((nscp->SCp.phase & 0xff) == SCSIRAWSERVICE) { - cmd_index=gdth_fill_raw_cmd(hanum,nscp,b); + if (!(cmd_index=gdth_fill_raw_cmd(hanum,nscp,BUS_L2P(ha,b)))) + this_cmd = FALSE; next_cmd = FALSE; } } else @@ -1893,13 +2022,15 @@ next_cmd = FALSE; } else #endif - if (b < ha->bus_cnt) { - if (!(cmd_index=gdth_fill_raw_cmd(hanum,nscp,b))) { + if (b != ha->virt_bus) { + if (ha->raw[BUS_L2P(ha,b)].io_cnt[t] >= GDTH_MAX_RAW || + !(cmd_index=gdth_fill_raw_cmd(hanum,nscp,BUS_L2P(ha,b)))) this_cmd = FALSE; - } - } else if (!ha->hdr[nscp->target].present || nscp->lun != 0) { + else + ha->raw[BUS_L2P(ha,b)].io_cnt[t]++; + } else if (t >= MAX_HDRIVES || !ha->hdr[t].present || nscp->lun != 0) { TRACE2(("Command 0x%x to bus %d id %d lun %d -> IGNORE\n", - nscp->cmnd[0], b, nscp->target, nscp->lun)); + nscp->cmnd[0], b, t, nscp->lun)); nscp->result = DID_BAD_TARGET << 16; GDTH_UNLOCK_HA(ha,flags); /* io_request_lock already active ! */ @@ -2405,14 +2536,13 @@ ushort idx, gdth_evt_data *evt) { gdth_evt_str *e; - ulong flags; struct timeval tv; + /* no GDTH_LOCK_HA() ! */ TRACE2(("gdth_store_event() source %d idx %d\n", source, idx)); if (source == 0) /* no source -> no event */ return 0; - GDTH_LOCK_HA(ha, flags); if (ebuffer[elastidx].event_source == source && ebuffer[elastidx].event_idx == idx && !memcmp((char *)&ebuffer[elastidx].event_data.eu, @@ -2440,7 +2570,6 @@ e->same_count = 1; e->event_data = *evt; } - GDTH_UNLOCK_HA(ha, flags); return e; } @@ -2808,9 +2937,12 @@ printk("\n"); } else { - scp->SCp.Message = (int)ha->status; + if (scp->SCp.Status == -1 && scp->channel != ha->virt_bus) { + ha->raw[BUS_L2P(ha,scp->channel)].io_cnt[scp->target]--; + } /* cache or raw service */ if (ha->status == S_OK) { + scp->SCp.Message = S_OK; if (scp->SCp.Status != -1) { TRACE2(("gdth_sync_event(): special cmd 0x%x OK\n", scp->SCp.Status)); @@ -2821,8 +2953,10 @@ scp->result = DID_OK << 16; } else if (ha->status == S_BSY) { TRACE2(("Controller busy -> retry !\n")); + scp->SCp.Message = S_BSY; return 2; } else { + scp->SCp.Message = (int)((ha->info<<16)|ha->status); if (scp->SCp.Status != -1) { TRACE2(("gdth_sync_event(): special cmd 0x%x error 0x%x\n", scp->SCp.Status, ha->status)); @@ -2836,7 +2970,10 @@ scp->sense_buffer[2] = NOT_READY; scp->result = (DID_OK << 16) | (CHECK_CONDITION << 1); - if (scp->done != gdth_scsi_done) { +#if LINUX_VERSION_CODE >= 0x010300 + if (scp->done != gdth_scsi_done) +#endif + { dvr.size = sizeof(dvr.eu.sync); dvr.eu.sync.ionode = hanum; dvr.eu.sync.service = service; @@ -2904,7 +3041,7 @@ "GDT HA %u, Array Drive %u: parity build failed", /*18*/ "\005\000\002\006\002" "GDT HA %u, Array Drive %u: drive rebuild failed", -/*19*/ "\007\000\002\010\002" +/*19*/ "\005\000\002\010\002" "GDT HA %u, Test of Hot Fix %u failed", /*20*/ "\005\000\002\006\002" "GDT HA %u, Array Drive %u: drive build finished successfully", @@ -3066,12 +3203,12 @@ dvr.eu.async.info = ha->info; *(ulong32 *)dvr.eu.async.scsi_coord = ha->info2; gdth_store_event(ha, ES_ASYNC, service, &dvr); - gdth_log_event( &dvr ); + gdth_log_event( &dvr, NULL ); } return 1; } -static void gdth_log_event(gdth_evt_data *dvr) +static void gdth_log_event(gdth_evt_data *dvr, char *buffer) { gdth_stackframe stack; char *f = NULL; @@ -3101,12 +3238,22 @@ break; } } - - printk(&f[(int)f[0]],stack); printk("\n"); + + if (buffer == NULL) { + printk(&f[(int)f[0]],stack); + printk("\n"); + } else { + sprintf(buffer,&f[(int)f[0]],stack); + } } else { - printk("GDT: Unknown async. event service %d event no. %d\n", - dvr->eu.async.service,dvr->eu.async.status); + if (buffer == NULL) { + printk("GDT HA %u, Unknown async. event service %d event no. %d\n", + dvr->eu.async.ionode,dvr->eu.async.service,dvr->eu.async.status); + } else { + sprintf(buffer,"GDT HA %u, Unknown async. event service %d event no. %d", + dvr->eu.async.ionode,dvr->eu.async.service,dvr->eu.async.status); + } } } @@ -3249,6 +3396,9 @@ scsi_unregister(shp); continue; } + if (hdr_channel < 0 || hdr_channel > ha->bus_cnt) + hdr_channel = ha->bus_cnt; + ha->virt_bus = hdr_channel; #if LINUX_VERSION_CODE >= 0x020000 shp->max_id = ha->tid_cnt; @@ -3333,6 +3483,9 @@ scsi_unregister(shp); continue; } + if (hdr_channel < 0 || hdr_channel > ha->bus_cnt) + hdr_channel = ha->bus_cnt; + ha->virt_bus = hdr_channel; #if LINUX_VERSION_CODE >= 0x020000 shp->max_id = ha->tid_cnt; @@ -3429,6 +3582,9 @@ scsi_unregister(shp); continue; } + if (hdr_channel < 0 || hdr_channel > ha->bus_cnt) + hdr_channel = ha->bus_cnt; + ha->virt_bus = hdr_channel; #if LINUX_VERSION_CODE >= 0x020000 shp->max_id = ha->tid_cnt; @@ -3479,7 +3635,9 @@ if (NUMDATA(shp)->busnum == 0) { hanum = NUMDATA(shp)->hanum; ha = HADATA(gdth_ctr_tab[hanum]); +#if LINUX_VERSION_CODE >= 0x010300 gdth_flush(hanum); +#endif if (shp->irq) { #if LINUX_VERSION_CODE >= 0x010346 @@ -3552,7 +3710,7 @@ hanum = NUMDATA(shp)->hanum; ha = HADATA(gdth_ctr_tab[hanum]); - return ((const char *)ha->ctr_name); + return ((const char *)ha->binfo.type_string); } /* old error handling */ @@ -3588,8 +3746,33 @@ int gdth_eh_bus_reset(Scsi_Cmnd *scp) { + int i, hanum; + gdth_ha_str *ha; + ulong flags; + Scsi_Cmnd *cmnd; + TRACE2(("gdth_eh_bus_reset()\n")); - return FAILED; + hanum = NUMDATA(scp->host)->hanum; + ha = HADATA(gdth_ctr_tab[hanum]); + if (scp->channel == ha->virt_bus) + return FAILED; + + GDTH_LOCK_HA(ha, flags); + for (i = 0; i < MAXID; ++i) + ha->raw[BUS_L2P(ha,scp->channel)].io_cnt[i] = 0; + for (i = 0; i < GDTH_MAXCMDS; ++i) { + cmnd = ha->cmd_tab[i].cmnd; + if (!SPECIAL_SCP(cmnd) && cmnd->channel == scp->channel) + ha->cmd_tab[i].cmnd = UNUSED_CMND; + } + gdth_polling = TRUE; + while (gdth_test_busy(hanum)) + gdth_delay(0); + gdth_internal_cmd(hanum, SCSIRAWSERVICE, GDT_RESET_BUS, + BUS_L2P(ha,scp->channel), 0, 0); + gdth_polling = FALSE; + GDTH_UNLOCK_HA(ha, flags); + return SUCCESS; } int gdth_eh_host_reset(Scsi_Cmnd *scp) @@ -3608,7 +3791,6 @@ unchar t; int hanum; gdth_ha_str *ha; - int drv_hds, drv_secs; hanum = NUMDATA(disk->device->host)->hanum; t = disk->device->id; @@ -3616,27 +3798,16 @@ hanum, disk->device->channel, t)); ha = HADATA(gdth_ctr_tab[hanum]); - if (ha->hdr[t].heads == 0) { - /* raw device: evaluate mapping (sectors per head, heads per cylinder) */ - if (disk->capacity /HEADS/SECS <= MAXCYLS) { - drv_hds = HEADS; - drv_secs= SECS; - } else if (disk->capacity /MEDHEADS/MEDSECS <= MAXCYLS) { - drv_hds = MEDHEADS; - drv_secs= MEDSECS; - } else { - drv_hds = BIGHEADS; - drv_secs= BIGSECS; - } - ha->hdr[t].heads = drv_hds; - ha->hdr[t].secs = drv_secs; - TRACE2(("gdth_bios_param(): raw device -> params evaluated\n")); + if (disk->device->channel != ha->virt_bus || ha->hdr[t].heads == 0) { + /* raw device or host drive without mapping information */ + TRACE2(("Evaluate mapping\n")); + gdth_eval_mapping(disk->capacity,&ip[2],&ip[0],&ip[1]); + } else { + ip[0] = ha->hdr[t].heads; + ip[1] = ha->hdr[t].secs; + ip[2] = disk->capacity / ip[0] / ip[1]; } - ip[0] = ha->hdr[t].heads; - ip[1] = ha->hdr[t].secs; - ip[2] = disk->capacity / ip[0] / ip[1]; - TRACE2(("gdth_bios_param(): %d heads, %d secs, %d cyls\n", ip[0],ip[1],ip[2])); return 0; @@ -3683,11 +3854,13 @@ if (scp->done == gdth_scsi_done) priority = scp->SCp.this_residual; #endif + gdth_update_timeout(hanum, scp, scp->timeout_per_command * 6); gdth_putq( hanum, scp, priority ); gdth_next( hanum ); return 0; } +#if LINUX_VERSION_CODE >= 0x010300 /* flush routine */ static void gdth_flush(int hanum) { @@ -3696,7 +3869,6 @@ Scsi_Cmnd scp; Scsi_Device sdev; gdth_cmd_str gdtcmd; - char cmnd[12]; TRACE2(("gdth_flush() hanum %d\n",hanum)); ha = HADATA(gdth_ctr_tab[hanum]); @@ -3719,18 +3891,7 @@ gdtcmd.u.cache.BlockNo = 1; gdtcmd.u.cache.sg_canz = 0; TRACE2(("gdth_flush(): flush ha %d drive %d\n", hanum, i)); - { - struct semaphore sem = MUTEX_LOCKED; - scp.request.rq_status = RQ_SCSI_BUSY; - scp.request.sem = &sem; - scp.SCp.this_residual = IOCTL_PRI; - GDTH_LOCK_SCSI_DOCMD(); - scsi_do_cmd(&scp, cmnd, &gdtcmd, - sizeof(gdth_cmd_str), gdth_scsi_done, - 30*HZ, 1); - GDTH_UNLOCK_SCSI_DOCMD(); - down(&sem); - } + gdth_do_cmd(&scp, &gdtcmd, 30); } } } @@ -3747,7 +3908,6 @@ Scsi_Cmnd scp; Scsi_Device sdev; gdth_cmd_str gdtcmd; - char cmnd[12]; #endif #if LINUX_VERSION_CODE >= 0x020100 @@ -3782,18 +3942,7 @@ gdtcmd.Service = CACHESERVICE; gdtcmd.OpCode = GDT_RESET; TRACE2(("gdth_halt(): reset controller %d\n", hanum)); - { - struct semaphore sem = MUTEX_LOCKED; - scp.request.rq_status = RQ_SCSI_BUSY; - scp.request.sem = &sem; - scp.SCp.this_residual = IOCTL_PRI; - GDTH_LOCK_SCSI_DOCMD(); - scsi_do_cmd(&scp, cmnd, &gdtcmd, - sizeof(gdth_cmd_str), gdth_scsi_done, - 10*HZ, 1); - GDTH_UNLOCK_SCSI_DOCMD(); - down(&sem); - } + gdth_do_cmd(&scp, &gdtcmd, 10); #endif } printk("Done.\n"); @@ -3806,6 +3955,7 @@ return NOTIFY_OK; #endif } +#endif /* called from init/main.c */ @@ -3846,6 +3996,8 @@ reserve_mode = val; else if (!strncmp(argv, "reverse_scan:", 13)) reverse_scan = val; + else if (!strncmp(argv, "hdr_channel:", 12)) + hdr_channel = val; else if (!strncmp(argv, "max_ids:", 8)) max_ids = val; else if (!strncmp(argv, "rescan:", 7)) diff -ur --new-file old/linux/drivers/scsi/gdth.h new/linux/drivers/scsi/gdth.h --- old/linux/drivers/scsi/gdth.h Thu Jan 28 21:42:11 1999 +++ new/linux/drivers/scsi/gdth.h Tue May 11 19:36:36 1999 @@ -4,13 +4,13 @@ /* * Header file for the GDT ISA/EISA/PCI Disk Array Controller driver for Linux * - * gdth.h Copyright (C) 1995-98 ICP vortex Computersysteme GmbH, Achim Leubner + * gdth.h Copyright (C) 1995-99 ICP vortex Computersysteme GmbH, Achim Leubner * See gdth.c for further informations and * below for supported controller types * * * - * $Id: gdth.h,v 1.16 1998/12/17 15:54:53 achim Exp $ + * $Id: gdth.h,v 1.21 1999/03/26 09:12:24 achim Exp $ */ #include @@ -29,9 +29,9 @@ /* defines, macros */ /* driver version */ -#define GDTH_VERSION_STR "1.10" +#define GDTH_VERSION_STR "1.14" #define GDTH_VERSION 1 -#define GDTH_SUBVERSION 10 +#define GDTH_SUBVERSION 14 /* protocol version */ #define PROTOCOL_VERSION 1 @@ -129,6 +129,7 @@ #define GDTH_SCRATCH 4096 /* 4KB scratch buffer */ #define GDTH_MAXCMDS 124 #define GDTH_MAXC_P_L 16 /* max. cmds per lun */ +#define GDTH_MAX_RAW 2 /* max. cmds per raw device */ #define MAXOFFSETS 128 #define MAXHA 16 #define MAXID 127 @@ -199,14 +200,27 @@ #define GDT_SCAN_END 20 /* stop device scan */ /* IOCTL command defines */ -#define SCSI_CHAN_CNT 5 /* subfunctions */ -#define GET_IOCHAN_DESC 0x5e -#define L_CTRL_PATTERN 0x20000000L -#define CACHE_INFO 4 -#define CACHE_CONFIG 5 -#define BOARD_INFO 0x28 -#define IO_CHANNEL 0x00020000L /* channels */ -#define INVALID_CHANNEL 0x0000ffffL +#define SCSI_DR_INFO 0x00 /* SCSI drive info */ +#define SCSI_CHAN_CNT 0x05 /* SCSI channel count */ +#define SCSI_DR_LIST 0x06 /* SCSI drive list */ +#define SCSI_DEF_CNT 0x15 /* grown/primary defects */ +#define DSK_STATISTICS 0x4b /* SCSI disk statistics */ +#define IOCHAN_DESC 0x5d /* description of IO channel */ +#define IOCHAN_RAW_DESC 0x5e /* description of raw IO channel */ +#define L_CTRL_PATTERN 0x20000000L /* SCSI IOCTL mask */ +#define ARRAY_INFO 0x12 /* array drive info */ +#define ARRAY_DRV_LIST 0x0f /* array drive list */ +#define LA_CTRL_PATTERN 0x10000000L /* array IOCTL mask */ +#define CACHE_DRV_CNT 0x01 /* cache drive count */ +#define CACHE_DRV_LIST 0x02 /* cache drive list */ +#define CACHE_INFO 0x04 /* cache info */ +#define CACHE_CONFIG 0x05 /* cache configuration */ +#define CACHE_DRV_INFO 0x07 /* cache drive info */ +#define BOARD_FEATURES 0x15 /* controller features */ +#define BOARD_INFO 0x28 /* controller info */ +#define HOST_GET 0x10001L /* get host drive list */ +#define IO_CHANNEL 0x00020000L /* default IO channel */ +#define INVALID_CHANNEL 0x0000ffffL /* invalid channel */ /* IOCTLs */ #define GDTIOCTL_MASK ('J'<<8) @@ -225,8 +239,8 @@ #define S_RAW_ILL 0xff /* raw serv.: illegal */ /* timeout values */ -#define INIT_RETRIES 10000 /* 10000 * 1ms = 10s */ -#define INIT_TIMEOUT 100000 /* 1000 * 1ms = 1s */ +#define INIT_RETRIES 100000 /* 100000 * 1ms = 100s */ +#define INIT_TIMEOUT 100000 /* 100000 * 1ms = 100s */ #define POLL_TIMEOUT 10000 /* 10000 * 1ms = 10s */ /* priorities */ @@ -276,29 +290,171 @@ char msg_text[MSGLEN+2]; /* the message text */ } PACKED gdth_msg_str; -/* get channel count IOCTL */ +/* IOCTL data structures */ +/* SCSI drive info */ +typedef struct { + unchar vendor[8]; /* vendor string */ + unchar product[16]; /* product string */ + unchar revision[4]; /* revision */ + ulong32 sy_rate; /* current rate for sync. tr. */ + ulong32 sy_max_rate; /* max. rate for sync. tr. */ + ulong32 no_ldrive; /* belongs to this logical drv.*/ + ulong32 blkcnt; /* number of blocks */ + ushort blksize; /* size of block in bytes */ + unchar available; /* flag: access is available */ + unchar init; /* medium is initialized */ + unchar devtype; /* SCSI devicetype */ + unchar rm_medium; /* medium is removable */ + unchar wp_medium; /* medium is write protected */ + unchar ansi; /* SCSI I/II or III? */ + unchar protocol; /* same as ansi */ + unchar sync; /* flag: sync. transfer enab. */ + unchar disc; /* flag: disconnect enabled */ + unchar queueing; /* flag: command queing enab. */ + unchar cached; /* flag: caching enabled */ + unchar target_id; /* target ID of device */ + unchar lun; /* LUN id of device */ + unchar orphan; /* flag: drive fragment */ + ulong32 last_error; /* sense key or drive state */ + ulong32 last_result; /* result of last command */ + ulong32 check_errors; /* err. in last surface check */ + unchar percent; /* progress for surface check */ + unchar last_check; /* IOCTRL operation */ + unchar res[2]; + ulong32 flags; /* from 1.19/2.19: raw reserv.*/ + unchar multi_bus; /* multi bus dev? (fibre ch.) */ + unchar mb_status; /* status: available? */ + unchar res2[2]; + unchar mb_alt_status; /* status on second bus */ + unchar mb_alt_bid; /* number of second bus */ + unchar mb_alt_tid; /* target id on second bus */ + unchar res3; + unchar fc_flag; /* from 1.22/2.22: info valid?*/ + unchar res4; + ushort fc_frame_size; /* frame size (bytes) */ + char wwn[8]; /* world wide name */ +} PACKED gdth_diskinfo_str; + +/* get SCSI channel count */ typedef struct { ulong32 channel_no; /* number of channel */ - ulong32 drive_cnt; /* number of drives */ + ulong32 drive_cnt; /* drive count */ unchar siop_id; /* SCSI processor ID */ unchar siop_state; /* SCSI processor state */ } PACKED gdth_getch_str; -/* get raw channel count IOCTL (NEW!) */ +/* get SCSI drive numbers */ typedef struct { - ulong32 version; /* version of information (-1UL: newest) */ - unchar list_entries; /* list entry count */ - unchar first_chan; /* first channel number */ - unchar last_chan; /* last channel number */ - unchar chan_count; /* (R) channel count */ - ulong32 list_offset; /* offset of list[0] */ + ulong32 sc_no; /* SCSI channel */ + ulong32 sc_cnt; /* sc_list[] elements */ + ulong32 sc_list[MAXID]; /* minor device numbers */ +} PACKED gdth_drlist_str; + +/* get grown/primary defect count */ +typedef struct { + unchar sddc_type; /* 0x08: grown, 0x10: prim. */ + unchar sddc_format; /* list entry format */ + unchar sddc_len; /* list entry length */ + unchar sddc_res; + ulong32 sddc_cnt; /* entry count */ +} PACKED gdth_defcnt_str; + +/* disk statistics */ +typedef struct { + ulong32 bid; /* SCSI channel */ + ulong32 first; /* first SCSI disk */ + ulong32 entries; /* number of elements */ + ulong32 count; /* (R) number of init. el. */ + ulong32 mon_time; /* time stamp */ struct { - unchar proc_id; /* processor id */ - unchar proc_defect; /* defect ? */ - unchar reserved[2]; + unchar tid; /* target ID */ + unchar lun; /* LUN */ + unchar res[2]; + ulong32 blk_size; /* block size in bytes */ + ulong32 rd_count; /* bytes read */ + ulong32 wr_count; /* bytes written */ + ulong32 rd_blk_count; /* blocks read */ + ulong32 wr_blk_count; /* blocks written */ + ulong32 retries; /* retries */ + ulong32 reassigns; /* reassigns */ + } PACKED list[1]; +} PACKED gdth_dskstat_str; + +/* IO channel header */ +typedef struct { + ulong32 version; /* version (-1UL: newest) */ + unchar list_entries; /* list entry count */ + unchar first_chan; /* first channel number */ + unchar last_chan; /* last channel number */ + unchar chan_count; /* (R) channel count */ + ulong32 list_offset; /* offset of list[0] */ +} PACKED gdth_iochan_header; + +/* get IO channel description */ +typedef struct { + gdth_iochan_header hdr; + struct { + ulong32 address; /* channel address */ + unchar type; /* type (SCSI, FCAL) */ + unchar local_no; /* local number */ + ushort features; /* channel features */ } PACKED list[MAXBUS]; } PACKED gdth_iochan_str; +/* get raw IO channel description */ +typedef struct { + gdth_iochan_header hdr; + struct { + unchar proc_id; /* processor id */ + unchar proc_defect; /* defect ? */ + unchar reserved[2]; + } PACKED list[MAXBUS]; +} PACKED gdth_raw_iochan_str; + +/* array drive component */ +typedef struct { + ulong32 al_controller; /* controller ID */ + unchar al_cache_drive; /* cache drive number */ + unchar al_status; /* cache drive state */ + unchar al_res[2]; +} PACKED gdth_arraycomp_str; + +/* array drive information */ +typedef struct { + unchar ai_type; /* array type (RAID0,4,5) */ + unchar ai_cache_drive_cnt; /* active cachedrives */ + unchar ai_state; /* array drive state */ + unchar ai_master_cd; /* master cachedrive */ + ulong32 ai_master_controller; /* ID of master controller */ + ulong32 ai_size; /* user capacity [sectors] */ + ulong32 ai_striping_size; /* striping size [sectors] */ + ulong32 ai_secsize; /* sector size [bytes] */ + ulong32 ai_err_info; /* failed cache drive */ + unchar ai_name[8]; /* name of the array drive */ + unchar ai_controller_cnt; /* number of controllers */ + unchar ai_removable; /* flag: removable */ + unchar ai_write_protected; /* flag: write protected */ + unchar ai_devtype; /* type: always direct access */ + gdth_arraycomp_str ai_drives[35]; /* drive components: */ + unchar ai_drive_entries; /* number of drive components */ + unchar ai_protected; /* protection flag */ + unchar ai_verify_state; /* state of a parity verify */ + unchar ai_ext_state; /* extended array drive state */ + unchar ai_expand_state; /* array expand state (>=2.18)*/ + unchar ai_reserved[3]; +} PACKED gdth_arrayinf_str; + +/* get array drive list */ +typedef struct { + ulong32 controller_no; /* controller no. */ + unchar cd_handle; /* master cachedrive */ + unchar is_arrayd; /* Flag: is array drive? */ + unchar is_master; /* Flag: is array master? */ + unchar is_parity; /* Flag: is parity drive? */ + unchar is_hotfix; /* Flag: is hotfix drive? */ + unchar res[3]; +} PACKED gdth_arraylist_str; + /* cache info/config IOCTL */ typedef struct { ulong32 version; /* firmware version */ @@ -322,6 +478,34 @@ gdth_cstat_str cstat; } PACKED gdth_cinfo_str; +/* cache drive info */ +typedef struct { + unchar cd_name[8]; /* cache drive name */ + ulong32 cd_devtype; /* SCSI devicetype */ + ulong32 cd_ldcnt; /* number of log. drives */ + ulong32 cd_last_error; /* last error */ + unchar cd_initialized; /* drive is initialized */ + unchar cd_removable; /* media is removable */ + unchar cd_write_protected; /* write protected */ + unchar cd_flags; /* Pool Hot Fix? */ + ulong32 ld_blkcnt; /* number of blocks */ + ulong32 ld_blksize; /* blocksize */ + ulong32 ld_dcnt; /* number of disks */ + ulong32 ld_slave; /* log. drive index */ + ulong32 ld_dtype; /* type of logical drive */ + ulong32 ld_last_error; /* last error */ + unchar ld_name[8]; /* log. drive name */ + unchar ld_error; /* error */ +} PACKED gdth_cdrinfo_str; + +/* board features */ +typedef struct { + unchar chaining; /* Chaining supported */ + unchar striping; /* Striping (RAID-0) supp. */ + unchar mirroring; /* Mirroring (RAID-1) supp. */ + unchar raid; /* RAID-4/5/10 supported */ +} PACKED gdth_bfeat_str; + /* board info IOCTL */ typedef struct { ulong32 ser_no; /* serial no. */ @@ -351,6 +535,28 @@ unchar ramparity_pres; /* RAM parity check hardware? */ } PACKED gdth_binfo_str; +/* get host drive info */ +typedef struct { + char name[8]; /* host drive name */ + ulong32 size; /* size (sectors) */ + unchar host_drive; /* host drive number */ + unchar log_drive; /* log. drive (master) */ + unchar reserved; + unchar rw_attribs; /* r/w attribs */ + ulong32 start_sec; /* start sector */ +} PACKED gdth_hentry_str; + +typedef struct { + ulong32 entries; /* entry count */ + ulong32 offset; /* offset of entries */ + unchar secs_p_head; /* sectors/head */ + unchar heads_p_cyl; /* heads/cylinder */ + unchar reserved; + unchar clust_drvtype; /* cluster drive type */ + ulong32 location; /* controller number */ + gdth_hentry_str entry[MAX_HDRIVES]; /* entries */ +} PACKED gdth_hget_str; + /* scatter/gather element */ typedef struct { ulong32 sg_ptr; /* address */ @@ -642,16 +848,30 @@ ulong32 info2; /* additional info */ Scsi_Cmnd *req_first; /* top of request queue */ struct { - unchar present; /* host drive present? */ + unchar present; /* Flag: host drive present? */ + unchar is_logdrv; /* Flag: logical drive (master)? */ + unchar is_arraydrv; /* Flag: array drive? */ + unchar is_master; /* Flag: array drive master? */ + unchar is_parity; /* Flag: parity drive? */ + unchar is_hotfix; /* Flag: hotfix drive? */ + unchar master_no; /* number of master drive */ unchar lock; /* drive locked? (hot plug) */ unchar heads; /* mapping */ unchar secs; ushort devtype; /* further information */ ulong32 size; /* capacity */ - } hdr[MAXID]; /* host drives */ + unchar ldr_no; /* log. drive no. */ + unchar rw_attribs; /* r/w attributes */ + ulong32 start_sec; /* start sector */ + } hdr[MAX_HDRIVES]; /* host drives */ struct { unchar lock; /* channel locked? (hot plug) */ - } raw[MAXBUS]; /* raw devices */ + unchar pdev_cnt; /* physical device count */ + unchar local_no; /* local channel number */ + unchar io_cnt[MAXID]; /* current IO count */ + ulong32 address; /* channel address */ + ulong32 id_list[MAXID]; /* IDs of the phys. devices */ + } raw[MAXBUS]; /* SCSI channels */ struct { Scsi_Cmnd *cmnd; /* pending request */ ushort service; /* service */ @@ -659,12 +879,15 @@ unchar bus_cnt; /* SCSI bus count */ unchar tid_cnt; /* Target ID count */ unchar bus_id[MAXBUS]; /* IOP IDs */ + unchar virt_bus; /* number of virtual bus */ + unchar more_proc; /* more /proc info supported */ ushort cmd_cnt; /* command count in DPRAM */ ushort cmd_len; /* length of actual command */ ushort cmd_offs_dpmem; /* actual offset in DPRAM */ ushort ic_all_size; /* sizeof DPRAM interf. area */ gdth_cpar_str cpar; /* controller cache par. */ - char ctr_name[16]; /* controller name */ + gdth_bfeat_str bfeat; /* controller features */ + gdth_binfo_str binfo; /* controller info */ #if LINUX_VERSION_CODE >= 0x02015F spinlock_t smp_lock; #endif diff -ur --new-file old/linux/drivers/scsi/gdth_proc.c new/linux/drivers/scsi/gdth_proc.c --- old/linux/drivers/scsi/gdth_proc.c Mon Jan 11 19:17:20 1999 +++ new/linux/drivers/scsi/gdth_proc.c Mon Apr 12 18:56:16 1999 @@ -1,5 +1,5 @@ /* gdth_proc.c - * $Id: gdth_proc.c,v 1.11 1998/12/17 15:52:35 achim Exp $ + * $Id: gdth_proc.c,v 1.13 1999/03/22 16:12:53 achim Exp $ */ #include "gdth_ioctl.h" @@ -68,7 +68,6 @@ static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Cmnd scp) { int orig_length, drive, wb_mode; - char cmnd[12]; int i, found; gdth_ha_str *ha; gdth_cmd_str gdtcmd; @@ -76,7 +75,6 @@ TRACE2(("gdth_set_asc_info() ha %d\n",hanum)); ha = HADATA(gdth_ctr_tab[hanum]); - memset(cmnd, 0,10); orig_length = length + 5; drive = -1; wb_mode = 0; @@ -107,18 +105,7 @@ gdtcmd.u.cache.DeviceNo = i; gdtcmd.u.cache.BlockNo = 1; gdtcmd.u.cache.sg_canz = 0; - { - struct semaphore sem = MUTEX_LOCKED; - scp.request.rq_status = RQ_SCSI_BUSY; - scp.request.sem = &sem; - scp.SCp.this_residual = IOCTL_PRI; - GDTH_LOCK_SCSI_DOCMD(); - scsi_do_cmd(&scp, cmnd, &gdtcmd, - sizeof(gdth_cmd_str), gdth_scsi_done, - 30*HZ, 1); - GDTH_UNLOCK_SCSI_DOCMD(); - down(&sem); - } + gdth_do_cmd(&scp, &gdtcmd, 30); } } if (!found) @@ -159,13 +146,9 @@ } if (wb_mode) { - pcpar = (gdth_cpar_str *)kmalloc( sizeof(gdth_cpar_str), - GFP_ATOMIC | GFP_DMA ); - if (pcpar == NULL) { - TRACE2(("gdth_set_info(): Unable to allocate memory.\n")); - printk("Unable to allocate memory.\n"); - return(-EINVAL); - } + if (!gdth_ioctl_alloc(hanum, sizeof(gdth_cpar_str))) + return(-EBUSY); + pcpar = (gdth_cpar_str *)ha->pscratch; memcpy( pcpar, &ha->cpar, sizeof(gdth_cpar_str) ); gdtcmd.BoardNode = LOCALBOARD; gdtcmd.Service = CACHESERVICE; @@ -175,18 +158,8 @@ gdtcmd.u.ioctl.subfunc = CACHE_CONFIG; gdtcmd.u.ioctl.channel = INVALID_CHANNEL; pcpar->write_back = wb_mode==1 ? 0:1; - { - struct semaphore sem = MUTEX_LOCKED; - scp.request.rq_status = RQ_SCSI_BUSY; - scp.request.sem = &sem; - scp.SCp.this_residual = IOCTL_PRI; - GDTH_LOCK_SCSI_DOCMD(); - scsi_do_cmd(&scp, cmnd, &gdtcmd, sizeof(gdth_cmd_str), - gdth_scsi_done, 30*HZ, 1); - GDTH_UNLOCK_SCSI_DOCMD(); - down(&sem); - } - kfree( pcpar ); + gdth_do_cmd(&scp, &gdtcmd, 30); + gdth_ioctl_free(hanum); printk("Done.\n"); return(orig_length); } @@ -197,21 +170,23 @@ static int gdth_set_bin_info(char *buffer,int length,int hanum,Scsi_Cmnd scp) { - char cmnd[12]; unchar i, j; gdth_ha_str *ha; gdth_iowr_str *piowr; gdth_iord_str *piord; gdth_cmd_str *pcmd; + gdth_evt_str *pevt; ulong32 *ppadd, add_size; + ulong32 *ppadd2, add_size2; ulong flags; TRACE2(("gdth_set_bin_info() ha %d\n",hanum)); ha = HADATA(gdth_ctr_tab[hanum]); - memset(cmnd, 0,10); piowr = (gdth_iowr_str *)buffer; piord = NULL; pcmd = NULL; + ppadd = ppadd2 = NULL; + add_size = add_size2 = 0; if (length < GDTOFFSOF(gdth_iowr_str,iu)) return(-EINVAL); @@ -238,6 +213,7 @@ } } else if (piowr->service == SCSIRAWSERVICE) { add_size = pcmd->u.raw.sdlen; + add_size2 = pcmd->u.raw.sense_len; if (ha->raw_feat & SCATTER_GATHER) { ppadd = &pcmd->u.raw.sg_lst[0].sg_ptr; pcmd->u.raw.sdata = 0xffffffff; @@ -247,32 +223,26 @@ ppadd = &pcmd->u.raw.sdata; pcmd->u.raw.sg_ranz = 0; } + ppadd2 = &pcmd->u.raw.sense_data; } else { return(-EINVAL); } - if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str) + add_size )) + if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str)+add_size+add_size2 )) return(-EBUSY); piord = (gdth_iord_str *)ha->pscratch; - piord->size = sizeof(gdth_iord_str) + add_size; + piord->size = sizeof(gdth_iord_str) + add_size + add_size2; if (add_size > 0) { memcpy(piord->iu.general.data, piowr->iu.general.data, add_size); *ppadd = virt_to_bus(piord->iu.general.data); } - /* do IOCTL */ - { - struct semaphore sem = MUTEX_LOCKED; - scp.request.rq_status = RQ_SCSI_BUSY; - scp.request.sem = &sem; - scp.SCp.this_residual = IOCTL_PRI; - GDTH_LOCK_SCSI_DOCMD(); - scsi_do_cmd(&scp, cmnd, pcmd, - sizeof(gdth_cmd_str), gdth_scsi_done, - piowr->timeout*HZ, 1); - GDTH_UNLOCK_SCSI_DOCMD(); - down(&sem); - piord->status = (ulong32)scp.SCp.Message; + if (add_size2 > 0) { + memcpy(piord->iu.general.data+add_size, piowr->iu.general.data, add_size2); + *ppadd2 = virt_to_bus(piord->iu.general.data+add_size); } + /* do IOCTL */ + gdth_do_cmd(&scp, pcmd, piowr->timeout); + piord->status = (ulong32)scp.SCp.Message; break; case GDTIOCTL_DRVERS: @@ -381,12 +351,21 @@ return(-EBUSY); piord = (gdth_iord_str *)ha->pscratch; if (piowr->iu.event.erase == 0xff) { - gdth_store_event(ha, - ((gdth_evt_str *)piowr->iu.event.evt)->event_source, - ((gdth_evt_str *)piowr->iu.event.evt)->event_idx, - &((gdth_evt_str *)piowr->iu.event.evt)->event_data); - if (((gdth_evt_str *)piowr->iu.event.evt)->event_source == ES_ASYNC) - gdth_log_event(&((gdth_evt_str *)piowr->iu.event.evt)->event_data); + pevt = (gdth_evt_str *)piowr->iu.event.evt; + if (pevt->event_source == ES_TEST) + pevt->event_data.size = sizeof(pevt->event_data.eu.test); + else if (pevt->event_source == ES_DRIVER) + pevt->event_data.size = sizeof(pevt->event_data.eu.driver); + else if (pevt->event_source == ES_SYNC) + pevt->event_data.size = sizeof(pevt->event_data.eu.sync); + else { + pevt->event_data.size = sizeof(pevt->event_data.eu.async); + gdth_log_event(&pevt->event_data, NULL); + } + GDTH_LOCK_HA(ha, flags); + gdth_store_event(ha, pevt->event_source, pevt->event_idx, + &pevt->event_data); + GDTH_UNLOCK_HA(ha, flags); } else if (piowr->iu.event.erase == 0xfe) { gdth_clear_events(); } else if (piowr->iu.event.erase == 0) { @@ -416,28 +395,98 @@ off_t begin = 0,pos = 0; gdth_ha_str *ha; gdth_iord_str *piord; - int id; + int id, i, j, k, sec, flag; + int no_mdrv = 0, drv_no, is_mirr; + ulong32 cnt; + + gdth_cmd_str gdtcmd; + gdth_evt_str estr; + Scsi_Cmnd scp; + Scsi_Device sdev; + char hrec[161]; + struct timeval tv; + + gdth_dskstat_str *pds; + gdth_diskinfo_str *pdi; + gdth_arrayinf_str *pai; + gdth_defcnt_str *pdef; + gdth_cdrinfo_str *pcdi; + gdth_hget_str *phg; TRACE2(("gdth_get_info() ha %d bus %d\n",hanum,busnum)); ha = HADATA(gdth_ctr_tab[hanum]); id = length; + memset(&sdev,0,sizeof(Scsi_Device)); + memset(&scp, 0,sizeof(Scsi_Cmnd)); + sdev.host = gdth_ctr_vtab[vh]; + sdev.id = sdev.host->this_id; + scp.cmd_len = 12; + scp.host = gdth_ctr_vtab[vh]; + scp.target = sdev.host->this_id; + scp.device = &sdev; + scp.use_sg = 0; + /* look for buffer ID in length */ if (id > 1) { -#if LINUX_VERSION_CODE >= 0x020000 + /* request is i.e. "cat /proc/scsi/gdth/0" */ + /* format: %-15s\t%-10s\t%-15s\t%s */ + /* driver parameters */ + size = sprintf(buffer+len,"Driver Parameters:\n"); + len += size; pos = begin + len; + if (reserve_list[0] == 0xff) + strcpy(hrec, "--"); + else { + sprintf(hrec, "%d", reserve_list[0]); + for (i = 1; i < MAX_RES_ARGS; i++) { + if (reserve_list[i] == 0xff) + break; + sprintf(hrec,"%s,%d", hrec, reserve_list[i]); + } + } size = sprintf(buffer+len, - "%s Disk Array Controller\n", - ha->ctr_name); -#else + " reserve_mode: \t%d \treserve_list: \t%s\n", + reserve_mode, hrec); + len += size; pos = begin + len; size = sprintf(buffer+len, - "%s Disk Array Controller (Bus %d)\n", - ha->ctr_name,busnum); + " max_ids: \t%-3d \thdr_channel: \t%d\n", + max_ids, hdr_channel); + len += size; pos = begin + len; + + if (pos < offset) { + len = 0; + begin = pos; + } + if (pos > offset + length) + goto stop_output; + + /* controller information */ + size = sprintf(buffer+len,"\nDisk Array Controller Information:\n"); + len += size; pos = begin + len; +#if LINUX_VERSION_CODE >= 0x020000 + strcpy(hrec, ha->binfo.type_string); +#else + sprintf(hrec, "%s (Bus %d)", ha->binfo.type_string, busnum); #endif + size = sprintf(buffer+len, + " Number: \t%d \tName: \t%s\n", + hanum, hrec); len += size; pos = begin + len; + + if (ha->more_proc) + sprintf(hrec, "%d.%02d.%02d-%c%03X", + (unchar)(ha->binfo.upd_fw_ver>>24), + (unchar)(ha->binfo.upd_fw_ver>>16), + (unchar)(ha->binfo.upd_fw_ver), + ha->bfeat.raid ? 'R':'N', + ha->binfo.upd_revision); + else + sprintf(hrec, "%d.%02d", (unchar)(ha->cpar.version>>8), + (unchar)(ha->cpar.version)); + size = sprintf(buffer+len, - "Firmware Version: %d.%2d\tDriver Version: %s\n", - (unchar)(ha->cpar.version>>8), - (unchar)(ha->cpar.version),GDTH_VERSION_STR); + " Driver Ver.: \t%-10s\tFirmware Ver.: \t%s\n", + GDTH_VERSION_STR, hrec); len += size; pos = begin + len; if (pos < offset) { @@ -447,7 +496,412 @@ if (pos > offset + length) goto stop_output; + if (ha->more_proc) { + /* more information: 1. about controller */ + size = sprintf(buffer+len, + " Serial No.: \t0x%8X\tCache RAM size:\t%d KB\n", + ha->binfo.ser_no, ha->binfo.memsize / 1024); + len += size; pos = begin + len; + + if (pos < offset) { + len = 0; + begin = pos; + } + if (pos > offset + length) + goto stop_output; + + /* 2. about physical devices */ + size = sprintf(buffer+len,"\nPhysical Devices:"); + len += size; pos = begin + len; + flag = FALSE; + + if (!gdth_ioctl_alloc(hanum, GDTH_SCRATCH)) + goto stop_output; + for (i = 0; i < ha->bus_cnt; ++i) { + /* 2.a statistics (and retries/reassigns) */ + TRACE2(("pdr_statistics() chn %d\n",i)); + pds = (gdth_dskstat_str *)(ha->pscratch + GDTH_SCRATCH/4); + gdtcmd.BoardNode = LOCALBOARD; + gdtcmd.Service = CACHESERVICE; + gdtcmd.OpCode = GDT_IOCTL; + gdtcmd.u.ioctl.p_param = virt_to_bus(pds); + gdtcmd.u.ioctl.param_size = 3*GDTH_SCRATCH/4; + gdtcmd.u.ioctl.subfunc = DSK_STATISTICS | L_CTRL_PATTERN; + gdtcmd.u.ioctl.channel = ha->raw[i].address | INVALID_CHANNEL; + pds->bid = ha->raw[i].local_no; + pds->first = 0; + pds->entries = ha->raw[i].pdev_cnt; + cnt = (3*GDTH_SCRATCH/4 - 5 * sizeof(ulong32)) / + sizeof(pds->list[0]); + if (pds->entries > cnt) + pds->entries = cnt; + gdth_do_cmd(&scp, &gdtcmd, 30); + if (scp.SCp.Message != S_OK) + pds->count = 0; + TRACE2(("pdr_statistics() entries %d status %d\n", + pds->count, scp.SCp.Message)); + + /* other IOCTLs must fit into area GDTH_SCRATCH/4 */ + for (j = 0; j < ha->raw[i].pdev_cnt; ++j) { + /* 2.b drive info */ + TRACE2(("scsi_drv_info() chn %d dev %d\n", + i, ha->raw[i].id_list[j])); + pdi = (gdth_diskinfo_str *)ha->pscratch; + gdtcmd.BoardNode = LOCALBOARD; + gdtcmd.Service = CACHESERVICE; + gdtcmd.OpCode = GDT_IOCTL; + gdtcmd.u.ioctl.p_param = virt_to_bus(pdi); + gdtcmd.u.ioctl.param_size = sizeof(gdth_diskinfo_str); + gdtcmd.u.ioctl.subfunc = SCSI_DR_INFO | L_CTRL_PATTERN; + gdtcmd.u.ioctl.channel = + ha->raw[i].address | ha->raw[i].id_list[j]; + gdth_do_cmd(&scp, &gdtcmd, 30); + if (scp.SCp.Message == S_OK) { + strncpy(hrec,pdi->vendor,8); + strncpy(hrec+8,pdi->product,16); + strncpy(hrec+24,pdi->revision,4); + hrec[28] = 0; + size = sprintf(buffer+len, + "\n Chn/ID/LUN: \t%c/%02d/%d \tName: \t%s\n", + 'A'+i,pdi->target_id,pdi->lun,hrec); + len += size; pos = begin + len; + flag = TRUE; + pdi->no_ldrive &= 0xffff; + if (pdi->no_ldrive == 0xffff) + strcpy(hrec,"--"); + else + sprintf(hrec,"%d",pdi->no_ldrive); + size = sprintf(buffer+len, + " Capacity [MB]:\t%-6d \tTo Log. Drive: \t%s\n", + pdi->blkcnt/(1024*1024/pdi->blksize), + hrec); + len += size; pos = begin + len; + } else { + pdi->devtype = 0xff; + } + + if (pdi->devtype == 0) { + /* search retries/reassigns */ + for (k = 0; k < pds->count; ++k) { + if (pds->list[k].tid == pdi->target_id && + pds->list[k].lun == pdi->lun) { + size = sprintf(buffer+len, + " Retries: \t%-6d \tReassigns: \t%d\n", + pds->list[k].retries, + pds->list[k].reassigns); + len += size; pos = begin + len; + break; + } + } + /* 2.c grown defects */ + TRACE2(("scsi_drv_defcnt() chn %d dev %d\n", + i, ha->raw[i].id_list[j])); + pdef = (gdth_defcnt_str *)ha->pscratch; + gdtcmd.BoardNode = LOCALBOARD; + gdtcmd.Service = CACHESERVICE; + gdtcmd.OpCode = GDT_IOCTL; + gdtcmd.u.ioctl.p_param = virt_to_bus(pdef); + gdtcmd.u.ioctl.param_size = sizeof(gdth_defcnt_str); + gdtcmd.u.ioctl.subfunc = SCSI_DEF_CNT | L_CTRL_PATTERN; + gdtcmd.u.ioctl.channel = + ha->raw[i].address | ha->raw[i].id_list[j]; + pdef->sddc_type = 0x08; + gdth_do_cmd(&scp, &gdtcmd, 30); + if (scp.SCp.Message == S_OK) { + size = sprintf(buffer+len, + " Grown Defects:\t%d\n", + pdef->sddc_cnt); + len += size; pos = begin + len; + } + } + } + } + gdth_ioctl_free(hanum); + + if (!flag) { + size = sprintf(buffer+len, "\n --\n"); + len += size; pos = begin + len; + } + if (pos < offset) { + len = 0; + begin = pos; + } + if (pos > offset + length) + goto stop_output; + + /* 3. about logical drives */ + size = sprintf(buffer+len,"\nLogical Drives:"); + len += size; pos = begin + len; + flag = FALSE; + + if (!gdth_ioctl_alloc(hanum, GDTH_SCRATCH)) + goto stop_output; + for (i = 0; i < MAX_HDRIVES; ++i) { + if (!ha->hdr[i].is_logdrv) + continue; + drv_no = i; + j = k = 0; + is_mirr = FALSE; + do { + /* 3.a log. drive info */ + TRACE2(("cache_drv_info() drive no %d\n",drv_no)); + pcdi = (gdth_cdrinfo_str *)ha->pscratch; + gdtcmd.BoardNode = LOCALBOARD; + gdtcmd.Service = CACHESERVICE; + gdtcmd.OpCode = GDT_IOCTL; + gdtcmd.u.ioctl.p_param = virt_to_bus(pcdi); + gdtcmd.u.ioctl.param_size = sizeof(gdth_cdrinfo_str); + gdtcmd.u.ioctl.subfunc = CACHE_DRV_INFO; + gdtcmd.u.ioctl.channel = drv_no; + gdth_do_cmd(&scp, &gdtcmd, 30); + if (scp.SCp.Message != S_OK) + break; + pcdi->ld_dtype >>= 16; + j++; + if (pcdi->ld_dtype > 2) { + strcpy(hrec, "missing"); + } else if (pcdi->ld_error & 1) { + strcpy(hrec, "fault"); + } else if (pcdi->ld_error & 2) { + strcpy(hrec, "invalid"); + k++; j--; + } else { + strcpy(hrec, "ok"); + } + + if (drv_no == i) { + size = sprintf(buffer+len, + "\n Number: \t%-2d \tStatus: \t%s\n", + drv_no, hrec); + len += size; pos = begin + len; + flag = TRUE; + no_mdrv = pcdi->cd_ldcnt; + if (no_mdrv > 1 || pcdi->ld_slave != -1) { + is_mirr = TRUE; + strcpy(hrec, "RAID-1"); + } else if (pcdi->ld_dtype == 0) { + strcpy(hrec, "Disk"); + } else if (pcdi->ld_dtype == 1) { + strcpy(hrec, "RAID-0"); + } else if (pcdi->ld_dtype == 2) { + strcpy(hrec, "Chain"); + } else { + strcpy(hrec, "???"); + } + size = sprintf(buffer+len, + " Capacity [MB]:\t%-6d \tType: \t%s\n", + pcdi->ld_blkcnt/(1024*1024/pcdi->ld_blksize), + hrec); + len += size; pos = begin + len; + } else { + size = sprintf(buffer+len, + " Slave Number: \t%-2d \tStatus: \t%s\n", + drv_no & 0x7fff, hrec); + len += size; pos = begin + len; + } + drv_no = pcdi->ld_slave; + } while (drv_no != -1); + + if (is_mirr) { + size = sprintf(buffer+len, + " Missing Drv.: \t%-2d \tInvalid Drv.: \t%d\n", + no_mdrv - j - k, k); + len += size; pos = begin + len; + } + + if (!ha->hdr[i].is_arraydrv) + strcpy(hrec, "--"); + else + sprintf(hrec, "%d", ha->hdr[i].master_no); + size = sprintf(buffer+len, + " To Array Drv.:\t%s\n", hrec); + len += size; pos = begin + len; + } + gdth_ioctl_free(hanum); + + if (!flag) { + size = sprintf(buffer+len, "\n --\n"); + len += size; pos = begin + len; + } + if (pos < offset) { + len = 0; + begin = pos; + } + if (pos > offset + length) + goto stop_output; + + /* 4. about array drives */ + size = sprintf(buffer+len,"\nArray Drives:"); + len += size; pos = begin + len; + flag = FALSE; + + if (!gdth_ioctl_alloc(hanum, GDTH_SCRATCH)) + goto stop_output; + for (i = 0; i < MAX_HDRIVES; ++i) { + if (!(ha->hdr[i].is_arraydrv && ha->hdr[i].is_master)) + continue; + /* 4.a array drive info */ + TRACE2(("array_info() drive no %d\n",i)); + pai = (gdth_arrayinf_str *)ha->pscratch; + gdtcmd.BoardNode = LOCALBOARD; + gdtcmd.Service = CACHESERVICE; + gdtcmd.OpCode = GDT_IOCTL; + gdtcmd.u.ioctl.p_param = virt_to_bus(pai); + gdtcmd.u.ioctl.param_size = sizeof(gdth_arrayinf_str); + gdtcmd.u.ioctl.subfunc = ARRAY_INFO | LA_CTRL_PATTERN; + gdtcmd.u.ioctl.channel = i; + gdth_do_cmd(&scp, &gdtcmd, 30); + if (scp.SCp.Message == S_OK) { + if (pai->ai_state == 0) + strcpy(hrec, "idle"); + else if (pai->ai_state == 2) + strcpy(hrec, "build"); + else if (pai->ai_state == 4) + strcpy(hrec, "ready"); + else if (pai->ai_state == 6) + strcpy(hrec, "fail"); + else if (pai->ai_state == 8 || pai->ai_state == 10) + strcpy(hrec, "rebuild"); + else + strcpy(hrec, "error"); + if (pai->ai_ext_state & 0x10) + strcat(hrec, "/expand"); + else if (pai->ai_ext_state & 0x1) + strcat(hrec, "/patch"); + size = sprintf(buffer+len, + "\n Number: \t%-2d \tStatus: \t%s\n", + i,hrec); + len += size; pos = begin + len; + flag = TRUE; + + if (pai->ai_type == 0) + strcpy(hrec, "RAID-0"); + else if (pai->ai_type == 4) + strcpy(hrec, "RAID-4"); + else if (pai->ai_type == 5) + strcpy(hrec, "RAID-5"); + else + strcpy(hrec, "RAID-10"); + size = sprintf(buffer+len, + " Capacity [MB]:\t%-6d \tType: \t%s\n", + pai->ai_size/(1024*1024/pai->ai_secsize), + hrec); + len += size; pos = begin + len; + } + } + gdth_ioctl_free(hanum); + + if (!flag) { + size = sprintf(buffer+len, "\n --\n"); + len += size; pos = begin + len; + } + if (pos < offset) { + len = 0; + begin = pos; + } + if (pos > offset + length) + goto stop_output; + + /* 5. about host drives */ + size = sprintf(buffer+len,"\nHost Drives:"); + len += size; pos = begin + len; + flag = FALSE; + + if (!gdth_ioctl_alloc(hanum, GDTH_SCRATCH)) + goto stop_output; + for (i = 0; i < MAX_HDRIVES; ++i) { + if (!ha->hdr[i].is_logdrv || + (ha->hdr[i].is_arraydrv && !ha->hdr[i].is_master)) + continue; + /* 5.a get host drive list */ + TRACE2(("host_get() drv_no %d\n",i)); + phg = (gdth_hget_str *)ha->pscratch; + gdtcmd.BoardNode = LOCALBOARD; + gdtcmd.Service = CACHESERVICE; + gdtcmd.OpCode = GDT_IOCTL; + gdtcmd.u.ioctl.p_param = virt_to_bus(phg); + gdtcmd.u.ioctl.param_size = sizeof(gdth_hget_str); + gdtcmd.u.ioctl.subfunc = HOST_GET | LA_CTRL_PATTERN; + gdtcmd.u.ioctl.channel = i; + phg->entries = MAX_HDRIVES; + phg->offset = GDTOFFSOF(gdth_hget_str, entry[0]); + gdth_do_cmd(&scp, &gdtcmd, 30); + if (scp.SCp.Message != S_OK) { + ha->hdr[i].ldr_no = i; + ha->hdr[i].rw_attribs = 0; + ha->hdr[i].start_sec = 0; + } else { + for (j = 0; j < phg->entries; ++j) { + k = phg->entry[j].host_drive; + if (k >= MAX_HDRIVES) + continue; + ha->hdr[k].ldr_no = phg->entry[j].log_drive; + ha->hdr[k].rw_attribs = phg->entry[j].rw_attribs; + ha->hdr[k].start_sec = phg->entry[j].start_sec; + } + } + TRACE2(("host_get entries %d status %d\n", + phg->entries, scp.SCp.Message)); + } + gdth_ioctl_free(hanum); + + for (i = 0; i < MAX_HDRIVES; ++i) { + if (!(ha->hdr[i].present)) + continue; + + size = sprintf(buffer+len, + "\n Number: \t%-2d \tArr/Log. Drive:\t%d\n", + i, ha->hdr[i].ldr_no); + len += size; pos = begin + len; + flag = TRUE; + + size = sprintf(buffer+len, + " Capacity [MB]:\t%-6d \tStart Sector: \t%d\n", + ha->hdr[i].size/2048, ha->hdr[i].start_sec); + len += size; pos = begin + len; + } + + if (!flag) { + size = sprintf(buffer+len, "\n --\n"); + len += size; pos = begin + len; + } + if (pos < offset) { + len = 0; + begin = pos; + } + if (pos > offset + length) + goto stop_output; + } + + /* controller events */ + size = sprintf(buffer+len,"\nController Events:\n"); + len += size; pos = begin + len; + + for (id = -1;;) { + id = gdth_read_event(ha, id, &estr); + if (estr.event_source == 0) + break; + if (estr.event_data.eu.driver.ionode == hanum && + estr.event_source == ES_ASYNC) { + gdth_log_event(&estr.event_data, hrec); + do_gettimeofday(&tv); + sec = (int)(tv.tv_sec - estr.first_stamp); + if (sec < 0) sec = 0; + size = sprintf(buffer+len," date- %02d:%02d:%02d\t%s\n", + sec/3600, sec%3600/60, sec%60, hrec); + len += size; pos = begin + len; + if (pos < offset) { + len = 0; + begin = pos; + } + if (pos > offset + length) + goto stop_output; + } + if (id == -1) + break; + } } else { + /* request from tool (GDTMON,..) */ piord = (gdth_iord_str *)ha->pscratch; if (piord == NULL) goto stop_output; @@ -474,6 +928,22 @@ return(len); } +static void gdth_do_cmd(Scsi_Cmnd *scp,gdth_cmd_str *gdtcmd,int timeout) +{ + char cmnd[12]; + struct semaphore sem = MUTEX_LOCKED; + + TRACE2(("gdth_do_cmd()\n")); + memset(cmnd, 0, 12); + scp->request.rq_status = RQ_SCSI_BUSY; + scp->request.sem = &sem; + scp->SCp.this_residual = IOCTL_PRI; + GDTH_LOCK_SCSI_DOCMD(); + scsi_do_cmd(scp, cmnd, gdtcmd, sizeof(gdth_cmd_str), + gdth_scsi_done, timeout*HZ, 1); + GDTH_UNLOCK_SCSI_DOCMD(); + down(&sem); +} void gdth_scsi_done(Scsi_Cmnd *scp) { @@ -492,7 +962,7 @@ int ret_val; if (size == 0 || size > GDTH_SCRATCH) - return -1; + return FALSE; ha = HADATA(gdth_ctr_tab[hanum]); GDTH_LOCK_HA(ha, flags); diff -ur --new-file old/linux/drivers/scsi/gdth_proc.h new/linux/drivers/scsi/gdth_proc.h --- old/linux/drivers/scsi/gdth_proc.h Mon Jan 11 19:17:20 1999 +++ new/linux/drivers/scsi/gdth_proc.h Mon Apr 12 18:56:16 1999 @@ -2,7 +2,7 @@ #define _GDTH_PROC_H /* gdth_proc.h - * $Id: gdth_proc.h,v 1.5 1998/12/17 15:43:53 achim Exp $ + * $Id: gdth_proc.h,v 1.6 1999/03/05 14:32:36 achim Exp $ */ static int gdth_set_info(char *buffer,int length,int vh,int hanum,int busnum); @@ -18,6 +18,7 @@ static void gdth_start_timeout(int hanum, int busnum, int id); static int gdth_update_timeout(int hanum, Scsi_Cmnd *scp, int timeout); +static void gdth_do_cmd(Scsi_Cmnd *scp,gdth_cmd_str *cmd,int timeout); void gdth_scsi_done(Scsi_Cmnd *scp); #endif diff -ur --new-file old/linux/drivers/scsi/hosts.c new/linux/drivers/scsi/hosts.c --- old/linux/drivers/scsi/hosts.c Mon Jan 18 03:32:26 1999 +++ new/linux/drivers/scsi/hosts.c Mon Apr 12 18:51:04 1999 @@ -195,6 +195,10 @@ #include "53c7,8xx.h" #endif +#ifdef CONFIG_SCSI_SYM53C8XX +#include "sym53c8xx.h" +#endif + #ifdef CONFIG_SCSI_NCR53C8XX #include "ncr53c8xx.h" #endif @@ -223,6 +227,10 @@ #include "NCR53c406a.h" #endif +#ifdef CONFIG_SCSI_SYM53C416 +#include "sym53c416.h" +#endif + #ifdef CONFIG_SCSI_DC390T #include "dc390.h" #endif @@ -283,6 +291,10 @@ #include "ini9100u.h" #endif +#ifdef CONFIG_SCSI_INIA100 +#include "inia100.h" +#endif + #ifdef CONFIG_SCSI_DEBUG #include "scsi_debug.h" #endif @@ -452,7 +464,7 @@ #ifdef CONFIG_SCSI_AIC7XXX AIC7XXX, #endif -#ifdef CONFIG_FD_MCS +#ifdef CONFIG_SCSI_FD_MCS FD_MCS, #endif #ifdef CONFIG_SCSI_FUTURE_DOMAIN @@ -467,6 +479,9 @@ #ifdef CONFIG_SCSI_NCR53C406A /* 53C406A should come before QLOGIC */ NCR53c406a, #endif +#ifdef CONFIG_SCSI_SYM53C416 + SYM53C416, +#endif #ifdef CONFIG_SCSI_QLOGIC_FAS QLOGICFAS, #endif @@ -491,6 +506,9 @@ #ifdef CONFIG_SCSI_NCR53C7xx NCR53c7xx, #endif +#ifdef CONFIG_SCSI_SYM53C8XX + SYM53C8XX, +#endif #ifdef CONFIG_SCSI_NCR53C8XX NCR53C8XX, #endif @@ -532,6 +550,9 @@ #endif #ifdef CONFIG_SCSI_INITIO INI9100U, +#endif +#ifdef CONFIG_SCSI_INIA100 + INIA100, #endif #ifdef CONFIG_SCSI_QLOGICPTI QLOGICPTI, diff -ur --new-file old/linux/drivers/scsi/i60uscsi.c new/linux/drivers/scsi/i60uscsi.c --- old/linux/drivers/scsi/i60uscsi.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/scsi/i60uscsi.c Thu Feb 25 01:27:54 1999 @@ -0,0 +1,956 @@ +/************************************************************************** + * Initio A100 device driver for Linux. + * + * Copyright (c) 1994-1998 Initio Corporation + * All rights reserved. + * + * 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; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * -------------------------------------------------------------------------- + * + * 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, + * without modification, immediately at the beginning of the file. + * 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. + * + * Where this Software is combined with software released under the terms of + * the GNU Public License ("GPL") and the terms of the GPL would require the + * combined work to also be released under the terms of the GPL, the terms + * and conditions of this License will apply in addition to those of the + * GPL with the exception of any terms or conditions of this License that + * conflict with, or are expressly prohibited by, the GPL. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + ************************************************************************* + * + * module: i60uscsi.c + * DESCRIPTION: + * This is the Linux low-level SCSI driver for Initio INIA100 SCSI host + * adapters + * + * 07/02/98 hl - v.91n Initial drivers. + * 09/14/98 hl - v1.01 Support new Kernel. + * 09/22/98 hl - v1.01a Support reset. + * 09/24/98 hl - v1.01b Fixed reset. + * 10/05/98 hl - v1.02 split the source code and release. + * 12/19/98 bv - v1.02a Use spinlocks for 2.1.95 and up + **************************************************************************/ + +#ifndef CVT_LINUX_VERSION +#define CVT_LINUX_VERSION(V,P,S) (V * 65536 + P * 256 + S) +#endif + +#include +#include +#include "i60uscsi.h" + + +/* ---- INTERNAL FUNCTIONS ---- */ +static UCHAR waitChipReady(ORC_HCS * hcsp); +static UCHAR waitFWReady(ORC_HCS * hcsp); +static UCHAR waitFWReady(ORC_HCS * hcsp); +static UCHAR waitSCSIRSTdone(ORC_HCS * hcsp); +static UCHAR waitHDOoff(ORC_HCS * hcsp); +static UCHAR waitHDIset(ORC_HCS * hcsp, UCHAR * pData); +static unsigned short get_FW_version(ORC_HCS * hcsp); +static UCHAR set_NVRAM(ORC_HCS * hcsp, unsigned char address, unsigned char value); +static UCHAR get_NVRAM(ORC_HCS * hcsp, unsigned char address, unsigned char *pDataIn); +static int se2_rd_all(ORC_HCS * hcsp); +static void se2_update_all(ORC_HCS * hcsp); /* setup default pattern */ +static void read_eeprom(ORC_HCS * hcsp); +static UCHAR load_FW(ORC_HCS * hcsp); +static void setup_SCBs(ORC_HCS * hcsp); +static void initAFlag(ORC_HCS * hcsp); +ORC_SCB *orc_alloc_scb(ORC_HCS * hcsp); + +/* ---- EXTERNAL FUNCTIONS ---- */ +extern void inia100SCBPost(BYTE * pHcb, BYTE * pScb); + +/* ---- INTERNAL VARIABLES ---- */ +ORC_HCS orc_hcs[MAX_SUPPORTED_ADAPTERS]; +static INIA100_ADPT_STRUCT inia100_adpt[MAX_SUPPORTED_ADAPTERS]; +/* set by inia100_setup according to the command line */ +int orc_num_scb; + +NVRAM nvram, *nvramp = &nvram; +static UCHAR dftNvRam[64] = +{ +/*----------header -------------*/ + 0x01, /* 0x00: Sub System Vendor ID 0 */ + 0x11, /* 0x01: Sub System Vendor ID 1 */ + 0x60, /* 0x02: Sub System ID 0 */ + 0x10, /* 0x03: Sub System ID 1 */ + 0x00, /* 0x04: SubClass */ + 0x01, /* 0x05: Vendor ID 0 */ + 0x11, /* 0x06: Vendor ID 1 */ + 0x60, /* 0x07: Device ID 0 */ + 0x10, /* 0x08: Device ID 1 */ + 0x00, /* 0x09: Reserved */ + 0x00, /* 0x0A: Reserved */ + 0x01, /* 0x0B: Revision of Data Structure */ + /* -- Host Adapter Structure --- */ + 0x01, /* 0x0C: Number Of SCSI Channel */ + 0x01, /* 0x0D: BIOS Configuration 1 */ + 0x00, /* 0x0E: BIOS Configuration 2 */ + 0x00, /* 0x0F: BIOS Configuration 3 */ + /* --- SCSI Channel 0 Configuration --- */ + 0x07, /* 0x10: H/A ID */ + 0x83, /* 0x11: Channel Configuration */ + 0x20, /* 0x12: MAX TAG per target */ + 0x0A, /* 0x13: SCSI Reset Recovering time */ + 0x00, /* 0x14: Channel Configuration4 */ + 0x00, /* 0x15: Channel Configuration5 */ + /* SCSI Channel 0 Target Configuration */ + /* 0x16-0x25 */ + 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, + 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, + /* --- SCSI Channel 1 Configuration --- */ + 0x07, /* 0x26: H/A ID */ + 0x83, /* 0x27: Channel Configuration */ + 0x20, /* 0x28: MAX TAG per target */ + 0x0A, /* 0x29: SCSI Reset Recovering time */ + 0x00, /* 0x2A: Channel Configuration4 */ + 0x00, /* 0x2B: Channel Configuration5 */ + /* SCSI Channel 1 Target Configuration */ + /* 0x2C-0x3B */ + 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, + 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, + 0x00, /* 0x3C: Reserved */ + 0x00, /* 0x3D: Reserved */ + 0x00, /* 0x3E: Reserved */ + 0x00 /* 0x3F: Checksum */ +}; + + +/***************************************************************************/ +static void waitForPause(unsigned amount) +{ + ULONG the_time = jiffies + amount; /* 0.01 seconds per jiffy */ + +#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95) + while (time_before_eq(jiffies, the_time)); +#else + while (jiffies < the_time); +#endif +} + +/***************************************************************************/ +UCHAR waitChipReady(ORC_HCS * hcsp) +{ + int i; + + for (i = 0; i < 2000; i++) { /* Wait 1 second for report timeout */ + if (ORC_RD(hcsp->HCS_Base, ORC_HCTRL) & HOSTSTOP) /* Wait HOSTSTOP set */ + return (TRUE); + waitForPause(5); /* wait 500ms before try again */ + } + return (FALSE); +} + +/***************************************************************************/ +UCHAR waitFWReady(ORC_HCS * hcsp) +{ + int i; + + for (i = 0; i < 2000; i++) { /* Wait 1 second for report timeout */ + if (ORC_RD(hcsp->HCS_Base, ORC_HSTUS) & RREADY) /* Wait READY set */ + return (TRUE); + waitForPause(5); /* wait 500ms before try again */ + } + return (FALSE); +} + +/***************************************************************************/ +UCHAR waitSCSIRSTdone(ORC_HCS * hcsp) +{ + int i; + + for (i = 0; i < 2000; i++) { /* Wait 1 second for report timeout */ + if (!(ORC_RD(hcsp->HCS_Base, ORC_HCTRL) & SCSIRST)) /* Wait SCSIRST done */ + return (TRUE); + waitForPause(5); /* wait 500ms before try again */ + } + return (FALSE); +} + +/***************************************************************************/ +UCHAR waitHDOoff(ORC_HCS * hcsp) +{ + int i; + + for (i = 0; i < 2000; i++) { /* Wait 1 second for report timeout */ + if (!(ORC_RD(hcsp->HCS_Base, ORC_HCTRL) & HDO)) /* Wait HDO off */ + return (TRUE); + waitForPause(5); /* wait 500ms before try again */ + } + return (FALSE); +} + +/***************************************************************************/ +UCHAR waitHDIset(ORC_HCS * hcsp, UCHAR * pData) +{ + int i; + + for (i = 0; i < 2000; i++) { /* Wait 1 second for report timeout */ + if ((*pData = ORC_RD(hcsp->HCS_Base, ORC_HSTUS)) & HDI) + return (TRUE); /* Wait HDI set */ + waitForPause(5); /* wait 500ms before try again */ + } + return (FALSE); +} + +/***************************************************************************/ +unsigned short get_FW_version(ORC_HCS * hcsp) +{ + UCHAR bData; + union { + unsigned short sVersion; + unsigned char cVersion[2]; + } Version; + + ORC_WR(hcsp->HCS_Base + ORC_HDATA, ORC_CMD_VERSION); + ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO); + if (waitHDOoff(hcsp) == FALSE) /* Wait HDO off */ + return (FALSE); + + if (waitHDIset(hcsp, &bData) == FALSE) /* Wait HDI set */ + return (FALSE); + Version.cVersion[0] = ORC_RD(hcsp->HCS_Base, ORC_HDATA); + ORC_WR(hcsp->HCS_Base + ORC_HSTUS, bData); /* Clear HDI */ + + if (waitHDIset(hcsp, &bData) == FALSE) /* Wait HDI set */ + return (FALSE); + Version.cVersion[1] = ORC_RD(hcsp->HCS_Base, ORC_HDATA); + ORC_WR(hcsp->HCS_Base + ORC_HSTUS, bData); /* Clear HDI */ + + return (Version.sVersion); +} + +/***************************************************************************/ +UCHAR set_NVRAM(ORC_HCS * hcsp, unsigned char address, unsigned char value) +{ + ORC_WR(hcsp->HCS_Base + ORC_HDATA, ORC_CMD_SET_NVM); /* Write command */ + ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO); + if (waitHDOoff(hcsp) == FALSE) /* Wait HDO off */ + return (FALSE); + + ORC_WR(hcsp->HCS_Base + ORC_HDATA, address); /* Write address */ + ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO); + if (waitHDOoff(hcsp) == FALSE) /* Wait HDO off */ + return (FALSE); + + ORC_WR(hcsp->HCS_Base + ORC_HDATA, value); /* Write value */ + ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO); + if (waitHDOoff(hcsp) == FALSE) /* Wait HDO off */ + return (FALSE); + + return (TRUE); +} + +/***************************************************************************/ +UCHAR get_NVRAM(ORC_HCS * hcsp, unsigned char address, unsigned char *pDataIn) +{ + unsigned char bData; + + ORC_WR(hcsp->HCS_Base + ORC_HDATA, ORC_CMD_GET_NVM); /* Write command */ + ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO); + if (waitHDOoff(hcsp) == FALSE) /* Wait HDO off */ + return (FALSE); + + ORC_WR(hcsp->HCS_Base + ORC_HDATA, address); /* Write address */ + ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO); + if (waitHDOoff(hcsp) == FALSE) /* Wait HDO off */ + return (FALSE); + + if (waitHDIset(hcsp, &bData) == FALSE) /* Wait HDI set */ + return (FALSE); + *pDataIn = ORC_RD(hcsp->HCS_Base, ORC_HDATA); + ORC_WR(hcsp->HCS_Base + ORC_HSTUS, bData); /* Clear HDI */ + + return (TRUE); +} + +/***************************************************************************/ +void orc_exec_scb(ORC_HCS * hcsp, ORC_SCB * scbp) +{ + scbp->SCB_Status = SCB_POST; + ORC_WR(hcsp->HCS_Base + ORC_PQUEUE, scbp->SCB_ScbIdx); + return; +} + + +/*********************************************************************** + Read SCSI H/A configuration parameters from serial EEPROM +************************************************************************/ +int se2_rd_all(ORC_HCS * hcsp) +{ + int i; + UCHAR *np, chksum = 0; + + np = (UCHAR *) nvramp; + for (i = 0; i < 64; i++, np++) { /* <01> */ + if (get_NVRAM(hcsp, (unsigned char) i, np) == FALSE) + return -1; +// *np++ = get_NVRAM(hcsp, (unsigned char ) i); + } + +/*------ Is ckecksum ok ? ------*/ + np = (UCHAR *) nvramp; + for (i = 0; i < 63; i++) + chksum += *np++; + + if (nvramp->CheckSum != (UCHAR) chksum) + return -1; + return 1; +} + +/************************************************************************ + Update SCSI H/A configuration parameters from serial EEPROM +*************************************************************************/ +void se2_update_all(ORC_HCS * hcsp) +{ /* setup default pattern */ + int i; + UCHAR *np, *np1, chksum = 0; + + /* Calculate checksum first */ + np = (UCHAR *) dftNvRam; + for (i = 0; i < 63; i++) + chksum += *np++; + *np = chksum; + + np = (UCHAR *) dftNvRam; + np1 = (UCHAR *) nvramp; + for (i = 0; i < 64; i++, np++, np1++) { + if (*np != *np1) { + set_NVRAM(hcsp, (unsigned char) i, *np); + } + } + return; +} + +/************************************************************************* + Function name : read_eeprom +**************************************************************************/ +void read_eeprom(ORC_HCS * hcsp) +{ + if (se2_rd_all(hcsp) != 1) { + se2_update_all(hcsp); /* setup default pattern */ + se2_rd_all(hcsp); /* load again */ + } +} + + +/***************************************************************************/ +UCHAR load_FW(ORC_HCS * hcsp) +{ + U32 dData; + USHORT wBIOSAddress; + USHORT i; + UCHAR *pData, bData; + + + bData = ORC_RD(hcsp->HCS_Base, ORC_GCFG); + ORC_WR(hcsp->HCS_Base + ORC_GCFG, bData | EEPRG); /* Enable EEPROM programming */ + ORC_WR(hcsp->HCS_Base + ORC_EBIOSADR2, 0x00); + ORC_WRSHORT(hcsp->HCS_Base + ORC_EBIOSADR0, 0x00); + if (ORC_RD(hcsp->HCS_Base, ORC_EBIOSDATA) != 0x55) { + ORC_WR(hcsp->HCS_Base + ORC_GCFG, bData); /* Disable EEPROM programming */ + return (FALSE); + } + ORC_WRSHORT(hcsp->HCS_Base + ORC_EBIOSADR0, 0x01); + if (ORC_RD(hcsp->HCS_Base, ORC_EBIOSDATA) != 0xAA) { + ORC_WR(hcsp->HCS_Base + ORC_GCFG, bData); /* Disable EEPROM programming */ + return (FALSE); + } + ORC_WR(hcsp->HCS_Base + ORC_RISCCTL, PRGMRST | DOWNLOAD); /* Enable SRAM programming */ + pData = (UCHAR *) & dData; + dData = 0; /* Initial FW address to 0 */ + ORC_WRSHORT(hcsp->HCS_Base + ORC_EBIOSADR0, 0x10); + *pData = ORC_RD(hcsp->HCS_Base, ORC_EBIOSDATA); /* Read from BIOS */ + ORC_WRSHORT(hcsp->HCS_Base + ORC_EBIOSADR0, 0x11); + *(pData + 1) = ORC_RD(hcsp->HCS_Base, ORC_EBIOSDATA); /* Read from BIOS */ + ORC_WRSHORT(hcsp->HCS_Base + ORC_EBIOSADR0, 0x12); + *(pData + 2) = ORC_RD(hcsp->HCS_Base, ORC_EBIOSDATA); /* Read from BIOS */ + ORC_WR(hcsp->HCS_Base + ORC_EBIOSADR2, *(pData + 2)); + ORC_WRLONG(hcsp->HCS_Base + ORC_FWBASEADR, dData); /* Write FW address */ + + wBIOSAddress = (USHORT) dData; /* FW code locate at BIOS address + ? */ + for (i = 0, pData = (UCHAR *) & dData; /* Download the code */ + i < 0x1000; /* Firmware code size = 4K */ + i++, wBIOSAddress++) { + ORC_WRSHORT(hcsp->HCS_Base + ORC_EBIOSADR0, wBIOSAddress); + *pData++ = ORC_RD(hcsp->HCS_Base, ORC_EBIOSDATA); /* Read from BIOS */ + if ((i % 4) == 3) { + ORC_WRLONG(hcsp->HCS_Base + ORC_RISCRAM, dData); /* Write every 4 bytes */ + pData = (UCHAR *) & dData; + } + } + + ORC_WR(hcsp->HCS_Base + ORC_RISCCTL, PRGMRST | DOWNLOAD); /* Reset program count 0 */ + wBIOSAddress -= 0x1000; /* Reset the BIOS adddress */ + for (i = 0, pData = (UCHAR *) & dData; /* Check the code */ + i < 0x1000; /* Firmware code size = 4K */ + i++, wBIOSAddress++) { + ORC_WRSHORT(hcsp->HCS_Base + ORC_EBIOSADR0, wBIOSAddress); + *pData++ = ORC_RD(hcsp->HCS_Base, ORC_EBIOSDATA); /* Read from BIOS */ + if ((i % 4) == 3) { + if (ORC_RDLONG(hcsp->HCS_Base, ORC_RISCRAM) != dData) { + ORC_WR(hcsp->HCS_Base + ORC_RISCCTL, PRGMRST); /* Reset program to 0 */ + ORC_WR(hcsp->HCS_Base + ORC_GCFG, bData); /*Disable EEPROM programming */ + return (FALSE); + } + pData = (UCHAR *) & dData; + } + } + ORC_WR(hcsp->HCS_Base + ORC_RISCCTL, PRGMRST); /* Reset program to 0 */ + ORC_WR(hcsp->HCS_Base + ORC_GCFG, bData); /* Disable EEPROM programming */ + return (TRUE); +} + +/***************************************************************************/ +void setup_SCBs(ORC_HCS * hcsp) +{ + ORC_SCB *pVirScb; + int i; + UCHAR j; + ESCB *pVirEscb; + PVOID pPhysEscb; + PVOID tPhysEscb; + + j = 0; + pVirScb = NULL; + tPhysEscb = (PVOID) NULL; + pPhysEscb = (PVOID) NULL; + /* Setup SCB HCS_Base and SCB Size registers */ + ORC_WR(hcsp->HCS_Base + ORC_SCBSIZE, orc_num_scb); /* Total number of SCBs */ + /* SCB HCS_Base address 0 */ + ORC_WRLONG(hcsp->HCS_Base + ORC_SCBBASE0, hcsp->HCS_physScbArray); + /* SCB HCS_Base address 1 */ + ORC_WRLONG(hcsp->HCS_Base + ORC_SCBBASE1, hcsp->HCS_physScbArray); + + /* setup scatter list address with one buffer */ + pVirScb = (ORC_SCB *) hcsp->HCS_virScbArray; + pVirEscb = (ESCB *) hcsp->HCS_virEscbArray; + + for (i = 0; i < orc_num_scb; i++) { +#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0) + pPhysEscb = (PVOID) ((ULONG) hcsp->HCS_virEscbArray + (sizeof(ESCB) * i)); + pVirScb->SCB_SGPAddr = (U32) VIRT_TO_BUS(pPhysEscb); + pVirScb->SCB_SensePAddr = (U32) VIRT_TO_BUS(pPhysEscb); +#else + pPhysEscb = (PVOID) (hcsp->HCS_physEscbArray + (sizeof(ESCB) * i)); + pVirScb->SCB_SGPAddr = (U32) pPhysEscb; + pVirScb->SCB_SensePAddr = (U32) pPhysEscb; +#endif + pVirScb->SCB_EScb = pVirEscb; + pVirScb->SCB_ScbIdx = i; + pVirScb++; + pVirEscb++; + } + + return; +} + +/***************************************************************************/ +static void initAFlag(ORC_HCS * hcsp) +{ + UCHAR i, j; + + for (i = 0; i < MAX_CHANNELS; i++) { + for (j = 0; j < 8; j++) { + hcsp->BitAllocFlag[i][j] = 0xffffffff; + } + } +} + +/***************************************************************************/ +int init_orchid(ORC_HCS * hcsp) +{ + UBYTE *readBytep; + USHORT revision; + UCHAR i; + + initAFlag(hcsp); + ORC_WR(hcsp->HCS_Base + ORC_GIMSK, 0xFF); /* Disable all interrupt */ + if (ORC_RD(hcsp->HCS_Base, ORC_HSTUS) & RREADY) { /* Orchid is ready */ + revision = get_FW_version(hcsp); + if (revision == 0xFFFF) { + ORC_WR(hcsp->HCS_Base + ORC_HCTRL, DEVRST); /* Reset Host Adapter */ + if (waitChipReady(hcsp) == FALSE) + return (-1); + load_FW(hcsp); /* Download FW */ + setup_SCBs(hcsp); /* Setup SCB HCS_Base and SCB Size registers */ + ORC_WR(hcsp->HCS_Base + ORC_HCTRL, 0); /* clear HOSTSTOP */ + if (waitFWReady(hcsp) == FALSE) + return (-1); + /* Wait for firmware ready */ + } else { + setup_SCBs(hcsp); /* Setup SCB HCS_Base and SCB Size registers */ + } + } else { /* Orchid is not Ready */ + ORC_WR(hcsp->HCS_Base + ORC_HCTRL, DEVRST); /* Reset Host Adapter */ + if (waitChipReady(hcsp) == FALSE) + return (-1); + load_FW(hcsp); /* Download FW */ + setup_SCBs(hcsp); /* Setup SCB HCS_Base and SCB Size registers */ + ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO); /* Do Hardware Reset & */ + + /* clear HOSTSTOP */ + if (waitFWReady(hcsp) == FALSE) /* Wait for firmware ready */ + return (-1); + } + +/*------------- get serial EEProm settting -------*/ + + read_eeprom(hcsp); + + if (nvramp->Revision != 1) + return (-1); + + hcsp->HCS_SCSI_ID = nvramp->SCSI0Id; + hcsp->HCS_BIOS = nvramp->BIOSConfig1; + hcsp->HCS_MaxTar = MAX_TARGETS; + readBytep = (UCHAR *) & (nvramp->Target00Config); + for (i = 0; i < 16; readBytep++, i++) { + hcsp->TargetFlag[i] = *readBytep; + hcsp->MaximumTags[i] = orc_num_scb; + } /* for */ + + if (nvramp->SCSI0Config & NCC_BUSRESET) { /* Reset SCSI bus */ + hcsp->HCS_Flags |= HCF_SCSI_RESET; + } + ORC_WR(hcsp->HCS_Base + ORC_GIMSK, 0xFB); /* enable RP FIFO interrupt */ + return (0); +} + +/***************************************************************************** + Function name : orc_reset_scsi_bus + Description : Reset registers, reset a hanging bus and + kill active and disconnected commands for target w/o soft reset + Input : pHCB - Pointer to host adapter structure + Output : None. + Return : pSRB - Pointer to SCSI request block. +*****************************************************************************/ +int orc_reset_scsi_bus(ORC_HCS * pHCB) +{ /* I need Host Control Block Information */ + ULONG flags; + +#if 0 + printk("inia100: enter inia100_reset\n"); +#endif + +#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95) + save_flags(flags); + cli(); +#else + spin_lock_irqsave(&(pHCB->BitAllocFlagLock), flags); +#endif + + initAFlag(pHCB); + /* reset scsi bus */ + ORC_WR(pHCB->HCS_Base + ORC_HCTRL, SCSIRST); + if (waitSCSIRSTdone(pHCB) == FALSE) { +#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95) + restore_flags(flags); +#else + spin_unlock_irqrestore(&(pHCB->BitAllocFlagLock), flags); +#endif + return (SCSI_RESET_ERROR); + } else { +#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95) + restore_flags(flags); +#else + spin_unlock_irqrestore(&(pHCB->BitAllocFlagLock), flags); +#endif + return (SCSI_RESET_SUCCESS); + } +} + +/***************************************************************************** + Function name : orc_device_reset + Description : Reset registers, reset a hanging bus and + kill active and disconnected commands for target w/o soft reset + Input : pHCB - Pointer to host adapter structure + Output : None. + Return : pSRB - Pointer to SCSI request block. +*****************************************************************************/ +int orc_device_reset(ORC_HCS * pHCB, ULONG SCpnt, unsigned int target, unsigned int ResetFlags) +{ /* I need Host Control Block Information */ + ORC_SCB *pScb; + ESCB *pVirEscb; + ORC_SCB *pVirScb; + UCHAR i; + ULONG flags; + +#if 0 + printk("inia100: enter inia100_reset\n"); +#endif + +#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95) + save_flags(flags); + cli(); +#else + spin_lock_irqsave(&(pHCB->BitAllocFlagLock), flags); +#endif + pScb = (ORC_SCB *) NULL; + pVirEscb = (ESCB *) NULL; + + /* setup scatter list address with one buffer */ + pVirScb = (ORC_SCB *) pHCB->HCS_virScbArray; + + initAFlag(pHCB); + /* device reset */ + for (i = 0; i < orc_num_scb; i++) { + pVirEscb = pVirScb->SCB_EScb; + if ((pVirScb->SCB_Status) && (pVirEscb->SCB_Srb == (unsigned char *) SCpnt)) + break; + pVirScb++; + } + + if (i == orc_num_scb) { + printk("Unable to Reset - No SCB Found\n"); +#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95) + restore_flags(flags); +#else + spin_unlock_irqrestore(&(pHCB->BitAllocFlagLock), flags); +#endif + return (SCSI_RESET_NOT_RUNNING); + } + if ((pScb = orc_alloc_scb(pHCB)) == NULL) { +#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95) + restore_flags(flags); +#else + spin_unlock_irqrestore(&(pHCB->BitAllocFlagLock), flags); +#endif + return (SCSI_RESET_NOT_RUNNING); + } + pScb->SCB_Opcode = ORC_BUSDEVRST; + pScb->SCB_Target = target; + pScb->SCB_HaStat = 0; + pScb->SCB_TaStat = 0; + pScb->SCB_Status = 0x0; + pScb->SCB_Link = 0xFF; + pScb->SCB_Reserved0 = 0; + pScb->SCB_Reserved1 = 0; + pScb->SCB_XferLen = 0; + pScb->SCB_SGLen = 0; + + pVirEscb->SCB_Srb = 0; + if (ResetFlags & SCSI_RESET_SYNCHRONOUS) { + pVirEscb->SCB_Srb = (unsigned char *) SCpnt; + } + orc_exec_scb(pHCB, pScb); /* Start execute SCB */ +#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95) + restore_flags(flags); +#else + spin_unlock_irqrestore(&(pHCB->BitAllocFlagLock), flags); +#endif + return SCSI_RESET_PENDING; +} + + +/***************************************************************************/ +ORC_SCB *orc_alloc_scb(ORC_HCS * hcsp) +{ + ORC_SCB *pTmpScb; + UCHAR Ch; + ULONG idx; + UCHAR index; + UCHAR i; + ULONG flags; + +#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95) + save_flags(flags); + cli(); +#else + spin_lock_irqsave(&(hcsp->BitAllocFlagLock), flags); +#endif + Ch = hcsp->HCS_Index; + for (i = 0; i < 8; i++) { + for (index = 0; index < 32; index++) { + if ((hcsp->BitAllocFlag[Ch][i] >> index) & 0x01) { + hcsp->BitAllocFlag[Ch][i] &= ~(1 << index); + break; + } + } + idx = index + 32 * i; + pTmpScb = (PVOID) ((ULONG) hcsp->HCS_virScbArray + (idx * sizeof(ORC_SCB))); +#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95) + restore_flags(flags); +#else + spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags); +#endif + return (pTmpScb); + } +#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95) + restore_flags(flags); +#else + spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags); +#endif + return (NULL); +} + + +/***************************************************************************/ +void orc_release_scb(ORC_HCS * hcsp, ORC_SCB * scbp) +{ + ULONG flags; + UCHAR Index; + UCHAR i; + UCHAR Ch; + +#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95) + save_flags(flags); + cli(); +#else + spin_lock_irqsave(&(hcsp->BitAllocFlagLock), flags); +#endif + Ch = hcsp->HCS_Index; + Index = scbp->SCB_ScbIdx; + i = Index / 32; + Index %= 32; + hcsp->BitAllocFlag[Ch][i] |= (1 << Index); +#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95) + restore_flags(flags); +#else + spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags); +#endif +} + + +/***************************************************************************** + Function name : Addinia100_into_Adapter_table + Description : This function will scan PCI bus to get all Orchid card + Input : None. + Output : None. + Return : SUCCESSFUL - Successful scan + ohterwise - No drives founded +*****************************************************************************/ +int Addinia100_into_Adapter_table(WORD wBIOS, WORD wBASE, BYTE bInterrupt, + BYTE bBus, BYTE bDevice) +{ + unsigned int i, j; + + for (i = 0; i < MAX_SUPPORTED_ADAPTERS; i++) { + if (inia100_adpt[i].ADPT_BIOS < wBIOS) + continue; + if (inia100_adpt[i].ADPT_BIOS == wBIOS) { + if (inia100_adpt[i].ADPT_BASE == wBASE) + if (inia100_adpt[i].ADPT_Bus != 0xFF) + return (FAILURE); + else if (inia100_adpt[i].ADPT_BASE < wBASE) + continue; + } + for (j = MAX_SUPPORTED_ADAPTERS - 1; j > i; j--) { + inia100_adpt[j].ADPT_BASE = inia100_adpt[j - 1].ADPT_BASE; + inia100_adpt[j].ADPT_INTR = inia100_adpt[j - 1].ADPT_INTR; + inia100_adpt[j].ADPT_BIOS = inia100_adpt[j - 1].ADPT_BIOS; + inia100_adpt[j].ADPT_Bus = inia100_adpt[j - 1].ADPT_Bus; + inia100_adpt[j].ADPT_Device = inia100_adpt[j - 1].ADPT_Device; + } + inia100_adpt[i].ADPT_BASE = wBASE; + inia100_adpt[i].ADPT_INTR = bInterrupt; + inia100_adpt[i].ADPT_BIOS = wBIOS; + inia100_adpt[i].ADPT_Bus = bBus; + inia100_adpt[i].ADPT_Device = bDevice; + return (SUCCESSFUL); + } + return (FAILURE); +} + + +/***************************************************************************** + Function name : init_inia100Adapter_table + Description : This function will scan PCI bus to get all Orchid card + Input : None. + Output : None. + Return : SUCCESSFUL - Successful scan + ohterwise - No drives founded +*****************************************************************************/ +void init_inia100Adapter_table(void) +{ + int i; + + for (i = 0; i < MAX_SUPPORTED_ADAPTERS; i++) { /* Initialize adapter structure */ + inia100_adpt[i].ADPT_BIOS = 0xffff; + inia100_adpt[i].ADPT_BASE = 0xffff; + inia100_adpt[i].ADPT_INTR = 0xff; + inia100_adpt[i].ADPT_Bus = 0xff; + inia100_adpt[i].ADPT_Device = 0xff; + } +} + +/***************************************************************************** + Function name : get_orcPCIConfig + Description : + Input : pHCB - Pointer to host adapter structure + Output : None. + Return : pSRB - Pointer to SCSI request block. +*****************************************************************************/ +void get_orcPCIConfig(ORC_HCS * pCurHcb, int ch_idx) +{ + pCurHcb->HCS_Base = inia100_adpt[ch_idx].ADPT_BASE; /* Supply base address */ + pCurHcb->HCS_BIOS = inia100_adpt[ch_idx].ADPT_BIOS; /* Supply BIOS address */ + pCurHcb->HCS_Intr = inia100_adpt[ch_idx].ADPT_INTR; /* Supply interrupt line */ + return; +} + + +/***************************************************************************** + Function name : abort_SCB + Description : Abort a queued command. + (commands that are on the bus can't be aborted easily) + Input : pHCB - Pointer to host adapter structure + Output : None. + Return : pSRB - Pointer to SCSI request block. +*****************************************************************************/ +int abort_SCB(ORC_HCS * hcsp, ORC_SCB * pScb) +{ + unsigned char bData, bStatus; + + ORC_WR(hcsp->HCS_Base + ORC_HDATA, ORC_CMD_ABORT_SCB); /* Write command */ + ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO); + if (waitHDOoff(hcsp) == FALSE) /* Wait HDO off */ + return (FALSE); + + ORC_WR(hcsp->HCS_Base + ORC_HDATA, pScb->SCB_ScbIdx); /* Write address */ + ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO); + if (waitHDOoff(hcsp) == FALSE) /* Wait HDO off */ + return (FALSE); + + if (waitHDIset(hcsp, &bData) == FALSE) /* Wait HDI set */ + return (FALSE); + bStatus = ORC_RD(hcsp->HCS_Base, ORC_HDATA); + ORC_WR(hcsp->HCS_Base + ORC_HSTUS, bData); /* Clear HDI */ + + if (bStatus == 1) /* 0 - Successfully */ + return (FALSE); /* 1 - Fail */ + return (TRUE); +} + +/***************************************************************************** + Function name : inia100_abort + Description : Abort a queued command. + (commands that are on the bus can't be aborted easily) + Input : pHCB - Pointer to host adapter structure + Output : None. + Return : pSRB - Pointer to SCSI request block. +*****************************************************************************/ +int orc_abort_srb(ORC_HCS * hcsp, ULONG SCpnt) +{ + ESCB *pVirEscb; + ORC_SCB *pVirScb; + UCHAR i; + ULONG flags; + +#if 0 + printk("inia100: abort SRB \n"); +#endif +#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95) + save_flags(flags); + cli(); +#else + spin_lock_irqsave(&(hcsp->BitAllocFlagLock), flags); +#endif + + pVirScb = (ORC_SCB *) hcsp->HCS_virScbArray; + + for (i = 0; i < orc_num_scb; i++, pVirScb++) { + pVirEscb = pVirScb->SCB_EScb; + if ((pVirScb->SCB_Status) && (pVirEscb->SCB_Srb == (unsigned char *) SCpnt)) { + if (pVirScb->SCB_TagMsg == 0) { +#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95) + restore_flags(flags); +#else + spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags); +#endif + return (SCSI_ABORT_BUSY); + } else { + if (abort_SCB(hcsp, pVirScb)) { + pVirEscb->SCB_Srb = NULL; +#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95) + restore_flags(flags); +#else + spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags); +#endif + return (SCSI_ABORT_SUCCESS); + } else { +#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95) + restore_flags(flags); +#else + spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags); +#endif + return (SCSI_ABORT_NOT_RUNNING); + } + } + } + } +#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95) + restore_flags(flags); +#else + spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags); +#endif + return (SCSI_ABORT_NOT_RUNNING); +} + +/*********************************************************************** + Routine Description: + This is the interrupt service routine for the Orchid SCSI adapter. + It reads the interrupt register to determine if the adapter is indeed + the source of the interrupt and clears the interrupt at the device. + Arguments: + HwDeviceExtension - HBA miniport driver's adapter data storage + Return Value: +***********************************************************************/ +void orc_interrupt( + ORC_HCS * hcsp +) +{ + BYTE bScbIdx; + ORC_SCB *pScb; + + if (ORC_RD(hcsp->HCS_Base, ORC_RQUEUECNT) == 0) { + return; // (FALSE); + + } + do { + bScbIdx = ORC_RD(hcsp->HCS_Base, ORC_RQUEUE); + + pScb = (ORC_SCB *) ((ULONG) hcsp->HCS_virScbArray + (ULONG) (sizeof(ORC_SCB) * bScbIdx)); + pScb->SCB_Status = 0x0; + + inia100SCBPost((BYTE *) hcsp, (BYTE *) pScb); + } while (ORC_RD(hcsp->HCS_Base, ORC_RQUEUECNT)); + return; //(TRUE); + +} /* End of I1060Interrupt() */ diff -ur --new-file old/linux/drivers/scsi/i60uscsi.h new/linux/drivers/scsi/i60uscsi.h --- old/linux/drivers/scsi/i60uscsi.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/scsi/i60uscsi.h Thu Feb 25 01:27:54 1999 @@ -0,0 +1,574 @@ +/************************************************************************** + * Initio A100 device driver for Linux. + * + * Copyright (c) 1994-1998 Initio Corporation + * All rights reserved. + * + * 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; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * -------------------------------------------------------------------------- + * + * 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, + * without modification, immediately at the beginning of the file. + * 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. + * + * Where this Software is combined with software released under the terms of + * the GNU Public License ("GPL") and the terms of the GPL would require the + * combined work to also be released under the terms of the GPL, the terms + * and conditions of this License will apply in addition to those of the + * GPL with the exception of any terms or conditions of this License that + * conflict with, or are expressly prohibited by, the GPL. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + ************************************************************************** + * + * Module: inia100.h + * Description: INI-A100U2W LINUX device driver header + * Revision History: + * 06/18/98 HL, Initial Version 1.02 + * 12/19/98 bv, v1.02a Use spinlocks for 2.1.95 and up. + **************************************************************************/ + +#include + +#define ULONG unsigned long +#define PVOID void * +#define USHORT unsigned short +#define UCHAR unsigned char +#define BYTE unsigned char +#define WORD unsigned short +#define DWORD unsigned long +#define UBYTE unsigned char +#define UWORD unsigned short +#define UDWORD unsigned long +#ifdef ALPHA +#define U32 unsigned int +#else +#define U32 unsigned long +#endif + +#ifndef NULL +#define NULL 0 /* zero */ +#endif +#ifndef TRUE +#define TRUE (1) /* boolean true */ +#endif +#ifndef FALSE +#define FALSE (0) /* boolean false */ +#endif +#ifndef FAILURE +#define FAILURE (-1) +#endif +#if 1 +#define ORC_MAXQUEUE 245 +#else +#define ORC_MAXQUEUE 25 +#endif + +#define TOTAL_SG_ENTRY 32 +#define MAX_TARGETS 16 +#define IMAX_CDB 15 +#define SENSE_SIZE 14 +#define MAX_SUPPORTED_ADAPTERS 4 +#define SUCCESSFUL 0x00 + +#define I920_DEVICE_ID 0x0002 /* Initio's inic-950 product ID */ + +/************************************************************************/ +/* Scatter-Gather Element Structure */ +/************************************************************************/ +typedef struct ORC_SG_Struc { + U32 SG_Ptr; /* Data Pointer */ + U32 SG_Len; /* Data Length */ +} ORC_SG; + +typedef struct inia100_Adpt_Struc { + UWORD ADPT_BIOS; /* 0 */ + UWORD ADPT_BASE; /* 1 */ + UBYTE ADPT_Bus; /* 2 */ + UBYTE ADPT_Device; /* 3 */ + UBYTE ADPT_INTR; /* 4 */ +} INIA100_ADPT_STRUCT; + + +/* SCSI related definition */ +#define DISC_NOT_ALLOW 0x80 /* Disconnect is not allowed */ +#define DISC_ALLOW 0xC0 /* Disconnect is allowed */ + + +#define ORC_OFFSET_SCB 16 +#define ORC_MAX_SCBS 250 +#define MAX_CHANNELS 2 +#define MAX_ESCB_ELE 64 +#define TCF_DRV_255_63 0x0400 + +/********************************************************/ +/* Orchid Configuration Register Set */ +/********************************************************/ +#define ORC_PVID 0x00 /* Vendor ID */ +#define ORC_VENDOR_ID 0x1101 /* Orchid vendor ID */ +#define ORC_PDID 0x02 /* Device ID */ +#define ORC_DEVICE_ID 0x1060 /* Orchid device ID */ +#define ORC_COMMAND 0x04 /* Command */ +#define BUSMS 0x04 /* BUS MASTER Enable */ +#define IOSPA 0x01 /* IO Space Enable */ +#define ORC_STATUS 0x06 /* Status register */ +#define ORC_REVISION 0x08 /* Revision number */ +#define ORC_BASE 0x10 /* Base address */ +#define ORC_BIOS 0x50 /* Expansion ROM base address */ +#define ORC_INT_NUM 0x3C /* Interrupt line */ +#define ORC_INT_PIN 0x3D /* Interrupt pin */ + + +/********************************************************/ +/* Orchid Host Command Set */ +/********************************************************/ +#define ORC_CMD_NOP 0x00 /* Host command - NOP */ +#define ORC_CMD_VERSION 0x01 /* Host command - Get F/W version */ +#define ORC_CMD_ECHO 0x02 /* Host command - ECHO */ +#define ORC_CMD_SET_NVM 0x03 /* Host command - Set NVRAM */ +#define ORC_CMD_GET_NVM 0x04 /* Host command - Get NVRAM */ +#define ORC_CMD_GET_BUS_STATUS 0x05 /* Host command - Get SCSI bus status */ +#define ORC_CMD_ABORT_SCB 0x06 /* Host command - Abort SCB */ +#define ORC_CMD_ISSUE_SCB 0x07 /* Host command - Issue SCB */ + +/********************************************************/ +/* Orchid Register Set */ +/********************************************************/ +#define ORC_GINTS 0xA0 /* Global Interrupt Status */ +#define QINT 0x04 /* Reply Queue Interrupt */ +#define ORC_GIMSK 0xA1 /* Global Interrupt MASK */ +#define MQINT 0x04 /* Mask Reply Queue Interrupt */ +#define ORC_GCFG 0xA2 /* Global Configure */ +#define EEPRG 0x01 /* Enable EEPROM programming */ +#define ORC_GSTAT 0xA3 /* Global status */ +#define WIDEBUS 0x10 /* Wide SCSI Devices connected */ +#define ORC_HDATA 0xA4 /* Host Data */ +#define ORC_HCTRL 0xA5 /* Host Control */ +#define SCSIRST 0x80 /* SCSI bus reset */ +#define HDO 0x40 /* Host data out */ +#define HOSTSTOP 0x02 /* Host stop RISC engine */ +#define DEVRST 0x01 /* Device reset */ +#define ORC_HSTUS 0xA6 /* Host Status */ +#define HDI 0x02 /* Host data in */ +#define RREADY 0x01 /* RISC engine is ready to receive */ +#define ORC_NVRAM 0xA7 /* Nvram port address */ +#define SE2CS 0x008 +#define SE2CLK 0x004 +#define SE2DO 0x002 +#define SE2DI 0x001 +#define ORC_PQUEUE 0xA8 /* Posting queue FIFO */ +#define ORC_PQCNT 0xA9 /* Posting queue FIFO Cnt */ +#define ORC_RQUEUE 0xAA /* Reply queue FIFO */ +#define ORC_RQUEUECNT 0xAB /* Reply queue FIFO Cnt */ +#define ORC_FWBASEADR 0xAC /* Firmware base address */ + +#define ORC_EBIOSADR0 0xB0 /* External Bios address */ +#define ORC_EBIOSADR1 0xB1 /* External Bios address */ +#define ORC_EBIOSADR2 0xB2 /* External Bios address */ +#define ORC_EBIOSDATA 0xB3 /* External Bios address */ + +#define ORC_SCBSIZE 0xB7 /* SCB size register */ +#define ORC_SCBBASE0 0xB8 /* SCB base address 0 */ +#define ORC_SCBBASE1 0xBC /* SCB base address 1 */ + +#define ORC_RISCCTL 0xE0 /* RISC Control */ +#define PRGMRST 0x002 +#define DOWNLOAD 0x001 +#define ORC_PRGMCTR0 0xE2 /* RISC program counter */ +#define ORC_PRGMCTR1 0xE3 /* RISC program counter */ +#define ORC_RISCRAM 0xEC /* RISC RAM data port 4 bytes */ + +typedef struct orc_extended_scb { /* Extended SCB */ + ORC_SG ESCB_SGList[TOTAL_SG_ENTRY]; /*0 Start of SG list */ + unsigned char *SCB_Srb; /*50 SRB Pointer */ +// Scsi_Cmnd *SCB_Srb; /*50 SRB Pointer */ +} ESCB; + +/*********************************************************************** + SCSI Control Block +************************************************************************/ +typedef struct orc_scb { /* Scsi_Ctrl_Blk */ + UBYTE SCB_Opcode; /*00 SCB command code&residual */ + UBYTE SCB_Flags; /*01 SCB Flags */ + UBYTE SCB_Target; /*02 Target Id */ + UBYTE SCB_Lun; /*03 Lun */ + U32 SCB_Reserved0; /*04 Reserved for ORCHID must 0 */ + U32 SCB_XferLen; /*08 Data Transfer Length */ + U32 SCB_Reserved1; /*0C Reserved for ORCHID must 0 */ + U32 SCB_SGLen; /*10 SG list # * 8 */ + U32 SCB_SGPAddr; /*14 SG List Buf physical Addr */ + U32 SCB_SGPAddrHigh; /*18 SG Buffer high physical Addr */ + UBYTE SCB_HaStat; /*1C Host Status */ + UBYTE SCB_TaStat; /*1D Target Status */ + UBYTE SCB_Status; /*1E SCB status */ + UBYTE SCB_Link; /*1F Link pointer, default 0xFF */ + UBYTE SCB_SenseLen; /*20 Sense Allocation Length */ + UBYTE SCB_CDBLen; /*21 CDB Length */ + UBYTE SCB_Ident; /*22 Identify */ + UBYTE SCB_TagMsg; /*23 Tag Message */ + UBYTE SCB_CDB[IMAX_CDB]; /*24 SCSI CDBs */ + UBYTE SCB_ScbIdx; /*3C Index for this ORCSCB */ + U32 SCB_SensePAddr; /*34 Sense Buffer physical Addr */ + + ESCB *SCB_EScb; /*38 Extended SCB Pointer */ +#ifndef ALPHA + UBYTE SCB_Reserved2[4]; /*3E Reserved for Driver use */ +#endif +} ORC_SCB; + +/* Opcodes of ORCSCB_Opcode */ +#define ORC_EXECSCSI 0x00 /* SCSI initiator command with residual */ +#define ORC_BUSDEVRST 0x01 /* SCSI Bus Device Reset */ + +/* Status of ORCSCB_Status */ +#define SCB_COMPLETE 0x00 /* SCB request completed */ +#define SCB_POST 0x01 /* SCB is posted by the HOST */ + +/* Bit Definition for ORCSCB_Flags */ +#define SCF_DISINT 0x01 /* Disable HOST interrupt */ +#define SCF_DIR 0x18 /* Direction bits */ +#define SCF_NO_DCHK 0x00 /* Direction determined by SCSI */ +#define SCF_DIN 0x08 /* From Target to Initiator */ +#define SCF_DOUT 0x10 /* From Initiator to Target */ +#define SCF_NO_XF 0x18 /* No data transfer */ +#define SCF_POLL 0x40 + +/* Error Codes for ORCSCB_HaStat */ +#define HOST_SEL_TOUT 0x11 +#define HOST_DO_DU 0x12 +#define HOST_BUS_FREE 0x13 +#define HOST_BAD_PHAS 0x14 +#define HOST_INV_CMD 0x16 +#define HOST_SCSI_RST 0x1B +#define HOST_DEV_RST 0x1C + + +/* Error Codes for ORCSCB_TaStat */ +#define TARGET_CHK_COND 0x02 +#define TARGET_BUSY 0x08 +#define TARGET_TAG_FULL 0x28 + + +/* Queue tag msg: Simple_quque_tag, Head_of_queue_tag, Ordered_queue_tag */ +#define MSG_STAG 0x20 +#define MSG_HTAG 0x21 +#define MSG_OTAG 0x22 + +#define MSG_IGNOREWIDE 0x23 + +#define MSG_IDENT 0x80 +#define MSG_DISC 0x40 /* Disconnect allowed */ + + +/* SCSI MESSAGE */ +#define MSG_EXTEND 0x01 +#define MSG_SDP 0x02 +#define MSG_ABORT 0x06 +#define MSG_REJ 0x07 +#define MSG_NOP 0x08 +#define MSG_PARITY 0x09 +#define MSG_DEVRST 0x0C +#define MSG_STAG 0x20 + +/*********************************************************************** + Target Device Control Structure +**********************************************************************/ + +typedef struct ORC_Tar_Ctrl_Struc { + UBYTE TCS_DrvDASD; /* 6 */ + UBYTE TCS_DrvSCSI; /* 7 */ + UBYTE TCS_DrvHead; /* 8 */ + UWORD TCS_DrvFlags; /* 4 */ + UBYTE TCS_DrvSector; /* 7 */ +} ORC_TCS, *PORC_TCS; + +/* Bit Definition for TCF_DrvFlags */ +#define TCS_DF_NODASD_SUPT 0x20 /* Suppress OS/2 DASD Mgr support */ +#define TCS_DF_NOSCSI_SUPT 0x40 /* Suppress OS/2 SCSI Mgr support */ + + +/*********************************************************************** + Host Adapter Control Structure +************************************************************************/ +typedef struct ORC_Ha_Ctrl_Struc { + USHORT HCS_Base; /* 00 */ + UBYTE HCS_Index; /* 02 */ + UBYTE HCS_Intr; /* 04 */ + UBYTE HCS_SCSI_ID; /* 06 H/A SCSI ID */ + UBYTE HCS_BIOS; /* 07 BIOS configuration */ + + UBYTE HCS_Flags; /* 0B */ + UBYTE HCS_HAConfig1; /* 1B SCSI0MAXTags */ + UBYTE HCS_MaxTar; /* 1B SCSI0MAXTags */ + + USHORT HCS_Units; /* Number of units this adapter */ + USHORT HCS_AFlags; /* Adapter info. defined flags */ + ULONG HCS_Timeout; /* Adapter timeout value */ + PVOID HCS_virScbArray; /* 28 Virtual Pointer to SCB array */ + U32 HCS_physScbArray; /* Scb Physical address */ + PVOID HCS_virEscbArray; /* Virtual pointer to ESCB Scatter list */ + U32 HCS_physEscbArray; /* scatter list Physical address */ + UBYTE TargetFlag[16]; /* 30 target configuration, TCF_EN_TAG */ + UBYTE MaximumTags[16]; /* 40 ORC_MAX_SCBS */ + UBYTE ActiveTags[16][16]; /* 50 */ + ORC_TCS HCS_Tcs[16]; /* 28 */ + U32 BitAllocFlag[MAX_CHANNELS][8]; /* Max STB is 256, So 256/32 */ +#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95) + spinlock_t BitAllocFlagLock; +#endif + ULONG pSRB_head; + ULONG pSRB_tail; +#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95) + spinlock_t pSRB_lock; +#endif +} ORC_HCS; + +/* Bit Definition for HCS_Flags */ + +#define HCF_SCSI_RESET 0x01 /* SCSI BUS RESET */ +#define HCF_PARITY 0x02 /* parity card */ +#define HCF_LVDS 0x10 /* parity card */ + +/* Bit Definition for TargetFlag */ + +#define TCF_EN_255 0x08 +#define TCF_EN_TAG 0x10 +#define TCF_BUSY 0x20 +#define TCF_DISCONNECT 0x40 +#define TCF_SPIN_UP 0x80 + +/* Bit Definition for HCS_AFlags */ +#define HCS_AF_IGNORE 0x01 /* Adapter ignore */ +#define HCS_AF_DISABLE_RESET 0x10 /* Adapter disable reset */ +#define HCS_AF_DISABLE_ADPT 0x80 /* Adapter disable */ + + +/*---------------------------------------*/ +/* TimeOut for RESET to complete (30s) */ +/* */ +/* After a RESET the drive is checked */ +/* every 200ms. */ +/*---------------------------------------*/ +#define DELAYED_RESET_MAX (30*1000L) +#define DELAYED_RESET_INTERVAL 200L + +/*----------------------------------------------*/ +/* TimeOut for IRQ from last interrupt (5s) */ +/*----------------------------------------------*/ +#define IRQ_TIMEOUT_INTERVAL (5*1000L) + +/*----------------------------------------------*/ +/* Retry Delay interval (200ms) */ +/*----------------------------------------------*/ +#define DELAYED_RETRY_INTERVAL 200L + +#define INQUIRY_SIZE 36 +#define CAPACITY_SIZE 8 +#define DEFAULT_SENSE_LEN 14 + +#define DEVICE_NOT_FOUND 0x86 + +/*----------------------------------------------*/ +/* Definition for PCI device */ +/*----------------------------------------------*/ +#define MAX_PCI_DEVICES 21 +#define MAX_PCI_BUSES 8 + +typedef struct Adpt_Struc { + USHORT ADPT_BIOS; /* 0 */ + UBYTE ADPT_BASE; /* 1 */ + UBYTE ADPT_Bus; /* 2 */ + UBYTE ADPT_Device; /* 3 */ + UBYTE ADPT_Reserved[3]; +} JACS, *PJACS; + +typedef struct _NVRAM { +/*----------header ---------------*/ + UCHAR SubVendorID0; /* 00 - Sub Vendor ID */ + UCHAR SubVendorID1; /* 00 - Sub Vendor ID */ + UCHAR SubSysID0; /* 02 - Sub System ID */ + UCHAR SubSysID1; /* 02 - Sub System ID */ + UCHAR SubClass; /* 04 - Sub Class */ + UCHAR VendorID0; /* 05 - Vendor ID */ + UCHAR VendorID1; /* 05 - Vendor ID */ + UCHAR DeviceID0; /* 07 - Device ID */ + UCHAR DeviceID1; /* 07 - Device ID */ + UCHAR Reserved0[2]; /* 09 - Reserved */ + UCHAR Revision; /* 0B - Revision of data structure */ + /* ----Host Adapter Structure ---- */ + UCHAR NumOfCh; /* 0C - Number of SCSI channel */ + UCHAR BIOSConfig1; /* 0D - BIOS configuration 1 */ + UCHAR BIOSConfig2; /* 0E - BIOS boot channel&target ID */ + UCHAR BIOSConfig3; /* 0F - BIOS configuration 3 */ + /* ----SCSI channel Structure ---- */ + /* from "CTRL-I SCSI Host Adapter SetUp menu " */ + UCHAR SCSI0Id; /* 10 - Channel 0 SCSI ID */ + UCHAR SCSI0Config; /* 11 - Channel 0 SCSI configuration */ + UCHAR SCSI0MaxTags; /* 12 - Channel 0 Maximum tags */ + UCHAR SCSI0ResetTime; /* 13 - Channel 0 Reset recovering time */ + UCHAR ReservedforChannel0[2]; /* 14 - Reserved */ + + /* ----SCSI target Structure ---- */ + /* from "CTRL-I SCSI device SetUp menu " */ + UCHAR Target00Config; /* 16 - Channel 0 Target 0 config */ + UCHAR Target01Config; /* 17 - Channel 0 Target 1 config */ + UCHAR Target02Config; /* 18 - Channel 0 Target 2 config */ + UCHAR Target03Config; /* 19 - Channel 0 Target 3 config */ + UCHAR Target04Config; /* 1A - Channel 0 Target 4 config */ + UCHAR Target05Config; /* 1B - Channel 0 Target 5 config */ + UCHAR Target06Config; /* 1C - Channel 0 Target 6 config */ + UCHAR Target07Config; /* 1D - Channel 0 Target 7 config */ + UCHAR Target08Config; /* 1E - Channel 0 Target 8 config */ + UCHAR Target09Config; /* 1F - Channel 0 Target 9 config */ + UCHAR Target0AConfig; /* 20 - Channel 0 Target A config */ + UCHAR Target0BConfig; /* 21 - Channel 0 Target B config */ + UCHAR Target0CConfig; /* 22 - Channel 0 Target C config */ + UCHAR Target0DConfig; /* 23 - Channel 0 Target D config */ + UCHAR Target0EConfig; /* 24 - Channel 0 Target E config */ + UCHAR Target0FConfig; /* 25 - Channel 0 Target F config */ + + UCHAR SCSI1Id; /* 26 - Channel 1 SCSI ID */ + UCHAR SCSI1Config; /* 27 - Channel 1 SCSI configuration */ + UCHAR SCSI1MaxTags; /* 28 - Channel 1 Maximum tags */ + UCHAR SCSI1ResetTime; /* 29 - Channel 1 Reset recovering time */ + UCHAR ReservedforChannel1[2]; /* 2A - Reserved */ + + /* ----SCSI target Structure ---- */ + /* from "CTRL-I SCSI device SetUp menu " */ + UCHAR Target10Config; /* 2C - Channel 1 Target 0 config */ + UCHAR Target11Config; /* 2D - Channel 1 Target 1 config */ + UCHAR Target12Config; /* 2E - Channel 1 Target 2 config */ + UCHAR Target13Config; /* 2F - Channel 1 Target 3 config */ + UCHAR Target14Config; /* 30 - Channel 1 Target 4 config */ + UCHAR Target15Config; /* 31 - Channel 1 Target 5 config */ + UCHAR Target16Config; /* 32 - Channel 1 Target 6 config */ + UCHAR Target17Config; /* 33 - Channel 1 Target 7 config */ + UCHAR Target18Config; /* 34 - Channel 1 Target 8 config */ + UCHAR Target19Config; /* 35 - Channel 1 Target 9 config */ + UCHAR Target1AConfig; /* 36 - Channel 1 Target A config */ + UCHAR Target1BConfig; /* 37 - Channel 1 Target B config */ + UCHAR Target1CConfig; /* 38 - Channel 1 Target C config */ + UCHAR Target1DConfig; /* 39 - Channel 1 Target D config */ + UCHAR Target1EConfig; /* 3A - Channel 1 Target E config */ + UCHAR Target1FConfig; /* 3B - Channel 1 Target F config */ + UCHAR reserved[3]; /* 3C - Reserved */ + /* ---------- CheckSum ---------- */ + UCHAR CheckSum; /* 3F - Checksum of NVRam */ +} NVRAM, *PNVRAM; + +/* Bios Configuration for nvram->BIOSConfig1 */ +#define NBC_BIOSENABLE 0x01 /* BIOS enable */ +#define NBC_CDROM 0x02 /* Support bootable CDROM */ +#define NBC_REMOVABLE 0x04 /* Support removable drive */ + +/* Bios Configuration for nvram->BIOSConfig2 */ +#define NBB_TARGET_MASK 0x0F /* Boot SCSI target ID number */ +#define NBB_CHANL_MASK 0xF0 /* Boot SCSI channel number */ + +/* Bit definition for nvram->SCSIConfig */ +#define NCC_BUSRESET 0x01 /* Reset SCSI bus at power up */ +#define NCC_PARITYCHK 0x02 /* SCSI parity enable */ +#define NCC_LVDS 0x10 /* Enable LVDS */ +#define NCC_ACTTERM1 0x20 /* Enable active terminator 1 */ +#define NCC_ACTTERM2 0x40 /* Enable active terminator 2 */ +#define NCC_AUTOTERM 0x80 /* Enable auto termination */ + +/* Bit definition for nvram->TargetxConfig */ +#define NTC_PERIOD 0x07 /* Maximum Sync. Speed */ +#define NTC_1GIGA 0x08 /* 255 head / 63 sectors (64/32) */ +#define NTC_NO_SYNC 0x10 /* NO SYNC. NEGO */ +#define NTC_NO_WIDESYNC 0x20 /* NO WIDE SYNC. NEGO */ +#define NTC_DISC_ENABLE 0x40 /* Enable SCSI disconnect */ +#define NTC_SPINUP 0x80 /* Start disk drive */ + +/* Default NVRam values */ +#define NBC_DEFAULT (NBC_ENABLE) +#define NCC_DEFAULT (NCC_BUSRESET | NCC_AUTOTERM | NCC_PARITYCHK) +#define NCC_MAX_TAGS 0x20 /* Maximum tags per target */ +#define NCC_RESET_TIME 0x0A /* SCSI RESET recovering time */ +#define NTC_DEFAULT (NTC_1GIGA | NTC_NO_WIDESYNC | NTC_DISC_ENABLE) + +typedef union { /* Union define for mechanism 1 */ + struct { + unsigned char RegNum; + unsigned char FcnNum:3; + unsigned char DeviceNum:5; + unsigned char BusNum; + unsigned char Reserved:7; + unsigned char Enable:1; + } sConfigAdr; + unsigned long lConfigAdr; +} CONFIG_ADR; + +typedef union { /* Union define for mechanism 2 */ + struct { + unsigned char RegNum; + unsigned char DeviceNum; + unsigned short Reserved; + } sHostAdr; + unsigned long lHostAdr; +} HOST_ADR; + +#define ORC_RD(x,y) (UCHAR)(inb( (int)((ULONG)((ULONG)x+(UCHAR)y)) )) +#define ORC_RDLONG(x,y) (long)(inl((int)((ULONG)((ULONG)x+(UCHAR)y)) )) + +#define ORC_WR( adr,data) outb( (UCHAR)(data), (int)(adr)) +#define ORC_WRSHORT(adr,data) outw( (UWORD)(data), (int)(adr)) +#define ORC_WRLONG( adr,data) outl( (ULONG)(data), (int)(adr)) + + +#define SCSI_ABORT_SNOOZE 0 +#define SCSI_ABORT_SUCCESS 1 +#define SCSI_ABORT_PENDING 2 +#define SCSI_ABORT_BUSY 3 +#define SCSI_ABORT_NOT_RUNNING 4 +#define SCSI_ABORT_ERROR 5 + +#define SCSI_RESET_SNOOZE 0 +#define SCSI_RESET_PUNT 1 +#define SCSI_RESET_SUCCESS 2 +#define SCSI_RESET_PENDING 3 +#define SCSI_RESET_WAKEUP 4 +#define SCSI_RESET_NOT_RUNNING 5 +#define SCSI_RESET_ERROR 6 + +#define SCSI_RESET_SYNCHRONOUS 0x01 +#define SCSI_RESET_ASYNCHRONOUS 0x02 +#define SCSI_RESET_SUGGEST_BUS_RESET 0x04 +#define SCSI_RESET_SUGGEST_HOST_RESET 0x08 + +#define SCSI_RESET_BUS_RESET 0x100 +#define SCSI_RESET_HOST_RESET 0x200 +#define SCSI_RESET_ACTION 0xff diff -ur --new-file old/linux/drivers/scsi/ibmmca.c new/linux/drivers/scsi/ibmmca.c --- old/linux/drivers/scsi/ibmmca.c Tue Dec 29 20:40:35 1998 +++ new/linux/drivers/scsi/ibmmca.c Mon May 10 22:00:10 1999 @@ -3,291 +3,30 @@ * * Copyright (c) 1995 Strom Systems, Inc. under the terms of the GNU * General Public License. Written by Martin Kolinek, December 1995. + * Further development by: Chris Beauregard, Klaus Kudielka, Michael Lang + * See the file README.ibmmca for a detailed description of this driver, + * the commandline arguments and the history of its development. + * See the WWW-page: http://www.uni-mainz.de/~langm000/linux.html for latest + * updates and info. */ -/* Update history: - Jan 15 1996: First public release. - - Martin Kolinek - - Jan 23 1996: Scrapped code which reassigned scsi devices to logical - device numbers. Instead, the existing assignment (created - when the machine is powered-up or rebooted) is used. - A side effect is that the upper layer of Linux SCSI - device driver gets bogus scsi ids (this is benign), - and also the hard disks are ordered under Linux the - same way as they are under dos (i.e., C: disk is sda, - D: disk is sdb, etc.). - - Martin Kolinek - - I think that the CD-ROM is now detected only if a CD is - inside CD_ROM while Linux boots. This can be fixed later, - once the driver works on all types of PS/2's. - - Martin Kolinek - - Feb 7 1996: Modified biosparam function. Fixed the CD-ROM detection. - For now, devices other than harddisk and CD_ROM are - ignored. Temporarily modified abort() function - to behave like reset(). - - Martin Kolinek - - Mar 31 1996: The integrated scsi subsystem is correctly found - in PS/2 models 56,57, but not in model 76. Therefore - the ibmmca_scsi_setup() function has been added today. - This function allows the user to force detection of - scsi subsystem. The kernel option has format - ibmmcascsi=n - where n is the scsi_id (pun) of the subsystem. Most likely, n is 7. - - Martin Kolinek - - Aug 21 1996: Modified the code which maps ldns to (pun,0). It was - insufficient for those of us with CD-ROM changers. - - Chris Beauregard - - Dec 14 1996: More improvements to the ldn mapping. See check_devices - for details. Did more fiddling with the integrated SCSI detection, - but I think it's ultimately hopeless without actually testing the - model of the machine. The 56, 57, 76 and 95 (ultimedia) all have - different integrated SCSI register configurations. However, the 56 - and 57 are the only ones that have problems with forced detection. - - Chris Beauregard - - Mar 8-16 1997: Modified driver to run as a module and to support - multiple adapters. A structure, called ibmmca_hostdata, is now - present, containing all the variables, that were once only - available for one single adapter. The find_subsystem-routine has vanished. - The hardware recognition is now done in ibmmca_detect directly. - This routine checks for presence of MCA-bus, checks the interrupt - level and continues with checking the installed hardware. - Certain PS/2-models do not recognize a SCSI-subsystem automatically. - Hence, the setup defined by command-line-parameters is checked first. - Thereafter, the routine probes for an integrated SCSI-subsystem. - Finally, adapters are checked. This method has the advantage to cover all - possible combinations of multiple SCSI-subsystems on one MCA-board. Up to - eight SCSI-subsystems can be recognized and announced to the upper-level - drivers with this improvement. A set of defines made changes to other - routines as small as possible. - - Klaus Kudielka - - May 30 1997: (v1.5b) - 1) SCSI-command capability enlarged by the recognition of MODE_SELECT. - This needs the RD-Bit to be disabled on IM_OTHER_SCSI_CMD_CMD which - allows data to be written from the system to the device. It is a - necessary step to be allowed to set blocksize of SCSI-tape-drives and - the tape-speed, whithout confusing the SCSI-Subsystem. - 2) The recognition of a tape is included in the check_devices routine. - This is done by checking for TYPE_TAPE, that is already defined in - the kernel-scsi-environment. The markup of a tape is done in the - global ldn_is_tape[] array. If the entry on index ldn - is 1, there is a tapedrive connected. - 3) The ldn_is_tape[] array is necessary to distinguish between tape- and - other devices. Fixed blocklength devices should not cause a problem - with the SCB-command for read and write in the ibmmca_queuecommand - subroutine. Therefore, I only derivate the READ_XX, WRITE_XX for - the tape-devices, as recommended by IBM in this Technical Reference, - mentioned below. (IBM recommends to avoid using the read/write of the - subsystem, but the fact was, that read/write causes a command error from - the subsystem and this causes kernel-panic.) - 4) In addition, I propose to use the ldn instead of a fix char for the - display of PS2_DISK_LED_ON(). On 95, one can distinguish between the - devices that are accessed. It shows activity and easyfies debugging. - The tape-support has been tested with a SONY SDT-5200 and a HP DDS-2 - (I do not know yet the type). Optimization and CD-ROM audio-support, - I am working on ... - - Michael Lang - - June 19 1997: (v1.6b) - 1) Submitting the extra-array ldn_is_tape[] -> to the local ld[] - device-array. - 2) CD-ROM Audio-Play seems to work now. - 3) When using DDS-2 (120M) DAT-Tapes, mtst shows still density-code - 0x13 for ordinary DDS (61000 BPM) instead 0x24 for DDS-2. This appears - also on Adaptec 2940 adaptor in a PCI-System. Therefore, I assume that - the problem is independent of the low-level-driver/bus-architecture. - 4) Hexadecimal ldn on PS/2-95 LED-display. - 5) Fixing of the PS/2-LED on/off that it works right with tapedrives and - does not confuse the disk_rw_in_progress counter. - - Michael Lang - - June 21 1997: (v1.7b) - 1) Adding of a proc_info routine to inform in /proc/scsi/ibmmca/ the - outer-world about operational load statistics on the different ldns, - seen by the driver. Everybody that has more than one IBM-SCSI should - test this, because I only have one and cannot see what happens with more - than one IBM-SCSI hosts. - 2) Definition of a driver version-number to have a better recognition of - the source when there are existing too much releases that may confuse - the user, when reading about release-specific problems. Up to know, - I calculated the version-number to be 1.7. Because we are in BETA-test - yet, it is today 1.7b. - 3) Sorry for the heavy bug I programmed on June 19 1997! After that, the - CD-ROM did not work any more! The C7-command was a fake impression - I got while programming. Now, the READ and WRITE commands for CD-ROM are - no longer running over the subsystem, but just over - IM_OTHER_SCSI_CMD_CMD. On my observations (PS/2-95), now CD-ROM mounts - much faster(!) and hopefully all fancy multimedia-functions, like direct - digital recording from audio-CDs also work. (I tried it with cdda2wav - from the cdwtools-package and it filled up the harddisk immediately :-).) - To easify boolean logics, a further local device-type in ld[], called - is_cdrom has been included. - 4) If one uses a SCSI-device of unsupported type/commands, one - immediately runs into a kernel-panic caused by Command Error. To better - understand which SCSI-command caused the problem, I extended this - specific panic-message slightly. - - Michael Lang - - June 25 1997: (v1.8b) - 1) Some cosmetical changes for the handling of SCSI-device-types. - Now, also CD-Burners / WORMs and SCSI-scanners should work. For - MO-drives I have no experience, therefore not yet supported. - In logical_devices I changed from different type-variables to one - called 'device_type' where the values, corresponding to scsi.h, - of a SCSI-device are stored. - 2) There existed a small bug, that maps a device, coming after a SCSI-tape - wrong. Therefore, e.g. a CD-ROM changer would have been mapped wrong - -> problem removed. - 3) Extension of the logical_device structure. Now it contains also device, - vendor and revision-level of a SCSI-device for internal usage. - - Michael Lang - - June 26-29 1997: (v2.0b) - 1) The release number 2.0b is necessary because of the completely new done - recognition and handling of SCSI-devices with the adapter. As I got - from Chris the hint, that the subsystem can reassign ldns dynamically, - I remembered this immediate_assign-command, I found once in the handbook. - Now, the driver first kills all ldn assignments that are set by default - on the SCSI-subsystem. After that, it probes on all puns and luns for - devices by going through all combinations with immediate_assign and - probing for devices, using device_inquiry. The found physical(!) pun,lun - structure is stored in get_scsi[][] as device types. This is followed - by the assignment of all ldns to existing SCSI-devices. If more ldns - than devices are available, they are assigned to non existing pun,lun - combinations to satisfy the adapter. With this, the dynamical mapping - was possible to implement. (For further info see the text in the - source-code and in the description below. Read the description - below BEFORE installing this driver on your system!) - 2) Changed the name IBMMCA_DRIVER_VERSION to IBMMCA_SCSI_DRIVER_VERSION. - 3) The LED-display shows on PS/2-95 no longer the ldn, but the SCSI-ID - (pun) of the accessed SCSI-device. This is now senseful, because the - pun known within the driver is exactly the pun of the physical device - and no longer a fake one. - 4) The /proc/scsi/ibmmca/ consists now of the first part, where - hit-statistics of ldns is shown and a second part, where the maps of - physical and logical SCSI-devices are displayed. This could be very - interesting, when one is using more than 15 SCSI-devices in order to - follow the dynamical remapping of ldns. - - Michael Lang - - June 26-29 1997: (v2.0b-1) - 1) I forgot to switch the local_checking_phase_flag to 1 and back to 0 - in the dynamical remapping part in ibmmca_queuecommand for the - device_exist routine. Sorry. - - Michael Lang - - July 1-13 1997: (v3.0b,c) - 1) Merging of the driver-developments of Klaus Kudielka and Michael Lang - in order to get a optimum and unified driver-release for the - IBM-SCSI-Subsystem-Adapter(s). - For people, using the Kernel-release >=2.1.0, module-support should - be no problem. For users, running under <2.1.0, module-support may not - work, because the methods have changed between 2.0.x and 2.1.x. - 2) Added some more effective statistics for /proc-output. - 3) Change typecasting at necessary points from (unsigned long) to - virt_to_bus(). - 4) Included #if... at special points to have specific adaption of the - driver to kernel 2.0.x and 2.1.x. It should therefore also run with - later releases. - 5) Magneto-Optical drives and medium-changers are also recognized, now. - Therefore, we have a completely gapfree recognition of all SCSI- - device-types, that are known by Linux up to kernel 2.1.31. - 6) The flag SCSI_IBMMCA_DEV_RESET has been inserted. If it is set within - the configuration, each connected SCSI-device will get a reset command - during boottime. This can be necessary for some special SCSI-devices. - This flag should be included in Config.in. - (See also the new Config.in file.) - Probable next improvement: bad disk handler. - - Michael Lang - - Sept 14 1997: (v3.0c) - 1) Some debugging and speed optimization applied. - - Michael Lang - - Dec 15, 1997 - - chrisb@truespectra.com - - made the front panel display thingy optional, specified from the - command-line via ibmmcascsi=display. Along the lines of the /LED - option for the OS/2 driver. - - fixed small bug in the LED display that would hang some machines. - - reversed ordering of the drives (using the - IBMMCA_SCSI_ORDER_STANDARD define). This is necessary for two main - reasons: - - users who've already installed Linux won't be screwed. Keep - in mind that not everyone is a kernel hacker. - - be consistent with the BIOS ordering of the drives. In the - BIOS, id 6 is C:, id 0 might be D:. With this scheme, they'd be - backwards. This confuses the crap out of those heathens who've - got a impure Linux installation (which, , I'm one of). - This whole problem arises because IBM is actually non-standard with - the id to BIOS mappings. You'll find, in fdomain.c, a similar - comment about a few FD BIOS revisions. The Linux (and apparently - industry) standard is that C: maps to scsi id (0,0). Let's stick - with that standard. - - Since this is technically a branch of my own, I changed the - version number to 3.0e-cpb. - - Jan 17, 1998: (v3.0f) - 1) Addition of some statistical info for /proc in proc_info. - 2) Taking care of the SCSI-assignment problem, dealed by Chris at Dec 15 - 1997. In fact, IBM is right, concerning the assignment of SCSI-devices - to driveletters. It is conform to the ANSI-definition of the SCSI- - standard to assign drive C: to SCSI-id 6, because it is the highest - hardware priority after the hostadapter (that has still today by - default everywhere id 7). Also realtime-operating systems that I use, - like LynxOS and OS9, which are quite industrial systems use top-down - numbering of the harddisks, that is also starting at id 6. Now, one - sits a bit between two chairs. On one hand side, using the define - IBMMCA_SCSI_ORDER_STANDARD makes Linux assigning disks conform to - the IBM- and ANSI-SCSI-standard and keeps this driver downward - compatible to older releases, on the other hand side, people is quite - habituated in believing that C: is assigned to (0,0) and much other - SCSI-BIOS do so. Therefore, I moved the IBMMCA_SCSI_ORDER_STANDARD - define out of the driver and put it into Config.in as subitem of - 'IBM SCSI support'. A help, added to Documentation/Configure.help - explains the differences between saying 'y' or 'n' to the user, when - IBMMCA_SCSI_ORDER_STANDARD prompts, so the ordinary user is enabled to - choose the way of assignment, depending on his own situation and gusto. - 3) Adapted SCSI_IBMMCA_DEV_RESET to the local naming convention, so it is - now called IBMMCA_SCSI_DEV_RESET. - 4) Optimization of proc_info and its subroutines. - 5) Added more in-source-comments and extended the driver description by - some explanation about the SCSI-device-assignment problem. - - Michael Lang - - Jan 18, 1998: (v3.0g) - 1) Correcting names to be absolutely conform to the later 2.1.x releases. - This is necessary for - IBMMCA_SCSI_DEV_RESET -> CONFIG_IBMMCA_SCSI_DEV_RESET - IBMMCA_SCSI_ORDER_STANDARD -> CONFIG_IBMMCA_SCSI_ORDER_STANDARD - - Michael Lang - - TODO: - - - It seems that the handling of bad disks is really bad - - non-existent, in fact. - - More testing of the full driver-controlled dynamical ldn - (re)mapping for up to 56 SCSI-devices. - - Support more SCSI-device-types, if Linux defines more. - - Support more of the SCSI-command set. - - Support some of the caching abilities, particularly Read Prefetch. - This fetches data into the cache, which later gets hit by the - regular Read Data. - - Abort and Reset functions still slightly buggy. Especially when - floppydisk(!) operations report errors. +/******************* HEADER FILE INCLUDES ************************************/ +#ifndef LINUX_VERSION_CODE +#include +#endif -******************************************************************************/ +/* choose adaption for Kernellevel */ +#define local_LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s)) +#if LINUX_VERSION_CODE < local_LinuxVersionCode(2,1,0) +#define OLDKERN +#else +#undef OLDKERN +#endif #include #include #include +#include #include #include #include @@ -297,7 +36,9 @@ #include #include #include +#ifndef OLDKERN #include +#endif #include #include "sd.h" #include "scsi.h" @@ -306,199 +47,29 @@ #include /* for CONFIG_SCSI_IBMMCA etc. */ -/*--------------------------------------------------------------------*/ - -/* current version of this driver-source: */ -#define IBMMCA_SCSI_DRIVER_VERSION "3.0f" - -/* use standard Linux ordering, where C: maps to (0,0), unlike the IBM -standard which seems to like C: => (6,0) */ -/* #define IBMMCA_SCSI_ORDER_STANDARD is defined/undefined in Config.in - * now, while configuring the kernel. */ +/******************* LOCAL DEFINES *******************************************/ -/* - Driver Description - - (A) Subsystem Detection - This is done in the ibmmca_detect() function and is easy, since - the information about MCA integrated subsystems and plug-in - adapters is readily available in structure *mca_info. - - (B) Physical Units, Logical Units, and Logical Devices - There can be up to 56 devices on SCSI bus (besides the adapter): - there are up to 7 "physical units" (each identified by physical unit - number or pun, also called the scsi id, this is the number you select - with hardware jumpers), and each physical unit can have up to 8 - "logical units" (each identified by logical unit number, or lun, - between 0 and 7). - - Typically the adapter has pun=7, so puns of other physical units - are between 0 and 6. Almost all physical units have only one - logical unit, with lun=0. A CD-ROM jukebox would be an example of - a physical unit with more than one logical unit. - - The embedded microprocessor of IBM SCSI subsystem hides the complex - two-dimensional (pun,lun) organization from the operating system. - When the machine is powered-up (or rebooted, I am not sure), the - embedded microprocessor checks, on it own, all 56 possible (pun,lun) - combinations, and first 15 devices found are assigned into a - one-dimensional array of so-called "logical devices", identified by - "logical device numbers" or ldn. The last ldn=15 is reserved for - the subsystem itself. - - One consequence of information hiding is that the real (pun,lun) - numbers are also hidden. Therefore this driver takes the following - approach: It checks the ldn's (0 to 6) to find out which ldn's - have devices assigned. This is done by function check_devices() and - device_exists(). The interrupt handler has a special paragraph of code - (see local_checking_phase_flag) to assist in the checking. Assume, for - example, that three logical devices were found assigned at ldn 0, 1, 2. - These are presented to the upper layer of Linux SCSI driver - as devices with bogus (pun, lun) equal to (0,0), (1,0), (2,0). - On the other hand, if the upper layer issues a command to device - say (4,0), this driver returns DID_NO_CONNECT error. - - That last paragraph is no longer correct, but is left for - historical purposes. It limited the number of devices to 7, far - fewer than the 15 that it could use. Now it just maps - ldn -> (ldn/8,ldn%8). We end up with a real mishmash of puns - and luns, but it all seems to work. - Chris Beaurgard - - And that last paragraph is also no longer correct. It uses a - slightly more complex mapping that will always map hard disks to - (x,0), for some x, and consecutive none disk devices will usually - share puns. - - Again, the last paragraphs are no longer correct. Now, the physical - SCSI-devices on the SCSI-bus are probed via immediate_assign- and - device_inquiry-commands. This delivers a exact map of the physical - SCSI-world that is now stored in the get_scsi[][]-array. This means, - that the once hidden pun,lun assignment is now known to this driver. - It no longer believes in default-settings of the subsystem and maps all - ldns to existing pun,lun by foot. This assures full control of the ldn - mapping and allows dynamical remapping of ldns to different pun,lun, if - there are more SCSI-devices installed than ldns available (n>15). The - ldns from 0 to 6 get 'hardwired' by this driver to puns 0 to 7 at lun=0, - excluding the pun of the subsystem. This assures, that at least simple - SCSI-installations have optimum access-speed and are not touched by - dynamical remapping. The ldns 7 to 14 are put to existing devices with - lun>0 or to non-existing devices, in order to satisfy the subsystem, if - there are less than 15 SCSI-devices connected. In the case of more than 15 - devices, the dynamical mapping goes active. If the get_scsi[][] reports a - device to be existant, but it has no ldn assigned, it gets a ldn out of 7 - to 14. The numbers are assigned in cyclic order. Therefore it takes 8 - dynamical assignments on SCSI-devices, until a certain device - looses its ldn again. This assures, that dynamical remapping is avoided - during intense I/O between up to eight SCSI-devices (means pun,lun - combinations). A further advantage of this method is, that people who - build their kernel without probing on all luns will get what they expect. - - IMPORTANT: Because of the now correct recognition of physical pun,lun, and - their report to mid-level- and higher-level-drivers, the new reported puns - can be different from the old, faked puns. Therefore, Linux will eventually - change /dev/sdXXX assignments and prompt you for corrupted superblock - repair on boottime. In this case DO NOT PANIC, YOUR DISKS ARE STILL OK!!! - You have to reboot (CTRL-D) with a old kernel and set the /etc/fstab-file - entries right. After that, the system should come up as errorfree as before. - If your boot-partition is not coming up, also edit the /etc/lilo.conf-file - in a Linux session booted on old kernel and run lilo before reboot. Check - lilo.conf anyway to get boot on other partitions with foreign OSes right - again. - - The problem is, that Linux does not assign the SCSI-devices in the - way as described in the ANSI-SCSI-standard. Linux assigns /dev/sda to - the device with at minimum id 0. But the first drive should be at id 6, - because for historical reasons, drive at id 6 has, by hardware, the highest - priority and a drive at id 0 the lowest. IBM was one of the rare producers, - where the BIOS assigns drives belonging to the ANSI-SCSI-standard. Most - other producers' BIOS does not (I think even Adaptec-BIOS). The - IBMMCA_SCSI_ORDER_STANDARD flag helps to be able to choose the preferred - way of SCSI-device-assignment. Defining this flag would result in Linux - determining the devices in the same order as DOS and OS/2 does on your - MCA-machine. This is also standard on most industrial computers. Leaving - this flag undefined will get your devices ordered in the default way of - Linux. See also the remarks of Chris Beauregard from Dec 15, 1997 and - the followups. - - (C) Regular Processing - Only three functions get involved: ibmmca_queuecommand(), issue_cmd(), - and interrupt_handler(). - - The upper layer issues a scsi command by calling function - ibmmca_queuecommand(). This function fills a "subsystem control block" - (scb) and calls a local function issue_cmd(), which writes a scb - command into subsystem I/O ports. Once the scb command is carried out, - interrupt_handler() is invoked. If a device is determined to be existant - and it has not assigned any ldn, it gets one dynamically. - - (D) Abort, Reset. - These are implemented with busy waiting for interrupt to arrive. - The abort does not worked well for me, so I instead call the - ibmmca_reset() from the ibmmca_abort() function. - - (E) Disk Geometry - The ibmmca_biosparams() function should return same disk geometry - as bios. This is needed for fdisk, etc. The returned geometry is - certainly correct for disk smaller than 1 gigabyte, but I am not - 100% sure that it is correct for larger disks. - - (F) Kernel Boot Option - The function ibmmca_scsi_setup() is called if option ibmmcascsi=n - is passed to the kernel. See file linux/init/main.c for details. - - (G) Driver Module Support - Is implemented and tested by K. Kudielka. This could probably not work - on kernels <2.1.0. - - (H) Multiple Hostadapter Support - This driver supports up to eight interfaces of type IBM-SCSI-Subsystem. - Integrated-, and MCA-adapters are automatically recognized. Unrecognizable - IBM-SCSI-Subsystem interfaces can be specified as kernel-parameters. - - (I) /proc-Filesystem Information - Information about the driver condition is given in - /proc/scsi/ibmmca/. ibmmca_proc_info provides this information. - */ +#ifndef mdelay +#define mdelay(a) udelay((a) * 1000) +#endif /*--------------------------------------------------------------------*/ -/* Here are the values and structures specific for the subsystem. - * The source of information is "Update for the PS/2 Hardware - * Interface Technical Reference, Common Interfaces", September 1991, - * part number 04G3281, available in the U.S. for $21.75 at - * 1-800-IBM-PCTB, elsewhere call your local friendly IBM - * representative. - * In addition to SCSI subsystem, this update contains fairly detailed - * (at hardware register level) sections on diskette controller, - * keyboard controller, serial port controller, VGA, and XGA. - * - * Additional information from "Personal System/2 Micro Channel SCSI - * Adapter with Cache Technical Reference", March 1990, PN 68X2365, - * probably available from the same source (or possibly found buried - * in officemates desk). - * - * Further literature/program-sources referred for this driver: - * - * Friedhelm Schmidt, "SCSI-Bus und IDE-Schnittstelle - Moderne Peripherie- - * Schnittstellen: Hardware, Protokollbeschreibung und Anwendung", 2. Aufl. - * Addison Wesley, 1996. - * - * Michael K. Johnson, "The Linux Kernel Hackers' Guide", Version 0.6, Chapel - * Hill - North Carolina, 1995 - * - * Andreas Kaiser, "SCSI TAPE BACKUP for OS/2 2.0", Version 2.12, Stuttgart - * 1993 - */ + +/* current version of this driver-source: */ +#define IBMMCA_SCSI_DRIVER_VERSION "3.1e" /*--------------------------------------------------------------------*/ /* driver configuration */ #define IM_MAX_HOSTS 8 /* maximum number of host adapters */ -#define IM_RESET_DELAY 10 /* seconds allowed for a reset */ +#define IM_RESET_DELAY 60 /* seconds allowed for a reset */ /* driver debugging - #undef all for normal operation */ /* if defined: count interrupts and ignore this special one: */ #undef IM_DEBUG_TIMEOUT 50 +#define TIMEOUT_PUN 0 +#define TIMEOUT_LUN 0 /* verbose interrupt: */ #undef IM_DEBUG_INT /* verbose queuecommand: */ @@ -512,11 +83,11 @@ #define IM_DEBUG_CMD_DEVICE TYPE_TAPE /* relative addresses of hardware registers on a subsystem */ -#define IM_CMD_REG (shpnt->io_port) /*Command Interface, (4 bytes long) */ -#define IM_ATTN_REG (shpnt->io_port+4) /*Attention (1 byte) */ -#define IM_CTR_REG (shpnt->io_port+5) /*Basic Control (1 byte) */ -#define IM_INTR_REG (shpnt->io_port+6) /*Interrupt Status (1 byte, r/o) */ -#define IM_STAT_REG (shpnt->io_port+7) /*Basic Status (1 byte, read only) */ +#define IM_CMD_REG(hi) (hosts[(hi)]->io_port) /*Command Interface, (4 bytes long) */ +#define IM_ATTN_REG(hi) (hosts[(hi)]->io_port+4) /*Attention (1 byte) */ +#define IM_CTR_REG(hi) (hosts[(hi)]->io_port+5) /*Basic Control (1 byte) */ +#define IM_INTR_REG(hi) (hosts[(hi)]->io_port+6) /*Interrupt Status (1 byte, r/o) */ +#define IM_STAT_REG(hi) (hosts[(hi)]->io_port+7) /*Basic Status (1 byte, read only) */ /* basic I/O-port of first adapter */ #define IM_IO_PORT 0x3540 @@ -668,9 +239,15 @@ /* use_display is set by the ibmmcascsi=display command line arg */ static int use_display = 0; +/* use_adisplay is set by ibmmcascsi=adisplay, which offers a higher + * level of displayed luxus on PS/2 95 (really fancy! :-))) */ +static int use_adisplay = 0; + #define PS2_DISK_LED_ON(ad,id) {\ if( use_display ) { outb((char)(id+48), MOD95_LED_PORT ); \ outb((char)(ad+48), MOD95_LED_PORT+1); } \ + else if( use_adisplay ) { if (id<7) outb((char)(id+48), \ + MOD95_LED_PORT+1+id); outb((char)(ad+48), MOD95_LED_PORT); } \ else outb(inb(PS2_SYS_CTR) | 0xc0, PS2_SYS_CTR); \ } @@ -678,6 +255,11 @@ #define PS2_DISK_LED_OFF() {\ if( use_display ) { outb( ' ', MOD95_LED_PORT ); \ outb(' ', MOD95_LED_PORT+1); } \ + if ( use_adisplay ) { outb(' ',MOD95_LED_PORT ); \ + outb(' ',MOD95_LED_PORT+1); outb(' ',MOD95_LED_PORT+2); \ + outb(' ',MOD95_LED_PORT+3); outb(' ',MOD95_LED_PORT+4); \ + outb(' ',MOD95_LED_PORT+5); outb(' ',MOD95_LED_PORT+6); \ + outb(' ',MOD95_LED_PORT+7); } \ else outb(inb(PS2_SYS_CTR) & 0x3f, PS2_SYS_CTR); \ } @@ -693,18 +275,20 @@ /* List of possible IBM-SCSI-adapters */ struct subsys_list_struct subsys_list[] = { - {0x8efc, "IBM Fast SCSI-2 Adapter"}, - {0x8efd, "IBM 7568 Industrial Computer SCSI Adapter w/cache"}, - {0x8ef8, "IBM Expansion Unit SCSI Controller"}, - {0x8eff, "IBM SCSI Adapter w/Cache"}, - {0x8efe, "IBM SCSI Adapter"}, -}; + {0x8efc, "IBM Fast SCSI-2 Adapter"}, /* special = 0 */ + {0x8efd, "IBM 7568 Industrial Computer SCSI Adapter w/cache"}, /* special = 1 */ + {0x8ef8, "IBM Expansion Unit SCSI Controller"},/* special = 2 */ + {0x8eff, "IBM SCSI Adapter w/Cache"}, /* special = 3 */ + {0x8efe, "IBM SCSI Adapter"}, /* special = 4 */ +}; /*for /proc filesystem */ struct proc_dir_entry proc_scsi_ibmmca = { PROC_SCSI_IBMMCA, 6, "ibmmca", - S_IFDIR | S_IRUGO | S_IXUGO, 2 + S_IFDIR | S_IRUGO | S_IXUGO, 2, + 0, 0, 0, NULL, NULL, NULL, NULL, + NULL, NULL, NULL }; /* Max number of logical devices (can be up from 0 to 14). 15 is the address @@ -715,8 +299,9 @@ struct logical_device { struct im_scb scb; /* SCSI-subsystem-control-block structure */ - struct im_tsb tsb; - struct im_sge sge[16]; + struct im_tsb tsb; /* SCSI command complete status block structure */ + struct im_sge sge[16]; /* scatter gather list structure */ + unsigned char buf[256]; /* SCSI command return data buffer */ Scsi_Cmnd *cmd; /* SCSI-command that is currently in progress */ int device_type; /* type of the SCSI-device. See include/scsi/scsi.h @@ -736,6 +321,7 @@ int total_accesses; /* total accesses on all ldns */ int total_interrupts; /* total interrupts (should be same as total_accesses) */ + int total_errors; /* command completed with error */ /* dynamical assignment statistics */ int total_scsi_devices; /* number of physical pun,lun */ int dyn_flag; /* flag showing dynamical mode */ @@ -747,44 +333,54 @@ /* data structure for each host adapter */ struct ibmmca_hostdata { - /* array of logical devices: */ - struct logical_device _ld[MAX_LOG_DEV]; - /* array to convert (pun, lun) into logical device number: */ - unsigned char _get_ldn[8][8]; - /*array that contains the information about the physical SCSI-devices - attached to this host adapter: */ - unsigned char _get_scsi[8][8]; - /* used only when checking logical devices: */ - int _local_checking_phase_flag; - /* report received interrupt: */ - int _got_interrupt; - /* report termination-status of SCSI-command: */ - int _stat_result; - /* reset status (used only when doing reset): */ - int _reset_status; - /* code of the last SCSI command (needed for panic info): */ - int _last_scsi_command; - /* Counter that points on the next reassignable ldn for dynamical - remapping. The default value is 7, that is the first reassignable - number in the list at boottime: */ - int _next_ldn; - /* Statistics-structure for this IBM-SCSI-host: */ - struct Driver_Statistics _IBM_DS; + /* array of logical devices: */ + struct logical_device _ld[MAX_LOG_DEV+1]; + /* array to convert (pun, lun) into logical device number: */ + unsigned char _get_ldn[8][8]; + /*array that contains the information about the physical SCSI-devices + attached to this host adapter: */ + unsigned char _get_scsi[8][8]; + /* used only when checking logical devices: */ + int _local_checking_phase_flag; + /* report received interrupt: */ + int _got_interrupt; + /* report termination-status of SCSI-command: */ + int _stat_result; + /* reset status (used only when doing reset): */ + int _reset_status; + /* code of the last SCSI command (needed for panic info): */ + int _last_scsi_command[MAX_LOG_DEV+1]; + /* identifier of the last SCSI-command type */ + int _last_scsi_type[MAX_LOG_DEV+1]; + /* Counter that points on the next reassignable ldn for dynamical + remapping. The default value is 7, that is the first reassignable + number in the list at boottime: */ + int _next_ldn; + /* Statistics-structure for this IBM-SCSI-host: */ + struct Driver_Statistics _IBM_DS; + /* This hostadapters pos-registers pos2 and pos3 */ + unsigned _pos2, _pos3; + /* assign a special variable, that contains dedicated info about the + adaptertype */ + int _special; }; /* macros to access host data structure */ -#define HOSTDATA(shpnt) ((struct ibmmca_hostdata *) shpnt->hostdata) -#define subsystem_pun (shpnt->this_id) -#define ld (HOSTDATA(shpnt)->_ld) -#define get_ldn (HOSTDATA(shpnt)->_get_ldn) -#define get_scsi (HOSTDATA(shpnt)->_get_scsi) -#define local_checking_phase_flag (HOSTDATA(shpnt)->_local_checking_phase_flag) -#define got_interrupt (HOSTDATA(shpnt)->_got_interrupt) -#define stat_result (HOSTDATA(shpnt)->_stat_result) -#define reset_status (HOSTDATA(shpnt)->_reset_status) -#define last_scsi_command (HOSTDATA(shpnt)->_last_scsi_command) -#define next_ldn (HOSTDATA(shpnt)->_next_ldn) -#define IBM_DS (HOSTDATA(shpnt)->_IBM_DS) +#define subsystem_pun(hi) (hosts[(hi)]->this_id) +#define ld(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_ld) +#define get_ldn(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_get_ldn) +#define get_scsi(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_get_scsi) +#define local_checking_phase_flag(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_local_checking_phase_flag) +#define got_interrupt(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_got_interrupt) +#define stat_result(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_stat_result) +#define reset_status(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_reset_status) +#define last_scsi_command(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_last_scsi_command) +#define last_scsi_type(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_last_scsi_type) +#define next_ldn(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_next_ldn) +#define IBM_DS(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_IBM_DS) +#define special(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_special) +#define pos2(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_pos2) +#define pos3(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_pos3) /* Define a arbitrary number as subsystem-marker-type. This number is, as described in the ANSI-SCSI-standard, not occupied by other device-types. */ @@ -805,11 +401,23 @@ #define SET_LDN 0 #define REMOVE_LDN 1 +/* ldn which is used to probe the SCSI devices */ +#define PROBE_LDN 0 + /* reset status flag contents */ -#define IM_RESET_NOT_IN_PROGRESS 0 -#define IM_RESET_IN_PROGRESS 1 -#define IM_RESET_FINISHED_OK 2 -#define IM_RESET_FINISHED_FAIL 3 +#define IM_RESET_NOT_IN_PROGRESS 0 +#define IM_RESET_IN_PROGRESS 1 +#define IM_RESET_FINISHED_OK 2 +#define IM_RESET_FINISHED_FAIL 3 +#define IM_RESET_NOT_IN_PROGRESS_NO_INT 4 +#define IM_RESET_FINISHED_OK_NO_INT 5 + +/* special flags for hostdata structure */ +#define FORCED_DETECTION 100 +#define INTEGRATED_SCSI 101 + +/* define undefined SCSI-command */ +#define NO_SCSI 0xffff /*-----------------------------------------------------------------------*/ @@ -823,277 +431,517 @@ MODULE_PARM(io_port, "1-" __MODULE_STRING(IM_MAX_HOSTS) "i"); MODULE_PARM(scsi_id, "1-" __MODULE_STRING(IM_MAX_HOSTS) "i"); MODULE_PARM(display, "1i"); +MODULE_PARM(adisplay, "1i"); +MODULE_PARM(bypass, "1i"); +MODULE_PARM(normal, "1i"); +MODULE_PARM(ansi, "1i"); #endif /*counter of concurrent disk read/writes, to turn on/off disk led */ static int disk_rw_in_progress = 0; +/* spinlock handling to avoid command clash while in operation */ +#ifndef OLDKERN +spinlock_t info_lock = SPIN_LOCK_UNLOCKED; +spinlock_t proc_lock = SPIN_LOCK_UNLOCKED; +spinlock_t abort_lock = SPIN_LOCK_UNLOCKED; +spinlock_t reset_lock = SPIN_LOCK_UNLOCKED; +spinlock_t issue_lock = SPIN_LOCK_UNLOCKED; +spinlock_t intr_lock = SPIN_LOCK_UNLOCKED; +#endif + /* host information */ static int found = 0; static struct Scsi_Host *hosts[IM_MAX_HOSTS+1] = { NULL }; +static unsigned int pos[8]; /* whole pos register-line */ +/* Taking into account the additions, made by ZP Gu. + * This selects now the preset value from the configfile and + * offers the 'normal' commandline option to be accepted */ +#ifdef CONFIG_IBMMCA_SCSI_ORDER_STANDARD +static char ibm_ansi_order = 1; +#else +static char ibm_ansi_order = 0; +#endif + /*-----------------------------------------------------------------------*/ -/*local functions in forward declaration */ -static void interrupt_handler (int irq, void *dev_id, struct pt_regs *regs); -static void do_interrupt_handler (int irq, void *dev_id, struct pt_regs *regs); -static void issue_cmd (struct Scsi_Host *shpnt, unsigned long cmd_reg, - unsigned char attn_reg); +/******************* FUNCTIONS IN FORWARD DECLARATION ************************/ + +static void interrupt_handler (int, void *, struct pt_regs *); +#ifndef OLDKERN +static void do_interrupt_handler (int, void *, struct pt_regs *); +#endif +static void issue_cmd (int, unsigned long, unsigned char); static void internal_done (Scsi_Cmnd * cmd); -static void check_devices (struct Scsi_Host *shpnt); -static int immediate_assign(struct Scsi_Host *shpnt, unsigned int pun, - unsigned int lun, unsigned int ldn, - unsigned int operation); -static int device_inquiry(struct Scsi_Host *shpnt, int ldn, - unsigned char *buf); -static char *ti_p(int value); -static char *ti_l(int value); -static int device_exists (struct Scsi_Host *shpnt, int ldn, int *block_length, - int *device_type); -static struct Scsi_Host *ibmmca_register(Scsi_Host_Template * template, - int port, int id); +static void check_devices (int); +static int immediate_assign(int, unsigned int, unsigned int, unsigned int, + unsigned int); +#ifdef CONFIG_IBMMCA_SCSI_DEV_RESET +static int immediate_reset(int, unsigned int); +#endif +static int device_inquiry(int, int); +static int read_capacity(int, int); +static char *ti_p(int); +static char *ti_l(int); +static int device_exists (int, int, int *, int *); +static struct Scsi_Host *ibmmca_register(Scsi_Host_Template *, + int, int, char *); /* local functions needed for proc_info */ -static int ldn_access_load(struct Scsi_Host *shpnt, int ldn); -static int ldn_access_total_read_write(struct Scsi_Host *shpnt); +static int ldn_access_load(int, int); +static int ldn_access_total_read_write(int); +static int bypass_controller = 0; /* bypass integrated SCSI-cmd set flag */ /*--------------------------------------------------------------------*/ -static void -do_interrupt_handler (int irq, void *dev_id, struct pt_regs *regs) +/******************* LOCAL FUNCTIONS IMPLEMENTATION *************************/ + +#ifndef OLDKERN +/* newer Kernels need the spinlock interrupt handler */ +static void do_interrupt_handler (int irq, void *dev_id, struct pt_regs *regs) { unsigned long flags; spin_lock_irqsave(&io_request_lock, flags); interrupt_handler(irq, dev_id, regs); spin_unlock_irqrestore(&io_request_lock, flags); + return; } +#endif -static void -interrupt_handler (int irq, void *dev_id, struct pt_regs *regs) +static void interrupt_handler (int irq, void *dev_id, struct pt_regs *regs) { - int i = 0; - struct Scsi_Host *shpnt; - unsigned int intr_reg; - unsigned int cmd_result; - unsigned int ldn; - unsigned long flags; + int host_index; + unsigned int intr_reg; + unsigned int cmd_result; + unsigned int ldn; + static unsigned long flags; + Scsi_Cmnd *cmd; + int errorflag; + int interror; - /* search for one adapter-response on shared interrupt */ - do - shpnt = hosts[i++]; - while (shpnt && !(inb(IM_STAT_REG) & IM_INTR_REQUEST)); - - /* return if some other device on this IRQ caused the interrupt */ - if (!shpnt) return; - - /*get command result and logical device */ - intr_reg = inb (IM_INTR_REG); - cmd_result = intr_reg & 0xf0; - ldn = intr_reg & 0x0f; - - /*must wait for attention reg not busy, then send EOI to subsystem */ - save_flags(flags); - while (1) { - cli (); - if (!(inb (IM_STAT_REG) & IM_BUSY)) - break; - restore_flags(flags); - } - outb (IM_EOI | ldn, IM_ATTN_REG); - restore_flags (flags); - - /*these should never happen (hw fails, or a local programming bug) */ - if (cmd_result == IM_ADAPTER_HW_FAILURE) - panic ("IBM MCA SCSI: subsystem hardware failure. Last SCSI_CMD=0x%X. \n", - last_scsi_command); - if (cmd_result == IM_CMD_ERROR) - panic ("IBM MCA SCSI: command error. Last SCSI_CMD=0x%X. \n", - last_scsi_command); - if (cmd_result == IM_SOFTWARE_SEQUENCING_ERROR) - panic ("IBM MCA SCSI: software sequencing error. Last SCSI_CMD=0x%X. \n", - last_scsi_command); - - /* if no panic appeared, increase the interrupt-counter */ - IBM_DS.total_interrupts++; - - /*only for local checking phase */ - if (local_checking_phase_flag) - { - stat_result = cmd_result; - got_interrupt = 1; - reset_status = IM_RESET_FINISHED_OK; - return; - } - - /*handling of commands coming from upper level of scsi driver */ - else - { - Scsi_Cmnd *cmd; - - /*verify ldn, and may handle rare reset immediate command */ - if (ldn >= MAX_LOG_DEV) - { - if (ldn == 0xf && reset_status == IM_RESET_IN_PROGRESS) - { - if (cmd_result == IM_CMD_COMPLETED_WITH_FAILURE) - { - reset_status = IM_RESET_FINISHED_FAIL; - } - else - { - /*reset disk led counter, turn off disk led */ - disk_rw_in_progress = 0; - PS2_DISK_LED_OFF (); - reset_status = IM_RESET_FINISHED_OK; - } - return; - } - else - panic ("IBM MCA SCSI: invalid logical device number.\n"); - } + host_index=0; /* make sure, host_index is 0, else this won't work and + never dare to ask, what happens, if an interrupt-handler + does not work :-((( .... */ + + /* search for one adapter-response on shared interrupt */ + while (hosts[host_index] + && !(inb(IM_STAT_REG(host_index)) & IM_INTR_REQUEST)) + host_index++; + + /* return if some other device on this IRQ caused the interrupt */ + if (!hosts[host_index]) return; -#ifdef IM_DEBUG_TIMEOUT - { - static int count = 0; + /* the reset-function already did all the job, even ints got + renabled on the subsystem, so just return */ + if ((reset_status(host_index) == IM_RESET_NOT_IN_PROGRESS_NO_INT)|| + (reset_status(host_index) == IM_RESET_FINISHED_OK_NO_INT)) + { + reset_status(host_index) = IM_RESET_NOT_IN_PROGRESS; + return; + } + + /*get command result and logical device */ + intr_reg = inb (IM_INTR_REG(host_index)); + cmd_result = intr_reg & 0xf0; + ldn = intr_reg & 0x0f; - if (++count == IM_DEBUG_TIMEOUT) { - printk("IBM MCA SCSI: Ignoring interrupt.\n"); - return; - } - } + /*must wait for attention reg not busy, then send EOI to subsystem */ + while (1) + { +#ifdef OLDKERN + save_flags(flags); + cli(); +#else + spin_lock_irqsave(&intr_lock, flags); +#endif + if (!(inb (IM_STAT_REG(host_index)) & IM_BUSY)) + break; +#ifdef OLDKERN + restore_flags(flags); +#else + spin_unlock_irqrestore(&intr_lock, flags); #endif + } + outb (IM_EOI | ldn, IM_ATTN_REG(host_index)); + /* get the last_scsi_command here */ + interror = last_scsi_command(host_index)[ldn]; +#ifdef OLDKERN + restore_flags(flags); +#else + spin_unlock_irqrestore(&intr_lock, flags); +#endif + errorflag = 0; /* no errors by default */ + /*these should never happen (hw fails, or a local programming bug) */ + if (cmd_result == IM_ADAPTER_HW_FAILURE) + { + printk("\n"); + printk("IBM MCA SCSI: ERROR - subsystem hardware failure!\n"); + printk(" Last SCSI-command=0x%X, ldn=%d, host=%d.\n", + last_scsi_command(host_index)[ldn],ldn,host_index); + errorflag = 1; + } + if (cmd_result == IM_SOFTWARE_SEQUENCING_ERROR) + { + printk("\n"); + printk("IBM MCA SCSI: ERROR - software sequencing error!\n"); + printk(" Last SCSI-command=0x%X, ldn=%d, host=%d.\n", + last_scsi_command(host_index)[ldn],ldn,host_index); + errorflag = 1; + } + if (cmd_result == IM_CMD_ERROR) + { + printk("\n"); + printk("IBM MCA SCSI: ERROR - command error!\n"); + printk(" Last SCSI-command=0x%X, ldn=%d, host=%d.\n", + last_scsi_command(host_index)[ldn],ldn,host_index); + errorflag = 1; + } + if (errorflag) + { /* if errors appear, enter this section to give detailed info */ + printk("IBM MCA SCSI: Subsystem Error-Status follows:\n"); + printk(" Command Type................: %x\n", + last_scsi_type(host_index)[ldn]); + printk(" Attention Register..........: %x\n", + inb (IM_ATTN_REG(host_index))); + printk(" Basic Control Register......: %x\n", + inb (IM_CTR_REG(host_index))); + printk(" Interrupt Status Register...: %x\n", + intr_reg); + printk(" Basic Status Register.......: %x\n", + inb (IM_STAT_REG(host_index))); + if ((last_scsi_type(host_index)[ldn]==IM_SCB)|| + (last_scsi_type(host_index)[ldn]==IM_LONG_SCB)) + { + printk(" SCB End Status Word.........: %x\n", + ld(host_index)[ldn].tsb.end_status); + printk(" Command Status..............: %x\n", + ld(host_index)[ldn].tsb.cmd_status); + printk(" Device Status...............: %x\n", + ld(host_index)[ldn].tsb.dev_status); + printk(" Command Error...............: %x\n", + ld(host_index)[ldn].tsb.cmd_error); + printk(" Device Error................: %x\n", + ld(host_index)[ldn].tsb.dev_error); + printk(" Last SCB Address (LSW)......: %x\n", + ld(host_index)[ldn].tsb.low_of_last_scb_adr); + printk(" Last SCB Address (MSW)......: %x\n", + ld(host_index)[ldn].tsb.high_of_last_scb_adr); + } + printk(" Send report to the maintainer.\n"); + panic("IBM MCA SCSI: Fatal errormessage from the subsystem!\n"); + } + + /* if no panic appeared, increase the interrupt-counter */ + IBM_DS(host_index).total_interrupts++; - /*if no command structure, just return, else clear cmd */ - cmd = ld[ldn].cmd; - if (!cmd) + /*only for local checking phase */ + if (local_checking_phase_flag(host_index)) + { + stat_result(host_index) = cmd_result; + got_interrupt(host_index) = 1; + reset_status(host_index) = IM_RESET_FINISHED_OK; + last_scsi_command(host_index)[ldn] = NO_SCSI; return; - ld[ldn].cmd = 0; - + } + /*handling of commands coming from upper level of scsi driver */ + else + { + if (last_scsi_type(host_index)[ldn] == IM_IMM_CMD) + { + /*verify ldn, and may handle rare reset immediate command */ + if ((reset_status(host_index) == IM_RESET_IN_PROGRESS)&& + (last_scsi_command(host_index)[ldn] == IM_RESET_IMM_CMD)) + { + if (cmd_result == IM_CMD_COMPLETED_WITH_FAILURE) + { + disk_rw_in_progress = 0; + PS2_DISK_LED_OFF (); + reset_status(host_index) = IM_RESET_FINISHED_FAIL; + } + else + { + /*reset disk led counter, turn off disk led */ + disk_rw_in_progress = 0; + PS2_DISK_LED_OFF (); + reset_status(host_index) = IM_RESET_FINISHED_OK; + } + stat_result(host_index) = cmd_result; + last_scsi_command(host_index)[ldn] = NO_SCSI; + return; + } + else if (last_scsi_command(host_index)[ldn] == IM_ABORT_IMM_CMD) + { /* react on SCSI abort command */ +#ifdef IM_DEBUG_PROBE + printk("IBM MCA SCSI: Interrupt from SCSI-abort.\n"); +#endif + disk_rw_in_progress = 0; + PS2_DISK_LED_OFF(); + cmd = ld(host_index)[ldn].cmd; + if (cmd_result == IM_CMD_COMPLETED_WITH_FAILURE) + cmd->result = DID_NO_CONNECT << 16; + else + cmd->result = DID_ABORT << 16; + stat_result(host_index) = cmd_result; + last_scsi_command(host_index)[ldn] = NO_SCSI; + if (cmd->scsi_done) + (cmd->scsi_done) (cmd); /* should be the internal_done */ + return; + } + else + { + disk_rw_in_progress = 0; + PS2_DISK_LED_OFF (); + reset_status(host_index) = IM_RESET_FINISHED_OK; + stat_result(host_index) = cmd_result; + last_scsi_command(host_index)[ldn] = NO_SCSI; + return; + } + } + last_scsi_command(host_index)[ldn] = NO_SCSI; + cmd = ld(host_index)[ldn].cmd; +#ifdef IM_DEBUG_TIMEOUT + if (cmd) + { + if ((cmd->target == TIMEOUT_PUN)&&(cmd->lun == TIMEOUT_LUN)) + { + printk("IBM MCA SCSI: Ignoring interrupt from pun=%x, lun=%x.\n", + cmd->target, cmd->lun); + return; + } + } +#endif + /*if no command structure, just return, else clear cmd */ + if (!cmd) + return; + ld(host_index)[ldn].cmd = NULL; + #ifdef IM_DEBUG_INT - printk("cmd=%02x ireg=%02x ds=%02x cs=%02x de=%02x ce=%02x\n", - cmd->cmnd[0], intr_reg, - ld[ldn].tsb.dev_status, ld[ldn].tsb.cmd_status, - ld[ldn].tsb.dev_error, ld[ldn].tsb.cmd_error); -#endif - - /*if this is end of media read/write, may turn off PS/2 disk led */ - if ((ld[ldn].device_type!=TYPE_NO_LUN)&& - (ld[ldn].device_type!=TYPE_NO_DEVICE)) - { /* only access this, if there was a valid device addressed */ - switch (cmd->cmnd[0]) - { - case READ_6: - case WRITE_6: - case READ_10: - case WRITE_10: - case READ_12: - case WRITE_12: - if (--disk_rw_in_progress == 0) - PS2_DISK_LED_OFF (); - } - } - - /*write device status into cmd->result, and call done function */ - if (cmd_result == IM_CMD_COMPLETED_WITH_FAILURE) - cmd->result = ld[ldn].tsb.dev_status & 0x1e; - else - cmd->result = 0; - (cmd->scsi_done) (cmd); - } -} - -/*--------------------------------------------------------------------*/ - -static void -issue_cmd (struct Scsi_Host *shpnt, unsigned long cmd_reg, - unsigned char attn_reg) -{ - unsigned long flags; - /*must wait for attention reg not busy */ - save_flags(flags); - while (1) - { - cli (); - if (!(inb (IM_STAT_REG) & IM_BUSY)) - break; - restore_flags (flags); - } + printk("cmd=%02x ireg=%02x ds=%02x cs=%02x de=%02x ce=%02x\n", + cmd->cmnd[0], intr_reg, + ld(host_index)[ldn].tsb.dev_status, + ld(host_index)[ldn].tsb.cmd_status, + ld(host_index)[ldn].tsb.dev_error, + ld(host_index)[ldn].tsb.cmd_error); +#endif + + /*if this is end of media read/write, may turn off PS/2 disk led */ + if ((ld(host_index)[ldn].device_type!=TYPE_NO_LUN)&& + (ld(host_index)[ldn].device_type!=TYPE_NO_DEVICE)) + { /* only access this, if there was a valid device addressed */ + switch (cmd->cmnd[0]) + { + case READ_6: + case WRITE_6: + case READ_10: + case WRITE_10: + case READ_12: + case WRITE_12: + if (--disk_rw_in_progress == 0) + PS2_DISK_LED_OFF (); + } + } - /*write registers and enable system interrupts */ - outl (cmd_reg, IM_CMD_REG); - outb (attn_reg, IM_ATTN_REG); - restore_flags (flags); + /* IBM describes the status-mask to be 0x1e, but this is not conform + * with SCSI-defintion, I suppose, it is a printing error in the + * technical reference and assume as mask 0x3e. (ML) */ + cmd->result = (ld(host_index)[ldn].tsb.dev_status & 0x3e); + /* write device status into cmd->result, and call done function */ + if (cmd_result == IM_CMD_COMPLETED_WITH_FAILURE) + IBM_DS(host_index).total_errors++; + if (interror == NO_SCSI) /* unexpected interrupt :-( */ + cmd->result |= DID_BAD_INTR << 16; + else + cmd->result |= DID_OK << 16; + (cmd->scsi_done) (cmd); + } + if (interror == NO_SCSI) + printk("IBM MCA SCSI: WARNING - Interrupt from non-pending SCSI-command!\n"); + return; } /*--------------------------------------------------------------------*/ -static void -internal_done (Scsi_Cmnd * cmd) +static void issue_cmd (int host_index, unsigned long cmd_reg, + unsigned char attn_reg) { - cmd->SCp.Status++; + static unsigned long flags; + /* must wait for attention reg not busy */ + while (1) + { +#ifdef OLDKERN + save_flags(flags); + cli(); +#else + spin_lock_irqsave(&issue_lock, flags); +#endif + if (!(inb (IM_STAT_REG(host_index)) & IM_BUSY)) + break; +#ifdef OLDKERN + restore_flags(flags); +#else + spin_unlock_irqrestore(&issue_lock, flags); +#endif + } + /*write registers and enable system interrupts */ + outl (cmd_reg, IM_CMD_REG(host_index)); + outb (attn_reg, IM_ATTN_REG(host_index)); +#ifdef OLDKERN + restore_flags(flags); +#else + spin_unlock_irqrestore(&issue_lock, flags); +#endif } /*--------------------------------------------------------------------*/ -static int ibmmca_getinfo (char *buf, int slot, void *dev) +static void internal_done (Scsi_Cmnd * cmd) { - struct Scsi_Host *shpnt = dev; - int len = 0; - - len += sprintf (buf + len, "Subsystem PUN: %d\n", subsystem_pun); - len += sprintf (buf + len, "I/O base address: 0x%lx\n", IM_CMD_REG); - return len; + cmd->SCp.Status++; } /*--------------------------------------------------------------------*/ /* SCSI-SCB-command for device_inquiry */ -static int device_inquiry(struct Scsi_Host *shpnt, int ldn, unsigned char *buf) +static int device_inquiry(int host_index, int ldn) { - struct im_scb scb; - struct im_tsb tsb; - int retries; - - for (retries = 0; retries < 3; retries++) - { - /*fill scb with inquiry command */ - scb.command = IM_DEVICE_INQUIRY_CMD; - scb.enable = IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT; - scb.sys_buf_adr = virt_to_bus(buf); - scb.sys_buf_length = 255; - scb.tsb_adr = virt_to_bus(&tsb); - - /*issue scb to passed ldn, and busy wait for interrupt */ - got_interrupt = 0; - issue_cmd (shpnt, virt_to_bus(&scb), IM_SCB | ldn); - while (!got_interrupt) - barrier (); - - /*if command succesful, break */ - if (stat_result == IM_SCB_CMD_COMPLETED) - break; - } + int retries; + Scsi_Cmnd cmd; + struct im_scb *scb; + struct im_tsb *tsb; + unsigned char *buf; + + scb = &(ld(host_index)[ldn].scb); + tsb = &(ld(host_index)[ldn].tsb); + buf = (unsigned char *)(&(ld(host_index)[ldn].buf)); + ld(host_index)[ldn].tsb.dev_status = 0; /* prepare stusblock */ + + if (bypass_controller) + { /* fill the commonly known field for device-inquiry SCSI cmnd */ + cmd.cmd_len = 6; + memset (&(cmd.cmnd), 0x0, sizeof(char) * cmd.cmd_len); + cmd.cmnd[0] = INQUIRY; /* device inquiry */ + cmd.cmnd[4] = 0xff; /* return buffer size = 255 */ + } + for (retries = 0; retries < 3; retries++) + { + if (bypass_controller) + { /* bypass the hardware integrated command set */ + scb->command = IM_OTHER_SCSI_CMD_CMD; + scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT; + scb->u1.scsi_cmd_length = cmd.cmd_len; + memcpy (scb->u2.scsi_command, &(cmd.cmnd), cmd.cmd_len); + last_scsi_command(host_index)[ldn] = INQUIRY; + last_scsi_type(host_index)[ldn] = IM_SCB; + } + else + { + /*fill scb with inquiry command */ + scb->command = IM_DEVICE_INQUIRY_CMD; + scb->enable = IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT; + last_scsi_command(host_index)[ldn] = IM_DEVICE_INQUIRY_CMD; + last_scsi_type(host_index)[ldn] = IM_SCB; + } + scb->sys_buf_adr = virt_to_bus(buf); + scb->sys_buf_length = 0xff; /* maximum bufferlength gives max info */ + scb->tsb_adr = virt_to_bus(tsb); + + /*issue scb to passed ldn, and busy wait for interrupt */ + got_interrupt(host_index) = 0; + issue_cmd (host_index, virt_to_bus(scb), IM_SCB | ldn); + while (!got_interrupt(host_index)) + barrier (); + + /*if command succesful, break */ + if ((stat_result(host_index) == IM_SCB_CMD_COMPLETED)|| + (stat_result(host_index) == IM_SCB_CMD_COMPLETED_WITH_RETRIES)) + { + return 1; + } + } + + /*if all three retries failed, return "no device at this ldn" */ + if (retries >= 3) + return 0; + else + return 1; +} - /*if all three retries failed, return "no device at this ldn" */ - if (retries >= 3) - return 0; - else - return 1; +static int read_capacity(int host_index, int ldn) +{ + int retries; + Scsi_Cmnd cmd; + struct im_scb *scb; + struct im_tsb *tsb; + unsigned char *buf; + + scb = &(ld(host_index)[ldn].scb); + tsb = &(ld(host_index)[ldn].tsb); + buf = (unsigned char *)(&(ld(host_index)[ldn].buf)); + ld(host_index)[ldn].tsb.dev_status = 0; + + if (bypass_controller) + { /* read capacity in commonly known default SCSI-format */ + cmd.cmd_len = 10; + memset (&(cmd.cmnd), 0x0, sizeof(char) * cmd.cmd_len); + cmd.cmnd[0] = READ_CAPACITY; /* read capacity */ + } + for (retries = 0; retries < 3; retries++) + { + /*fill scb with read capacity command */ + if (bypass_controller) + { /* bypass the SCSI-command */ + scb->command = IM_OTHER_SCSI_CMD_CMD; + scb->enable |= IM_READ_CONTROL; + scb->u1.scsi_cmd_length = cmd.cmd_len; + memcpy (scb->u2.scsi_command, &(cmd.cmnd), cmd.cmd_len); + last_scsi_command(host_index)[ldn] = READ_CAPACITY; + last_scsi_type(host_index)[ldn] = IM_SCB; + } + else + { + scb->command = IM_READ_CAPACITY_CMD; + scb->enable = IM_READ_CONTROL; + last_scsi_command(host_index)[ldn] = IM_READ_CAPACITY_CMD; + last_scsi_type(host_index)[ldn] = IM_SCB; + } + scb->sys_buf_adr = virt_to_bus(buf); + scb->sys_buf_length = 8; + scb->tsb_adr = virt_to_bus(tsb); + + /*issue scb to passed ldn, and busy wait for interrupt */ + got_interrupt(host_index) = 0; + issue_cmd (host_index, virt_to_bus(scb), IM_SCB | ldn); + while (!got_interrupt(host_index)) + barrier (); + + /*if got capacity, get block length and return one device found */ + if ((stat_result(host_index) == IM_SCB_CMD_COMPLETED)|| + (stat_result(host_index) == IM_SCB_CMD_COMPLETED_WITH_RETRIES)) + { + return 1; + } + } + /*if all three retries failed, return "no device at this ldn" */ + if (retries >= 3) + return 0; + else + return 1; } /* SCSI-immediate-command for assign. This functions maps/unmaps specific - ldn-numbers on SCSI (PUN,LUN). It is needed for presetting of the - subsystem and for dynamical remapping od ldns. */ -static int immediate_assign(struct Scsi_Host *shpnt, unsigned int pun, + ldn-numbers on SCSI (PUN,LUN). It is needed for presetting of the + subsystem and for dynamical remapping od ldns. */ +static int immediate_assign(int host_index, unsigned int pun, unsigned int lun, unsigned int ldn, unsigned int operation) { int retries; unsigned long imm_command; - + for (retries=0; retries<3; retries ++) - { - imm_command = inl(IM_CMD_REG); + { + imm_command = inl(IM_CMD_REG(host_index)); imm_command &= (unsigned long)(0xF8000000); /* keep reserved bits */ imm_command |= (unsigned long)(IM_ASSIGN_IMM_CMD); imm_command |= (unsigned long)((lun & 7) << 24); @@ -1101,14 +949,64 @@ imm_command |= (unsigned long)((pun & 7) << 20); imm_command |= (unsigned long)((ldn & 15) << 16); - got_interrupt = 0; - issue_cmd (shpnt, (unsigned long)(imm_command), IM_IMM_CMD | 0xf); - while (!got_interrupt) - barrier (); - + last_scsi_command(host_index)[0xf] = IM_ASSIGN_IMM_CMD; + last_scsi_type(host_index)[0xf] = IM_IMM_CMD; + got_interrupt(host_index) = 0; + issue_cmd (host_index, (unsigned long)(imm_command), IM_IMM_CMD | 0xf); + while (!got_interrupt(host_index)) + barrier (); + + /*if command succesful, break */ + if (stat_result(host_index) == IM_IMMEDIATE_CMD_COMPLETED) + { + return 1; + } + } + + if (retries >= 3) + return 0; + else + return 1; +} + +#ifdef CONFIG_IBMMCA_SCSI_DEV_RESET +static int immediate_reset(int host_index, unsigned int ldn) +{ + int retries; + int ticks; + unsigned long imm_command; + + for (retries=0; retries<3; retries ++) + { + imm_command = inl(IM_CMD_REG(host_index)); + imm_command &= (unsigned long)(0xFFFF0000); /* keep reserved bits */ + imm_command |= (unsigned long)(IM_RESET_IMM_CMD); + last_scsi_command(host_index)[ldn] = IM_RESET_IMM_CMD; + last_scsi_type(host_index)[ldn] = IM_IMM_CMD; + + got_interrupt(host_index) = 0; + reset_status(host_index) = IM_RESET_IN_PROGRESS; + issue_cmd (host_index, (unsigned long)(imm_command), IM_IMM_CMD | ldn); + ticks = IM_RESET_DELAY*HZ; + while (reset_status(host_index) == IM_RESET_IN_PROGRESS && --ticks) + { + mdelay(1+999/HZ); + barrier(); + } + /* if reset did not complete, just claim */ + if (!ticks) + { + printk("IBM MCA SCSI: reset did not complete within %d seconds.\n", + IM_RESET_DELAY); + reset_status(host_index) = IM_RESET_FINISHED_OK; + /* did not work, finish */ + return 1; + } /*if command succesful, break */ - if (stat_result == IM_IMMEDIATE_CMD_COMPLETED) - break; + if (stat_result(host_index) == IM_IMMEDIATE_CMD_COMPLETED) + { + return 1; + } } if (retries >= 3) @@ -1116,24 +1014,25 @@ else return 1; } +#endif /* type-interpreter for physical device numbers */ static char *ti_p(int value) { switch (value) { - case TYPE_IBM_SCSI_ADAPTER: return("A"); break; - case TYPE_DISK: return("D"); break; - case TYPE_TAPE: return("T"); break; - case TYPE_PROCESSOR: return("P"); break; - case TYPE_WORM: return("W"); break; - case TYPE_ROM: return("R"); break; - case TYPE_SCANNER: return("S"); break; - case TYPE_MOD: return("M"); break; - case TYPE_MEDIUM_CHANGER: return("C"); break; - case TYPE_NO_LUN: return("+"); break; /* show NO_LUN */ - case TYPE_NO_DEVICE: - default: return("-"); break; + case TYPE_IBM_SCSI_ADAPTER: return("A"); break; + case TYPE_DISK: return("D"); break; + case TYPE_TAPE: return("T"); break; + case TYPE_PROCESSOR: return("P"); break; + case TYPE_WORM: return("W"); break; + case TYPE_ROM: return("R"); break; + case TYPE_SCANNER: return("S"); break; + case TYPE_MOD: return("M"); break; + case TYPE_MEDIUM_CHANGER: return("C"); break; + case TYPE_NO_LUN: return("+"); break; /* show NO_LUN */ + case TYPE_NO_DEVICE: + default: return("-"); break; } return("-"); } @@ -1141,9 +1040,9 @@ /* interpreter for logical device numbers (ldn) */ static char *ti_l(int value) { - const char hex[16] = ("0123456789abcdef"); + const char hex[16] = "0123456789abcdef"; static char answer[2]; - + answer[1] = (char)(0x0); if (value<=MAX_LOG_DEV) answer[0] = hex[value]; @@ -1154,182 +1053,181 @@ } /* - The following routine probes the SCSI-devices in four steps: - 1. The current ldn -> pun,lun mapping is removed on the SCSI-adapter. - 2. ldn 0 is used to go through all possible combinations of pun,lun and - a device_inquiry is done to fiddle out whether there is a device - responding or not. This physical map is stored in get_scsi[][]. - 3. The 15 available ldns (0-14) are mapped to existing pun,lun. - If there are more devices than ldns, it stops at 14 for the boot - time. Dynamical remapping will be done in ibmmca_queuecommand. - 4. If there are less than 15 valid pun,lun, the remaining ldns are - mapped to NON-existing pun,lun to satisfy the adapter. Information - about pun,lun -> ldn is stored as before in get_ldn[][]. - This method leads to the result, that the SCSI-pun,lun shown to Linux - mid-level- and higher-level-drivers is exactly corresponding to the - physical reality on the SCSI-bus. Therefore, it is possible that users - of older releases of this driver have to rewrite their fstab-file, because - the /dev/sdXXX could have changed due to the right pun,lun report, now. - The assignment of ALL ldns avoids dynamical remapping by the adapter - itself. + The following routine probes the SCSI-devices in four steps: + 1. The current ldn -> pun,lun mapping is removed on the SCSI-adapter. + 2. ldn 0 is used to go through all possible combinations of pun,lun and + a device_inquiry is done to fiddle out whether there is a device + responding or not. This physical map is stored in get_scsi[][]. + 3. The 15 available ldns (0-14) are mapped to existing pun,lun. + If there are more devices than ldns, it stops at 14 for the boot + time. Dynamical remapping will be done in ibmmca_queuecommand. + 4. If there are less than 15 valid pun,lun, the remaining ldns are + mapped to NON-existing pun,lun to satisfy the adapter. Information + about pun,lun -> ldn is stored as before in get_ldn[][]. + This method leads to the result, that the SCSI-pun,lun shown to Linux + mid-level- and higher-level-drivers is exactly corresponding to the + physical reality on the SCSI-bus. Therefore, it is possible that users + of older releases of this driver have to rewrite their fstab-file, because + the /dev/sdXXX could have changed due to the right pun,lun report, now. + The assignment of ALL ldns avoids dynamical remapping by the adapter + itself. */ -static void check_devices (struct Scsi_Host *shpnt) +static void check_devices (int host_index) { - int id, lun, ldn; - unsigned char buf[256]; - int count_devices = 0; /* local counter for connected device */ - - /* assign default values to certain variables */ - - IBM_DS.dyn_flag = 0; /* normally no need for dynamical ldn management */ - next_ldn = 7; /* next ldn to be assigned is 7, because 0-6 is 'hardwired'*/ - last_scsi_command = 0; /* emptify last SCSI-command storage */ - - /* initialize the very important driver-informational arrays/structs */ - memset (ld, 0, sizeof ld); - memset (get_ldn, TYPE_NO_DEVICE, sizeof get_ldn); /* this is essential ! */ - memset (get_scsi, TYPE_NO_DEVICE, sizeof get_scsi); /* this is essential ! */ - - for (lun=0; lun<8; lun++) /* mark the adapter at its pun on all luns*/ - { - get_scsi[subsystem_pun][lun] = TYPE_IBM_SCSI_ADAPTER; - get_ldn[subsystem_pun][lun] = MAX_LOG_DEV; /* make sure, the subsystem - ldn is active for all - luns. */ - } - - /* STEP 1: */ - printk("IBM MCA SCSI: Removing current logical SCSI-device mapping."); - for (ldn=0; ldn 0) - { - /* remove mapping */ - get_ldn[id][lun]=TYPE_NO_DEVICE; - immediate_assign(shpnt,0,0,ldn,REMOVE_LDN); - } - else ldn++; - } - } - else if (lun == 0) - { - /* map lun == 0, even if no device exists */ - immediate_assign(shpnt,id,lun,ldn,SET_LDN); - get_ldn[id][lun]=ldn; /* map ldn */ - ldn++; - } + printk("resetting device at ldn=%x ... ",ldn); + immediate_reset(host_index,ldn); +#endif + ldn++; + } + else + { + /* device vanished, probably because we don't know how to + * handle it or because it has problems */ + if (lun > 0) + { + /* remove mapping */ + get_ldn(host_index)[id][lun]=TYPE_NO_DEVICE; + immediate_assign(host_index,0,0,ldn,REMOVE_LDN); + } + else ldn++; + } + } + else if (lun == 0) + { + /* map lun == 0, even if no device exists */ + immediate_assign(host_index,id,lun,ldn,SET_LDN); + get_ldn(host_index)[id][lun]=ldn; /* map ldn */ + ldn++; + } } - } - + } + /* STEP 4: */ /* map remaining ldns to non-existing devices */ for (lun=1; lun<8 && ldn=MAX_LOG_DEV) - IBM_DS.dyn_flag = 1; /* dynamical assignment is necessary */ + IBM_DS(host_index).dyn_flag = 1; /* dynamical assignment is necessary */ else - IBM_DS.dyn_flag = 0; /* dynamical assignment is not necessary */ - + IBM_DS(host_index).dyn_flag = 0; /* dynamical assignment is not necessary */ + /* If no SCSI-devices are assigned, return 1 in order to cause message. */ if (ldn == 0) - printk("IBM MCA SCSI: Warning: No SCSI-devices found/assignable!\n"); - - /* reset the counters for statistics on the current adapter */ - IBM_DS.total_accesses = 0; - IBM_DS.total_interrupts = 0; - IBM_DS.dynamical_assignments = 0; - memset (IBM_DS.ldn_access, 0x0, sizeof (IBM_DS.ldn_access)); - memset (IBM_DS.ldn_read_access, 0x0, sizeof (IBM_DS.ldn_read_access)); - memset (IBM_DS.ldn_write_access, 0x0, sizeof (IBM_DS.ldn_write_access)); - memset (IBM_DS.ldn_inquiry_access, 0x0, sizeof (IBM_DS.ldn_inquiry_access)); - memset (IBM_DS.ldn_modeselect_access, 0x0, sizeof (IBM_DS.ldn_modeselect_access)); - memset (IBM_DS.ldn_assignments, 0x0, sizeof (IBM_DS.ldn_assignments)); + printk("IBM MCA SCSI: Warning: No SCSI-devices found/assigned!\n"); - return; -} - -/*--------------------------------------------------------------------*/ - -static int -device_exists (struct Scsi_Host *shpnt, int ldn, int *block_length, - int *device_type) -{ - struct im_scb scb; - struct im_tsb tsb; - unsigned char buf[256]; - int retries; - - /* if no valid device found, return immediately with 0 */ - if (!(device_inquiry(shpnt, ldn, buf))) return 0; - - /*if device is CD_ROM, assume block size 2048 and return */ - if (buf[0] == TYPE_ROM) - { - *device_type = TYPE_ROM; - *block_length = 2048; /* (standard blocksize for yellow-/red-book) */ - return 1; - } - - if (buf[0] == TYPE_WORM) /* CD-burner, WORM, Linux handles this as CD-ROM - therefore, the block_length is also 2048. */ - { - *device_type = TYPE_WORM; - *block_length = 2048; - return 1; - } - - /* if device is disk, use "read capacity" to find its block size */ - if (buf[0] == TYPE_DISK) - { - *device_type = TYPE_DISK; - - for (retries = 0; retries < 3; retries++) - { - /*fill scb with read capacity command */ - scb.command = IM_READ_CAPACITY_CMD; - scb.enable = IM_READ_CONTROL; - scb.sys_buf_adr = virt_to_bus(buf); - scb.sys_buf_length = 8; - scb.tsb_adr = virt_to_bus(&tsb); - - /*issue scb to passed ldn, and busy wait for interrupt */ - got_interrupt = 0; - issue_cmd (shpnt, virt_to_bus(&scb), IM_SCB | ldn); - while (!got_interrupt) - barrier (); - - /*if got capacity, get block length and return one device found */ - if (stat_result == IM_SCB_CMD_COMPLETED) - { - *block_length = buf[7] + (buf[6] << 8) + (buf[5] << 16) + (buf[4] << 24); - return 1; - } - } - - /*if all three retries failed, return "no device at this ldn" */ - if (retries >= 3) - return 0; - } - - /* if this is a magneto-optical drive, treat it like a harddisk */ - if (buf[0] == TYPE_MOD) - { - *device_type = TYPE_MOD; - - for (retries = 0; retries < 3; retries++) - { - /*fill scb with read capacity command */ - scb.command = IM_READ_CAPACITY_CMD; - scb.enable = IM_READ_CONTROL; - scb.sys_buf_adr = virt_to_bus(buf); - scb.sys_buf_length = 8; - scb.tsb_adr = virt_to_bus(&tsb); - - /*issue scb to passed ldn, and busy wait for interrupt */ - got_interrupt = 0; - issue_cmd (shpnt, virt_to_bus(&scb), IM_SCB | ldn); - while (!got_interrupt) - barrier (); - - /*if got capacity, get block length and return one device found */ - if (stat_result == IM_SCB_CMD_COMPLETED) - { - *block_length = buf[7] + (buf[6] << 8) + (buf[5] << 16) + (buf[4] << 24); - return 1; - } - } - - /*if all three retries failed, return "no device at this ldn" */ - if (retries >= 3) - return 0; - } + /* reset the counters for statistics on the current adapter */ + IBM_DS(host_index).total_accesses = 0; + IBM_DS(host_index).total_interrupts = 0; + IBM_DS(host_index).dynamical_assignments = 0; + memset (IBM_DS(host_index).ldn_access, 0x0, + sizeof (IBM_DS(host_index).ldn_access)); + memset (IBM_DS(host_index).ldn_read_access, 0x0, + sizeof (IBM_DS(host_index).ldn_read_access)); + memset (IBM_DS(host_index).ldn_write_access, 0x0, + sizeof (IBM_DS(host_index).ldn_write_access)); + memset (IBM_DS(host_index).ldn_inquiry_access, 0x0, + sizeof (IBM_DS(host_index).ldn_inquiry_access)); + memset (IBM_DS(host_index).ldn_modeselect_access, 0x0, + sizeof (IBM_DS(host_index).ldn_modeselect_access)); + memset (IBM_DS(host_index).ldn_assignments, 0x0, + sizeof (IBM_DS(host_index).ldn_assignments)); - if (buf[0] == TYPE_TAPE) /* TAPE-device found */ - { - *device_type = TYPE_TAPE; - *block_length = 0; /* not in use (setting by mt and mtst in op.) */ - return 1; - } - - if (buf[0] == TYPE_PROCESSOR) /* HP-Scanners, diverse SCSI-processing units*/ - { - *device_type = TYPE_PROCESSOR; - *block_length = 0; /* they set their stuff on drivers */ - return 1; - } - - if (buf[0] == TYPE_SCANNER) /* other SCSI-scanners */ - { - *device_type = TYPE_SCANNER; - *block_length = 0; /* they set their stuff on drivers */ - return 1; - } - - if (buf[0] == TYPE_MEDIUM_CHANGER) /* Medium-Changer */ - { - *device_type = TYPE_MEDIUM_CHANGER; - *block_length = 0; /* One never knows, what to expect on a medium - changer device. */ - return 1; - } - - /* Up to now, no SCSI-devices that are known up to kernel 2.1.31 are - ignored! MO-drives are now supported and treated as harddisk. */ - return 0; + return; } /*--------------------------------------------------------------------*/ -#ifdef CONFIG_SCSI_IBMMCA - -void -ibmmca_scsi_setup (char *str, int *ints) +static int device_exists (int host_index, int ldn, int *block_length, + int *device_type) { - if( str && !strcmp( str, "display" ) ) { - use_display = 1; - } else if( ints ) { - int i; - for (i = 0; i < IM_MAX_HOSTS && 2*i+2 < ints[0]; i++) { - io_port[i] = ints[2*i+2]; - scsi_id[i] = ints[2*i+2]; - } - } -} + unsigned char *buf; + + /* if no valid device found, return immediately with 0 */ + if (!(device_inquiry(host_index, ldn))) + return 0; + + buf = (unsigned char *)(&(ld(host_index)[ldn].buf)); -#endif + /*if device is CD_ROM, assume block size 2048 and return */ + if (*buf == TYPE_ROM) + { + *device_type = TYPE_ROM; + *block_length = 2048; /* (standard blocksize for yellow-/red-book) */ + return 1; + } + + if (*buf == TYPE_WORM) /* CD-burner, WORM, Linux handles this as CD-ROM + therefore, the block_length is also 2048. */ + { + *device_type = TYPE_WORM; + *block_length = 2048; + return 1; + } + + /* if device is disk, use "read capacity" to find its block size */ + if (*buf == TYPE_DISK) + { + *device_type = TYPE_DISK; + if (read_capacity( host_index, ldn)) + { + *block_length = *(buf+7) + (*(buf+6) << 8) + + (*(buf+5) << 16) + (*(buf+4) << 24); + return 1; + } + else + return 0; + } + + /* if this is a magneto-optical drive, treat it like a harddisk */ + if (*buf == TYPE_MOD) + { + *device_type = TYPE_MOD; + if (read_capacity( host_index, ldn)) + { + *block_length = *(buf+7) + (*(buf+6) << 8) + + (*(buf+5) << 16) + (*(buf+4) << 24); + return 1; + } + else + return 0; + } + + if (*buf == TYPE_TAPE) /* TAPE-device found */ + { + *device_type = TYPE_TAPE; + *block_length = 0; /* not in use (setting by mt and mtst in op.) */ + return 1; + } + + if (*buf == TYPE_PROCESSOR) /* HP-Scanners, diverse SCSI-processing units*/ + { + *device_type = TYPE_PROCESSOR; + *block_length = 0; /* they set their stuff on drivers */ + return 1; + } + + if (*buf == TYPE_SCANNER) /* other SCSI-scanners */ + { + *device_type = TYPE_SCANNER; + *block_length = 0; /* they set their stuff on drivers */ + return 1; + } + + if (*buf == TYPE_MEDIUM_CHANGER) /* Medium-Changer */ + { + *device_type = TYPE_MEDIUM_CHANGER; + *block_length = 0; /* One never knows, what to expect on a medium + changer device. */ + return 1; + } + + /* Up to now, no SCSI-devices that are known up to kernel 2.1.31 are + ignored! MO-drives are now supported and treated as harddisk. */ + return 0; +} /*--------------------------------------------------------------------*/ + +#ifdef CONFIG_SCSI_IBMMCA -int -ibmmca_detect (Scsi_Host_Template * template) +void ibmmca_scsi_setup (char *str, int *ints) { - struct Scsi_Host *shpnt; - int port, id, i, list_size, slot; - unsigned pos2, pos3; - - /* if this is not MCA machine, return "nothing found" */ - if (!MCA_bus) - return 0; - - /* get interrupt request level */ - if (request_irq (IM_IRQ, do_interrupt_handler, SA_SHIRQ, "ibmmca", hosts)) - { - printk("IBM MCA SCSI: Unable to get IRQ %d.\n", IM_IRQ); - return 0; - } - - /* if ibmmcascsi setup option was passed to kernel, return "found" */ - for (i = 0; i < IM_MAX_HOSTS; i++) - if (io_port[i] > 0 && scsi_id[i] >= 0 && scsi_id[i] < 8) - { - printk("IBM MCA SCSI: forced detection, io=0x%x, scsi id=%d.\n", - io_port[i], scsi_id[i]); - ibmmca_register(template, io_port[i], scsi_id[i]); - } - if (found) return found; + int i, j, io_base, id_base; + char *token; + + io_base = 0; + id_base = 0; + + if (str) + { + token = strtok(str,","); + j = 0; + while (token) + { + if (!strcmp(token,"display")) + { + use_display = 1; + } + if (!strcmp(token,"adisplay")) + { + use_adisplay = 1; + } + if (!strcmp(token,"bypass")) + { + bypass_controller = 1; + } + if (!strcmp(token,"normal")) + { + ibm_ansi_order = 0; + } + if (!strcmp(token,"ansi")) + { + ibm_ansi_order = 1; + } + if ( (*token == '-') || (isdigit(*token)) ) + { + if (!(j%2) && (io_base < IM_MAX_HOSTS)) + { + io_port[io_base++] = simple_strtoul(token,NULL,0); + } + if ((j%2) && (id_base < IM_MAX_HOSTS)) + { + scsi_id[id_base++] = simple_strtoul(token,NULL,0); + } + j++; + } + token = strtok(NULL,","); + } + } + else if (ints) + { + for (i = 0; i < IM_MAX_HOSTS && 2*i+2 < ints[0]; i++) + { + io_port[i] = ints[2*i+2]; + scsi_id[i] = ints[2*i+2]; + } + } + return; +} - /* - * Patched by ZP Gu to work with the 9556 as well; the 9556 has - * pos2 = 05, but it should be 00, as it should be interfaced - * via port = 0x3540. - */ - - /* first look for the SCSI integrated on the motherboard */ - pos2 = mca_read_stored_pos(MCA_INTEGSCSI, 2); -// if (pos2 != 0xff) { - if ((pos2 & 1) == 0) { - port = IM_IO_PORT + ((pos2 & 0x0e) << 2); - } else { - port = IM_IO_PORT; - } - pos3 = mca_read_stored_pos(MCA_INTEGSCSI, 3); - id = (pos3 & 0xe0) >> 5; - - printk("IBM MCA SCSI: integrated SCSI found, io=0x%x, scsi id=%d.\n", - port, id); - if ((shpnt = ibmmca_register(template, port, id))) - { - mca_set_adapter_name(MCA_INTEGSCSI, "PS/2 Integrated SCSI"); - mca_set_adapter_procfn(MCA_INTEGSCSI, (MCA_ProcFn) ibmmca_getinfo, - shpnt); - } -// } - - /* now look for other adapters */ - list_size = sizeof(subsys_list) / sizeof(struct subsys_list_struct); - for (i = 0; i < list_size; i++) - { - slot = 0; - while ((slot = mca_find_adapter(subsys_list[i].mca_id, slot)) - != MCA_NOTFOUND) - { - pos2 = mca_read_stored_pos(slot, 2); - pos3 = mca_read_stored_pos(slot, 3); - port = IM_IO_PORT + ((pos2 & 0x0e) << 2); - id = (pos3 & 0xe0) >> 5; - printk ("IBM MCA SCSI: %s found in slot %d, io=0x%x, scsi id=%d.\n", - subsys_list[i].description, slot + 1, port, id); - if ((shpnt = ibmmca_register(template, port, id))) - { - mca_set_adapter_name (slot, subsys_list[i].description); - mca_set_adapter_procfn (slot, (MCA_ProcFn) ibmmca_getinfo, - shpnt); - } - slot++; - } - } - - if (!found) { - free_irq (IM_IRQ, hosts); - printk("IBM MCA SCSI: No adapter attached.\n"); - } +#endif + +/*--------------------------------------------------------------------*/ + +static int ibmmca_getinfo (char *buf, int slot, void *dev) +{ + struct Scsi_Host *shpnt; + int len, special; + unsigned int pos2, pos3; + static unsigned long flags; + +#ifdef OLDKERN + save_flags(flags); + cli(); +#else + spin_lock_irqsave(&info_lock, flags); +#endif + + shpnt = dev; /* assign host-structure to local pointer */ + len = 0; /* set filled text-buffer index to 0 */ + /* get the _special contents of the hostdata structure */ + special = ((struct ibmmca_hostdata *)shpnt->hostdata)->_special; + pos2 = ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos2; + pos3 = ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos3; + + if (special == FORCED_DETECTION) /* forced detection */ + { + len += sprintf (buf + len, "Adapter cathegory: forced detected\n"); + len += sprintf(buf + len, "***************************************\n"); + len += sprintf(buf + len, "*** Forced detected SCSI Adapter ***\n"); + len += sprintf(buf + len, "*** No chip-information available ***\n"); + len += sprintf(buf + len, "***************************************\n"); + } + else if (special == INTEGRATED_SCSI) + { /* if the integrated subsystem has been found automatically: */ + len += sprintf (buf + len, "Adapter cathegory: integrated\n"); + len += sprintf (buf + len, "Chip revision level: %d\n", + ((pos2 & 0xf0) >> 4)); + len += sprintf (buf + len, "Chip status: %s\n", + (pos2 & 1) ? "enabled" : "disabled"); + len += sprintf (buf + len, "8 kByte NVRAM status: %s\n", + (pos2 & 2) ? "locked" : "accessible"); + } + else if ((special>=0)&& + (special<(sizeof(subsys_list)/sizeof(struct subsys_list_struct)))) + { /* if the subsystem is a slot adapter */ + len += sprintf (buf + len, "Adapter cathegory: slot-card\n"); + len += sprintf (buf + len, "Chip revision level: %d\n", + ((pos2 & 0xf0) >> 4)); + len += sprintf (buf + len, "Chip status: %s\n", + (pos2 & 1) ? "enabled" : "disabled"); + len += sprintf (buf + len, "Port offset: 0x%x\n", + ((pos2 & 0x0e) << 2)); + } + else + { + len += sprintf (buf + len, "Adapter cathegory: unknown\n"); + } + /* common subsystem information to write to the slotn file */ + len += sprintf (buf + len, "Subsystem PUN: %d\n", shpnt->this_id); + len += sprintf (buf + len, "I/O base address range: 0x%x-0x%x", + (unsigned int)(shpnt->io_port), + (unsigned int)(shpnt->io_port+7)); + /* Now make sure, the bufferlength is devideable by 4 to avoid + * paging problems of the buffer. */ + while ( len % sizeof( int ) != ( sizeof ( int ) - 1 ) ) + { + len += sprintf (buf + len, " "); + } + len += sprintf (buf + len, "\n"); - return found; +#ifdef OLDKERN + restore_flags(flags); +#else + spin_unlock_irqrestore(&info_lock, flags); +#endif + return len; +} + +int ibmmca_detect (Scsi_Host_Template * scsi_template) +{ + struct Scsi_Host *shpnt; + int port, id, i, j, list_size, slot; + + found = 0; /* make absolutely sure, that found is set to 0 */ + + /* if this is not MCA machine, return "nothing found" */ + if (!MCA_bus) + { + printk("IBM MCA SCSI: No Microchannel-bus support present -> Aborting.\n"); + return 0; + } + else + printk("IBM MCA SCSI: Version %s\n",IBMMCA_SCSI_DRIVER_VERSION); + + /* get interrupt request level */ +#ifdef OLDKERN + if (request_irq (IM_IRQ, interrupt_handler, SA_SHIRQ, "ibmmcascsi", + hosts)) +#else + if (request_irq (IM_IRQ, do_interrupt_handler, SA_SHIRQ, "ibmmcascsi", + hosts)) +#endif + { + printk("IBM MCA SCSI: Unable to get shared IRQ %d.\n", IM_IRQ); + return 0; + } + + /* if ibmmcascsi setup option was passed to kernel, return "found" */ + for (i = 0; i < IM_MAX_HOSTS; i++) + if (io_port[i] > 0 && scsi_id[i] >= 0 && scsi_id[i] < 8) + { + printk("IBM MCA SCSI: forced detected SCSI Adapter, io=0x%x, scsi id=%d.\n", + io_port[i], scsi_id[i]); + if ((shpnt = ibmmca_register(scsi_template, io_port[i], scsi_id[i], + "forced detected SCSI Adapter"))) + { + ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos2 = 0; + ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos3 = 0; + ((struct ibmmca_hostdata *)shpnt->hostdata)->_special = + FORCED_DETECTION; + mca_set_adapter_name(MCA_INTEGSCSI, "forced detected SCSI Adapter"); + mca_set_adapter_procfn(MCA_INTEGSCSI, (MCA_ProcFn) ibmmca_getinfo, + shpnt); + mca_mark_as_used(MCA_INTEGSCSI); + } + } + if (found) return found; + + /* The POS2-register of all PS/2 model SCSI-subsystems has the following + * interpretation of bits: + * Bit 7 - 4 : Chip Revision ID (Release) + * Bit 3 - 2 : Reserved + * Bit 1 : 8k NVRAM Disabled + * Bit 0 : Chip Enable (EN-Signal) + * The POS3-register is interpreted as follows: + * Bit 7 - 5 : SCSI ID + * Bit 4 : Reserved = 0 + * Bit 3 - 0 : Reserved = 0 + * (taken from "IBM, PS/2 Hardware Interface Technical Reference, Common + * Interfaces (1991)"). + * In short words, this means, that IBM PS/2 machines only support + * 1 single subsystem by default. The slot-adapters must have another + * configuration on pos2. Here, one has to assume the following + * things for POS2-register: + * Bit 7 - 4 : Chip Revision ID (Release) + * Bit 3 - 1 : port offset factor + * Bit 0 : Chip Enable (EN-Signal) + * As I found a patch here, setting the IO-registers to 0x3540 forced, + * as there was a 0x05 in POS2 on a model 56, I assume, that the + * port 0x3540 must be fix for integrated SCSI-controllers. + * Ok, this discovery leads to the following implementation: (M.Lang) */ + + /* first look for the IBM SCSI integrated subsystem on the motherboard */ + for (j=0;j<8;j++) /* read the pos-information */ + pos[j] = mca_read_stored_pos(MCA_INTEGSCSI,j); + /* pos2 = pos3 = 0xff if there is no integrated SCSI-subsystem present */ + if (( pos[2] != 0xff) || (pos[3] != 0xff )) + { + if ((pos[2] & 1) == 1) /* is the subsystem chip enabled ? */ + { + port = IM_IO_PORT; + } + else + { /* if disabled, no IRQs will be generated, as the chip won't + * listen to the incomming commands and will do really nothing, + * except for listening to the pos-register settings. If this + * happens, I need to hugely think about it, as one has to + * write something to the MCA-Bus pos register in order to + * enable the chip. Normally, IBM-SCSI won't pass the POST, + * when the chip is disabled (see IBM tech. ref.). */ + port = IM_IO_PORT; /* anyway, set the portnumber and warn */ + printk("IBM MCA SCSI: WARNING - Your SCSI-subsystem is disabled!\n"); + printk(" SCSI-operations may not work.\n"); + } + id = (pos[3] & 0xe0) >> 5; /* this is correct and represents the PUN */ + + /* give detailed information on the subsystem. This helps me + * additionally during debugging and analyzing bug-reports. */ + printk("IBM MCA SCSI: IBM Integrated SCSI Controller found, io=0x%x, scsi id=%d,\n", + port, id); + printk(" chip rev.=%d, 8K NVRAM=%s, subsystem=%s\n", + ((pos[2] & 0xf0) >> 4), (pos[2] & 2) ? "locked" : "accessible", + (pos[2] & 1) ? "enabled." : "disabled."); + + /* register the found integrated SCSI-subsystem */ + if ((shpnt = ibmmca_register(scsi_template, port, id, + "IBM Integrated SCSI Controller"))) + { + ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos2 = pos[2]; + ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos3 = pos[3]; + ((struct ibmmca_hostdata *)shpnt->hostdata)->_special = + INTEGRATED_SCSI; + mca_set_adapter_name(MCA_INTEGSCSI, "IBM Integrated SCSI Controller"); + mca_set_adapter_procfn(MCA_INTEGSCSI, (MCA_ProcFn) ibmmca_getinfo, + shpnt); + mca_mark_as_used(MCA_INTEGSCSI); + } + } + + /* now look for other adapters in MCA slots, */ + /* determine the number of known IBM-SCSI-subsystem types */ + /* see the pos[2] dependence to get the adapter port-offset. */ + list_size = sizeof(subsys_list) / sizeof(struct subsys_list_struct); + for (i = 0; i < list_size; i++) + { /* scan each slot for a fitting adapter id */ + slot = 0; /* start at slot 0 */ + while ((slot = mca_find_adapter(subsys_list[i].mca_id, slot)) + != MCA_NOTFOUND) + { /* scan through all slots */ + for (j=0;j<8;j++) /* read the pos-information */ + pos[j] = mca_read_stored_pos(slot, j); + if ((pos[2] & 1) == 1) /* is the subsystem chip enabled ? */ + { /* (explanations see above) */ + port = IM_IO_PORT + ((pos[2] & 0x0e) << 2); + } + else + { /* anyway, set the portnumber and warn */ + port = IM_IO_PORT + ((pos[2] & 0x0e) << 2); + printk("IBM MCA SCSI: WARNING - Your SCSI-subsystem is disabled!\n"); + printk(" SCSI-operations may not work.\n"); + } + id = (pos[3] & 0xe0) >> 5; /* get subsystem PUN */ + printk("IBM MCA SCSI: %s found in slot %d, io=0x%x, scsi id=%d,\n", + subsys_list[i].description, slot + 1, port, id); + printk(" chip rev.=%d, port-offset=0x%x, subsystem=%s\n", + ((pos[2] & 0xf0) >> 4), + ((pos[2] & 0x0e) << 2), + (pos[2] & 1) ? "enabled." : "disabled."); + + /* register the hostadapter */ + if ((shpnt = ibmmca_register(scsi_template, port, id, + subsys_list[i].description))) + { + ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos2 = pos[2]; + ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos3 = pos[3]; + ((struct ibmmca_hostdata *)shpnt->hostdata)->_special = i; + + mca_set_adapter_name (slot, subsys_list[i].description); + mca_set_adapter_procfn (slot, (MCA_ProcFn) ibmmca_getinfo, + shpnt); + mca_mark_as_used(slot); + } + slot++; /* advance to next slot */ + } /* advance to next adapter id in the list of IBM-SCSI-subsystems*/ + } + + if (!found) + { /* maybe ESDI, or other producers' SCSI-hosts */ + free_irq (IM_IRQ, hosts); + printk("IBM MCA SCSI: No IBM SCSI-subsystem adapter attached.\n"); + } + return found; /* return the number of found SCSI hosts. Should be 1 or 0. */ } static struct Scsi_Host * -ibmmca_register(Scsi_Host_Template * template, int port, int id) +ibmmca_register(Scsi_Host_Template * scsi_template, int port, int id, + char *hostname) { - struct Scsi_Host *shpnt; - int i, j; + struct Scsi_Host *shpnt; + int i, j; + unsigned int ctrl; + + /* check I/O region */ + if (check_region(port, IM_N_IO_PORT)) + { + printk("IBM MCA SCSI: Unable to get I/O region 0x%x-0x%x (%d ports).\n", + port, port + IM_N_IO_PORT - 1, IM_N_IO_PORT); + return NULL; + } + + /* register host */ + shpnt = scsi_register(scsi_template, sizeof(struct ibmmca_hostdata)); + if (!shpnt) + { + printk("IBM MCA SCSI: Unable to register host.\n"); + return NULL; + } + + /* request I/O region */ + request_region(port, IM_N_IO_PORT, hostname); - /* check I/O region */ - if (check_region(port, IM_N_IO_PORT)) - { - printk("IBM MCA SCSI: Unable to get I/O region 0x%x-0x%x.\n", - port, port + IM_N_IO_PORT); - return NULL; - } - - /* register host */ - shpnt = scsi_register(template, sizeof(struct ibmmca_hostdata)); - if (!shpnt) - { - printk("IBM MCA SCSI: Unable to register host.\n"); - return NULL; - } - - /* request I/O region */ - request_region(port, IM_N_IO_PORT, "ibmmca"); - - hosts[found++] = shpnt; - shpnt->irq = IM_IRQ; - shpnt->io_port = port; - shpnt->n_io_port = IM_N_IO_PORT; - shpnt->this_id = id; - - reset_status = IM_RESET_NOT_IN_PROGRESS; - - for (i = 0; i < 8; i++) - for (j = 0; j < 8; j++) - get_ldn[i][j] = MAX_LOG_DEV; - - /* check which logical devices exist */ - local_checking_phase_flag = 1; - check_devices(shpnt); - local_checking_phase_flag = 0; + hosts[found] = shpnt; /* add new found hostadapter to the list */ + shpnt->irq = IM_IRQ; /* assign necessary stuff for the adapter */ + shpnt->io_port = port; + shpnt->n_io_port = IM_N_IO_PORT; + shpnt->this_id = id; + /* now, the SCSI-subsystem is connected to Linux */ - /* an ibm mca subsystem has been detected */ - return shpnt; + ctrl = (unsigned int)(inb(IM_CTR_REG(found))); /* get control-register status */ +#ifdef IM_DEBUG_PROBE + printk("IBM MCA SCSI: Control Register contents: %x, status: %x\n", + ctrl,inb(IM_STAT_REG(found))); + printk("IBM MCA SCSI: This adapters' POS-registers: "); + for (i=0;i<8;i++) + printk("%x ",pos[i]); + printk("\n"); + if (bypass_controller) + printk("IBM MCA SCSI: Subsystem SCSI-commands get bypassed.\n"); +#endif + + reset_status(found) = IM_RESET_NOT_IN_PROGRESS; + + for (i = 0; i < 8; i++) /* reset the tables */ + for (j = 0; j < 8; j++) + get_ldn(found)[i][j] = MAX_LOG_DEV; + + /* check which logical devices exist */ + local_checking_phase_flag(found) = 1; + check_devices(found); /* call by value, using the global variable hosts*/ + local_checking_phase_flag(found) = 0; + + found++; /* now increase index to be prepared for next found subsystem */ + /* an ibm mca subsystem has been detected */ + return shpnt; } /*--------------------------------------------------------------------*/ -int -ibmmca_command (Scsi_Cmnd * cmd) +int ibmmca_command (Scsi_Cmnd * cmd) { ibmmca_queuecommand (cmd, internal_done); cmd->SCp.Status = 0; @@ -1678,8 +1765,7 @@ /*--------------------------------------------------------------------*/ -int -ibmmca_release(struct Scsi_Host *shpnt) +int ibmmca_release(struct Scsi_Host *shpnt) { release_region(shpnt->io_port, shpnt->n_io_port); if (!(--found)) @@ -1708,231 +1794,267 @@ are sufficient. (The adapter uses always ldn=15, at whatever pun it is.) */ int ibmmca_queuecommand (Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)) { - unsigned int ldn; - unsigned int scsi_cmd; - struct im_scb *scb; - struct Scsi_Host *shpnt = cmd->host; - - int current_ldn; - int id,lun; - - /* use industry standard ordering of the IDs */ -#ifdef CONFIG_IBMMCA_SCSI_ORDER_STANDARD - int target = 6 - cmd->target; -#else - int target = cmd->target; -#endif - - /*if (target,lun) is NO LUN or not existing at all, return error */ - if ((get_scsi[target][cmd->lun] == TYPE_NO_LUN)|| - (get_scsi[target][cmd->lun] == TYPE_NO_DEVICE)) + unsigned int ldn; + unsigned int scsi_cmd; + struct im_scb *scb; + struct Scsi_Host *shpnt; + int current_ldn; + int id,lun; + int target; + int host_index; + + if (ibm_ansi_order) + target = 6 - cmd->target; + else + target = cmd->target; + + shpnt = cmd->host; + + /* search for the right hostadapter */ + for (host_index = 0; hosts[host_index] && hosts[host_index]->host_no != shpnt->host_no; host_index++); + + if (!hosts[host_index]) + { /* invalid hostadapter descriptor address */ + cmd->result = DID_NO_CONNECT << 16; + done (cmd); + return 0; + } + + /*if (target,lun) is NO LUN or not existing at all, return error */ + if ((get_scsi(host_index)[target][cmd->lun] == TYPE_NO_LUN)|| + (get_scsi(host_index)[target][cmd->lun] == TYPE_NO_DEVICE)) { cmd->result = DID_NO_CONNECT << 16; done (cmd); return 0; } - /*if (target,lun) unassigned, do further checks... */ - ldn = get_ldn[target][cmd->lun]; - if (ldn >= MAX_LOG_DEV) /* on invalid ldn do special stuff */ - { - if (ldn > MAX_LOG_DEV) /* dynamical remapping if ldn unassigned */ - { - current_ldn = next_ldn; /* stop-value for one circle */ - while (ld[next_ldn].cmd) /* search for a occupied, but not in */ - { /* command-processing ldn. */ - next_ldn ++; - if (next_ldn>=MAX_LOG_DEV) - next_ldn = 7; - if (current_ldn == next_ldn) /* One circle done ? */ - { /* no non-processing ldn found */ - printk("IBM MCA SCSI: Cannot assign SCSI-device dynamically!\n"); - printk(" On ldn 7-14 SCSI-commands everywhere in progress.\n"); - printk(" Reporting DID_NO_CONNECT for device (%d,%d).\n", - target, cmd->lun); - cmd->result = DID_NO_CONNECT << 16;/* return no connect*/ - done (cmd); - return 0; - } - } - - /* unmap non-processing ldn */ - for (id=0; id<8; id ++) - for (lun=0; lun<8; lun++) - { - if (get_ldn[id][lun] == next_ldn) - { - get_ldn[id][lun] = TYPE_NO_DEVICE; /* unmap entry */ - goto DYN_ASSIGN; /* jump out as fast as possible */ - } - } - -DYN_ASSIGN: - /* unassign found ldn (pun,lun does not matter for remove) */ - immediate_assign(shpnt,0,0,next_ldn,REMOVE_LDN); - /* assign found ldn to aimed pun,lun */ - immediate_assign(shpnt,target,cmd->lun,next_ldn,SET_LDN); - /* map found ldn to pun,lun */ - get_ldn[target][cmd->lun] = next_ldn; - /* change ldn to the right value, that is now next_ldn */ - ldn = next_ldn; - /* set reduced interrupt_handler-mode for checking */ - local_checking_phase_flag = 1; - /* get device information for ld[ldn] */ - if (device_exists (shpnt, ldn, &ld[ldn].block_length, - &ld[ldn].device_type)) + /*if (target,lun) unassigned, do further checks... */ + ldn = get_ldn(host_index)[target][cmd->lun]; + if (ldn >= MAX_LOG_DEV) /* on invalid ldn do special stuff */ + { + if (ldn > MAX_LOG_DEV) /* dynamical remapping if ldn unassigned */ + { + current_ldn = next_ldn(host_index); /* stop-value for one circle */ + while (ld(host_index)[next_ldn(host_index)].cmd) /* search for a occupied, but not in */ + { /* command-processing ldn. */ + next_ldn(host_index)++; + if (next_ldn(host_index)>=MAX_LOG_DEV) + next_ldn(host_index) = 7; + if (current_ldn == next_ldn(host_index)) /* One circle done ? */ + { /* no non-processing ldn found */ + printk("IBM MCA SCSI: Cannot assign SCSI-device dynamically!\n"); + printk(" On ldn 7-14 SCSI-commands everywhere in progress.\n"); + printk(" Reporting DID_NO_CONNECT for device (%d,%d).\n", + target, cmd->lun); + cmd->result = DID_NO_CONNECT << 16;/* return no connect*/ + done (cmd); + return 0; + } + } + + /* unmap non-processing ldn */ + for (id=0; id<8; id ++) + for (lun=0; lun<8; lun++) { - ld[ldn].cmd = 0; /* To prevent panic set 0, because - devices that were not assigned, - should have nothing in progress. */ + if (get_ldn(host_index)[id][lun] == next_ldn(host_index)) + { + get_ldn(host_index)[id][lun] = TYPE_NO_DEVICE; + /* unmap entry */ + } + } + /* set reduced interrupt_handler-mode for checking */ + local_checking_phase_flag(host_index) = 1; + /* unassign found ldn (pun,lun does not matter for remove) */ + immediate_assign(host_index,0,0,next_ldn(host_index),REMOVE_LDN); + /* assign found ldn to aimed pun,lun */ + immediate_assign(host_index,target,cmd->lun,next_ldn(host_index),SET_LDN); + /* map found ldn to pun,lun */ + get_ldn(host_index)[target][cmd->lun] = next_ldn(host_index); + /* change ldn to the right value, that is now next_ldn */ + ldn = next_ldn(host_index); + /* get device information for ld[ldn] */ + if (device_exists (host_index, ldn, + &ld(host_index)[ldn].block_length, + &ld(host_index)[ldn].device_type)) + { + ld(host_index)[ldn].cmd = 0; /* To prevent panic set 0, because + devices that were not assigned, + should have nothing in progress. */ - /* increase assignment counters for statistics in /proc */ - IBM_DS.dynamical_assignments++; - IBM_DS.ldn_assignments[ldn]++; + /* increase assignment counters for statistics in /proc */ + IBM_DS(host_index).dynamical_assignments++; + IBM_DS(host_index).ldn_assignments[ldn]++; } - else - /* panic here, because a device, found at boottime has - vanished */ - panic("IBM MCA SCSI: ldn=0x%x, SCSI-device on (%d,%d) vanished!\n", - ldn, target, cmd->lun); - - /* set back to normal interrupt_handling */ - local_checking_phase_flag = 0; - - /* Information on syslog terminal */ - printk("IBM MCA SCSI: ldn=0x%x dynamically reassigned to (%d,%d).\n", - ldn, target, cmd->lun); - - /* increase next_ldn for next dynamical assignment */ - next_ldn ++; - if (next_ldn>=MAX_LOG_DEV) next_ldn = 7; - } - else - { /* wall against Linux accesses to the subsystem adapter */ - cmd->result = DID_NO_CONNECT << 16; - done (cmd); - return 0; - } - } - - /*verify there is no command already in progress for this log dev */ - if (ld[ldn].cmd) - panic ("IBM MCA SCSI: cmd already in progress for this ldn.\n"); - - /*save done in cmd, and save cmd for the interrupt handler */ - cmd->scsi_done = done; - ld[ldn].cmd = cmd; - - /*fill scb information independent of the scsi command */ - scb = &(ld[ldn].scb); - scb->enable = IM_REPORT_TSB_ONLY_ON_ERROR; - scb->tsb_adr = virt_to_bus(&(ld[ldn].tsb)); - if (cmd->use_sg) - { - int i = cmd->use_sg; - struct scatterlist *sl = (struct scatterlist *) cmd->request_buffer; - if (i > 16) - panic ("IBM MCA SCSI: scatter-gather list too long.\n"); - while (--i >= 0) - { - ld[ldn].sge[i].address = (void *) virt_to_bus(sl[i].address); - ld[ldn].sge[i].byte_length = sl[i].length; - } - scb->enable |= IM_POINTER_TO_LIST; - scb->sys_buf_adr = virt_to_bus(&(ld[ldn].sge[0])); - scb->sys_buf_length = cmd->use_sg * sizeof (struct im_sge); - } - else - { - scb->sys_buf_adr = virt_to_bus(cmd->request_buffer); - scb->sys_buf_length = cmd->request_bufflen; - } - - /*fill scb information dependent on scsi command */ - scsi_cmd = cmd->cmnd[0]; + else + /* panic here, because a device, found at boottime has + vanished */ + panic("IBM MCA SCSI: ldn=0x%x, SCSI-device on (%d,%d) vanished!\n", + ldn, target, cmd->lun); + + /* set back to normal interrupt_handling */ + local_checking_phase_flag(host_index) = 0; + + /* Information on syslog terminal */ + printk("IBM MCA SCSI: ldn=0x%x dynamically reassigned to (%d,%d).\n", + ldn, target, cmd->lun); + + /* increase next_ldn for next dynamical assignment */ + next_ldn(host_index)++; + if (next_ldn(host_index)>=MAX_LOG_DEV) + next_ldn(host_index) = 7; + } + else + { /* wall against Linux accesses to the subsystem adapter */ + cmd->result = DID_BAD_TARGET << 16; + done (cmd); + return 0; + } + } + + /*verify there is no command already in progress for this log dev */ + if (ld(host_index)[ldn].cmd) + panic ("IBM MCA SCSI: cmd already in progress for this ldn.\n"); + + /*save done in cmd, and save cmd for the interrupt handler */ + cmd->scsi_done = done; + ld(host_index)[ldn].cmd = cmd; + + /*fill scb information independent of the scsi command */ + scb = &(ld(host_index)[ldn].scb); + ld(host_index)[ldn].tsb.dev_status = 0; + scb->enable = IM_REPORT_TSB_ONLY_ON_ERROR; + scb->tsb_adr = virt_to_bus(&(ld(host_index)[ldn].tsb)); + if (cmd->use_sg) + { + int i = cmd->use_sg; + struct scatterlist *sl = (struct scatterlist *) cmd->request_buffer; + if (i > 16) + panic ("IBM MCA SCSI: scatter-gather list too long.\n"); + while (--i >= 0) + { + ld(host_index)[ldn].sge[i].address = (void *) virt_to_bus(sl[i].address); + ld(host_index)[ldn].sge[i].byte_length = sl[i].length; + } + scb->enable |= IM_POINTER_TO_LIST; + scb->sys_buf_adr = virt_to_bus(&(ld(host_index)[ldn].sge[0])); + scb->sys_buf_length = cmd->use_sg * sizeof (struct im_sge); + } + else + { + scb->sys_buf_adr = virt_to_bus(cmd->request_buffer); + scb->sys_buf_length = cmd->request_bufflen; + } + + /*fill scb information dependent on scsi command */ + scsi_cmd = cmd->cmnd[0]; #ifdef IM_DEBUG_CMD - printk("issue scsi cmd=%02x to ldn=%d\n", scsi_cmd, ldn); + printk("issue scsi cmd=%02x to ldn=%d\n", scsi_cmd, ldn); #endif - - /* for specific device-type debugging: */ + + /* for specific device-type debugging: */ #ifdef IM_DEBUG_CMD_SPEC_DEV - if (ld[ldn].device_type==IM_DEBUG_CMD_DEVICE) + if (ld(host_index)[ldn].device_type==IM_DEBUG_CMD_DEVICE) printk("(SCSI-device-type=0x%x) issue scsi cmd=%02x to ldn=%d\n", - ld[ldn].device_type, scsi_cmd, ldn); + ld(host_index)[ldn].device_type, scsi_cmd, ldn); #endif - - /* for possible panics store current command */ - last_scsi_command = scsi_cmd; - /* update statistical info */ - IBM_DS.total_accesses++; - IBM_DS.ldn_access[ldn]++; - - switch (scsi_cmd) - { - case READ_6: - case WRITE_6: - case READ_10: - case WRITE_10: - case READ_12: - case WRITE_12: - /* statistics for proc_info */ - if ((scsi_cmd == READ_6)||(scsi_cmd == READ_10)||(scsi_cmd == READ_12)) - IBM_DS.ldn_read_access[ldn]++; /* increase READ-access on ldn stat. */ - else if ((scsi_cmd == WRITE_6)||(scsi_cmd == WRITE_10)|| - (scsi_cmd == WRITE_12)) - IBM_DS.ldn_write_access[ldn]++; /* increase write-count on ldn stat.*/ - - /* Distinguish between disk and other devices. Only disks (that are the - most frequently accessed devices) should be supported by the + /* for possible panics store current command */ + last_scsi_command(host_index)[ldn] = scsi_cmd; + last_scsi_type(host_index)[ldn] = IM_SCB; + + /* update statistical info */ + IBM_DS(host_index).total_accesses++; + IBM_DS(host_index).ldn_access[ldn]++; + + switch (scsi_cmd) + { + case READ_6: + case WRITE_6: + case READ_10: + case WRITE_10: + case READ_12: + case WRITE_12: + /* statistics for proc_info */ + if ((scsi_cmd == READ_6)||(scsi_cmd == READ_10)||(scsi_cmd == READ_12)) + IBM_DS(host_index).ldn_read_access[ldn]++; /* increase READ-access on ldn stat. */ + else if ((scsi_cmd == WRITE_6)||(scsi_cmd == WRITE_10)|| + (scsi_cmd == WRITE_12)) + IBM_DS(host_index).ldn_write_access[ldn]++; /* increase write-count on ldn stat.*/ + + /* Distinguish between disk and other devices. Only disks (that are the + most frequently accessed devices) should be supported by the IBM-SCSI-Subsystem commands. */ - switch (ld[ldn].device_type) - { - case TYPE_DISK: /* for harddisks enter here ... */ - case TYPE_MOD: /* ... try it also for MO-drives (send flames as */ - /* you like, if this won't work.) */ - if (scsi_cmd == READ_6 || scsi_cmd == READ_10 || - scsi_cmd == READ_12) - { - scb->command = IM_READ_DATA_CMD; - scb->enable |= IM_READ_CONTROL; - } - else - { - scb->command = IM_WRITE_DATA_CMD; - } - if (scsi_cmd == READ_6 || scsi_cmd == WRITE_6) - { - scb->u1.log_blk_adr = (((unsigned) cmd->cmnd[3]) << 0) | - (((unsigned) cmd->cmnd[2]) << 8) | - ((((unsigned) cmd->cmnd[1]) & 0x1f) << 16); - scb->u2.blk.count = (unsigned) cmd->cmnd[4]; - } - else - { - scb->u1.log_blk_adr = (((unsigned) cmd->cmnd[5]) << 0) | - (((unsigned) cmd->cmnd[4]) << 8) | - (((unsigned) cmd->cmnd[3]) << 16) | - (((unsigned) cmd->cmnd[2]) << 24); - scb->u2.blk.count = (((unsigned) cmd->cmnd[8]) << 0) | - (((unsigned) cmd->cmnd[7]) << 8); - } - scb->u2.blk.length = ld[ldn].block_length; - if (++disk_rw_in_progress == 1) - PS2_DISK_LED_ON (shpnt->host_no, target); - break; - - /* for other devices, enter here. Other types are not known by - Linux! TYPE_NO_LUN is forbidden as valid device. */ - case TYPE_ROM: - case TYPE_TAPE: - case TYPE_PROCESSOR: - case TYPE_WORM: - case TYPE_SCANNER: - case TYPE_MEDIUM_CHANGER: - - /* If there is a sequential-device, IBM recommends to use + switch (ld(host_index)[ldn].device_type) + { + case TYPE_DISK: /* for harddisks enter here ... */ + case TYPE_MOD: /* ... try it also for MO-drives (send flames as */ + /* you like, if this won't work.) */ + if (scsi_cmd == READ_6 || scsi_cmd == READ_10 || + scsi_cmd == READ_12) + { /* read command preparations */ + if (bypass_controller) + { + scb->command = IM_OTHER_SCSI_CMD_CMD; + scb->enable |= IM_READ_CONTROL; + scb->u1.scsi_cmd_length = cmd->cmd_len; + memcpy(scb->u2.scsi_command,cmd->cmnd,cmd->cmd_len); + } + else + { + scb->command = IM_READ_DATA_CMD; + scb->enable |= IM_READ_CONTROL; + } + } + else + { /* write command preparations */ + if (bypass_controller) + { + scb->command = IM_OTHER_SCSI_CMD_CMD; + scb->u1.scsi_cmd_length = cmd->cmd_len; + memcpy(scb->u2.scsi_command,cmd->cmnd,cmd->cmd_len); + } + else + { + scb->command = IM_WRITE_DATA_CMD; + } + } + + if (!bypass_controller) + { + if (scsi_cmd == READ_6 || scsi_cmd == WRITE_6) + { + scb->u1.log_blk_adr = (((unsigned) cmd->cmnd[3]) << 0) | + (((unsigned) cmd->cmnd[2]) << 8) | + ((((unsigned) cmd->cmnd[1]) & 0x1f) << 16); + scb->u2.blk.count = (unsigned) cmd->cmnd[4]; + } + else + { + scb->u1.log_blk_adr = (((unsigned) cmd->cmnd[5]) << 0) | + (((unsigned) cmd->cmnd[4]) << 8) | + (((unsigned) cmd->cmnd[3]) << 16) | + (((unsigned) cmd->cmnd[2]) << 24); + scb->u2.blk.count = (((unsigned) cmd->cmnd[8]) << 0) | + (((unsigned) cmd->cmnd[7]) << 8); + } + scb->u2.blk.length = ld(host_index)[ldn].block_length; + } + if (++disk_rw_in_progress == 1) + PS2_DISK_LED_ON (shpnt->host_no, target); + break; + + /* for other devices, enter here. Other types are not known by + Linux! TYPE_NO_LUN is forbidden as valid device. */ + case TYPE_ROM: + case TYPE_TAPE: + case TYPE_PROCESSOR: + case TYPE_WORM: + case TYPE_SCANNER: + case TYPE_MEDIUM_CHANGER: + + /* If there is a sequential-device, IBM recommends to use IM_OTHER_SCSI_CMD_CMD instead of subsystem READ/WRITE. Good/modern CD-ROM-drives are capable of reading sequential AND random-access. This leads to the problem, @@ -1943,241 +2065,422 @@ to have a stable state. In addition, data-access on CD-ROMs works faster like that. Strange, but obvious. */ - scb->command = IM_OTHER_SCSI_CMD_CMD; - if (scsi_cmd == READ_6 || scsi_cmd == READ_10 || - scsi_cmd == READ_12) /* enable READ */ - scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT; - else - scb->enable |= IM_SUPRESS_EXCEPTION_SHORT; /* assume WRITE */ - - scb->u1.scsi_cmd_length = cmd->cmd_len; - memcpy (scb->u2.scsi_command, cmd->cmnd, cmd->cmd_len); - - /* Read/write on this non-disk devices is also displayworthy, + scb->command = IM_OTHER_SCSI_CMD_CMD; + if (scsi_cmd == READ_6 || scsi_cmd == READ_10 || + scsi_cmd == READ_12) /* enable READ */ + { + scb->enable |= IM_READ_CONTROL; + } + + scb->u1.scsi_cmd_length = cmd->cmd_len; + memcpy (scb->u2.scsi_command, cmd->cmnd, cmd->cmd_len); + + /* Read/write on this non-disk devices is also displayworthy, so flash-up the LED/display. */ - if (++disk_rw_in_progress == 1) - PS2_DISK_LED_ON (shpnt->host_no, target); - break; - } - break; - case INQUIRY: - IBM_DS.ldn_inquiry_access[ldn]++; - scb->command = IM_DEVICE_INQUIRY_CMD; - scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT; - break; - - case READ_CAPACITY: - scb->command = IM_READ_CAPACITY_CMD; - scb->enable |= IM_READ_CONTROL; - /* the length of system memory buffer must be exactly 8 bytes */ - if (scb->sys_buf_length >= 8) - scb->sys_buf_length = 8; - break; - - /* Commands that need read-only-mode (system <- device): */ - case REQUEST_SENSE: - scb->command = IM_REQUEST_SENSE_CMD; - scb->enable |= IM_READ_CONTROL; - break; - - /* Commands that need write-only-mode (system -> device): */ - case MODE_SELECT: - case MODE_SELECT_10: - IBM_DS.ldn_modeselect_access[ldn]++; - scb->command = IM_OTHER_SCSI_CMD_CMD; - scb->enable |= IM_SUPRESS_EXCEPTION_SHORT; /*Select needs WRITE-enabled*/ - scb->u1.scsi_cmd_length = cmd->cmd_len; - memcpy (scb->u2.scsi_command, cmd->cmnd, cmd->cmd_len); - break; - - /* For other commands, read-only is useful. Most other commands are - running without an input-data-block. */ - default: - scb->command = IM_OTHER_SCSI_CMD_CMD; - scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT; - scb->u1.scsi_cmd_length = cmd->cmd_len; - memcpy (scb->u2.scsi_command, cmd->cmnd, cmd->cmd_len); - break; - } + if (++disk_rw_in_progress == 1) + PS2_DISK_LED_ON (shpnt->host_no, target); + break; + } + break; + case INQUIRY: + IBM_DS(host_index).ldn_inquiry_access[ldn]++; + if (bypass_controller) + { + scb->command = IM_OTHER_SCSI_CMD_CMD; + scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT; + scb->u1.scsi_cmd_length = cmd->cmd_len; + memcpy (scb->u2.scsi_command, cmd->cmnd, cmd->cmd_len); + } + else + { + scb->command = IM_DEVICE_INQUIRY_CMD; + scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT; + } + break; - /*issue scb command, and return */ - issue_cmd (shpnt, virt_to_bus(scb), IM_SCB | ldn); - return 0; + case READ_CAPACITY: + /* the length of system memory buffer must be exactly 8 bytes */ + if (scb->sys_buf_length > 8) + scb->sys_buf_length = 8; + if (bypass_controller) + { + scb->command = IM_OTHER_SCSI_CMD_CMD; + scb->enable |= IM_READ_CONTROL; + scb->u1.scsi_cmd_length = cmd->cmd_len; + memcpy (scb->u2.scsi_command, cmd->cmnd, cmd->cmd_len); + } + else + { + scb->command = IM_READ_CAPACITY_CMD; + scb->enable |= IM_READ_CONTROL; + } + break; + + /* Commands that need read-only-mode (system <- device): */ + case REQUEST_SENSE: + if (bypass_controller) + { + scb->command = IM_OTHER_SCSI_CMD_CMD; + scb->enable |= IM_READ_CONTROL; + scb->u1.scsi_cmd_length = cmd->cmd_len; + memcpy (scb->u2.scsi_command, cmd->cmnd, cmd->cmd_len); + } + else + { + scb->command = IM_REQUEST_SENSE_CMD; + scb->enable |= IM_READ_CONTROL; + } + break; + + /* Commands that need write-only-mode (system -> device): */ + case MODE_SELECT: + case MODE_SELECT_10: + IBM_DS(host_index).ldn_modeselect_access[ldn]++; + scb->command = IM_OTHER_SCSI_CMD_CMD; + scb->enable |= IM_SUPRESS_EXCEPTION_SHORT; /*Select needs WRITE-enabled*/ + scb->u1.scsi_cmd_length = cmd->cmd_len; + memcpy (scb->u2.scsi_command, cmd->cmnd, cmd->cmd_len); + break; + + /* For other commands, read-only is useful. Most other commands are + running without an input-data-block. */ + default: + scb->command = IM_OTHER_SCSI_CMD_CMD; + scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT; + scb->u1.scsi_cmd_length = cmd->cmd_len; + memcpy (scb->u2.scsi_command, cmd->cmnd, cmd->cmd_len); + break; + } + + /*issue scb command, and return */ + issue_cmd (host_index, virt_to_bus(scb), IM_SCB | ldn); + return 0; } /*--------------------------------------------------------------------*/ -int -ibmmca_abort (Scsi_Cmnd * cmd) +int ibmmca_abort (Scsi_Cmnd * cmd) { - /* The code below doesn't work right now, so we tell the upper layer - that we can't abort. This eventually causes a reset. - */ - return SCSI_ABORT_SNOOZE ; - -#if 0 - struct Scsi_host *shpnt = cmd->host; - unsigned int ldn; - void (*saved_done) (Scsi_Cmnd *); + /* Abort does not work, as the adapter never generates an interrupt on + * whatever situation is simulated, even when really pending commands + * are running on the adapters' hardware ! */ + + struct Scsi_Host *shpnt; + unsigned int ldn; + void (*saved_done) (Scsi_Cmnd *); + int target; + int host_index; + static unsigned long flags; + unsigned long imm_command; -#ifdef CONFIG_IBMMCA_SCSI_ORDER_STANDARD - int target = 6 - cmd->target; + /* return SCSI_ABORT_SNOOZE ; */ + +#ifdef OLDKERN + save_flags(flags); + cli(); #else - int target = cmd->target; -#endif + spin_lock_irqsave(&abort_lock, flags); +#endif + if (ibm_ansi_order) + target = 6 - cmd->target; + else + target = cmd->target; + + shpnt = cmd->host; - /*get logical device number, and disable system interrupts */ - printk ("IBM MCA SCSI: sending abort to device id=%d lun=%d.\n", - target, cmd->lun); - ldn = get_ldn[target][cmd->lun]; - cli (); - - /*if cmd for this ldn has already finished, no need to abort */ - if (!ld[ldn].cmd) - { - /* sti (); */ - return SCSI_ABORT_NOT_RUNNING; - } - - /* Clear ld.cmd, save done function, install internal done, - * send abort immediate command (this enables sys. interrupts), - * and wait until the interrupt arrives. - */ - ld[ldn].cmd = 0; - saved_done = cmd->scsi_done; - cmd->scsi_done = internal_done; - cmd->SCp.Status = 0; - issue_cmd (shpnt, T_IMM_CMD, IM_IMM_CMD | ldn); - while (!cmd->SCp.Status) - barrier (); + /* search for the right hostadapter */ + for (host_index = 0; hosts[host_index] && hosts[host_index]->host_no != shpnt->host_no; host_index++); + + if (!hosts[host_index]) + { /* invalid hostadapter descriptor address */ + cmd->result = DID_NO_CONNECT << 16; + if (cmd->scsi_done) + (cmd->done) (cmd); + return SCSI_ABORT_SNOOZE; + } + + /*get logical device number, and disable system interrupts */ + printk ("IBM MCA SCSI: Sending abort to device pun=%d, lun=%d.\n", + target, cmd->lun); + ldn = get_ldn(host_index)[target][cmd->lun]; + + /*if cmd for this ldn has already finished, no need to abort */ + if (!ld(host_index)[ldn].cmd) + { +#ifdef OLDKERN + restore_flags(flags); +#else + spin_unlock_irqrestore(&abort_lock, flags); +#endif + return SCSI_ABORT_NOT_RUNNING; + } - /*if abort went well, call saved done, then return success or error */ - if (cmd->result == 0) - { - cmd->result |= DID_ABORT << 16; - saved_done (cmd); - return SCSI_ABORT_SUCCESS; - } - else - return SCSI_ABORT_ERROR; + /* Clear ld.cmd, save done function, install internal done, + * send abort immediate command (this enables sys. interrupts), + * and wait until the interrupt arrives. + */ + saved_done = cmd->scsi_done; + cmd->scsi_done = internal_done; + cmd->SCp.Status = 0; + last_scsi_command(host_index)[ldn] = IM_ABORT_IMM_CMD; + last_scsi_type(host_index)[ldn] = IM_IMM_CMD; + imm_command = inl(IM_CMD_REG(host_index)); + imm_command &= (unsigned long)(0xffff0000); /* mask reserved stuff */ + imm_command |= (unsigned long)(IM_ABORT_IMM_CMD); + /* must wait for attention reg not busy */ + while (1) + { + if (!(inb (IM_STAT_REG(host_index)) & IM_BUSY)) + break; +#ifdef OLDKERN + restore_flags (flags); +#else + spin_unlock_irqrestore(&abort_lock, flags); +#endif +#ifdef OLDKERN + save_flags(flags); + cli(); +#else + spin_lock_irqsave(&abort_lock, flags); +#endif + } + /*write registers and enable system interrupts */ + outl (imm_command, IM_CMD_REG(host_index)); + outb (IM_IMM_CMD | ldn, IM_ATTN_REG(host_index)); +#ifdef OLDKERN + restore_flags (flags); +#else + spin_unlock_irqrestore(&abort_lock, flags); #endif + +#ifdef IM_DEBUG_PROBE + printk("IBM MCA SCSI: Abort submitted, waiting for adapter response...\n"); +#endif + while (!cmd->SCp.Status) + barrier (); + cmd->scsi_done = saved_done; + /*if abort went well, call saved done, then return success or error */ + if (cmd->result == (DID_ABORT << 16)) + { + cmd->result |= DID_ABORT << 16; + if (cmd->scsi_done) + (cmd->scsi_done) (cmd); + ld(host_index)[ldn].cmd = NULL; +#ifdef IM_DEBUG_PROBE + printk("IBM MCA SCSI: Abort finished with success.\n"); +#endif + return SCSI_ABORT_SUCCESS; + } + else + { + cmd->result |= DID_NO_CONNECT << 16; + if (cmd->scsi_done) + (cmd->scsi_done) (cmd); + ld(host_index)[ldn].cmd = NULL; +#ifdef IM_DEBUG_PROBE + printk("IBM MCA SCSI: Abort failed.\n"); +#endif + return SCSI_ABORT_ERROR; + } } /*--------------------------------------------------------------------*/ -int -ibmmca_reset (Scsi_Cmnd * cmd, unsigned int reset_flags) +int ibmmca_reset (Scsi_Cmnd * cmd, unsigned int reset_flags) { - struct Scsi_Host *shpnt = cmd->host; - int ticks = IM_RESET_DELAY*HZ; + struct Scsi_Host *shpnt; + Scsi_Cmnd *cmd_aid; + int ticks,i; + int host_index; + static unsigned long flags; + unsigned long imm_command; + +#ifdef OLDKERN + save_flags(flags); + cli(); +#else + spin_lock_irqsave(&reset_lock, flags); +#endif + ticks = IM_RESET_DELAY*HZ; + shpnt = cmd->host; + /* search for the right hostadapter */ + for (host_index = 0; hosts[host_index] && hosts[host_index]->host_no != shpnt->host_no; host_index++); + + if (!hosts[host_index]) + { /* invalid hostadapter descriptor address */ + if (!local_checking_phase_flag(host_index)) + { + cmd->result = DID_NO_CONNECT << 16; + if (cmd->scsi_done) + (cmd->done) (cmd); + } + return SCSI_ABORT_SNOOZE; + } - if (local_checking_phase_flag) { - printk("IBM MCA SCSI: unable to reset while checking devices.\n"); - return SCSI_RESET_SNOOZE; - } - - /* issue reset immediate command to subsystem, and wait for interrupt */ - printk("IBM MCA SCSI: resetting all devices.\n"); - cli (); - reset_status = IM_RESET_IN_PROGRESS; - issue_cmd (shpnt, IM_RESET_IMM_CMD, IM_IMM_CMD | 0xf); - while (reset_status == IM_RESET_IN_PROGRESS && --ticks) { - mdelay(1+999/HZ); - barrier(); - } - /* if reset did not complete, just return an error*/ - if (!ticks) { - printk("IBM MCA SCSI: reset did not complete within %d seconds.\n", - IM_RESET_DELAY); - reset_status = IM_RESET_FINISHED_FAIL; - return SCSI_RESET_ERROR; - } - - /* if reset failed, just return an error */ - if (reset_status == IM_RESET_FINISHED_FAIL) { - printk("IBM MCA SCSI: reset failed.\n"); - return SCSI_RESET_ERROR; - } + if (local_checking_phase_flag(host_index)) + { + printk("IBM MCA SCSI: unable to reset while checking devices.\n"); +#ifdef OLDKERN + restore_flags(flags); +#else + spin_unlock_irqrestore(&reset_lock, flags); +#endif + return SCSI_RESET_SNOOZE; + } - /* so reset finished ok - call outstanding done's, and return success */ - printk ("IBM MCA SCSI: reset completed without error.\n"); - { - int i; - for (i = 0; i < MAX_LOG_DEV; i++) - { - Scsi_Cmnd *cmd = ld[i].cmd; - if (cmd && cmd->scsi_done) - { - ld[i].cmd = 0; - cmd->result = DID_RESET; - (cmd->scsi_done) (cmd); - } - } - } - return SCSI_RESET_SUCCESS; + /* issue reset immediate command to subsystem, and wait for interrupt */ + printk("IBM MCA SCSI: resetting all devices.\n"); + reset_status(host_index) = IM_RESET_IN_PROGRESS; + last_scsi_command(host_index)[0xf] = IM_RESET_IMM_CMD; + last_scsi_type(host_index)[0xf] = IM_IMM_CMD; + imm_command = inl(IM_CMD_REG(host_index)); + imm_command &= (unsigned long)(0xffff0000); /* mask reserved stuff */ + imm_command |= (unsigned long)(IM_RESET_IMM_CMD); + /* must wait for attention reg not busy */ + while (1) + { + if (!(inb (IM_STAT_REG(host_index)) & IM_BUSY)) + break; +#ifdef OLDKERN + restore_flags(flags); +#else + spin_unlock_irqrestore(&reset_lock, flags); +#endif +#ifdef OLDKERN + save_flags(flags); + cli(); +#else + spin_lock_irqsave(&reset_lock, flags); +#endif + } + /*write registers and enable system interrupts */ + outl (imm_command, IM_CMD_REG(host_index)); + outb (IM_IMM_CMD | 0xf, IM_ATTN_REG(host_index)); + /* wait for interrupt finished or intr_stat register to be set, as the + * interrupt will not be executed, while we are in here! */ + while (reset_status(host_index) == IM_RESET_IN_PROGRESS && --ticks + && ((inb(IM_INTR_REG(host_index)) & 0x8f)!=0x8f)) { + mdelay(1+999/HZ); + barrier(); + } + /* if reset did not complete, just return an error*/ + if (!ticks) { + printk("IBM MCA SCSI: reset did not complete within %d seconds.\n", + IM_RESET_DELAY); + reset_status(host_index) = IM_RESET_FINISHED_FAIL; +#ifdef OLDKERN + restore_flags(flags); +#else + spin_unlock_irqrestore(&reset_lock, flags); +#endif + return SCSI_RESET_ERROR; + } + + if ((inb(IM_INTR_REG(host_index)) & 0x8f)==0x8f) + { /* analysis done by this routine and not by the intr-routine */ + if (inb(IM_INTR_REG(host_index))==0xaf) + reset_status(host_index) = IM_RESET_FINISHED_OK_NO_INT; + else if (inb(IM_INTR_REG(host_index))==0xcf) + reset_status(host_index) = IM_RESET_FINISHED_FAIL; + else /* failed, 4get it */ + reset_status(host_index) = IM_RESET_NOT_IN_PROGRESS_NO_INT; + outb (IM_EOI | 0xf, IM_ATTN_REG(host_index)); + } + + /* if reset failed, just return an error */ + if (reset_status(host_index) == IM_RESET_FINISHED_FAIL) { + printk("IBM MCA SCSI: reset failed.\n"); +#ifdef OLDKERN + restore_flags(flags); +#else + spin_unlock_irqrestore(&reset_lock, flags); +#endif + return SCSI_RESET_ERROR; + } + + /* so reset finished ok - call outstanding done's, and return success */ + printk ("IBM MCA SCSI: Reset completed without known error.\n"); +#ifdef OLDKERN + restore_flags(flags); +#else + spin_unlock_irqrestore(&reset_lock, flags); +#endif + for (i = 0; i < MAX_LOG_DEV; i++) + { + cmd_aid = ld(host_index)[i].cmd; + if (cmd_aid && cmd_aid->scsi_done) + { + ld(host_index)[i].cmd = NULL; + cmd_aid->result = DID_RESET << 16; + (cmd_aid->scsi_done) (cmd_aid); + } + } + return SCSI_RESET_SUCCESS; } /*--------------------------------------------------------------------*/ -int -ibmmca_biosparam (Disk * disk, kdev_t dev, int *info) +int ibmmca_biosparam (Disk * disk, kdev_t dev, int *info) { - info[0] = 64; - info[1] = 32; - info[2] = disk->capacity / (info[0] * info[1]); - if (info[2] >= 1024) - { - info[0] = 128; - info[1] = 63; - info[2] = disk->capacity / (info[0] * info[1]); - if (info[2] >= 1024) - { - info[0] = 255; - info[1] = 63; - info[2] = disk->capacity / (info[0] * info[1]); - if (info[2] >= 1024) - info[2] = 1023; - } - } - return 0; + info[0] = 64; + info[1] = 32; + info[2] = disk->capacity / (info[0] * info[1]); + if (info[2] >= 1024) + { + info[0] = 128; + info[1] = 63; + info[2] = disk->capacity / (info[0] * info[1]); + if (info[2] >= 1024) + { + info[0] = 255; + info[1] = 63; + info[2] = disk->capacity / (info[0] * info[1]); + if (info[2] >= 1024) + info[2] = 1023; + } + } + return 0; } /* calculate percentage of total accesses on a ldn */ -static int ldn_access_load(struct Scsi_Host *shpnt, int ldn) +static int ldn_access_load(int host_index, int ldn) { - if (IBM_DS.total_accesses == 0) return (0); - if (IBM_DS.ldn_access[ldn] == 0) return (0); - return (IBM_DS.ldn_access[ldn] * 100) / IBM_DS.total_accesses; + if (IBM_DS(host_index).total_accesses == 0) return (0); + if (IBM_DS(host_index).ldn_access[ldn] == 0) return (0); + return (IBM_DS(host_index).ldn_access[ldn] * 100) / IBM_DS(host_index).total_accesses; } /* calculate total amount of r/w-accesses */ -static int ldn_access_total_read_write(struct Scsi_Host *shpnt) +static int ldn_access_total_read_write(int host_index) { - int a = 0; + int a; int i; + a = 0; for (i=0; i<=MAX_LOG_DEV; i++) - a+=IBM_DS.ldn_read_access[i]+IBM_DS.ldn_write_access[i]; + a+=IBM_DS(host_index).ldn_read_access[i]+IBM_DS(host_index).ldn_write_access[i]; return(a); } -static int ldn_access_total_inquiry(struct Scsi_Host *shpnt) +static int ldn_access_total_inquiry(int host_index) { - int a = 0; + int a; int i; + a = 0; for (i=0; i<=MAX_LOG_DEV; i++) - a+=IBM_DS.ldn_inquiry_access[i]; + a+=IBM_DS(host_index).ldn_inquiry_access[i]; return(a); } -static int ldn_access_total_modeselect(struct Scsi_Host *shpnt) +static int ldn_access_total_modeselect(int host_index) { - int a = 0; + int a; int i; + a = 0; for (i=0; i<=MAX_LOG_DEV; i++) - a+=IBM_DS.ldn_modeselect_access[i]; + a+=IBM_DS(host_index).ldn_modeselect_access[i]; return(a); } @@ -2186,28 +2489,30 @@ int hostno, int inout) { int len=0; - int i,id,lun; + int i,id,lun,host_index; struct Scsi_Host *shpnt; unsigned long flags; +#ifdef OLDKERN + save_flags(flags); + cli(); +#else + spin_lock_irqsave(&proc_lock, flags); +#endif + for (i = 0; hosts[i] && hosts[i]->host_no != hostno; i++); shpnt = hosts[i]; + host_index = i; if (!shpnt) { len += sprintf(buffer+len, "\nCan't find adapter for host number %d\n", hostno); return len; } - save_flags(flags); - cli(); - len += sprintf(buffer+len, "\n IBM-SCSI-Subsystem-Linux-Driver, Version %s\n\n\n", IBMMCA_SCSI_DRIVER_VERSION); len += sprintf(buffer+len, " SCSI Access-Statistics:\n"); -#ifdef CONFIG_IBMMCA_SCSI_ORDER_STANDARD - len += sprintf(buffer+len, " ANSI-SCSI-standard order.: Yes\n"); -#else - len += sprintf(buffer+len, " ANSI-SCSI-standard order.: No\n"); -#endif + len += sprintf(buffer+len, " Device Scanning Order....: %s\n", + (ibm_ansi_order) ? "IBM/ANSI" : "New Industry Standard"); #ifdef CONFIG_SCSI_MULTI_LUN len += sprintf(buffer+len, " Multiple LUN probing.....: Yes\n"); #else @@ -2215,72 +2520,74 @@ #endif len += sprintf(buffer+len, " This Hostnumber..........: %d\n", hostno); - len += sprintf(buffer+len, " Base I/O-Port............: 0x%lx\n", - IM_CMD_REG); + len += sprintf(buffer+len, " Base I/O-Port............: 0x%x\n", + (unsigned int)(IM_CMD_REG(host_index))); len += sprintf(buffer+len, " (Shared) IRQ.............: %d\n", IM_IRQ); + len += sprintf(buffer+len, " SCSI-command set used....: %s\n", + (bypass_controller) ? "software" : "hardware integrated"); len += sprintf(buffer+len, " Total Interrupts.........: %d\n", - IBM_DS.total_interrupts); + IBM_DS(host_index).total_interrupts); len += sprintf(buffer+len, " Total SCSI Accesses......: %d\n", - IBM_DS.total_accesses); + IBM_DS(host_index).total_accesses); len += sprintf(buffer+len, " Total SCSI READ/WRITE..: %d\n", - ldn_access_total_read_write(shpnt)); + ldn_access_total_read_write(host_index)); len += sprintf(buffer+len, " Total SCSI Inquiries...: %d\n", - ldn_access_total_inquiry(shpnt)); + ldn_access_total_inquiry(host_index)); len += sprintf(buffer+len, " Total SCSI Modeselects.: %d\n", - ldn_access_total_modeselect(shpnt)); - len += sprintf(buffer+len, " Total SCSI other cmds..: %d\n\n", - IBM_DS.total_accesses - ldn_access_total_read_write(shpnt) - - ldn_access_total_modeselect(shpnt) - - ldn_access_total_inquiry(shpnt)); - + ldn_access_total_modeselect(host_index)); + len += sprintf(buffer+len, " Total SCSI other cmds..: %d\n", + IBM_DS(host_index).total_accesses - ldn_access_total_read_write(host_index) + - ldn_access_total_modeselect(host_index) + - ldn_access_total_inquiry(host_index)); + len += sprintf(buffer+len, " Total SCSI command fails.: %d\n\n", + IBM_DS(host_index).total_errors); len += sprintf(buffer+len, " Logical-Device-Number (LDN) Access-Statistics:\n"); len += sprintf(buffer+len, " LDN | Accesses [%%] | READ | WRITE | ASSIGNMENTS\n"); len += sprintf(buffer+len, " -----|--------------|-----------|-----------|--------------\n"); for (i=0; i<=MAX_LOG_DEV; i++) len += sprintf(buffer+len, " %2X | %3d | %8d | %8d | %8d\n", - i, ldn_access_load(shpnt, i), IBM_DS.ldn_read_access[i], - IBM_DS.ldn_write_access[i], IBM_DS.ldn_assignments[i]); + i, ldn_access_load(host_index, i), IBM_DS(host_index).ldn_read_access[i], + IBM_DS(host_index).ldn_write_access[i], IBM_DS(host_index).ldn_assignments[i]); len += sprintf(buffer+len, " -----------------------------------------------------------\n\n"); len += sprintf(buffer+len, " Dynamical-LDN-Assignment-Statistics:\n"); len += sprintf(buffer+len, " Number of physical SCSI-devices..: %d (+ Adapter)\n", - IBM_DS.total_scsi_devices); + IBM_DS(host_index).total_scsi_devices); len += sprintf(buffer+len, " Dynamical Assignment necessaray..: %s\n", - IBM_DS.dyn_flag ? "Yes" : "No "); + IBM_DS(host_index).dyn_flag ? "Yes" : "No "); len += sprintf(buffer+len, " Next LDN to be assigned..........: 0x%x\n", - next_ldn); + next_ldn(host_index)); len += sprintf(buffer+len, " Dynamical assignments done yet...: %d\n", - IBM_DS.dynamical_assignments); + IBM_DS(host_index).dynamical_assignments); len += sprintf(buffer+len, "\n Current SCSI-Device-Mapping:\n"); len += sprintf(buffer+len, " Physical SCSI-Device Map Logical SCSI-Device Map\n"); len += sprintf(buffer+len, " ID\\LUN 0 1 2 3 4 5 6 7 ID\\LUN 0 1 2 3 4 5 6 7\n"); for (id=0; id<=7; id++) { - len += sprintf(buffer+len, " %2d %2s %2s %2s %2s %2s %2s %2s %2s", - id, ti_p(get_scsi[id][0]), ti_p(get_scsi[id][1]), - ti_p(get_scsi[id][2]), ti_p(get_scsi[id][3]), - ti_p(get_scsi[id][4]), ti_p(get_scsi[id][5]), - ti_p(get_scsi[id][6]), ti_p(get_scsi[id][7])); - - len += sprintf(buffer+len, " %2d ",id); + len += sprintf(buffer+len, " %2d ",id); for (lun=0; lun<8; lun++) - len += sprintf(buffer+len,"%2s ",ti_l(get_ldn[id][lun])); + len += sprintf(buffer+len,"%2s ",ti_p(get_scsi(host_index)[id][lun])); + len += sprintf(buffer+len, " %2d ",id); + for (lun=0; lun<8; lun++) + len += sprintf(buffer+len,"%2s ",ti_l(get_ldn(host_index)[id][lun])); len += sprintf(buffer+len,"\n"); } len += sprintf(buffer+len, "(A = IBM-Subsystem, D = Harddisk, T = Tapedrive, P = Processor, W = WORM,\n"); len += sprintf(buffer+len, " R = CD-ROM, S = Scanner, M = MO-Drive, C = Medium-Changer, + = unprovided LUN,\n"); - len += sprintf(buffer+len, " - = nothing found)\n\n"); + len += sprintf(buffer+len, " - = nothing found, nothing assigned or unprobed LUN)\n\n"); *start = buffer + offset; len -= offset; if (len > length) len = length; - +#ifdef OLDKERN restore_flags(flags); - +#else + spin_unlock_irqrestore(&proc_lock, flags); +#endif return len; } @@ -2292,6 +2599,4 @@ #endif /*--------------------------------------------------------------------*/ - - diff -ur --new-file old/linux/drivers/scsi/ibmmca.h new/linux/drivers/scsi/ibmmca.h --- old/linux/drivers/scsi/ibmmca.h Fri Feb 13 01:25:04 1998 +++ new/linux/drivers/scsi/ibmmca.h Tue May 11 19:36:33 1999 @@ -1,24 +1,37 @@ #ifndef _IBMMCA_H #define _IBMMCA_H +#ifndef LINUX_VERSION_CODE +#include +#endif + +#ifndef ibmmca_header_linux_version +#define ibmmca_header_linux_version(v,p,s) (((v)<<16)+((p)<<8)+(s)) +#endif + /* * Low Level Driver for the IBM Microchannel SCSI Subsystem + * (Headerfile, see README.ibmmca for description of the IBM MCA SCSI-driver) */ +/* Common forward declarations for all Linux-versions: */ + /*services provided to the higher level of Linux SCSI driver */ -int ibmmca_proc_info (char *, char **, off_t, int, int, int); -int ibmmca_detect (Scsi_Host_Template *); -int ibmmca_release (struct Scsi_Host *); -int ibmmca_command (Scsi_Cmnd *); -int ibmmca_queuecommand (Scsi_Cmnd *, void (*done) (Scsi_Cmnd *)); -int ibmmca_abort (Scsi_Cmnd *); -int ibmmca_reset (Scsi_Cmnd *, unsigned int); -int ibmmca_biosparam (Disk *, kdev_t, int *); +extern int ibmmca_proc_info (char *, char **, off_t, int, int, int); +extern int ibmmca_detect (Scsi_Host_Template *); +extern int ibmmca_release (struct Scsi_Host *); +extern int ibmmca_command (Scsi_Cmnd *); +extern int ibmmca_queuecommand (Scsi_Cmnd *, void (*done) (Scsi_Cmnd *)); +extern int ibmmca_abort (Scsi_Cmnd *); +extern int ibmmca_reset (Scsi_Cmnd *, unsigned int); +extern int ibmmca_biosparam (Disk *, kdev_t, int *); /*structure for /proc filesystem */ extern struct proc_dir_entry proc_scsi_ibmmca; -/*initialization for Scsi_host_template type */ +#if LINUX_VERSION_CODE >= ibmmca_header_linux_version(2,1,0) +/* Stuff for Linux >= 2.1.0: */ +/*initialization for Scsi_host_template type (Linux >= 2.1.0) */ /* * 2/8/98 * Note to maintainer of IBMMCA. Do not change this initializer back to @@ -28,7 +41,7 @@ #define IBMMCA { \ proc_dir: &proc_scsi_ibmmca, /*proc_dir*/ \ proc_info: ibmmca_proc_info, /*proc info fn*/ \ - name: "IBMMCA", /*name*/ \ + name: "IBM SCSI-Subsystem", /*name*/ \ detect: ibmmca_detect, /*detect fn*/ \ release: ibmmca_release, /*release fn*/ \ command: ibmmca_command, /*command fn*/ \ @@ -40,9 +53,37 @@ this_id: 7, /*set by detect*/ \ sg_tablesize: 16, /*sg_tablesize*/ \ cmd_per_lun: 1, /*cmd_per_lun*/ \ + unchecked_isa_dma: 0, /*32-Bit Busmaster */ \ use_clustering: ENABLE_CLUSTERING /*use_clustering*/ \ } -#endif /* _IBMMCA_H */ +#else +/* Stuff for Linux < 2.1.0: */ +/*initialization for Scsi_host_template type (Linux < 2.1.0) */ +#define IBMMCA { \ + NULL, /*next*/ \ + NULL, /*usage_count*/ \ + &proc_scsi_ibmmca, /*proc_dir*/ \ + ibmmca_proc_info, /*proc info fn*/ \ + "IBM SCSI-Subsystem", /*name*/ \ + ibmmca_detect, /*detect fn*/ \ + ibmmca_release, /*release fn*/ \ + NULL, /*info fn*/ \ + ibmmca_command, /*command fn*/ \ + ibmmca_queuecommand, /*queuecommand fn*/ \ + ibmmca_abort, /*abort fn*/ \ + ibmmca_reset, /*reset fn*/ \ + NULL, /*slave_attach fn*/ \ + ibmmca_biosparam, /*bios fn*/ \ + 16, /*can_queue*/ \ + 7, /*set by detect*/ \ + 16, /*sg_tablesize*/ \ + 1, /*cmd_per_lun*/ \ + 0, /*present*/ \ + 0, /*unchecked_isa_dma*/ \ + ENABLE_CLUSTERING /*use_clustering*/ \ + } +#endif /* kernelversion selection */ +#endif /* _IBMMCA_H */ diff -ur --new-file old/linux/drivers/scsi/ide-scsi.c new/linux/drivers/scsi/ide-scsi.c --- old/linux/drivers/scsi/ide-scsi.c Fri Jan 15 23:41:04 1999 +++ new/linux/drivers/scsi/ide-scsi.c Fri Apr 23 04:24:50 1999 @@ -23,8 +23,9 @@ * Ver 0.6 Jan 27 98 Allow disabling of SCSI command translation layer * for access through /dev/sg. * Fix MODE_SENSE_6/MODE_SELECT_6/INQUIRY translation. - * Ver 0.7 Dev 04 98 Ignore commands where lun != 0 to avoid multiple + * 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. */ #define IDESCSI_VERSION "0.6" @@ -66,7 +67,7 @@ int b_count; /* Bytes transferred from current entry */ Scsi_Cmnd *scsi_cmd; /* SCSI command */ void (*done)(Scsi_Cmnd *); /* Scsi completion routine */ - unsigned int flags; /* Status/Action flags */ + unsigned long flags; /* Status/Action flags */ unsigned long timeout; /* Command timeout */ } idescsi_pc_t; @@ -91,9 +92,9 @@ typedef struct { ide_drive_t *drive; idescsi_pc_t *pc; /* Current packet command */ - unsigned int flags; /* Status/Action flags */ - int transform; /* SCSI cmd translation layer */ - int log; /* log flags */ + unsigned long flags; /* Status/Action flags */ + unsigned long transform; /* SCSI cmd translation layer */ + unsigned long log; /* log flags */ } idescsi_scsi_t; /* @@ -178,7 +179,7 @@ if (!test_bit(PC_TRANSFORM, &pc->flags)) return; - if (drive->media == ide_cdrom) { + if (drive->media == ide_cdrom || drive->media == ide_optical) { if (c[0] == READ_6 || c[0] == WRITE_6) { c[8] = c[4]; c[5] = c[3]; c[4] = c[2]; c[3] = c[1] & 0x1f; c[2] = 0; c[1] &= 0xe0; @@ -217,7 +218,7 @@ if (!test_bit(PC_TRANSFORM, &pc->flags)) return; - if (drive->media == ide_cdrom) { + if (drive->media == ide_cdrom || drive->media == ide_optical) { if (pc->c[0] == MODE_SENSE_10 && sc[0] == MODE_SENSE) { scsi_buf[0] = atapi_buf[1]; /* Mode data length */ scsi_buf[1] = atapi_buf[2]; /* Medium type */ @@ -730,9 +731,6 @@ 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; pc = kmalloc (sizeof (idescsi_pc_t), GFP_ATOMIC); rq = kmalloc (sizeof (struct request), GFP_ATOMIC); @@ -794,7 +792,7 @@ int idescsi_reset (Scsi_Cmnd *cmd, unsigned int resetflags) { - return SCSI_RESET_PUNT; + return SCSI_RESET_SUCCESS; } int idescsi_bios (Disk *disk, kdev_t dev, int *parm) diff -ur --new-file old/linux/drivers/scsi/imm.c new/linux/drivers/scsi/imm.c --- old/linux/drivers/scsi/imm.c Sun Jan 10 04:16:43 1999 +++ new/linux/drivers/scsi/imm.c Fri May 7 19:57:42 1999 @@ -881,6 +881,7 @@ { imm_struct *tmp = (imm_struct *) data; Scsi_Cmnd *cmd = tmp->cur_cmd; + unsigned long flags; if (!cmd) { printk("IMM: bug in imm_interrupt\n"); @@ -931,8 +932,10 @@ if (cmd->SCp.phase > 0) imm_pb_release(cmd->host->unique_id); + spin_lock_irqsave(&io_request_lock, flags); tmp->cur_cmd = 0; cmd->scsi_done(cmd); + spin_unlock_irqrestore(&io_request_lock, flags); return; } @@ -1204,19 +1207,16 @@ status = imm_out(host_no, &cmd[l << 1], 2); if (!status) { - imm_disconnect(host_no); - imm_connect(host_no, CONNECT_EPP_MAYBE); - w_dtr(ppb, 0x40); - w_ctr(ppb, 0x08); - udelay(30); - w_ctr(ppb, 0x0c); - udelay(1000); - imm_disconnect(host_no); - udelay(1000); - if (imm_hosts[host_no].mode == IMM_EPP_32) { - imm_hosts[host_no].mode = old_mode; - goto second_pass; - } + imm_disconnect(host_no); + imm_connect(host_no, CONNECT_EPP_MAYBE); + imm_reset_pulse(IMM_BASE(host_no)); + udelay(1000); + imm_disconnect(host_no); + udelay(1000); + if (imm_hosts[host_no].mode == IMM_EPP_32) { + imm_hosts[host_no].mode = old_mode; + goto second_pass; + } printk("imm: Unable to establish communication, aborting driver load.\n"); return 1; } diff -ur --new-file old/linux/drivers/scsi/inia100.c new/linux/drivers/scsi/inia100.c --- old/linux/drivers/scsi/inia100.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/scsi/inia100.c Thu Feb 25 01:27:54 1999 @@ -0,0 +1,952 @@ +/************************************************************************** + * Initio A100 device driver for Linux. + * + * Copyright (c) 1994-1998 Initio Corporation + * All rights reserved. + * + * 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; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * -------------------------------------------------------------------------- + * + * 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, + * without modification, immediately at the beginning of the file. + * 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. + * + * Where this Software is combined with software released under the terms of + * the GNU Public License ("GPL") and the terms of the GPL would require the + * combined work to also be released under the terms of the GPL, the terms + * and conditions of this License will apply in addition to those of the + * GPL with the exception of any terms or conditions of this License that + * conflict with, or are expressly prohibited by, the GPL. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + ************************************************************************** + * + * module: inia100.c + * DESCRIPTION: + * This is the Linux low-level SCSI driver for Initio INIA100 SCSI host + * adapters + * 09/24/98 hl - v1.02 initial production release. + * 12/19/98 bv - v1.02a Use spinlocks for 2.1.95 and up. + **************************************************************************/ + +#define CVT_LINUX_VERSION(V,P,S) (V * 65536 + P * 256 + S) + +#ifndef LINUX_VERSION_CODE +#include +#endif + +#ifdef MODULE +#include +#endif + +#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 +#include +#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 + +#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; +#include "scsi_module.c" +#endif + +#define ORC_RDWORD(x,y) (short)(inl((int)((ULONG)((ULONG)x+(UCHAR)y)) )) + +char *inia100_Copyright = "Copyright (C) 1998-99"; +char *inia100_InitioName = "by Initio Corporation"; +char *inia100_ProductName = "INI-A100U2W"; +char *inia100_Version = "v1.02a"; + +#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0) +struct proc_dir_entry proc_scsi_inia100 = +{ + PROC_SCSI_INIA100, 7, "INIA100", + S_IFDIR | S_IRUGO | S_IXUGO, 2, + 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL +}; +#endif + +/* set by inia100_setup according to the command line */ +static int setup_called = 0; +static int orc_num_ch = MAX_SUPPORTED_ADAPTERS; /* Maximum 4 adapters */ + +/* ---- INTERNAL VARIABLES ---- */ +#define NUMBER(arr) (sizeof(arr) / sizeof(arr[0])) +static char *setup_str = (char *) NULL; + +#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0) +static void inia100_intr0(int irq, void *dev_id, struct pt_regs *); +static void inia100_intr1(int irq, void *dev_id, struct pt_regs *); +static void inia100_intr2(int irq, void *dev_id, struct pt_regs *); +static void inia100_intr3(int irq, void *dev_id, struct pt_regs *); +static void inia100_intr4(int irq, void *dev_id, struct pt_regs *); +static void inia100_intr5(int irq, void *dev_id, struct pt_regs *); +static void inia100_intr6(int irq, void *dev_id, struct pt_regs *); +static void inia100_intr7(int irq, void *dev_id, struct pt_regs *); +#else +static void inia100_intr0(int irq, struct pt_regs *); +static void inia100_intr1(int irq, struct pt_regs *); +static void inia100_intr2(int irq, struct pt_regs *); +static void inia100_intr3(int irq, struct pt_regs *); +static void inia100_intr4(int irq, struct pt_regs *); +static void inia100_intr5(int irq, struct pt_regs *); +static void inia100_intr6(int irq, struct pt_regs *); +static void inia100_intr7(int irq, struct pt_regs *); +#endif + +static void inia100_panic(char *msg); +void inia100SCBPost(BYTE * pHcb, BYTE * pScb); + +/* ---- EXTERNAL VARIABLES ---- */ +extern int Addinia100_into_Adapter_table(WORD, WORD, BYTE, BYTE, BYTE); +extern void init_inia100Adapter_table(void); +extern ORC_SCB *orc_alloc_scb(ORC_HCS * hcsp); +extern void orc_exec_scb(ORC_HCS * hcsp, ORC_SCB * scbp); +extern void orc_release_scb(ORC_HCS * hcsp, ORC_SCB * scbp); +extern void orc_interrupt(ORC_HCS * hcsp); +extern int orc_device_reset(ORC_HCS * pHCB, ULONG SCpnt, unsigned int target, unsigned int ResetFlags); +extern int orc_reset_scsi_bus(ORC_HCS * pHCB); +extern int abort_SCB(ORC_HCS * hcsp, ORC_SCB * pScb); +extern int orc_abort_srb(ORC_HCS * hcsp, ULONG SCpnt); +extern void get_orcPCIConfig(ORC_HCS * pCurHcb, int ch_idx); +extern int init_orchid(ORC_HCS * hcsp); + +extern int orc_num_scb; +extern ORC_HCS orc_hcs[]; + +/***************************************************************************** + Function name : inia100AppendSRBToQueue + Description : This function will push current request into save list + Input : pSRB - Pointer to SCSI request block. + pHCB - Pointer to host adapter structure + Output : None. + Return : None. +*****************************************************************************/ +static void inia100AppendSRBToQueue(ORC_HCS * pHCB, Scsi_Cmnd * pSRB) +{ + ULONG flags; + +#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95) + spin_lock_irqsave(&(pHCB->pSRB_lock), flags); +#else + save_flags(flags); + cli(); +#endif + + pSRB->next = NULL; /* Pointer to next */ + if (pHCB->pSRB_head == NULL) + pHCB->pSRB_head = pSRB; + else + pHCB->pSRB_tail->next = pSRB; /* Pointer to next */ + pHCB->pSRB_tail = pSRB; +#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95) + spin_unlock_irqrestore(&(pHCB->pSRB_lock), flags); +#else + restore_flags(flags); +#endif + return; +} + +/***************************************************************************** + Function name : inia100PopSRBFromQueue + Description : This function will pop current request from save list + Input : pHCB - Pointer to host adapter structure + Output : None. + Return : pSRB - Pointer to SCSI request block. +*****************************************************************************/ +static Scsi_Cmnd *inia100PopSRBFromQueue(ORC_HCS * pHCB) +{ + Scsi_Cmnd *pSRB; + ULONG flags; +#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95) + spin_lock_irqsave(&(pHCB->pSRB_lock), flags); +#else + save_flags(flags); + cli(); +#endif + + if ((pSRB = (Scsi_Cmnd *) pHCB->pSRB_head) != NULL) { + pHCB->pSRB_head = pHCB->pSRB_head->next; + pSRB->next = NULL; + } +#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95) + spin_unlock_irqrestore(&(pHCB->pSRB_lock), flags); +#else + restore_flags(flags); +#endif + return (pSRB); +} + +/***************************************************************************** + Function name : inia100_setup + Description : + Input : pHCB - Pointer to host adapter structure + Output : None. + Return : pSRB - Pointer to SCSI request block. +*****************************************************************************/ +void inia100_setup(char *str, int *ints) +{ + if (setup_called) + inia100_panic("inia100: inia100_setup called twice.\n"); + + setup_called = ints[0]; + setup_str = str; +} + +/***************************************************************************** + Function name : orc_ReturnNumberOfAdapters + Description : This function will scan PCI bus to get all Orchid card + Input : None. + Output : None. + Return : SUCCESSFUL - Successful scan + ohterwise - No drives founded +*****************************************************************************/ +int orc_ReturnNumberOfAdapters(void) +{ + unsigned int i, iAdapters; + + iAdapters = 0; + /* + * PCI-bus probe. + */ + if (pcibios_present()) { + struct { + unsigned short vendor_id; + unsigned short device_id; + } const inia100_pci_devices[] = + { + {ORC_VENDOR_ID, I920_DEVICE_ID}, + {ORC_VENDOR_ID, ORC_DEVICE_ID} + }; + + unsigned int dRegValue; + unsigned short command; + WORD wBIOS, wBASE; + BYTE bPCIBusNum, bInterrupt, bPCIDeviceNum; + +#ifdef MMAPIO + unsigned long page_offset, base; +#endif + +#if LINUX_VERSION_CODE > CVT_LINUX_VERSION(2,1,92) + struct pci_dev *pdev = NULL; +#else + int index; + unsigned char pci_bus, pci_devfn; +#endif + + bPCIBusNum = 0; + bPCIDeviceNum = 0; + init_inia100Adapter_table(); + for (i = 0; i < NUMBER(inia100_pci_devices); i++) { +#if LINUX_VERSION_CODE > CVT_LINUX_VERSION(2,1,92) + pdev = NULL; + while ((pdev = pci_find_device(inia100_pci_devices[i].vendor_id, + inia100_pci_devices[i].device_id, + pdev))) +#else + index = 0; + while (!(pcibios_find_device(inia100_pci_devices[i].vendor_id, + inia100_pci_devices[i].device_id, + index++, &pci_bus, &pci_devfn))) +#endif + { + if (iAdapters >= MAX_SUPPORTED_ADAPTERS) + break; /* Never greater than maximum */ + + if (i == 0) { + /* + printk("inia100: The RAID controller is not supported by\n"); + printk("inia100: this driver, we are ignoring it.\n"); + */ + } else { + /* + * Read sundry information from PCI BIOS. + */ +#if LINUX_VERSION_CODE > CVT_LINUX_VERSION(2,1,92) + bPCIBusNum = pdev->bus->number; + bPCIDeviceNum = pdev->devfn; + dRegValue = pdev->base_address[0]; + if (dRegValue == -1) { /* Check return code */ + printk("\n\rinia100: orchid read configuration error.\n"); + return (0); /* Read configuration space error */ + } + /* <02> read from base address + 0x50 offset to get the wBIOS balue. */ + wBASE = (WORD) dRegValue; + + /* Now read the interrupt line */ + dRegValue = pdev->irq; + bInterrupt = dRegValue & 0xFF; /* Assign interrupt line */ + pci_read_config_word(pdev, PCI_COMMAND, &command); + pci_write_config_word(pdev, PCI_COMMAND, + command | PCI_COMMAND_MASTER | PCI_COMMAND_IO); + +#else + bPCIBusNum = pci_bus; + bPCIDeviceNum = pci_devfn; + pcibios_read_config_dword(pci_bus, pci_devfn, PCI_BASE_ADDRESS_0, + &dRegValue); + if (dRegValue == -1) { /* Check return code */ + printk("\n\rinia100: Orchid read configuration error.\n"); + return (0); /* Read configuration space error */ + } + /* <02> read from base address + 0x50 offset to get the wBIOS balue. */ + wBASE = (WORD) dRegValue; + + /* Now read the interrupt line */ + pcibios_read_config_dword(pci_bus, pci_devfn, PCI_INTERRUPT_LINE, + &dRegValue); + bInterrupt = dRegValue & 0xFF; /* Assign interrupt line */ + pcibios_read_config_word(pci_bus, pci_devfn, PCI_COMMAND, &command); + pcibios_write_config_word(pci_bus, pci_devfn, PCI_COMMAND, + command | PCI_COMMAND_MASTER | PCI_COMMAND_IO); +#endif + wBASE &= PCI_BASE_ADDRESS_IO_MASK; + wBIOS = ORC_RDWORD(wBASE, 0x50); + +#ifdef MMAPIO + base = wBASE & PAGE_MASK; + page_offset = wBASE - base; + + /* + * replace the next line with this one if you are using 2.1.x: + * temp_p->maddr = ioremap(base, page_offset + 256); + */ +#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,0) + wBASE = ioremap(base, page_offset + 256); +#else + wBASE = (WORD) vremap(base, page_offset + 256); +#endif + if (wBASE) { + wBASE += page_offset; + } +#endif + + if (Addinia100_into_Adapter_table(wBIOS, wBASE, bInterrupt, bPCIBusNum, + bPCIDeviceNum) == SUCCESSFUL) + iAdapters++; + } + } /* while(pdev=....) */ + } /* for PCI_DEVICES */ + } /* PCI BIOS present */ + return (iAdapters); +} + +/***************************************************************************** + Function name : inia100_detect + Description : + Input : pHCB - Pointer to host adapter structure + Output : None. + Return : pSRB - Pointer to SCSI request block. +*****************************************************************************/ +int inia100_detect(Scsi_Host_Template * tpnt) +{ + ORC_HCS *pHCB; + struct Scsi_Host *hreg; + U32 sz; + U32 i; /* 01/14/98 */ + int ok = 0, iAdapters; + ULONG dBiosAdr; + BYTE *pbBiosAdr; + +#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0) + tpnt->proc_dir = &proc_scsi_inia100; +#endif + if (setup_called) { + /* Setup by inia100_setup */ + printk("inia100: processing commandline: "); + } + /* Get total number of adapters in the motherboard */ + iAdapters = orc_ReturnNumberOfAdapters(); + + /* printk("inia100: Total Initio Adapters = %d\n", iAdapters); */ + if (iAdapters == 0) /* If no orc founded, return */ + return (0); + + orc_num_ch = (iAdapters > orc_num_ch) ? orc_num_ch : iAdapters; + orc_num_scb = ORC_MAXQUEUE; + + /* clear the memory needed for HCS */ + i = orc_num_ch * sizeof(ORC_HCS); + memset((unsigned char *) &orc_hcs[0], 0, i); /* Initialize orc_hcs 0 */ + +#if 0 + printk("orc_num_scb= %x orc_num_ch= %x hcsize= %x scbsize= %x escbsize= %x\n", + orc_num_scb, orc_num_ch, sizeof(ORC_HCS), sizeof(ORC_SCB), sizeof(ESCB)); +#endif + + for (i = 0, pHCB = &orc_hcs[0]; /* Get pointer for control block */ + i < orc_num_ch; + i++, pHCB++) { + + pHCB->pSRB_head = NULL; /* Initial SRB save queue */ + pHCB->pSRB_tail = NULL; /* Initial SRB save queue */ +#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95) + pHCB->pSRB_lock = SPIN_LOCK_UNLOCKED; /* SRB save queue lock */ +#endif + /* Get total memory needed for SCB */ + sz = orc_num_scb * sizeof(ORC_SCB); + if ((pHCB->HCS_virScbArray = (PVOID) kmalloc(sz, GFP_ATOMIC | GFP_DMA)) == NULL) { + printk("inia100: SCB memory allocation error\n"); + return (0); + } + memset((unsigned char *) pHCB->HCS_virScbArray, 0, sz); + pHCB->HCS_physScbArray = (U32) VIRT_TO_BUS(pHCB->HCS_virScbArray); + + /* Get total memory needed for ESCB */ + sz = orc_num_scb * sizeof(ESCB); + if ((pHCB->HCS_virEscbArray = (PVOID) kmalloc(sz, GFP_ATOMIC | GFP_DMA)) == NULL) { + printk("inia100: ESCB memory allocation error\n"); + return (0); + } + memset((unsigned char *) pHCB->HCS_virEscbArray, 0, sz); + pHCB->HCS_physEscbArray = (U32) VIRT_TO_BUS(pHCB->HCS_virEscbArray); + + request_region(pHCB->HCS_Base, 0x100, "inia100"); /* Register */ + get_orcPCIConfig(pHCB, i); + + dBiosAdr = pHCB->HCS_BIOS; + dBiosAdr = (dBiosAdr << 4); + +#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0) + pbBiosAdr = phys_to_virt(dBiosAdr); +#endif + + if (init_orchid(pHCB)) { /* Initial orchid chip */ + printk("inia100: initial orchid fail!!\n"); + return (0); + } + hreg = scsi_register(tpnt, sizeof(ORC_HCS)); + if (hreg == NULL) { + printk("Invalid scsi_register pointer.\n"); + } + hreg->io_port = pHCB->HCS_Base; + hreg->n_io_port = 0xff; + hreg->can_queue = orc_num_scb; /* 03/05/98 */ + +#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0) + hreg->unique_id = pHCB->HCS_Base; + hreg->max_id = pHCB->HCS_MaxTar; +#endif + + hreg->max_lun = 32; /* 10/21/97 */ +/* + hreg->max_lun = 8; + hreg->max_channel = 1; + */ + hreg->irq = pHCB->HCS_Intr; + hreg->this_id = pHCB->HCS_SCSI_ID; /* Assign HCS index */ + hreg->base = (UCHAR *) pHCB; + +#if 1 + hreg->sg_tablesize = TOTAL_SG_ENTRY; /* Maximun support is 32 */ +#else + hreg->sg_tablesize = SG_NONE; /* No SG */ +#endif + + /* Initial orc chip */ + switch (i) { +#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0) + case 0: + ok = request_irq(pHCB->HCS_Intr, inia100_intr0, SA_INTERRUPT | SA_SHIRQ, "inia100", NULL); + break; + case 1: + ok = request_irq(pHCB->HCS_Intr, inia100_intr1, SA_INTERRUPT | SA_SHIRQ, "inia100", NULL); + break; + case 2: + ok = request_irq(pHCB->HCS_Intr, inia100_intr2, SA_INTERRUPT | SA_SHIRQ, "inia100", NULL); + break; + case 3: + ok = request_irq(pHCB->HCS_Intr, inia100_intr3, SA_INTERRUPT | SA_SHIRQ, "inia100", NULL); + break; + case 4: + ok = request_irq(pHCB->HCS_Intr, inia100_intr4, SA_INTERRUPT | SA_SHIRQ, "inia100", NULL); + break; + case 5: + ok = request_irq(pHCB->HCS_Intr, inia100_intr5, SA_INTERRUPT | SA_SHIRQ, "inia100", NULL); + break; + case 6: + ok = request_irq(pHCB->HCS_Intr, inia100_intr6, SA_INTERRUPT | SA_SHIRQ, "inia100", NULL); + break; + case 7: + ok = request_irq(pHCB->HCS_Intr, inia100_intr7, SA_INTERRUPT | SA_SHIRQ, "inia100", NULL); + break; + default: + inia100_panic("inia100: Too many host adapters\n"); + break; + } + + if (ok < 0) { + if (ok == -EINVAL) { + printk("inia100: bad IRQ %d.\n", pHCB->HCS_Intr); + printk(" Contact author.\n"); + } else { + if (ok == -EBUSY) + printk("inia100: IRQ %d already in use. Configure another.\n", pHCB->HCS_Intr); + else { + printk("\ninia100: Unexpected error code on requesting IRQ %d.\n", + pHCB->HCS_Intr); + printk(" Contact author.\n"); + } + } + inia100_panic("inia100: driver needs an IRQ.\n"); + } +#endif + } + + tpnt->this_id = -1; + tpnt->can_queue = 1; + return 1; +} + +/***************************************************************************** + Function name : inia100BuildSCB + Description : + Input : pHCB - Pointer to host adapter structure + Output : None. + Return : pSRB - Pointer to SCSI request block. +*****************************************************************************/ +static void inia100BuildSCB(ORC_HCS * pHCB, ORC_SCB * pSCB, Scsi_Cmnd * SCpnt) +{ /* Create corresponding SCB */ + struct scatterlist *pSrbSG; + ORC_SG *pSG; /* Pointer to SG list */ + int i; + U32 TotalLen; + ESCB *pEScb; + + pEScb = pSCB->SCB_EScb; + pEScb->SCB_Srb = SCpnt; + pSG = NULL; + + pSCB->SCB_Opcode = ORC_EXECSCSI; + pSCB->SCB_Flags = SCF_NO_DCHK; /* Clear done bit */ + pSCB->SCB_Target = SCpnt->target; + pSCB->SCB_Lun = SCpnt->lun; + pSCB->SCB_Reserved0 = 0; + pSCB->SCB_Reserved1 = 0; + pSCB->SCB_SGLen = 0; + + if ((pSCB->SCB_XferLen = (U32) SCpnt->request_bufflen)) { + pSG = (ORC_SG *) & pEScb->ESCB_SGList[0]; + if (SCpnt->use_sg) { + TotalLen = 0; + pSCB->SCB_SGLen = (U32) (SCpnt->use_sg * 8); + pSrbSG = (struct scatterlist *) SCpnt->request_buffer; + for (i = 0; i < SCpnt->use_sg; i++, pSG++, pSrbSG++) { +#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0) + pSG->SG_Ptr = (U32) (VIRT_TO_BUS(pSrbSG->address)); +#else + pSG->SG_Ptr = (U32) pSrbSG->address; +#endif + pSG->SG_Len = (U32) pSrbSG->length; + TotalLen += (U32) pSrbSG->length; + } + } else { /* Non SG */ + pSCB->SCB_SGLen = 0x8; +#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0) + pSG->SG_Ptr = (U32) (VIRT_TO_BUS(SCpnt->request_buffer)); +#else + pSG->SG_PTR = (U32) SCpnt->request_buffer; +#endif + pSG->SG_Len = (U32) SCpnt->request_bufflen; + } + } + pSCB->SCB_SGPAddr = (U32) pSCB->SCB_SensePAddr; + pSCB->SCB_HaStat = 0; + pSCB->SCB_TaStat = 0; + pSCB->SCB_Link = 0xFF; + pSCB->SCB_SenseLen = SENSE_SIZE; + pSCB->SCB_CDBLen = SCpnt->cmd_len; + if (pSCB->SCB_CDBLen >= IMAX_CDB) { + printk("max cdb length= %x\b", SCpnt->cmd_len); + pSCB->SCB_CDBLen = IMAX_CDB; + } + pSCB->SCB_Ident = SCpnt->lun | DISC_ALLOW; + if (SCpnt->device->tagged_supported) { /* Tag Support */ + pSCB->SCB_TagMsg = SIMPLE_QUEUE_TAG; /* Do simple tag only */ + } else { + pSCB->SCB_TagMsg = 0; /* No tag support */ + } + memcpy(&pSCB->SCB_CDB[0], &SCpnt->cmnd, pSCB->SCB_CDBLen); + return; +} + +/***************************************************************************** + Function name : inia100_queue + Description : Queue a command and setup interrupts for a free bus. + Input : pHCB - Pointer to host adapter structure + Output : None. + Return : pSRB - Pointer to SCSI request block. +*****************************************************************************/ +int inia100_queue(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *)) +{ + register ORC_SCB *pSCB; + ORC_HCS *pHCB; /* Point to Host adapter control block */ + + if (SCpnt->lun > 16) { + SCpnt->result = (DID_TIME_OUT << 16); + done(SCpnt); /* Notify system DONE */ + return (0); + } + pHCB = (ORC_HCS *) SCpnt->host->base; + SCpnt->scsi_done = done; + /* Get free SCSI control block */ + if ((pSCB = orc_alloc_scb(pHCB)) == NULL) { + inia100AppendSRBToQueue(pHCB, SCpnt); /* Buffer this request */ + /* printk("inia100_entry: can't allocate SCB\n"); */ + return (0); + } + inia100BuildSCB(pHCB, pSCB, SCpnt); + orc_exec_scb(pHCB, pSCB); /* Start execute SCB */ + + return (0); +} + +/***************************************************************************** + Function name : inia100_command + Description : We only support command in interrupt-driven fashion + Input : pHCB - Pointer to host adapter structure + Output : None. + Return : pSRB - Pointer to SCSI request block. +*****************************************************************************/ +int inia100_command(Scsi_Cmnd * SCpnt) +{ + printk("inia100: interrupt driven driver; use inia100_queue()\n"); + return -1; +} + +/***************************************************************************** + Function name : inia100_abort + Description : Abort a queued command. + (commands that are on the bus can't be aborted easily) + Input : pHCB - Pointer to host adapter structure + Output : None. + Return : pSRB - Pointer to SCSI request block. +*****************************************************************************/ +int inia100_abort(Scsi_Cmnd * SCpnt) +{ + ORC_HCS *hcsp; + + hcsp = (ORC_HCS *) SCpnt->host->base; + return orc_abort_srb(hcsp, (ULONG) SCpnt); +} + +/***************************************************************************** + Function name : inia100_reset + Description : Reset registers, reset a hanging bus and + kill active and disconnected commands for target w/o soft reset + Input : pHCB - Pointer to host adapter structure + Output : None. + Return : pSRB - Pointer to SCSI request block. +*****************************************************************************/ +int inia100_reset(Scsi_Cmnd * SCpnt, unsigned int reset_flags) +{ /* I need Host Control Block Information */ + ORC_HCS *pHCB; + pHCB = (ORC_HCS *) SCpnt->host->base; + + if (reset_flags & (SCSI_RESET_SUGGEST_BUS_RESET | SCSI_RESET_SUGGEST_HOST_RESET)) + return orc_reset_scsi_bus(pHCB); + else + return orc_device_reset(pHCB, (ULONG) SCpnt, SCpnt->target, reset_flags); + +} + +/***************************************************************************** + Function name : inia100SCBPost + Description : This is callback routine be called when orc finish one + SCSI command. + Input : pHCB - Pointer to host adapter control block. + pSCB - Pointer to SCSI control block. + Output : None. + Return : None. +*****************************************************************************/ +void inia100SCBPost(BYTE * pHcb, BYTE * pScb) +{ + Scsi_Cmnd *pSRB; /* Pointer to SCSI request block */ + ORC_HCS *pHCB; + ORC_SCB *pSCB; + ESCB *pEScb; + + pHCB = (ORC_HCS *) pHcb; + pSCB = (ORC_SCB *) pScb; + pEScb = pSCB->SCB_EScb; + if ((pSRB = (Scsi_Cmnd *) pEScb->SCB_Srb) == 0) { + printk("inia100SCBPost: SRB pointer is empty\n"); + orc_release_scb(pHCB, pSCB); /* Release SCB for current channel */ + return; + } + pEScb->SCB_Srb = NULL; + + switch (pSCB->SCB_HaStat) { + case 0x0: + case 0xa: /* Linked command complete without error and linked normally */ + case 0xb: /* Linked command complete without error interrupt generated */ + pSCB->SCB_HaStat = 0; + break; + + case 0x11: /* Selection time out-The initiator selection or target + reselection was not complete within the SCSI Time out period */ + pSCB->SCB_HaStat = DID_TIME_OUT; + break; + + case 0x14: /* Target bus phase sequence failure-An invalid bus phase or bus + phase sequence was requested by the target. The host adapter + will generate a SCSI Reset Condition, notifying the host with + a SCRD interrupt */ + pSCB->SCB_HaStat = DID_RESET; + break; + + case 0x1a: /* SCB Aborted. 07/21/98 */ + pSCB->SCB_HaStat = DID_ABORT; + break; + + case 0x12: /* Data overrun/underrun-The target attempted to transfer more data + than was allocated by the Data Length field or the sum of the + Scatter / Gather Data Length fields. */ + case 0x13: /* Unexpected bus free-The target dropped the SCSI BSY at an unexpected time. */ + case 0x16: /* Invalid CCB Operation Code-The first byte of the CCB was invalid. */ + + default: + printk("inia100: %x %x\n", pSCB->SCB_HaStat, pSCB->SCB_TaStat); + pSCB->SCB_HaStat = DID_ERROR; /* Couldn't find any better */ + break; + } + + if (pSCB->SCB_TaStat == 2) { /* Check condition */ + memcpy((unsigned char *) &pSRB->sense_buffer[0], + (unsigned char *) &pEScb->ESCB_SGList[0], SENSE_SIZE); + } + pSRB->result = pSCB->SCB_TaStat | (pSCB->SCB_HaStat << 16); + pSRB->scsi_done(pSRB); /* Notify system DONE */ + + /* Find the next pending SRB */ + if ((pSRB = inia100PopSRBFromQueue(pHCB)) != NULL) { /* Assume resend will success */ + /* Reuse old SCB */ + inia100BuildSCB(pHCB, pSCB, pSRB); /* Create corresponding SCB */ + orc_exec_scb(pHCB, pSCB); /* Start execute SCB */ + } else { /* No Pending SRB */ + orc_release_scb(pHCB, pSCB); /* Release SCB for current channel */ + } + return; +} + +/***************************************************************************** + Function name : inia100_biosparam + Description : Return the "logical geometry" + Input : pHCB - Pointer to host adapter structure + Output : None. + Return : pSRB - Pointer to SCSI request block. +*****************************************************************************/ +#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0) +int inia100_biosparam(Scsi_Disk * disk, kdev_t dev, int *info_array) +#else +int inia100_biosparam(Scsi_Disk * disk, int dev, int *info_array) +#endif +{ + ORC_HCS *pHcb; /* Point to Host adapter control block */ + ORC_TCS *pTcb; + + pHcb = (ORC_HCS *) disk->device->host->base; + pTcb = &pHcb->HCS_Tcs[disk->device->id]; + + if (pTcb->TCS_DrvHead) { + info_array[0] = pTcb->TCS_DrvHead; + info_array[1] = pTcb->TCS_DrvSector; + info_array[2] = disk->capacity / pTcb->TCS_DrvHead / pTcb->TCS_DrvSector; + } else { + if (pTcb->TCS_DrvFlags & TCF_DRV_255_63) { + info_array[0] = 255; + info_array[1] = 63; + info_array[2] = disk->capacity / 255 / 63; + } else { + info_array[0] = 64; + info_array[1] = 32; + info_array[2] = disk->capacity >> 11; + } + } + return 0; +} + + +static void subIntr(ORC_HCS * pHCB, int irqno) +{ +#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95) + unsigned long flags; + + spin_lock_irqsave(&io_request_lock, flags); +#endif + + if (pHCB->HCS_Intr != irqno) { +#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95) + spin_unlock_irqrestore(&io_request_lock, flags); +#endif + return; + } + orc_interrupt(pHCB); + +#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95) + spin_unlock_irqrestore(&io_request_lock, flags); +#endif +} + +/* + * Interrupts handler (main routine of the driver) + */ +#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0) +static void inia100_intr0(int irqno, void *dev_id, struct pt_regs *regs) +#else +static void inia100_intr0(int irqno, struct pt_regs *regs) +#endif +{ + subIntr(&orc_hcs[0], irqno); +} + +#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0) +static void inia100_intr1(int irqno, void *dev_id, struct pt_regs *regs) +#else +static void inia100_intr1(int irqno, struct pt_regs *regs) +#endif +{ + subIntr(&orc_hcs[1], irqno); +} + +#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0) +static void inia100_intr2(int irqno, void *dev_id, struct pt_regs *regs) +#else +static void inia100_intr2(int irqno, struct pt_regs *regs) +#endif +{ + subIntr(&orc_hcs[2], irqno); +} + +#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0) +static void inia100_intr3(int irqno, void *dev_id, struct pt_regs *regs) +#else +static void inia100_intr3(int irqno, struct pt_regs *regs) +#endif +{ + subIntr(&orc_hcs[3], irqno); +} + +#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0) +static void inia100_intr4(int irqno, void *dev_id, struct pt_regs *regs) +#else +static void inia100_intr4(int irqno, struct pt_regs *regs) +#endif +{ + subIntr(&orc_hcs[4], irqno); +} + +#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0) +static void inia100_intr5(int irqno, void *dev_id, struct pt_regs *regs) +#else +static void inia100_intr5(int irqno, struct pt_regs *regs) +#endif +{ + subIntr(&orc_hcs[5], irqno); +} + +#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0) +static void inia100_intr6(int irqno, void *dev_id, struct pt_regs *regs) +#else +static void inia100_intr6(int irqno, struct pt_regs *regs) +#endif +{ + subIntr(&orc_hcs[6], irqno); +} + +#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0) +static void inia100_intr7(int irqno, void *dev_id, struct pt_regs *regs) +#else +static void inia100_intr7(int irqno, struct pt_regs *regs) +#endif +{ + subIntr(&orc_hcs[7], irqno); +} + +/* + * Dump the current driver status and panic... + */ +static void inia100_panic(char *msg) +{ + printk("\ninia100_panic: %s\n", msg); + panic("inia100 panic"); +} + +/*#include "inia100scsi.c" */ diff -ur --new-file old/linux/drivers/scsi/inia100.h new/linux/drivers/scsi/inia100.h --- old/linux/drivers/scsi/inia100.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/scsi/inia100.h Tue May 11 19:36:58 1999 @@ -0,0 +1,503 @@ +/************************************************************************** + * Initio A100 device driver for Linux. + * + * Copyright (c) 1994-1998 Initio Corporation + * All rights reserved. + * + * 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; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * -------------------------------------------------------------------------- + * + * 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, + * without modification, immediately at the beginning of the file. + * 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. + * + * Where this Software is combined with software released under the terms of + * the GNU Public License ("GPL") and the terms of the GPL would require the + * combined work to also be released under the terms of the GPL, the terms + * and conditions of this License will apply in addition to those of the + * GPL with the exception of any terms or conditions of this License that + * conflict with, or are expressly prohibited by, the GPL. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + ************************************************************************** + * + * Module: inia100.h + * Description: INI-A100U2W LINUX device driver header + * Revision History: + * 06/18/98 HL, Initial production Version 1.02 + * 12/19/98 bv, Use spinlocks for 2.1.95 and up + ****************************************************************************/ + +#ifndef CVT_LINUX_VERSION +#define CVT_LINUX_VERSION(V,P,S) (((V) * 65536) + ((P) * 256) + (S)) +#endif + +#ifndef LINUX_VERSION_CODE +#include +#endif + +#include "sd.h" + +extern int inia100_detect(Scsi_Host_Template *); +extern int inia100_command(Scsi_Cmnd *); +extern int inia100_queue(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *)); +extern int inia100_abort(Scsi_Cmnd *); +extern int inia100_reset(Scsi_Cmnd *, unsigned int); + +#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1, 3, 0) +extern int inia100_biosparam(Scsi_Disk *, kdev_t, int *); /*for linux v2.0 */ +extern struct proc_dir_entry proc_scsi_inia100; +#else +extern int inia100_biosparam(Disk *, int, int *); /*for linux v1.13 */ +#endif + +#define inia100_REVID "Initio INI-A100U2W SCSI device driver; Revision: 1.02a" + +#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(1, 3, 0) +#define INIA100 { \ + NULL, \ + NULL, \ + inia100_REVID, \ + inia100_detect, \ + NULL, \ + NULL, \ + inia100_command, \ + inia100_queue, \ + inia100_abort, \ + inia100_reset, \ + NULL, \ + inia100_biosparam, \ + 1, \ +7, \ +SG_ALL, \ +1, \ +0, \ +0, \ +ENABLE_CLUSTERING \ +} + +#else + +#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2, 1, 75) +#define INIA100 { \ + NULL, \ + NULL, \ + &proc_scsi_inia100, \ + NULL, \ + inia100_REVID, \ + inia100_detect, \ + NULL, \ + NULL, \ + inia100_command, \ + inia100_queue, \ + inia100_abort, \ + inia100_reset, \ + NULL, \ + inia100_biosparam, \ + 1, \ + 7, \ + 0, \ + 1, \ + 0, \ + 0, \ + ENABLE_CLUSTERING \ +} +#else /* Version >= 2.1.75 */ +#define INIA100 { \ + next: NULL, \ + module: NULL, \ + proc_dir: &proc_scsi_inia100, \ + proc_info: NULL, \ + name: inia100_REVID, \ + detect: inia100_detect, \ + release: NULL, \ + info: NULL, \ + command: inia100_command, \ + queuecommand: inia100_queue, \ + eh_strategy_handler: NULL, \ + eh_abort_handler: NULL, \ + eh_device_reset_handler: NULL, \ + eh_bus_reset_handler: NULL, \ + eh_host_reset_handler: NULL, \ + abort: inia100_abort, \ + reset: inia100_reset, \ + slave_attach: NULL, \ + bios_param: inia100_biosparam, \ + can_queue: 1, \ + this_id: 1, \ + sg_tablesize: SG_ALL, \ + cmd_per_lun: 1, \ + present: 0, \ + unchecked_isa_dma: 0, \ + use_clustering: ENABLE_CLUSTERING, \ + use_new_eh_code: 0 \ +} +#endif +#endif + +#define VIRT_TO_BUS(i) (unsigned int) virt_to_bus((void *)(i)) +#define ULONG unsigned long +#define PVOID void * +#define USHORT unsigned short +#define UCHAR unsigned char +#define BYTE unsigned char +#define WORD unsigned short +#define DWORD unsigned long +#define UBYTE unsigned char +#define UWORD unsigned short +#define UDWORD unsigned long +#ifdef ALPHA +#define U32 unsigned int +#else +#define U32 unsigned long +#endif + +#ifndef NULL +#define NULL 0 /* zero */ +#endif +#ifndef TRUE +#define TRUE (1) /* boolean true */ +#endif +#ifndef FALSE +#define FALSE (0) /* boolean false */ +#endif +#ifndef FAILURE +#define FAILURE (-1) +#endif +#if 1 +#define ORC_MAXQUEUE 245 +#else +#define ORC_MAXQUEUE 25 +#endif + +#define TOTAL_SG_ENTRY 32 +#define MAX_TARGETS 16 +#define IMAX_CDB 15 +#define SENSE_SIZE 14 +#define MAX_SUPPORTED_ADAPTERS 4 +#define SUCCESSFUL 0x00 + +#define I920_DEVICE_ID 0x0002 /* Initio's inic-950 product ID */ + +/************************************************************************/ +/* Scatter-Gather Element Structure */ +/************************************************************************/ +typedef struct ORC_SG_Struc { + U32 SG_Ptr; /* Data Pointer */ + U32 SG_Len; /* Data Length */ +} ORC_SG; + + +/* SCSI related definition */ +#define DISC_NOT_ALLOW 0x80 /* Disconnect is not allowed */ +#define DISC_ALLOW 0xC0 /* Disconnect is allowed */ + + +#define ORC_OFFSET_SCB 16 +#define ORC_MAX_SCBS 250 +#define MAX_CHANNELS 2 +#define MAX_ESCB_ELE 64 +#define TCF_DRV_255_63 0x0400 + +/********************************************************/ +/* Orchid Configuration Register Set */ +/********************************************************/ +#define ORC_PVID 0x00 /* Vendor ID */ +#define ORC_VENDOR_ID 0x1101 /* Orchid vendor ID */ +#define ORC_PDID 0x02 /* Device ID */ +#define ORC_DEVICE_ID 0x1060 /* Orchid device ID */ +#define ORC_COMMAND 0x04 /* Command */ +#define BUSMS 0x04 /* BUS MASTER Enable */ +#define IOSPA 0x01 /* IO Space Enable */ +#define ORC_STATUS 0x06 /* Status register */ +#define ORC_REVISION 0x08 /* Revision number */ +#define ORC_BASE 0x10 /* Base address */ +#define ORC_BIOS 0x50 /* Expansion ROM base address */ +#define ORC_INT_NUM 0x3C /* Interrupt line */ +#define ORC_INT_PIN 0x3D /* Interrupt pin */ + +/********************************************************/ +/* Orchid Host Command Set */ +/********************************************************/ +#define ORC_CMD_NOP 0x00 /* Host command - NOP */ +#define ORC_CMD_VERSION 0x01 /* Host command - Get F/W version */ +#define ORC_CMD_ECHO 0x02 /* Host command - ECHO */ +#define ORC_CMD_SET_NVM 0x03 /* Host command - Set NVRAM */ +#define ORC_CMD_GET_NVM 0x04 /* Host command - Get NVRAM */ +#define ORC_CMD_GET_BUS_STATUS 0x05 /* Host command - Get SCSI bus status */ +#define ORC_CMD_ABORT_SCB 0x06 /* Host command - Abort SCB */ +#define ORC_CMD_ISSUE_SCB 0x07 /* Host command - Issue SCB */ + +/********************************************************/ +/* Orchid Register Set */ +/********************************************************/ +#define ORC_GINTS 0xA0 /* Global Interrupt Status */ +#define QINT 0x04 /* Reply Queue Interrupt */ +#define ORC_GIMSK 0xA1 /* Global Interrupt MASK */ +#define MQINT 0x04 /* Mask Reply Queue Interrupt */ +#define ORC_GCFG 0xA2 /* Global Configure */ +#define EEPRG 0x01 /* Enable EEPROM programming */ +#define ORC_GSTAT 0xA3 /* Global status */ +#define WIDEBUS 0x10 /* Wide SCSI Devices connected */ +#define ORC_HDATA 0xA4 /* Host Data */ +#define ORC_HCTRL 0xA5 /* Host Control */ +#define SCSIRST 0x80 /* SCSI bus reset */ +#define HDO 0x40 /* Host data out */ +#define HOSTSTOP 0x02 /* Host stop RISC engine */ +#define DEVRST 0x01 /* Device reset */ +#define ORC_HSTUS 0xA6 /* Host Status */ +#define HDI 0x02 /* Host data in */ +#define RREADY 0x01 /* RISC engine is ready to receive */ +#define ORC_NVRAM 0xA7 /* Nvram port address */ +#define SE2CS 0x008 +#define SE2CLK 0x004 +#define SE2DO 0x002 +#define SE2DI 0x001 +#define ORC_PQUEUE 0xA8 /* Posting queue FIFO */ +#define ORC_PQCNT 0xA9 /* Posting queue FIFO Cnt */ +#define ORC_RQUEUE 0xAA /* Reply queue FIFO */ +#define ORC_RQUEUECNT 0xAB /* Reply queue FIFO Cnt */ +#define ORC_FWBASEADR 0xAC /* Firmware base address */ + +#define ORC_EBIOSADR0 0xB0 /* External Bios address */ +#define ORC_EBIOSADR1 0xB1 /* External Bios address */ +#define ORC_EBIOSADR2 0xB2 /* External Bios address */ +#define ORC_EBIOSDATA 0xB3 /* External Bios address */ + +#define ORC_SCBSIZE 0xB7 /* SCB size register */ +#define ORC_SCBBASE0 0xB8 /* SCB base address 0 */ +#define ORC_SCBBASE1 0xBC /* SCB base address 1 */ + +#define ORC_RISCCTL 0xE0 /* RISC Control */ +#define PRGMRST 0x002 +#define DOWNLOAD 0x001 +#define ORC_PRGMCTR0 0xE2 /* RISC program counter */ +#define ORC_PRGMCTR1 0xE3 /* RISC program counter */ +#define ORC_RISCRAM 0xEC /* RISC RAM data port 4 bytes */ + +typedef struct orc_extended_scb { /* Extended SCB */ + ORC_SG ESCB_SGList[TOTAL_SG_ENTRY]; /*0 Start of SG list */ + Scsi_Cmnd *SCB_Srb; /*50 SRB Pointer */ +} ESCB; + +/*********************************************************************** + SCSI Control Block +************************************************************************/ +typedef struct orc_scb { /* Scsi_Ctrl_Blk */ + UBYTE SCB_Opcode; /*00 SCB command code&residual */ + UBYTE SCB_Flags; /*01 SCB Flags */ + UBYTE SCB_Target; /*02 Target Id */ + UBYTE SCB_Lun; /*03 Lun */ + U32 SCB_Reserved0; /*04 Reserved for ORCHID must 0 */ + U32 SCB_XferLen; /*08 Data Transfer Length */ + U32 SCB_Reserved1; /*0C Reserved for ORCHID must 0 */ + U32 SCB_SGLen; /*10 SG list # * 8 */ + U32 SCB_SGPAddr; /*14 SG List Buf physical Addr */ + U32 SCB_SGPAddrHigh; /*18 SG Buffer high physical Addr */ + UBYTE SCB_HaStat; /*1C Host Status */ + UBYTE SCB_TaStat; /*1D Target Status */ + UBYTE SCB_Status; /*1E SCB status */ + UBYTE SCB_Link; /*1F Link pointer, default 0xFF */ + UBYTE SCB_SenseLen; /*20 Sense Allocation Length */ + UBYTE SCB_CDBLen; /*21 CDB Length */ + UBYTE SCB_Ident; /*22 Identify */ + UBYTE SCB_TagMsg; /*23 Tag Message */ + UBYTE SCB_CDB[IMAX_CDB]; /*24 SCSI CDBs */ + UBYTE SCB_ScbIdx; /*3C Index for this ORCSCB */ + U32 SCB_SensePAddr; /*34 Sense Buffer physical Addr */ + + ESCB *SCB_EScb; /*38 Extended SCB Pointer */ +#ifndef ALPHA + UBYTE SCB_Reserved2[4]; /*3E Reserved for Driver use */ +#endif +} ORC_SCB; + +/* Opcodes of ORCSCB_Opcode */ +#define ORC_EXECSCSI 0x00 /* SCSI initiator command with residual */ +#define ORC_BUSDEVRST 0x01 /* SCSI Bus Device Reset */ + +/* Status of ORCSCB_Status */ +#define SCB_COMPLETE 0x00 /* SCB request completed */ +#define SCB_POST 0x01 /* SCB is posted by the HOST */ + +/* Bit Definition for ORCSCB_Flags */ +#define SCF_DISINT 0x01 /* Disable HOST interrupt */ +#define SCF_DIR 0x18 /* Direction bits */ +#define SCF_NO_DCHK 0x00 /* Direction determined by SCSI */ +#define SCF_DIN 0x08 /* From Target to Initiator */ +#define SCF_DOUT 0x10 /* From Initiator to Target */ +#define SCF_NO_XF 0x18 /* No data transfer */ +#define SCF_POLL 0x40 + +/* Error Codes for ORCSCB_HaStat */ +#define HOST_SEL_TOUT 0x11 +#define HOST_DO_DU 0x12 +#define HOST_BUS_FREE 0x13 +#define HOST_BAD_PHAS 0x14 +#define HOST_INV_CMD 0x16 +#define HOST_SCSI_RST 0x1B +#define HOST_DEV_RST 0x1C + + +/* Error Codes for ORCSCB_TaStat */ +#define TARGET_CHK_COND 0x02 +#define TARGET_BUSY 0x08 +#define TARGET_TAG_FULL 0x28 + + +/* Queue tag msg: Simple_quque_tag, Head_of_queue_tag, Ordered_queue_tag */ +#define MSG_STAG 0x20 +#define MSG_HTAG 0x21 +#define MSG_OTAG 0x22 + +#define MSG_IGNOREWIDE 0x23 + +#define MSG_IDENT 0x80 +#define MSG_DISC 0x40 /* Disconnect allowed */ + + +/* SCSI MESSAGE */ +#define MSG_EXTEND 0x01 +#define MSG_SDP 0x02 +#define MSG_ABORT 0x06 +#define MSG_REJ 0x07 +#define MSG_NOP 0x08 +#define MSG_PARITY 0x09 +#define MSG_DEVRST 0x0C +#define MSG_STAG 0x20 + +/*********************************************************************** + Target Device Control Structure +**********************************************************************/ + +typedef struct ORC_Tar_Ctrl_Struc { + UBYTE TCS_DrvDASD; /* 6 */ + UBYTE TCS_DrvSCSI; /* 7 */ + UBYTE TCS_DrvHead; /* 8 */ + UWORD TCS_DrvFlags; /* 4 */ + UBYTE TCS_DrvSector; /* 7 */ +} ORC_TCS, *PORC_TCS; + +/* Bit Definition for TCF_DrvFlags */ +#define TCS_DF_NODASD_SUPT 0x20 /* Suppress OS/2 DASD Mgr support */ +#define TCS_DF_NOSCSI_SUPT 0x40 /* Suppress OS/2 SCSI Mgr support */ + + +/*********************************************************************** + Host Adapter Control Structure +************************************************************************/ +typedef struct ORC_Ha_Ctrl_Struc { + USHORT HCS_Base; /* 00 */ + UBYTE HCS_Index; /* 02 */ + UBYTE HCS_Intr; /* 04 */ + UBYTE HCS_SCSI_ID; /* 06 H/A SCSI ID */ + UBYTE HCS_BIOS; /* 07 BIOS configuration */ + + UBYTE HCS_Flags; /* 0B */ + UBYTE HCS_HAConfig1; /* 1B SCSI0MAXTags */ + UBYTE HCS_MaxTar; /* 1B SCSI0MAXTags */ + + USHORT HCS_Units; /* Number of units this adapter */ + USHORT HCS_AFlags; /* Adapter info. defined flags */ + ULONG HCS_Timeout; /* Adapter timeout value */ + PVOID HCS_virScbArray; /* 28 Virtual Pointer to SCB array */ + U32 HCS_physScbArray; /* Scb Physical address */ + PVOID HCS_virEscbArray; /* Virtual pointer to ESCB Scatter list */ + U32 HCS_physEscbArray; /* scatter list Physical address */ + UBYTE TargetFlag[16]; /* 30 target configuration, TCF_EN_TAG */ + UBYTE MaximumTags[16]; /* 40 ORC_MAX_SCBS */ + UBYTE ActiveTags[16][16]; /* 50 */ + ORC_TCS HCS_Tcs[16]; /* 28 */ + U32 BitAllocFlag[MAX_CHANNELS][8]; /* Max STB is 256, So 256/32 */ +#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95) + spinlock_t BitAllocFlagLock; +#endif + Scsi_Cmnd *pSRB_head; + Scsi_Cmnd *pSRB_tail; +#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95) + spinlock_t pSRB_lock; +#endif +} ORC_HCS; + +/* Bit Definition for HCS_Flags */ + +#define HCF_SCSI_RESET 0x01 /* SCSI BUS RESET */ +#define HCF_PARITY 0x02 /* parity card */ +#define HCF_LVDS 0x10 /* parity card */ + +/* Bit Definition for TargetFlag */ + +#define TCF_EN_255 0x08 +#define TCF_EN_TAG 0x10 +#define TCF_BUSY 0x20 +#define TCF_DISCONNECT 0x40 +#define TCF_SPIN_UP 0x80 + +/* Bit Definition for HCS_AFlags */ +#define HCS_AF_IGNORE 0x01 /* Adapter ignore */ +#define HCS_AF_DISABLE_RESET 0x10 /* Adapter disable reset */ +#define HCS_AF_DISABLE_ADPT 0x80 /* Adapter disable */ + + +/*---------------------------------------*/ +/* TimeOut for RESET to complete (30s) */ +/* */ +/* After a RESET the drive is checked */ +/* every 200ms. */ +/*---------------------------------------*/ +#define DELAYED_RESET_MAX (30*1000L) +#define DELAYED_RESET_INTERVAL 200L + +/*----------------------------------------------*/ +/* TimeOut for IRQ from last interrupt (5s) */ +/*----------------------------------------------*/ +#define IRQ_TIMEOUT_INTERVAL (5*1000L) + +/*----------------------------------------------*/ +/* Retry Delay interval (200ms) */ +/*----------------------------------------------*/ +#define DELAYED_RETRY_INTERVAL 200L + +#define INQUIRY_SIZE 36 +#define CAPACITY_SIZE 8 +#define DEFAULT_SENSE_LEN 14 + +#define DEVICE_NOT_FOUND 0x86 + +/*----------------------------------------------*/ +/* Definition for PCI device */ +/*----------------------------------------------*/ +#define MAX_PCI_DEVICES 21 +#define MAX_PCI_BUSES 8 diff -ur --new-file old/linux/drivers/scsi/megaraid.c new/linux/drivers/scsi/megaraid.c --- old/linux/drivers/scsi/megaraid.c Sun Jan 10 04:16:43 1999 +++ new/linux/drivers/scsi/megaraid.c Fri May 7 08:14:37 1999 @@ -1,24 +1,27 @@ /*=================================================================== * * Linux MegaRAID device driver - * + * * Copyright 1998 American Megatrends Inc. * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. + * 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. * - * Version : 0.92 + * Version : 1.00 * * Description: Linux device driver for AMI MegaRAID controller * + * Supported controllers: MegaRAID 418, 428, 438, 466, 762 + * + * Maintainer: Jeff L Jones + * * History: * * Version 0.90: - * Works and has been tested with the MegaRAID 428 controller, and - * the MegaRAID 438 controller. Probably works with the 466 also, - * but not tested. + * Original source contributed by Dell; integrated it into the kernel and + * cleaned up some things. Added support for 438/466 controllers. * * Version 0.91: * Aligned mailbox area on 16-byte boundry. @@ -35,43 +38,79 @@ * Removed setting of SA_INTERRUPT flag when requesting Irq. * * Version 0.92ac: - * 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 + * 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 * * Merged with 2.1.131 source tree. - * 12 Dec 98 K. Baranowski + * 12 Dec 98 K. Baranowski + * + * Version 0.93: + * Added support for vendor specific ioctl commands (0x80+xxh) + * Changed some fields in MEGARAID struct to better values. + * Added signature check for Rp controllers under 2.0 kernels + * Changed busy-wait loop to be time-based + * Fixed SMP race condition in isr + * Added kfree (sgList) on release + * Added #include linux/version.h to megaraid.h for hosts.h + * Changed max_id to represent max logical drives instead of targets. + * + * Version 0.94: + * Got rid of some excess locking/unlocking + * Fixed slight memory corruption problem while memcpy'ing into mailbox + * Changed logical drives to be reported as luns rather than targets + * Changed max_id to 16 since it is now max targets/chan again. + * Improved ioctl interface for upcoming megamgr + * + * Version 0.95: + * Fixed problem of queueing multiple commands to adapter; + * still has some strange problems on some setups, so still + * defaults to single. To enable parallel commands change + * #define MULTI_IO in megaraid.h + * Changed kmalloc allocation to be done in beginning. + * Got rid of C++ style comments + * + * 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. + * + * Version 1.00: + * Checks to see if an irq ocurred while in isr, and runs through + * 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 + * Put spinlocks around entire queue function for now... + * Full multi-io commands working stablely without previous problems + * Added skipXX LILO option for Madrona motherboard support + * * * BUGS: - * Tested with 2.1.90, but unfortunately there is a bug in pci.c which - * fails to detect our controller. Does work with 2.1.118--don't know - * which kernel in between it was fixed in. - * With SMP enabled under 2.1.118 with more than one processor, gets an - * error message "scsi_end_request: buffer-list destroyed" under heavy - * IO, but doesn't seem to affect operation, or data integrity. The - * message doesn't occur without SMP enabled, or with one proccessor with - * SMP enabled, or under any combination under 2.0 kernels. + * Some older 2.1 kernels (eg. 2.1.90) have a bug in pci.c that + * fails to detect the controller as a pci device on the system. + * + * Timeout period for mid scsi layer is too short for + * this controller. Must be increased or Aborts will occur. * *===================================================================*/ -#define QISR 1 #define CRLFSTR "\n" -#define MULTIQ 1 - #include #ifdef MODULE +#include #include #if LINUX_VERSION_CODE >= 0x20100 char kernel_version[] = UTS_RELEASE; -/* originally ported by Dell Corporation; updated, released, and maintained by - American Megatrends */ -MODULE_AUTHOR("American Megatrends Inc."); -MODULE_DESCRIPTION("AMI MegaRAID driver"); +MODULE_AUTHOR ("American Megatrends Inc."); +MODULE_DESCRIPTION ("AMI MegaRAID driver"); #endif #endif @@ -112,14 +151,18 @@ * * #Defines * - *================================================================*/ + *================================================================ + */ #if LINUX_VERSION_CODE < 0x020100 #define ioremap vremap #define iounmap vfree /* simulate spin locks */ -typedef struct {volatile char lock;} spinlock_t; +typedef struct { + volatile char lock; +} spinlock_t; + #define spin_lock_init(x) { (x)->lock = 0;} #define spin_lock_irqsave(x,flags) { while ((x)->lock) barrier();\ (x)->lock=1; save_flags(flags);\ @@ -143,7 +186,15 @@ (*node) = obj; \ (*node)->##next = NULL; \ spin_unlock_irqrestore(&mega_lock,cpuflag);\ -}; +} + +/* a non-locking version (if we already have the lock) */ +#define ENQUEUE_NL(obj,type,list,next) \ +{ type **node; \ + for(node=&(list); *node; node=(type **)&(*node)->##next); \ + (*node) = obj; \ + (*node)->##next = NULL; \ +} #define DEQUEUE(obj,type,list,next) \ { long cpuflag; \ @@ -154,125 +205,146 @@ spin_unlock_irqrestore(&mega_lock,cpuflag);\ }; -u_long RDINDOOR(mega_host_config *megaCfg) +u_long RDINDOOR (mega_host_config * megaCfg) { - return readl(megaCfg->base + 0x20); + return readl (megaCfg->base + 0x20); } -void WRINDOOR(mega_host_config *megaCfg, u_long value) +void WRINDOOR (mega_host_config * megaCfg, u_long value) { - writel(value,megaCfg->base+0x20); + writel (value, megaCfg->base + 0x20); } -u_long RDOUTDOOR(mega_host_config *megaCfg) +u_long RDOUTDOOR (mega_host_config * megaCfg) { - return readl(megaCfg->base+0x2C); + return readl (megaCfg->base + 0x2C); } -void WROUTDOOR(mega_host_config *megaCfg, u_long value) +void WROUTDOOR (mega_host_config * megaCfg, u_long value) { - writel(value,megaCfg->base+0x2C); + writel (value, megaCfg->base + 0x2C); } /*================================================================ * * Function prototypes * - *================================================================*/ -static int MegaIssueCmd(mega_host_config *megaCfg, - u_char *mboxData, - mega_scb *scb, + *================================================================ + */ +static int megaIssueCmd (mega_host_config * megaCfg, + u_char * mboxData, + mega_scb * scb, int intr); -static int build_sglist(mega_host_config *megaCfg, mega_scb *scb, - u_long *buffer, u_long *length); +static int build_sglist (mega_host_config * megaCfg, mega_scb * scb, + u_long * buffer, u_long * length); -static void mega_runque(void *); -static void mega_rundoneq(void); -static void mega_cmd_done(mega_host_config *,mega_scb *, int); +static int mega_busyWaitMbox(mega_host_config *); +static void mega_runpendq (mega_host_config *); +static void mega_rundoneq (void); +static void mega_cmd_done (mega_host_config *, mega_scb *, int); +static mega_scb *mega_ioctl (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt); +static inline void freeSgList(mega_host_config *megaCfg); /* set SERDEBUG to 1 to enable serial debugging */ #define SERDEBUG 0 #if SERDEBUG -static void ser_init(void); -static void ser_puts(char *str); -static void ser_putc(char c); -static int ser_printk(const char *fmt, ...); +static void ser_init (void); +static void ser_puts (char *str); +static void ser_putc (char c); +static int ser_printk (const char *fmt,...); #endif /*================================================================ * * Global variables * - *================================================================*/ -static int numCtlrs = 0; -static mega_host_config *megaCtlrs[4] = { 0 }; + *================================================================ + */ -/* Change this to 0 if you want to see the raw drives */ -static int use_raid = 1; +/* Use "megaraid=skipXX" to prohibit driver from scanning XX scsi id + on each channel. Used for Madrona motherboard, where SAF_TE + processor id cannot be scanned */ +static char *megaraid; +#if LINUX_VERSION_CODE > 0x20100 +#ifdef MODULE +MODULE_PARM(megaraid, "s"); +#endif +#endif +static int skip_id; + +static int numCtlrs = 0; +static mega_host_config *megaCtlrs[12] = {0}; + +#if DEBUG +static u_long maxCmdTime = 0; +#endif + +static mega_scb *pLastScb = NULL; /* Queue of pending/completed SCBs */ -static mega_scb *qPending = NULL; static Scsi_Cmnd *qCompleted = NULL; +#if SERDEBUG +volatile static spinlock_t serial_lock; +#endif volatile static spinlock_t mega_lock; -static struct tq_struct runq = {0,0,mega_runque,NULL}; -struct proc_dir_entry proc_scsi_megaraid = { +struct proc_dir_entry proc_scsi_megaraid = +{ PROC_SCSI_MEGARAID, 8, "megaraid", S_IFDIR | S_IRUGO | S_IXUGO, 2 }; #if SERDEBUG -static char strbuf[MAX_SERBUF+1]; +static char strbuf[MAX_SERBUF + 1]; -static void ser_init() +static void ser_init () { - unsigned port=COM_BASE; + unsigned port = COM_BASE; - outb(0x80,port+3); - outb(0,port+1); - /* 9600 Baud, if 19200: outb(6,port) */ - outb(12, port); - outb(3,port+3); - outb(0,port+1); + outb (0x80, port + 3); + outb (0, port + 1); + /* 9600 Baud, if 19200: outb(6,port) */ + outb (12, port); + outb (3, port + 3); + outb (0, port + 1); } -static void ser_puts(char *str) +static void ser_puts (char *str) { - char *ptr; + char *ptr; - ser_init(); - for (ptr=str;*ptr;++ptr) - ser_putc(*ptr); + ser_init (); + for (ptr = str; *ptr; ++ptr) + ser_putc (*ptr); } -static void ser_putc(char c) +static void ser_putc (char c) { - unsigned port=COM_BASE; + unsigned port = COM_BASE; - while ((inb(port+5) & 0x20)==0); - outb(c,port); - if (c==0x0a) - { - while ((inb(port+5) & 0x20)==0); - outb(0x0d,port); - } + while ((inb (port + 5) & 0x20) == 0); + outb (c, port); + if (c == 0x0a) { + while ((inb (port + 5) & 0x20) == 0); + outb (0x0d, port); + } } -static int ser_printk(const char *fmt, ...) +static int ser_printk (const char *fmt,...) { - va_list args; - int i; - long flags; + va_list args; + int i; + long flags; - spin_lock_irqsave(mega_lock,flags); - va_start(args,fmt); - i = vsprintf(strbuf,fmt,args); - ser_puts(strbuf); - va_end(args); - spin_unlock_irqrestore(&mega_lock,flags); + spin_lock_irqsave(&serial_lock,flags); + va_start (args, fmt); + i = vsprintf (strbuf, fmt, args); + ser_puts (strbuf); + va_end (args); + spin_unlock_irqrestore(&serial_lock,flags); - return i; + return i; } #define TRACE(a) { ser_printk a;} @@ -281,14 +353,14 @@ #define TRACE(A) #endif -void callDone(Scsi_Cmnd *SCpnt) +void callDone (Scsi_Cmnd * SCpnt) { if (SCpnt->result) { - TRACE(("*** %.08lx %.02x <%d.%d.%d> = %x\n", SCpnt->serial_number, - SCpnt->cmnd[0], SCpnt->channel, SCpnt->target, SCpnt->lun, - SCpnt->result)); + TRACE (("*** %.08lx %.02x <%d.%d.%d> = %x\n", SCpnt->serial_number, + SCpnt->cmnd[0], SCpnt->channel, SCpnt->target, SCpnt->lun, + SCpnt->result)); } - SCpnt->scsi_done(SCpnt); + SCpnt->scsi_done (SCpnt); } /*------------------------------------------------------------------------- @@ -297,165 +369,164 @@ * *-------------------------------------------------------------------------*/ -/*================================================ - * Initialize SCB structures - *================================================*/ -static void initSCB(mega_host_config *megaCfg) +/*======================= + * Free a SCB structure + *======================= + */ +static void freeSCB (mega_host_config *megaCfg, mega_scb * pScb) { - int idx; + mega_scb **ppScb; - for(idx=0; idxmax_cmds; idx++) { - megaCfg->scbList[idx].idx = -1; - megaCfg->scbList[idx].flag = 0; - megaCfg->scbList[idx].sgList = NULL; - megaCfg->scbList[idx].SCpnt = NULL; + /* Unlink from pending queue */ + for(ppScb=&megaCfg->qPending; *ppScb; ppScb=&(*ppScb)->next) { + if (*ppScb == pScb) { + *ppScb = pScb->next; + break; + } } + + /* Link back into list */ + pScb->state = SCB_FREE; + pScb->SCpnt = NULL; + + pScb->next = megaCfg->qFree; + megaCfg->qFree = pScb; } /*=========================== * Allocate a SCB structure - *===========================*/ -static mega_scb *allocateSCB(mega_host_config *megaCfg,Scsi_Cmnd *SCpnt) + *=========================== + */ +static mega_scb * allocateSCB (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt) { - int idx; - long flags; - - spin_lock_irqsave(&mega_lock,flags); - for(idx=0; idxmax_cmds; idx++) { - if (megaCfg->scbList[idx].idx < 0) { + mega_scb *pScb; - /* Set Index and SCB pointer */ - megaCfg->scbList[idx].flag = 0; - megaCfg->scbList[idx].idx = idx; - megaCfg->scbList[idx].SCpnt = SCpnt; - megaCfg->scbList[idx].next = NULL; - spin_unlock_irqrestore(&mega_lock,flags); - - if (megaCfg->scbList[idx].sgList == NULL) { - megaCfg->scbList[idx].sgList = - kmalloc(sizeof(mega_sglist)*MAX_SGLIST,GFP_ATOMIC|GFP_DMA); - } + /* Unlink command from Free List */ + if ((pScb = megaCfg->qFree) != NULL) { + megaCfg->qFree = pScb->next; + + pScb->isrcount = jiffies; + pScb->next = NULL; + pScb->state = SCB_ACTIVE; + pScb->SCpnt = SCpnt; - return &megaCfg->scbList[idx]; - } + return pScb; } - spin_unlock_irqrestore(&mega_lock,flags); - printk(KERN_WARNING "Megaraid: Could not allocate free SCB!!!\n"); - + printk (KERN_WARNING "Megaraid: Could not allocate free SCB!!!\n"); + return NULL; } -/*======================= - * Free a SCB structure - *=======================*/ -static void freeSCB(mega_scb *scb) +/*================================================ + * Initialize SCB structures + *================================================ + */ +static int initSCB (mega_host_config * megaCfg) { - long flags; + int idx; - spin_lock_irqsave(&mega_lock,flags); - scb->flag = 0; - scb->idx = -1; - scb->next = NULL; - scb->SCpnt = NULL; - spin_unlock_irqrestore(&mega_lock,flags); + megaCfg->qFree = NULL; + for (idx = megaCfg->max_cmds-1; idx >= 0; idx--) { + megaCfg->scbList[idx].idx = idx; + megaCfg->scbList[idx].sgList = kmalloc(sizeof(mega_sglist) * MAX_SGLIST, + GFP_ATOMIC | GFP_DMA); + if (megaCfg->scbList[idx].sgList == NULL) { + printk(KERN_WARNING "Can't allocate sglist for id %d\n",idx); + freeSgList(megaCfg); + return -1; + } + + if (idx < MAX_COMMANDS) { + /* Link to free list */ + freeSCB(megaCfg, &megaCfg->scbList[idx]); + } + } + return 0; } /* Run through the list of completed requests */ -static void mega_rundoneq() +static void mega_rundoneq () { - mega_host_config *megaCfg; - Scsi_Cmnd *SCpnt; - long islogical; + Scsi_Cmnd *SCpnt; - while(1) { - DEQUEUE(SCpnt, Scsi_Cmnd, qCompleted, host_scribble); - if (SCpnt == NULL) return; - - megaCfg = (mega_host_config *)SCpnt->host->hostdata; - - /* Check if we're allowing access to RAID drives or physical - * if use_raid == 1 and this wasn't a disk on the max channel or - * if use_raid == 0 and this was a disk on the max channel - * then fail. - */ - islogical = (SCpnt->channel == megaCfg->host->max_channel) ? 1 : 0; - if (SCpnt->cmnd[0] == INQUIRY && - ((((u_char*)SCpnt->request_buffer)[0] & 0x1F) == TYPE_DISK) && - (islogical != use_raid)) { - SCpnt->result = 0xF0; - } - - /* Convert result to error */ - switch(SCpnt->result) { - case 0x00: case 0x02: - SCpnt->result |= (DID_OK << 16); - break; - case 0x8: - SCpnt->result |= (DID_BUS_BUSY << 16); - break; - default: - SCpnt->result |= (DID_BAD_TARGET << 16); - break; - } + while (1) { + DEQUEUE (SCpnt, Scsi_Cmnd, qCompleted, host_scribble); + if (SCpnt == NULL) + return; /* Callback */ - callDone(SCpnt); + callDone (SCpnt); } } -/* Add command to the list of completed requests */ -static void mega_cmd_done(mega_host_config *megaCfg,mega_scb *pScb, int status) -{ - pScb->SCpnt->result = status; - ENQUEUE(pScb->SCpnt, Scsi_Cmnd, qCompleted, host_scribble); - freeSCB(pScb); +/* + Runs through the list of pending requests + Assumes that mega_lock spin_lock has been acquired. +*/ +static void mega_runpendq(mega_host_config *megaCfg) +{ + mega_scb *pScb; + + /* Issue any pending commands to the card */ + for(pScb=megaCfg->qPending; pScb; pScb=pScb->next) { + if (pScb->state == SCB_ACTIVE) { + megaIssueCmd(megaCfg, pScb->mboxData, pScb, 1); + } + } } -/*---------------------------------------------------- - * Process pending queue list - * - * Run as a scheduled task - *----------------------------------------------------*/ -static void mega_runque(void *dummy) +/* Add command to the list of completed requests */ +static void mega_cmd_done (mega_host_config * megaCfg, mega_scb * pScb, + int status) { - mega_host_config *megaCfg; - mega_scb *pScb; - long flags; + int islogical; + Scsi_Cmnd *SCpnt; - /* Take care of any completed requests */ - mega_rundoneq(); - - DEQUEUE(pScb,mega_scb,qPending,next); - - if (pScb) { - megaCfg = (mega_host_config *)pScb->SCpnt->host->hostdata; - - if (megaCfg->mbox->busy || megaCfg->flag & (IN_ISR|PENDING)) { - TRACE(("%.08lx %.02x <%d.%d.%d> intr%d busy%d isr%d pending%d\n", - pScb->SCpnt->serial_number, - pScb->SCpnt->cmnd[0], - pScb->SCpnt->channel, - pScb->SCpnt->target, - pScb->SCpnt->lun, - intr_count, - megaCfg->mbox->busy, - (megaCfg->flag & IN_ISR) ? 1 : 0, - (megaCfg->flag & PENDING) ? 1 : 0)); - } - - if (MegaIssueCmd(megaCfg, pScb->mboxData, pScb, 1)) { - /* We're BUSY... come back later */ - spin_lock_irqsave(&mega_lock,flags); - pScb->next = qPending; - qPending = pScb; - spin_unlock_irqrestore(&mega_lock,flags); + if (pScb == NULL) { + TRACE(("NULL pScb in mega_cmd_done!")); + printk("NULL pScb in mega_cmd_done!"); + } + + SCpnt = pScb->SCpnt; + freeSCB(megaCfg, pScb); + + if (SCpnt == NULL) { + TRACE(("NULL SCpnt in mega_cmd_done!")); + TRACE(("pScb->idx = ",pScb->idx)); + TRACE(("pScb->state = ",pScb->state)); + TRACE(("pScb->state = ",pScb->state)); + printk("Problem...!\n"); + while(1); + } + + islogical = (SCpnt->channel == megaCfg->host->max_channel && + SCpnt->target == 0); + if (SCpnt->cmnd[0] == INQUIRY && + ((((u_char *) SCpnt->request_buffer)[0] & 0x1F) == TYPE_DISK) && + !islogical) { + status = 0xF0; + } + + SCpnt->result = 0; /* clear result; otherwise, success returns corrupt + value */ - if (!(megaCfg->flag & PENDING)) { /* If PENDING, irq will schedule task */ - queue_task(&runq, &tq_scheduler); - } - } + /* Convert MegaRAID status to Linux error code */ + switch (status) { + case 0x00: /* SUCCESS */ + case 0x02: /* ERROR_ABORTED */ + SCpnt->result |= (DID_OK << 16); + break; + case 0x8: /* ERR_DEST_DRIVE_FAILED */ + SCpnt->result |= (DID_BUS_BUSY << 16); + break; + default: + SCpnt->result |= (DID_BAD_TARGET << 16); + break; } + + /* Add Scsi_Command to end of completed queue */ + ENQUEUE_NL(SCpnt, Scsi_Cmnd, qCompleted, host_scribble); } /*------------------------------------------------------------------- @@ -466,64 +537,82 @@ * If NULL is returned, the scsi_done function MUST have been called * *-------------------------------------------------------------------*/ -static mega_scb *mega_build_cmd(mega_host_config *megaCfg, Scsi_Cmnd *SCpnt) +static mega_scb * mega_build_cmd (mega_host_config * megaCfg, + Scsi_Cmnd * SCpnt) { - mega_scb *pScb; - mega_mailbox *mbox; + mega_scb *pScb; + mega_mailbox *mbox; mega_passthru *pthru; - long seg; + long seg; + char islogical; - /* We don't support multi-luns */ - if (SCpnt->lun != 0) { + if (SCpnt == NULL) { + printk("NULL SCpnt in mega_build_cmd!\n"); + while(1); + } + + if (SCpnt->cmnd[0] & 0x80) /* ioctl from megamgr */ + return mega_ioctl (megaCfg, SCpnt); + + islogical = (SCpnt->channel == megaCfg->host->max_channel && SCpnt->target == 0); + + if (!islogical && SCpnt->lun != 0) { SCpnt->result = (DID_BAD_TARGET << 16); - callDone(SCpnt); + callDone (SCpnt); return NULL; } + if (!islogical && SCpnt->target == skip_id) { + SCpnt->result = (DID_BAD_TARGET << 16); + callDone (SCpnt); + return NULL; + } + /*----------------------------------------------------- * * Logical drive commands * *-----------------------------------------------------*/ - if (SCpnt->channel == megaCfg->host->max_channel) { - switch(SCpnt->cmnd[0]) { + if (islogical) { + switch (SCpnt->cmnd[0]) { case TEST_UNIT_READY: - memset(SCpnt->request_buffer, 0, SCpnt->request_bufflen); + memset (SCpnt->request_buffer, 0, SCpnt->request_bufflen); SCpnt->result = (DID_OK << 16); - callDone(SCpnt); + callDone (SCpnt); return NULL; case MODE_SENSE: - memset(SCpnt->request_buffer, 0, SCpnt->cmnd[4]); + memset (SCpnt->request_buffer, 0, SCpnt->cmnd[4]); SCpnt->result = (DID_OK << 16); - callDone(SCpnt); + callDone (SCpnt); return NULL; case READ_CAPACITY: case INQUIRY: /* Allocate a SCB and initialize passthru */ - if ((pScb = allocateSCB(megaCfg,SCpnt)) == NULL) { + if ((pScb = allocateSCB (megaCfg, SCpnt)) == NULL) { SCpnt->result = (DID_ERROR << 16); - callDone(SCpnt); + callDone (SCpnt); return NULL; } pthru = &pScb->pthru; - mbox = (mega_mailbox *)&pScb->mboxData; + mbox = (mega_mailbox *) & pScb->mboxData; - memset(mbox, 0, sizeof(pScb->mboxData)); - memset(pthru, 0, sizeof(mega_passthru)); - pthru->timeout = 0; - pthru->ars = 0; - pthru->islogical = 1; - pthru->logdrv = SCpnt->target; - pthru->cdblen = SCpnt->cmd_len; - pthru->dataxferaddr = virt_to_bus(SCpnt->request_buffer); - pthru->dataxferlen = SCpnt->request_bufflen; - memcpy(pthru->cdb, SCpnt->cmnd, SCpnt->cmd_len); + memset (mbox, 0, sizeof (pScb->mboxData)); + memset (pthru, 0, sizeof (mega_passthru)); + pthru->timeout = 0; + pthru->ars = 1; + pthru->reqsenselen = 14; + pthru->islogical = 1; + pthru->logdrv = SCpnt->lun; + pthru->cdblen = SCpnt->cmd_len; + pthru->dataxferaddr = virt_to_bus (SCpnt->request_buffer); + pthru->dataxferlen = SCpnt->request_bufflen; + memcpy (pthru->cdb, SCpnt->cmnd, SCpnt->cmd_len); /* Initialize mailbox area */ - mbox->cmd = MEGA_MBOXCMD_PASSTHRU; - mbox->xferaddr = virt_to_bus(pthru); + mbox->cmd = MEGA_MBOXCMD_PASSTHRU; + mbox->xferaddr = virt_to_bus (pthru); return pScb; @@ -532,51 +621,51 @@ case READ_10: case WRITE_10: /* Allocate a SCB and initialize mailbox */ - if ((pScb = allocateSCB(megaCfg,SCpnt)) == NULL) { + if ((pScb = allocateSCB (megaCfg, SCpnt)) == NULL) { SCpnt->result = (DID_ERROR << 16); - callDone(SCpnt); + callDone (SCpnt); return NULL; } - mbox = (mega_mailbox *)&pScb->mboxData; + mbox = (mega_mailbox *) & pScb->mboxData; - memset(mbox, 0, sizeof(pScb->mboxData)); - mbox->logdrv = SCpnt->target; - mbox->cmd = (*SCpnt->cmnd == READ_6 || *SCpnt->cmnd == READ_10) ? + memset (mbox, 0, sizeof (pScb->mboxData)); + mbox->logdrv = SCpnt->lun; + mbox->cmd = (*SCpnt->cmnd == READ_6 || *SCpnt->cmnd == READ_10) ? MEGA_MBOXCMD_LREAD : MEGA_MBOXCMD_LWRITE; - + /* 6-byte */ if (*SCpnt->cmnd == READ_6 || *SCpnt->cmnd == WRITE_6) { - mbox->numsectors = - (u_long)SCpnt->cmnd[4]; - mbox->lba = - ((u_long)SCpnt->cmnd[1] << 16) | - ((u_long)SCpnt->cmnd[2] << 8) | - (u_long)SCpnt->cmnd[3]; + mbox->numsectors = + (u_long) SCpnt->cmnd[4]; + mbox->lba = + ((u_long) SCpnt->cmnd[1] << 16) | + ((u_long) SCpnt->cmnd[2] << 8) | + (u_long) SCpnt->cmnd[3]; mbox->lba &= 0x1FFFFF; } - + /* 10-byte */ if (*SCpnt->cmnd == READ_10 || *SCpnt->cmnd == WRITE_10) { - mbox->numsectors = - (u_long)SCpnt->cmnd[8] | - ((u_long)SCpnt->cmnd[7] << 8); + mbox->numsectors = + (u_long) SCpnt->cmnd[8] | + ((u_long) SCpnt->cmnd[7] << 8); mbox->lba = - ((u_long)SCpnt->cmnd[2] << 24) | - ((u_long)SCpnt->cmnd[3] << 16) | - ((u_long)SCpnt->cmnd[4] << 8) | - (u_long)SCpnt->cmnd[5]; + ((u_long) SCpnt->cmnd[2] << 24) | + ((u_long) SCpnt->cmnd[3] << 16) | + ((u_long) SCpnt->cmnd[4] << 8) | + (u_long) SCpnt->cmnd[5]; } - + /* Calculate Scatter-Gather info */ - mbox->numsgelements = build_sglist(megaCfg, pScb, - (u_long*)&mbox->xferaddr, - (u_long*)&seg); + mbox->numsgelements = build_sglist (megaCfg, pScb, + (u_long *) & mbox->xferaddr, + (u_long *) & seg); return pScb; - + default: SCpnt->result = (DID_BAD_TARGET << 16); - callDone(SCpnt); + callDone (SCpnt); return NULL; } } @@ -587,31 +676,32 @@ *-----------------------------------------------------*/ else { /* Allocate a SCB and initialize passthru */ - if ((pScb = allocateSCB(megaCfg,SCpnt)) == NULL) { + if ((pScb = allocateSCB (megaCfg, SCpnt)) == NULL) { SCpnt->result = (DID_ERROR << 16); - callDone(SCpnt); + callDone (SCpnt); return NULL; } pthru = &pScb->pthru; - mbox = (mega_mailbox *)pScb->mboxData; - - memset(mbox, 0, sizeof(pScb->mboxData)); - memset(pthru, 0, sizeof(mega_passthru)); - pthru->timeout = 0; - pthru->ars = 0; + mbox = (mega_mailbox *) pScb->mboxData; + + memset (mbox, 0, sizeof (pScb->mboxData)); + memset (pthru, 0, sizeof (mega_passthru)); + pthru->timeout = 0; + pthru->ars = 1; + pthru->reqsenselen = 14; pthru->islogical = 0; - pthru->channel = SCpnt->channel; - pthru->target = SCpnt->target; - pthru->cdblen = SCpnt->cmd_len; - memcpy(pthru->cdb, SCpnt->cmnd, SCpnt->cmd_len); - - pthru->numsgelements = build_sglist(megaCfg, pScb, - (u_long *)&pthru->dataxferaddr, - (u_long *)&pthru->dataxferlen); - + pthru->channel = SCpnt->channel; + pthru->target = SCpnt->target; + pthru->cdblen = SCpnt->cmd_len; + memcpy (pthru->cdb, SCpnt->cmnd, SCpnt->cmd_len); + + pthru->numsgelements = build_sglist (megaCfg, pScb, + (u_long *) & pthru->dataxferaddr, + (u_long *) & pthru->dataxferlen); + /* Initialize mailbox */ - mbox->cmd = MEGA_MBOXCMD_PASSTHRU; - mbox->xferaddr = virt_to_bus(pthru); + mbox->cmd = MEGA_MBOXCMD_PASSTHRU; + mbox->xferaddr = virt_to_bus (pthru); return pScb; } @@ -619,105 +709,229 @@ } /*-------------------------------------------------------------------- + * build RAID commands for controller, passed down through ioctl() + *--------------------------------------------------------------------*/ +static mega_scb * mega_ioctl (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt) +{ + mega_scb *pScb; + mega_ioctl_mbox *mbox; + mega_mailbox *mailbox; + mega_passthru *pthru; + long seg; + unsigned char *data = (unsigned char *)SCpnt->request_buffer; + int i; + + if ((pScb = allocateSCB (megaCfg, SCpnt)) == NULL) { + SCpnt->result = (DID_ERROR << 16); + callDone (SCpnt); + return NULL; + } + +#if 0 + printk("\nBUF: "); + for (i=0;i<18;i++) { + printk(" %x",data[i]); + } + printk("......\n"); +#endif + + mbox = (mega_ioctl_mbox *) & pScb->mboxData; + mailbox = (mega_mailbox *) & pScb->mboxData; + memset (mailbox, 0, sizeof (pScb->mboxData)); + + 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; + pthru->timeout = data[cdblen+3] & 0x07; + pthru->reqsenselen = 14; + pthru->ars = (data[cdblen+3] & 0x08) ? 1:0; + pthru->logdrv = data[cdblen+4]; + pthru->channel = data[cdblen+5]; + pthru->target = data[cdblen+6]; + pthru->cdblen = cdblen; + memcpy (pthru->cdb, &data[3], cdblen); + + mailbox->cmd = MEGA_MBOXCMD_PASSTHRU; + mailbox->xferaddr = virt_to_bus (pthru); + + + pthru->numsgelements = build_sglist (megaCfg, pScb, + (u_long *) & pthru->dataxferaddr, + (u_long *) & pthru->dataxferlen); + + for (i=0;i<(SCpnt->request_bufflen-cdblen-7);i++) { + data[i] = data[i+cdblen+7]; + } + + return pScb; + } + /* else normal (nonpassthru) command */ + + mbox->cmd = data[0]; + mbox->channel = data[1]; + mbox->param = data[2]; + mbox->pad[0] = data[3]; + mbox->logdrv = data[4]; + + mbox->numsgelements = build_sglist (megaCfg, pScb, + (u_long *) & mbox->xferaddr, + (u_long *) & seg); + + for (i=0;i<(SCpnt->request_bufflen-6);i++) { + data[i] = data[i+6]; + } + + return (pScb); +} + +#if DEBUG +static void showMbox(mega_scb *pScb) +{ + mega_mailbox *mbox; + + if (pScb == NULL) return; + + mbox = (mega_mailbox *)pScb->mboxData; + printk("%u cmd:%x id:%x #scts:%x lba:%x addr:%x logdrv:%x #sg:%x\n", + pScb->SCpnt->pid, + mbox->cmd, mbox->cmdid, mbox->numsectors, + mbox->lba, mbox->xferaddr, mbox->logdrv, + mbox->numsgelements); +} +#endif + +/*-------------------------------------------------------------------- * Interrupt service routine *--------------------------------------------------------------------*/ -static void megaraid_isr(int irq, void *devp, struct pt_regs *regs) +static void megaraid_isr (int irq, void *devp, struct pt_regs *regs) { - mega_host_config *megaCfg; - u_char byte, idx, sIdx; - u_long dword; - mega_mailbox *mbox; - mega_scb *pScb; - long flags; - int qCnt, qStatus; + mega_host_config *megaCfg; + u_char byte, idx, sIdx, tmpBox[MAILBOX_SIZE]; + u_long dword; + mega_mailbox *mbox; + mega_scb *pScb; + long flags; + int qCnt, qStatus; + + megaCfg = (mega_host_config *) devp; + mbox = (mega_mailbox *)tmpBox; - megaCfg = (mega_host_config *)devp; - mbox = (mega_mailbox *)megaCfg->mbox; +#if LINUX_VERSION_CODE >= 0x20100 + spin_lock_irqsave (&io_request_lock, flags); +#endif + + while (megaCfg->host->irq == irq) { - if (megaCfg->host->irq == irq) { - spin_lock_irqsave(&mega_lock,flags); + spin_lock_irqsave (&mega_lock, flags); if (megaCfg->flag & IN_ISR) { - TRACE(("ISR called reentrantly!!\n")); + TRACE (("ISR called reentrantly!!\n")); } megaCfg->flag |= IN_ISR; + if (mega_busyWaitMbox(megaCfg)) { + printk(KERN_WARNING "Error: mailbox busy in isr!\n"); + } + + /* Check if a valid interrupt is pending */ if (megaCfg->flag & BOARD_QUARTZ) { - dword = RDOUTDOOR(megaCfg); - if (dword != 0x10001234) { - /* Spurious interrupt */ - megaCfg->flag &= ~IN_ISR; - spin_unlock_irqrestore(&mega_lock,flags); - return; - } - WROUTDOOR(megaCfg,dword); - } else { - byte = READ_PORT(megaCfg->host->io_port, INTR_PORT); - if ((byte & VALID_INTR_BYTE) == 0) { - /* Spurious interrupt */ - megaCfg->flag &= ~IN_ISR; - spin_unlock_irqrestore(&mega_lock,flags); - return; - } - WRITE_PORT(megaCfg->host->io_port, INTR_PORT, byte); + dword = RDOUTDOOR (megaCfg); + if (dword != 0x10001234) { + /* Spurious interrupt */ + megaCfg->flag &= ~IN_ISR; + spin_unlock_irqrestore (&mega_lock, flags); + break; + } + WROUTDOOR (megaCfg, dword); + + /* Copy to temp location */ + memcpy(tmpBox, (mega_mailbox *)megaCfg->mbox, MAILBOX_SIZE); + + /* Acknowledge interrupt */ + WRINDOOR (megaCfg, virt_to_bus (megaCfg->mbox) | 0x2); + while (RDINDOOR (megaCfg) & 0x02); } - - qCnt = mbox->numstatus; - qStatus = mbox->status; + else { + byte = READ_PORT (megaCfg->host->io_port, INTR_PORT); + if ((byte & VALID_INTR_BYTE) == 0) { + /* Spurious interrupt */ + megaCfg->flag &= ~IN_ISR; + spin_unlock_irqrestore (&mega_lock, flags); + break; + } + WRITE_PORT (megaCfg->host->io_port, INTR_PORT, byte); + + /* Copy to temp location */ + memcpy(tmpBox, (mega_mailbox *)megaCfg->mbox, MAILBOX_SIZE); - if (qCnt > 1) {TRACE(("ISR: Received %d status\n", qCnt)) - printk(KERN_DEBUG "Got numstatus = %d\n",qCnt); + /* Acknowledge interrupt */ + CLEAR_INTR (megaCfg->host->io_port); } - - for(idx=0; idxnumstatus; + qStatus = mbox->status; + + for (idx = 0; idx < qCnt; idx++) { sIdx = mbox->completed[idx]; if (sIdx > 0) { - pScb = &megaCfg->scbList[sIdx-1]; - spin_unlock_irqrestore(&mega_lock,flags); /* locks within cmd_done */ - mega_cmd_done(megaCfg,&megaCfg->scbList[sIdx-1], qStatus); - spin_lock_irqsave(&mega_lock,flags); + pScb = &megaCfg->scbList[sIdx - 1]; + + /* ASSERT(pScb->state == SCB_ISSUED); */ + +#if DEBUG + if (((jiffies) - pScb->isrcount) > maxCmdTime) { + maxCmdTime = (jiffies) - pScb->isrcount; + printk("cmd time = %u\n", maxCmdTime); + } +#endif + + if (pScb->state == SCB_ABORTED) { + printk("Received aborted SCB! %u\n", (int)((jiffies)-pScb->isrcount)); + } + + /* Mark command as completed */ + mega_cmd_done(megaCfg, pScb, qStatus); } + } - if (megaCfg->flag & BOARD_QUARTZ) { - WRINDOOR(megaCfg,virt_to_bus(megaCfg->mbox)|0x2); - while (RDINDOOR(megaCfg) & 0x02); - } else { - CLEAR_INTR(megaCfg->host->io_port); - } + spin_unlock_irqrestore (&mega_lock, flags); megaCfg->flag &= ~IN_ISR; - megaCfg->flag &= ~PENDING; - spin_unlock_irqrestore(&mega_lock,flags); + mega_rundoneq(); - spin_lock_irqsave(&io_request_lock, flags); - mega_runque(NULL); - spin_unlock_irqrestore(&io_request_lock,flags); - -#if 0 - /* Queue as a delayed ISR routine */ - queue_task_irq_off(&runq, &tq_immediate); - mark_bh(IMMEDIATE_BH); + /* Loop through any pending requests */ + spin_lock_irqsave(&mega_lock, flags); + mega_runpendq(megaCfg); spin_unlock_irqrestore(&mega_lock,flags); -#endif - } + +#if LINUX_VERSION_CODE >= 0x20100 + spin_unlock_irqrestore (&io_request_lock, flags); +#endif } /*==================================================*/ /* Wait until the controller's mailbox is available */ /*==================================================*/ -static int busyWaitMbox(mega_host_config *megaCfg) +static int mega_busyWaitMbox (mega_host_config * megaCfg) { - mega_mailbox *mbox = (mega_mailbox *)megaCfg->mbox; - long counter; + mega_mailbox *mbox = (mega_mailbox *) megaCfg->mbox; + long counter; - for(counter=0; counter<0xFFFFFF; counter++) { - if (!mbox->busy) return 0; + for (counter = 0; counter < 10000; counter++) { + if (!mbox->busy) { + return 0; + } + udelay (100); + barrier(); } - return -1; + return -1; /* give up after 1 second */ } /*===================================================== @@ -728,93 +942,113 @@ * u_char *mboxData - Mailbox area, 16 bytes * mega_scb *pScb - SCB posting (or NULL if N/A) * int intr - if 1, interrupt, 0 is blocking - *=====================================================*/ -static int MegaIssueCmd(mega_host_config *megaCfg, - u_char *mboxData, - mega_scb *pScb, - int intr) -{ - mega_mailbox *mbox = (mega_mailbox *)megaCfg->mbox; - long flags; - u_char byte; - u_long cmdDone; - - mboxData[0x1] = (pScb ? pScb->idx+1 : 0x00); /* Set cmdid */ - mboxData[0xF] = 1; /* Set busy */ - - /* one bad report of problem when issuing a command while pending. - * Wasn't able to duplicate, but it doesn't really affect performance - * anyway, so don't allow command while PENDING - */ - if (megaCfg->flag & PENDING) { - return -1; + *===================================================== + */ +static int megaIssueCmd (mega_host_config * megaCfg, + u_char * mboxData, + mega_scb * pScb, + int intr) +{ + mega_mailbox *mbox = (mega_mailbox *) megaCfg->mbox; + u_char byte; + u_long cmdDone; + Scsi_Cmnd *SCpnt; + + mboxData[0x1] = (pScb ? pScb->idx + 1: 0x0); /* Set cmdid */ + mboxData[0xF] = 1; /* Set busy */ + +#if 0 + if (intr && mbox->busy) { + return 0; } +#endif /* Wait until mailbox is free */ - if (busyWaitMbox(megaCfg)) { - if (pScb) { - TRACE(("Mailbox busy %.08lx <%d.%d.%d>\n", pScb->SCpnt->serial_number, - pScb->SCpnt->channel, pScb->SCpnt->target, pScb->SCpnt->lun)); + while (mega_busyWaitMbox (megaCfg)) { + printk("Blocked mailbox!!\n"); + udelay(1000); + +#if DEBUG + showMbox(pLastScb); +#endif + + /* Abort command */ + if (pScb == NULL) { + printk("NULL pScb in megaIssue\n"); + TRACE(("NULL pScb in megaIssue\n")); } - return -1; + SCpnt = pScb->SCpnt; + freeSCB(megaCfg, pScb); + + SCpnt->result = (DID_ABORT << 16); + callDone(SCpnt); + return 0; } + pLastScb = pScb; + /* Copy mailbox data into host structure */ - spin_lock_irqsave(&mega_lock,flags); - memset(mbox, 0, sizeof(mega_mailbox)); - memcpy(mbox, mboxData, 16); - spin_unlock_irqrestore(&mega_lock,flags); + memcpy (mbox, mboxData, 16); /* Kick IO */ - megaCfg->flag |= PENDING; if (intr) { + /* Issue interrupt (non-blocking) command */ if (megaCfg->flag & BOARD_QUARTZ) { - mbox->mraid_poll = 0; - mbox->mraid_ack = 0; - WRINDOOR(megaCfg, virt_to_bus(megaCfg->mbox) | 0x1); - } else { - ENABLE_INTR(megaCfg->host->io_port); - ISSUE_COMMAND(megaCfg->host->io_port); + mbox->mraid_poll = 0; + mbox->mraid_ack = 0; + WRINDOOR (megaCfg, virt_to_bus (megaCfg->mbox) | 0x1); + } + else { + ENABLE_INTR (megaCfg->host->io_port); + ISSUE_COMMAND (megaCfg->host->io_port); } + pScb->state = SCB_ISSUED; } - else { /* Issue non-ISR (blocking) command */ - + else { /* Issue non-ISR (blocking) command */ + disable_irq(megaCfg->host->irq); if (megaCfg->flag & BOARD_QUARTZ) { + mbox->mraid_poll = 0; + mbox->mraid_ack = 0; + WRINDOOR (megaCfg, virt_to_bus (megaCfg->mbox) | 0x1); - mbox->mraid_poll = 0; - mbox->mraid_ack = 0; - WRINDOOR(megaCfg, virt_to_bus(megaCfg->mbox) | 0x1); - - while((cmdDone=RDOUTDOOR(megaCfg)) != 0x10001234); - WROUTDOOR(megaCfg, cmdDone); + while ((cmdDone = RDOUTDOOR (megaCfg)) != 0x10001234); + WROUTDOOR (megaCfg, cmdDone); if (pScb) { - mega_cmd_done(megaCfg,pScb, mbox->status); - mega_rundoneq(); + mega_cmd_done (megaCfg, pScb, mbox->status); + mega_rundoneq (); } - WRINDOOR(megaCfg,virt_to_bus(megaCfg->mbox) | 0x2); - while(RDINDOOR(megaCfg) & 0x2); + WRINDOOR (megaCfg, virt_to_bus (megaCfg->mbox) | 0x2); + while (RDINDOOR (megaCfg) & 0x2); - megaCfg->flag &= ~PENDING; } else { - DISABLE_INTR(megaCfg->host->io_port); - ISSUE_COMMAND(megaCfg->host->io_port); - - while(!((byte=READ_PORT(megaCfg->host->io_port,INTR_PORT))&INTR_VALID)); - WRITE_PORT(megaCfg->host->io_port, INTR_PORT, byte); - - ENABLE_INTR(megaCfg->host->io_port); - CLEAR_INTR(megaCfg->host->io_port); - + DISABLE_INTR (megaCfg->host->io_port); + ISSUE_COMMAND (megaCfg->host->io_port); + + while (!((byte = READ_PORT (megaCfg->host->io_port, INTR_PORT)) & INTR_VALID)); + WRITE_PORT (megaCfg->host->io_port, INTR_PORT, byte); + + + ENABLE_INTR (megaCfg->host->io_port); + CLEAR_INTR (megaCfg->host->io_port); + if (pScb) { - mega_cmd_done(megaCfg,pScb, mbox->status); - mega_rundoneq(); + mega_cmd_done (megaCfg, pScb, mbox->status); + mega_rundoneq (); + } + else { + TRACE (("Error: NULL pScb!\n")); } - megaCfg->flag &= ~PENDING; + } + enable_irq(megaCfg->host->irq); + } + while (mega_busyWaitMbox (megaCfg)) { + printk("Blocked mailbox on exit!\n"); + udelay(1000); } return 0; @@ -823,42 +1057,42 @@ /*------------------------------------------------------------------- * Copies data to SGLIST *-------------------------------------------------------------------*/ -static int build_sglist(mega_host_config *megaCfg, mega_scb *scb, - u_long *buffer, u_long *length) +static int build_sglist (mega_host_config * megaCfg, mega_scb * scb, + u_long * buffer, u_long * length) { struct scatterlist *sgList; int idx; /* Scatter-gather not used */ if (scb->SCpnt->use_sg == 0) { - *buffer = virt_to_bus(scb->SCpnt->request_buffer); - *length = (u_long)scb->SCpnt->request_bufflen; + *buffer = virt_to_bus (scb->SCpnt->request_buffer); + *length = (u_long) scb->SCpnt->request_bufflen; return 0; } - sgList = (struct scatterlist *)scb->SCpnt->buffer; + sgList = (struct scatterlist *) scb->SCpnt->request_buffer; if (scb->SCpnt->use_sg == 1) { - *buffer = virt_to_bus(sgList[0].address); - *length = (u_long)sgList[0].length; + *buffer = virt_to_bus (sgList[0].address); + *length = (u_long) sgList[0].length; return 0; } /* Copy Scatter-Gather list info into controller structure */ - for(idx=0; idxSCpnt->use_sg; idx++) { - scb->sgList[idx].address = virt_to_bus(sgList[idx].address); - scb->sgList[idx].length = (u_long)sgList[idx].length; + for (idx = 0; idx < scb->SCpnt->use_sg; idx++) { + scb->sgList[idx].address = virt_to_bus (sgList[idx].address); + scb->sgList[idx].length = (u_long) sgList[idx].length; } - + /* Reset pointer and length fields */ - *buffer = virt_to_bus(scb->sgList); + *buffer = virt_to_bus (scb->sgList); *length = 0; /* Return count of SG requests */ return scb->SCpnt->use_sg; } - + /*-------------------------------------------------------------------- - * Initializes the address of the controller's mailbox register + * Initializes the adress of the controller's mailbox register * The mailbox register is used to issue commands to the card. * Format of the mailbox area: * 00 01 command @@ -873,25 +1107,25 @@ * 10 01 numstatus byte * 11 01 status byte *--------------------------------------------------------------------*/ -static int mega_register_mailbox(mega_host_config *megaCfg, u_long paddr) +static int mega_register_mailbox (mega_host_config * megaCfg, u_long paddr) { /* align on 16-byte boundry */ megaCfg->mbox = &megaCfg->mailbox; - megaCfg->mbox = (mega_mailbox *) ((((ulong)megaCfg->mbox) + 16)&0xfffffff0); - paddr = (paddr+16)&0xfffffff0; + megaCfg->mbox = (mega_mailbox *) ((((ulong) megaCfg->mbox) + 16) & 0xfffffff0); + paddr = (paddr + 16) & 0xfffffff0; /* Register mailbox area with the firmware */ if (megaCfg->flag & BOARD_QUARTZ) { } else { - WRITE_PORT(megaCfg->host->io_port, MBOX_PORT0, paddr & 0xFF); - WRITE_PORT(megaCfg->host->io_port, MBOX_PORT1, (paddr >> 8) & 0xFF); - WRITE_PORT(megaCfg->host->io_port, MBOX_PORT2, (paddr >> 16) & 0xFF); - WRITE_PORT(megaCfg->host->io_port, MBOX_PORT3, (paddr >> 24) & 0xFF); - WRITE_PORT(megaCfg->host->io_port, ENABLE_MBOX_REGION, ENABLE_MBOX_BYTE); - - CLEAR_INTR(megaCfg->host->io_port); - ENABLE_INTR(megaCfg->host->io_port); + WRITE_PORT (megaCfg->host->io_port, MBOX_PORT0, paddr & 0xFF); + WRITE_PORT (megaCfg->host->io_port, MBOX_PORT1, (paddr >> 8) & 0xFF); + WRITE_PORT (megaCfg->host->io_port, MBOX_PORT2, (paddr >> 16) & 0xFF); + WRITE_PORT (megaCfg->host->io_port, MBOX_PORT3, (paddr >> 24) & 0xFF); + WRITE_PORT (megaCfg->host->io_port, ENABLE_MBOX_REGION, ENABLE_MBOX_BYTE); + + CLEAR_INTR (megaCfg->host->io_port); + ENABLE_INTR (megaCfg->host->io_port); } return 0; } @@ -899,77 +1133,80 @@ /*------------------------------------------------------------------- * Issue an adapter info query to the controller *-------------------------------------------------------------------*/ -static int mega_i_query_adapter(mega_host_config *megaCfg) +static int mega_i_query_adapter (mega_host_config * megaCfg) { mega_RAIDINQ *adapterInfo; mega_mailbox *mbox; - u_char mboxData[16]; - u_long paddr; + u_char mboxData[16]; + u_long paddr; + + spin_lock_init (&mega_lock); - spin_lock_init(&mega_lock); /* Initialize adapter inquiry */ - paddr = virt_to_bus(megaCfg->mega_buffer); - mbox = (mega_mailbox *)mboxData; + paddr = virt_to_bus (megaCfg->mega_buffer); + mbox = (mega_mailbox *) mboxData; - memset((void *)megaCfg->mega_buffer, 0, sizeof(megaCfg->mega_buffer)); - memset(mbox, 0, 16); + memset ((void *) megaCfg->mega_buffer, 0, sizeof (megaCfg->mega_buffer)); + memset (mbox, 0, 16); /* Initialize mailbox registers */ - mbox->cmd = MEGA_MBOXCMD_ADAPTERINQ; + mbox->cmd = MEGA_MBOXCMD_ADAPTERINQ; mbox->xferaddr = paddr; /* Issue a blocking command to the card */ - MegaIssueCmd(megaCfg, mboxData, NULL, 0); - + megaIssueCmd (megaCfg, mboxData, NULL, 0); + /* Initialize host/local structures with Adapter info */ - adapterInfo = (mega_RAIDINQ *)megaCfg->mega_buffer; + adapterInfo = (mega_RAIDINQ *) megaCfg->mega_buffer; megaCfg->host->max_channel = adapterInfo->AdpInfo.ChanPresent; - megaCfg->host->max_id = adapterInfo->AdpInfo.MaxTargPerChan; - megaCfg->numldrv = adapterInfo->LogdrvInfo.NumLDrv; +/* megaCfg->host->max_id = adapterInfo->AdpInfo.MaxTargPerChan; */ + megaCfg->host->max_id = 16; /* max targets/chan */ + megaCfg->numldrv = adapterInfo->LogdrvInfo.NumLDrv; #if 0 - printk(KERN_DEBUG "---- Logical drive info ----\n"); - for(i=0; inumldrv; i++) { - printk(KERN_DEBUG "%d: size: %ld prop: %x state: %x\n",i, - adapterInfo->LogdrvInfo.LDrvSize[i], - adapterInfo->LogdrvInfo.LDrvProp[i], - adapterInfo->LogdrvInfo.LDrvState[i]); - } - printk(KERN_DEBUG "---- Physical drive info ----\n"); - for(i=0; iPhysdrvInfo.PDrvState[i]); + printk ("KERN_DEBUG ---- Logical drive info ----\n"); + for (i = 0; i < megaCfg->numldrv; i++) { + printk ("%d: size: %ld prop: %x state: %x\n", i, + adapterInfo->LogdrvInfo.LDrvSize[i], + adapterInfo->LogdrvInfo.LDrvProp[i], + adapterInfo->LogdrvInfo.LDrvState[i]); + } + printk (KERN_DEBUG "---- Physical drive info ----\n"); + for (i = 0; i < MAX_PHYSICAL_DRIVES; i++) { + if (i && !(i % 8)) + printk ("\n"); + printk ("%d: %x ", i, adapterInfo->PhysdrvInfo.PDrvState[i]); } - printk("\n"); + printk ("\n"); #endif megaCfg->max_cmds = adapterInfo->AdpInfo.MaxConcCmds; -#ifdef HP /* use HP firmware and bios version encoding */ - sprintf(megaCfg->fwVer,"%c%d%d.%d%d", - adapterInfo->AdpInfo.FwVer[2], - adapterInfo->AdpInfo.FwVer[1] >> 8, - adapterInfo->AdpInfo.FwVer[1] & 0x0f, - adapterInfo->AdpInfo.FwVer[2] >> 8, - adapterInfo->AdpInfo.FwVer[2] & 0x0f); - sprintf(megaCfg->biosVer,"%c%d%d.%d%d", - adapterInfo->AdpInfo.BiosVer[2], - adapterInfo->AdpInfo.BiosVer[1] >> 8, - adapterInfo->AdpInfo.BiosVer[1] & 0x0f, - adapterInfo->AdpInfo.BiosVer[2] >> 8, - adapterInfo->AdpInfo.BiosVer[2] & 0x0f); +#ifdef HP /* use HP firmware and bios version encoding */ + sprintf (megaCfg->fwVer, "%c%d%d.%d%d", + adapterInfo->AdpInfo.FwVer[2], + adapterInfo->AdpInfo.FwVer[1] >> 8, + adapterInfo->AdpInfo.FwVer[1] & 0x0f, + adapterInfo->AdpInfo.FwVer[2] >> 8, + adapterInfo->AdpInfo.FwVer[2] & 0x0f); + sprintf (megaCfg->biosVer, "%c%d%d.%d%d", + adapterInfo->AdpInfo.BiosVer[2], + adapterInfo->AdpInfo.BiosVer[1] >> 8, + adapterInfo->AdpInfo.BiosVer[1] & 0x0f, + adapterInfo->AdpInfo.BiosVer[2] >> 8, + adapterInfo->AdpInfo.BiosVer[2] & 0x0f); #else - memcpy(megaCfg->fwVer, adapterInfo->AdpInfo.FwVer, 4); - megaCfg->fwVer[4] = 0; + memcpy (megaCfg->fwVer, adapterInfo->AdpInfo.FwVer, 4); + megaCfg->fwVer[4] = 0; - memcpy(megaCfg->biosVer, adapterInfo->AdpInfo.BiosVer, 4); - megaCfg->biosVer[4] = 0; + memcpy (megaCfg->biosVer, adapterInfo->AdpInfo.BiosVer, 4); + megaCfg->biosVer[4] = 0; #endif - printk(KERN_INFO "megaraid: [%s:%s] detected %d logical drives" CRLFSTR, - megaCfg->fwVer, - megaCfg->biosVer, - megaCfg->numldrv); + printk (KERN_INFO "megaraid: [%s:%s] detected %d logical drives" CRLFSTR, + megaCfg->fwVer, + megaCfg->biosVer, + megaCfg->numldrv); return 0; } @@ -982,56 +1219,72 @@ /*---------------------------------------------------------- * Returns data to be displayed in /proc/scsi/megaraid/X *----------------------------------------------------------*/ -int megaraid_proc_info(char *buffer, char **start, off_t offset, - int length, int inode, int inout) +int megaraid_proc_info (char *buffer, char **start, off_t offset, + int length, int host_no, int inout) { *start = buffer; return 0; } -int findCard(Scsi_Host_Template *pHostTmpl, - u_short pciVendor, u_short pciDev, - long flag) +int findCard (Scsi_Host_Template * pHostTmpl, + u_short pciVendor, u_short pciDev, + long flag) { mega_host_config *megaCfg; struct Scsi_Host *host; - u_char pciBus, pciDevFun, megaIrq; - u_long megaBase; - u_short pciIdx = 0; + u_char pciBus, pciDevFun, megaIrq; + u_long megaBase; + u_short jdx,pciIdx = 0; + u_short numFound = 0; #if LINUX_VERSION_CODE < 0x20100 - while(!pcibios_find_device(pciVendor, pciDev, pciIdx,&pciBus,&pciDevFun)) { -#else - struct pci_dev *pdev=pci_devices; + while (!pcibios_find_device (pciVendor, pciDev, pciIdx, &pciBus, &pciDevFun)) { - while((pdev = pci_find_device(pciVendor, pciDev, pdev))) { +#if 0 + } /* keep auto-indenters happy */ +#endif +#else + + struct pci_dev *pdev = pci_devices; + + while ((pdev = pci_find_device (pciVendor, pciDev, pdev))) { pciBus = pdev->bus->number; pciDevFun = pdev->devfn; #endif - printk(KERN_INFO "megaraid: found 0x%4.04x:0x%4.04x:idx %d:bus %d:slot %d:fun %d\n", - pciVendor, - pciDev, - pciIdx, pciBus, - PCI_SLOT(pciDevFun), - PCI_FUNC(pciDevFun)); - + if (flag & BOARD_QUARTZ) { + u_short magic; + pcibios_read_config_word (pciBus, pciDevFun, + PCI_CONF_AMISIG, + &magic); + if (magic != AMI_SIGNATURE) { + pciIdx++; + continue; /* not an AMI board */ + } + } + printk (KERN_INFO "megaraid: found 0x%4.04x:0x%4.04x:idx %d:bus %d:slot %d:fun %d\n", + pciVendor, + pciDev, + pciIdx, pciBus, + PCI_SLOT (pciDevFun), + PCI_FUNC (pciDevFun)); + /* Read the base port and IRQ from PCI */ #if LINUX_VERSION_CODE < 0x20100 - pcibios_read_config_dword(pciBus, pciDevFun, - PCI_BASE_ADDRESS_0, - (u_int *)&megaBase); - pcibios_read_config_byte(pciBus, pciDevFun, - PCI_INTERRUPT_LINE, - &megaIrq); + pcibios_read_config_dword (pciBus, pciDevFun, + PCI_BASE_ADDRESS_0, + (u_int *) & megaBase); + pcibios_read_config_byte (pciBus, pciDevFun, + PCI_INTERRUPT_LINE, + &megaIrq); #else megaBase = pdev->base_address[0]; - megaIrq = pdev->irq; + megaIrq = pdev->irq; #endif pciIdx++; if (flag & BOARD_QUARTZ) { megaBase &= PCI_BASE_ADDRESS_MEM_MASK; - megaBase = (long) ioremap(megaBase,128); + megaBase = (long) ioremap (megaBase, 128); } else { megaBase &= PCI_BASE_ADDRESS_IO_MASK; @@ -1039,72 +1292,92 @@ } /* Initialize SCSI Host structure */ - host = scsi_register(pHostTmpl, sizeof(mega_host_config)); - megaCfg = (mega_host_config *)host->hostdata; - memset(megaCfg, 0, sizeof(mega_host_config)); + host = scsi_register (pHostTmpl, sizeof (mega_host_config)); + megaCfg = (mega_host_config *) host->hostdata; + memset (megaCfg, 0, sizeof (mega_host_config)); + + printk (" scsi%d: Found a MegaRAID controller at 0x%x, IRQ: %d" CRLFSTR, + host->host_no, (u_int) megaBase, megaIrq); - printk(KERN_INFO " scsi%d: Found a MegaRAID controller at 0x%x, IRQ: %d" CRLFSTR, - host->host_no, (u_int)megaBase, megaIrq); - /* Copy resource info into structure */ - megaCfg->flag = flag; - megaCfg->host = host; - megaCfg->base = megaBase; - megaCfg->host->irq = megaIrq; - megaCfg->host->io_port = megaBase; + megaCfg->qPending = NULL; + megaCfg->qFree = NULL; + megaCfg->flag = flag; + megaCfg->host = host; + megaCfg->base = megaBase; + megaCfg->host->irq = megaIrq; + megaCfg->host->io_port = megaBase; megaCfg->host->n_io_port = 16; megaCfg->host->unique_id = (pciBus << 8) | pciDevFun; - megaCtlrs[numCtlrs++] = megaCfg; + megaCtlrs[numCtlrs++] = megaCfg; if (flag != BOARD_QUARTZ) { /* Request our IO Range */ - if (check_region(megaBase, 16)) { - printk(KERN_WARNING "megaraid: Couldn't register I/O range!" CRLFSTR); - scsi_unregister(host); + if (check_region (megaBase, 16)) { + printk (KERN_WARNING "megaraid: Couldn't register I/O range!" CRLFSTR); + scsi_unregister (host); continue; } - request_region(megaBase, 16, "megaraid"); + request_region (megaBase, 16, "megaraid"); } /* Request our IRQ */ - if (request_irq(megaIrq, megaraid_isr, SA_SHIRQ, - "megaraid", megaCfg)) { - printk(KERN_WARNING "megaraid: Couldn't register IRQ %d!" CRLFSTR, - megaIrq); - scsi_unregister(host); + if (request_irq (megaIrq, megaraid_isr, SA_SHIRQ, + "megaraid", megaCfg)) { + printk (KERN_WARNING "megaraid: Couldn't register IRQ %d!" CRLFSTR, + megaIrq); + scsi_unregister (host); continue; } - mega_register_mailbox(megaCfg, virt_to_bus((void*)&megaCfg->mailbox)); - mega_i_query_adapter(megaCfg); + mega_register_mailbox (megaCfg, virt_to_bus ((void *) &megaCfg->mailbox)); + mega_i_query_adapter (megaCfg); + + for(jdx=0; jdxnReads[jdx] = 0; + megaCfg->nWrites[jdx] = 0; + } /* Initialize SCBs */ - initSCB(megaCfg); + if (initSCB (megaCfg)) { + scsi_unregister (host); + continue; + } + numFound++; } - return pciIdx; + return numFound; } /*--------------------------------------------------------- * Detects if a megaraid controller exists in this system *---------------------------------------------------------*/ -int megaraid_detect(Scsi_Host_Template *pHostTmpl) +int megaraid_detect (Scsi_Host_Template * pHostTmpl) { int count = 0; pHostTmpl->proc_dir = &proc_scsi_megaraid; #if LINUX_VERSION_CODE < 0x20100 - if (!pcibios_present()) - { - printk(KERN_WARNING "megaraid: PCI bios not present." CRLFSTR); - return 0; - } + if (!pcibios_present ()) { + printk (KERN_WARNING "megaraid: PCI bios not present." CRLFSTR); + return 0; + } #endif + skip_id = -1; + if (megaraid && !strncmp(megaraid,"skip",strlen("skip"))) { + if (megaraid[4] != '\0') { + skip_id = megaraid[4] - '0'; + if (megaraid[5] != '\0') { + skip_id = (skip_id * 10) + (megaraid[5] - '0'); + } + } + skip_id = (skip_id > 15) ? -1 : skip_id; + } - count += findCard(pHostTmpl, 0x101E, 0x9010, 0); - count += findCard(pHostTmpl, 0x101E, 0x9060, 0); - count += findCard(pHostTmpl, 0x8086, 0x1960, BOARD_QUARTZ); + count += findCard (pHostTmpl, 0x101E, 0x9010, 0); + count += findCard (pHostTmpl, 0x101E, 0x9060, 0); + count += findCard (pHostTmpl, 0x8086, 0x1960, BOARD_QUARTZ); return count; } @@ -1112,54 +1385,66 @@ /*--------------------------------------------------------------------- * Release the controller's resources *---------------------------------------------------------------------*/ -int megaraid_release(struct Scsi_Host *pSHost) +int megaraid_release (struct Scsi_Host *pSHost) { mega_host_config *megaCfg; - mega_mailbox *mbox; - u_char mboxData[16]; + mega_mailbox *mbox; + u_char mboxData[16]; - megaCfg = (mega_host_config*)pSHost->hostdata; - mbox = (mega_mailbox *)mboxData; + megaCfg = (mega_host_config *) pSHost->hostdata; + mbox = (mega_mailbox *) mboxData; /* Flush cache to disk */ - memset(mbox, 0, 16); + memset (mbox, 0, 16); mboxData[0] = 0xA; - /* Issue a blocking (interrupts disabled) command to the card */ - MegaIssueCmd(megaCfg, mboxData, NULL, 0); + free_irq (megaCfg->host->irq, megaCfg);/* Must be freed first, otherwise + extra interrupt is generated */ - schedule(); + /* Issue a blocking (interrupts disabled) command to the card */ + megaIssueCmd (megaCfg, mboxData, NULL, 0); /* Free our resources */ if (megaCfg->flag & BOARD_QUARTZ) { - iounmap((void *)megaCfg->base); - } else { - release_region(megaCfg->host->io_port, 16); - } - free_irq(megaCfg->host->irq, megaCfg); /* Must be freed first, otherwise - extra interrupt is generated */ - scsi_unregister(pSHost); + iounmap ((void *) megaCfg->base); + } + else { + release_region (megaCfg->host->io_port, 16); + } + + freeSgList(megaCfg); + scsi_unregister (pSHost); return 0; } +static inline void freeSgList(mega_host_config *megaCfg) +{ + int i; + + for (i = 0; i < megaCfg->max_cmds; i++) { + if (megaCfg->scbList[i].sgList) + kfree (megaCfg->scbList[i].sgList); /* free sgList */ + } +} + /*---------------------------------------------- * Get information about the card/driver *----------------------------------------------*/ -const char *megaraid_info(struct Scsi_Host *pSHost) +const char * megaraid_info (struct Scsi_Host *pSHost) { - static char buffer[512]; - mega_host_config *megaCfg; - mega_RAIDINQ *adapterInfo; + static char buffer[512]; + mega_host_config *megaCfg; + mega_RAIDINQ *adapterInfo; - megaCfg = (mega_host_config *)pSHost->hostdata; - adapterInfo = (mega_RAIDINQ *)megaCfg->mega_buffer; + megaCfg = (mega_host_config *) pSHost->hostdata; + adapterInfo = (mega_RAIDINQ *) megaCfg->mega_buffer; - sprintf(buffer, "AMI MegaRAID %s %d commands %d targs %d chans", - megaCfg->fwVer, - adapterInfo->AdpInfo.MaxConcCmds, - megaCfg->host->max_id, - megaCfg->host->max_channel); + sprintf (buffer, "AMI MegaRAID %s %d commands %d targs %d chans", + megaCfg->fwVer, + adapterInfo->AdpInfo.MaxConcCmds, + megaCfg->host->max_id, + megaCfg->host->max_channel); return buffer; } @@ -1178,67 +1463,86 @@ * 10 01 numstatus byte * 11 01 status byte *-----------------------------------------------------------------*/ -int megaraid_queue(Scsi_Cmnd *SCpnt, void (*pktComp)(Scsi_Cmnd *)) +int megaraid_queue (Scsi_Cmnd * SCpnt, void (*pktComp) (Scsi_Cmnd *)) { mega_host_config *megaCfg; - mega_scb *pScb; + mega_scb *pScb; + long flags; - megaCfg = (mega_host_config *)SCpnt->host->hostdata; + spin_lock_irqsave(&mega_lock,flags); + + megaCfg = (mega_host_config *) SCpnt->host->hostdata; if (!(megaCfg->flag & (1L << SCpnt->channel))) { - printk(KERN_INFO "scsi%d: scanning channel %c for devices.\n", - megaCfg->host->host_no, - SCpnt->channel + 'A'); + printk (KERN_INFO "scsi%d: scanning channel %c for devices.\n", + megaCfg->host->host_no, + SCpnt->channel + 'A'); megaCfg->flag |= (1L << SCpnt->channel); } SCpnt->scsi_done = pktComp; + /* If driver in abort or reset.. cancel this command */ + if (megaCfg->flag & IN_ABORT) { + SCpnt->result = (DID_ABORT << 16); + ENQUEUE_NL(SCpnt, Scsi_Cmnd, qCompleted, host_scribble); + + spin_unlock_irqrestore(&mega_lock,flags); + return 0; + } + else if (megaCfg->flag & IN_RESET) { + SCpnt->result = (DID_RESET << 16); + ENQUEUE_NL(SCpnt, Scsi_Cmnd, qCompleted, host_scribble); + + spin_unlock_irqrestore(&mega_lock,flags); + return 0; + } + /* Allocate and build a SCB request */ - if ((pScb = mega_build_cmd(megaCfg, SCpnt)) != NULL) { + if ((pScb = mega_build_cmd (megaCfg, SCpnt)) != NULL) { /* Add SCB to the head of the pending queue */ - ENQUEUE(pScb, mega_scb, qPending, next); + ENQUEUE_NL (pScb, mega_scb, megaCfg->qPending, next); - /* Issue the command to the card */ - mega_runque(NULL); + /* Issue any pending command to the card if not in ISR */ + if (!(megaCfg->flag & IN_ISR)) { + mega_runpendq(megaCfg); + } + else { + printk("IRQ pend...\n"); + } } + spin_unlock_irqrestore(&mega_lock,flags); + return 0; } /*---------------------------------------------------------------------- * Issue a blocking command to the controller - * - * Note - this isnt 2.0.x SMP safe *----------------------------------------------------------------------*/ -volatile static int internal_done_flag = 0; +volatile static int internal_done_flag = 0; volatile static int internal_done_errcode = 0; +static struct wait_queue *internal_wait = NULL; -static void internal_done(Scsi_Cmnd *SCpnt) +static void internal_done (Scsi_Cmnd * SCpnt) { internal_done_errcode = SCpnt->result; internal_done_flag++; + wake_up(&internal_wait); } -/* - * This seems dangerous in an SMP environment because - * while spinning on internal_done_flag in 2.0.x SMP - * no IRQ's will be taken, including those that might - * be needed to clear this. - * - * I think this should be using a wait queue ? - * -- AC - */ - -int megaraid_command(Scsi_Cmnd *SCpnt) +/* shouldn't be used, but included for completeness */ + +int megaraid_command (Scsi_Cmnd * SCpnt) { internal_done_flag = 0; /* Queue command, and wait until it has completed */ - megaraid_queue(SCpnt, internal_done); + megaraid_queue (SCpnt, internal_done); - while(!internal_done_flag) - barrier(); + while (!internal_done_flag) { + interruptible_sleep_on(&internal_wait); + } return internal_done_errcode; } @@ -1246,67 +1550,122 @@ /*--------------------------------------------------------------------- * Abort a previous SCSI request *---------------------------------------------------------------------*/ -int megaraid_abort(Scsi_Cmnd *SCpnt) +int megaraid_abort (Scsi_Cmnd * SCpnt) { mega_host_config *megaCfg; - int idx; - long flags; + int rc, idx; + long flags; + mega_scb *pScb; - spin_lock_irqsave(&mega_lock,flags); + rc = SCSI_ABORT_SUCCESS; + + spin_lock_irqsave (&mega_lock, flags); + + megaCfg = (mega_host_config *) SCpnt->host->hostdata; - megaCfg = (mega_host_config *)SCpnt->host->hostdata; + megaCfg->flag |= IN_ABORT; + + for(pScb=megaCfg->qPending; pScb; pScb=pScb->next) { + if (pScb->SCpnt == SCpnt) { + /* Found an aborting command */ +#if DEBUG + showMbox(pScb); +#endif + + printk("Abort: %d %u\n", + SCpnt->timeout_per_command, + (uint)((jiffies) - pScb->isrcount)); + + switch(pScb->state) { + case SCB_ABORTED: /* Already aborted */ + rc = SCSI_ABORT_SNOOZE; + break; + case SCB_ISSUED: /* Waiting on ISR result */ + rc = SCSI_ABORT_PENDING; + pScb->state = SCB_ABORTED; + break; + } + } + } + +#if 0 + TRACE (("ABORT!!! %.08lx %.02x <%d.%d.%d>\n", + SCpnt->serial_number, SCpnt->cmnd[0], SCpnt->channel, SCpnt->target, + SCpnt->lun)); + for(pScb=megaCfg->qPending; pScb; pScb=pScb->next) { + if (pScb->SCpnt == SCpnt) { + ser_printk("** %d<%x> %c\n", pScb->SCpnt->pid, pScb->idx+1, + pScb->state == SCB_ACTIVE ? 'A' : 'I'); +#if DEBUG + showMbox(pScb); +#endif + } + } +#endif - TRACE(("ABORT!!! %.08lx %.02x <%d.%d.%d>\n", - SCpnt->serial_number, SCpnt->cmnd[0], SCpnt->channel, SCpnt->target, - SCpnt->lun)); /* * Walk list of SCBs for any that are still outstanding */ - for(idx=0; idxmax_cmds; idx++) { - if (megaCfg->scbList[idx].idx >= 0) { + for (idx = 0; idx < megaCfg->max_cmds; idx++) { + if (megaCfg->scbList[idx].state != SCB_FREE) { if (megaCfg->scbList[idx].SCpnt == SCpnt) { - freeSCB(&megaCfg->scbList[idx]); + freeSCB (megaCfg, &megaCfg->scbList[idx]); - SCpnt->result = (DID_RESET << 16) | (SUGGEST_RETRY<<24); - callDone(SCpnt); + SCpnt->result = (DID_ABORT << 16) | (SUGGEST_RETRY << 24); + ENQUEUE_NL(SCpnt, Scsi_Cmnd, qCompleted, host_scribble); } } } - spin_unlock_irqrestore(&mega_lock,flags); - return SCSI_ABORT_SNOOZE; + + megaCfg->flag &= ~IN_ABORT; + + spin_unlock_irqrestore (&mega_lock, flags); + + mega_rundoneq(); + + return rc; } /*--------------------------------------------------------------------- * Reset a previous SCSI request *---------------------------------------------------------------------*/ -int megaraid_reset(Scsi_Cmnd *SCpnt, unsigned int rstflags) +int megaraid_reset (Scsi_Cmnd * SCpnt, unsigned int rstflags) { mega_host_config *megaCfg; - int idx; - long flags; + int idx; + long flags; - spin_lock_irqsave(&mega_lock,flags); + spin_lock_irqsave (&mega_lock, flags); + + megaCfg = (mega_host_config *) SCpnt->host->hostdata; - megaCfg = (mega_host_config *)SCpnt->host->hostdata; + megaCfg->flag |= IN_RESET; - TRACE(("RESET: %.08lx %.02x <%d.%d.%d>\n", - SCpnt->serial_number, SCpnt->cmnd[0], SCpnt->channel, SCpnt->target, - SCpnt->lun)); + TRACE (("RESET: %.08lx %.02x <%d.%d.%d>\n", + SCpnt->serial_number, SCpnt->cmnd[0], SCpnt->channel, SCpnt->target, + SCpnt->lun)); /* * Walk list of SCBs for any that are still outstanding */ - for(idx=0; idxmax_cmds; idx++) { - if (megaCfg->scbList[idx].idx >= 0) { + for (idx = 0; idx < megaCfg->max_cmds; idx++) { + if (megaCfg->scbList[idx].state != SCB_FREE) { SCpnt = megaCfg->scbList[idx].SCpnt; - freeSCB(&megaCfg->scbList[idx]); - SCpnt->result = (DID_RESET << 16) | (SUGGEST_RETRY<<24); - callDone(SCpnt); + if (SCpnt != NULL) { + freeSCB (megaCfg, &megaCfg->scbList[idx]); + SCpnt->result = (DID_RESET << 16) | (SUGGEST_RETRY << 24); + ENQUEUE_NL(SCpnt, Scsi_Cmnd, qCompleted, host_scribble); + } } } - spin_unlock_irqrestore(&mega_lock,flags); + + megaCfg->flag &= ~IN_RESET; + + spin_unlock_irqrestore (&mega_lock, flags); + + mega_rundoneq(); return SCSI_RESET_PUNT; -} +} /*------------------------------------------------------------- * Return the disk geometry for a particular disk @@ -1318,23 +1677,23 @@ * geom[1] = sectors * geom[2] = cylinders *-------------------------------------------------------------*/ -int megaraid_biosparam(Disk *disk, kdev_t dev, int *geom) +int megaraid_biosparam (Disk * disk, kdev_t dev, int *geom) { - int heads, sectors, cylinders; + int heads, sectors, cylinders; mega_host_config *megaCfg; /* Get pointer to host config structure */ - megaCfg = (mega_host_config *)disk->device->host->hostdata; + megaCfg = (mega_host_config *) disk->device->host->hostdata; /* Default heads (64) & sectors (32) */ - heads = 64; - sectors = 32; + heads = 64; + sectors = 32; cylinders = disk->capacity / (heads * sectors); /* Handle extended translation size for logical drives > 1Gb */ if (disk->capacity >= 0x200000) { - heads = 255; - sectors = 63; + heads = 255; + sectors = 63; cylinders = disk->capacity / (heads * sectors); } diff -ur --new-file old/linux/drivers/scsi/megaraid.h new/linux/drivers/scsi/megaraid.h --- old/linux/drivers/scsi/megaraid.h Thu Jan 28 21:42:10 1999 +++ new/linux/drivers/scsi/megaraid.h Tue May 11 19:36:36 1999 @@ -1,27 +1,28 @@ #ifndef __MEGARAID_H__ #define __MEGARAID_H__ +#ifndef LINUX_VERSION_CODE #include +#endif #define IN_ISR 0x80000000L -#define NO_INTR 0x40000000L -#define IN_TIMEOUT 0x20000000L -#define PENDING 0x10000000L +#define IN_ABORT 0x40000000L +#define IN_RESET 0x20000000L #define BOARD_QUARTZ 0x08000000L -#define SCB_ACTIVE 0x1 -#define SCB_WAITQ 0x2 -#define SCB_ISSUED 0x4 - -#define SCB_FREE -1 -#define SCB_RESET -2 -#define SCB_ABORT -3 -#define SCB_LOCKED -4 +#define SCB_FREE 0x0 +#define SCB_ACTIVE 0x1 +#define SCB_WAITQ 0x2 +#define SCB_ISSUED 0x3 +#define SCB_COMPLETE 0x4 +#define SCB_ABORTED 0x5 +#define SCB_RESET 0x6 #define MEGA_CMD_TIMEOUT 10 -#define MAX_SGLIST 20 -#define MAX_COMMANDS 254 +#define MAX_SGLIST 17 +#define MAX_COMMANDS 250 +#define MAX_CMD_PER_LUN 63 #define MAX_LOGICAL_DRIVES 8 #define MAX_CHANNEL 5 @@ -56,7 +57,7 @@ #define I_TOGGLE_PORT 0x01 #define INTR_PORT 0x0a -#define MAILBOX_SIZE 70 +#define MAILBOX_SIZE (sizeof(mega_mailbox)-16) #define MBOX_BUSY_PORT 0x00 #define MBOX_PORT0 0x04 #define MBOX_PORT1 0x05 @@ -96,6 +97,8 @@ #define PCI_CONF_BASE_ADDR_OFFSET 0x10 #define PCI_CONF_IRQ_OFFSET 0x3c +#define PCI_CONF_AMISIG 0xa0 +#define AMI_SIGNATURE 0x3344 #if LINUX_VERSION_CODE < 0x20100 #define MEGARAID \ @@ -113,14 +116,14 @@ megaraid_reset, /* Reset Command Function */\ NULL, /* Slave Attach Function */\ megaraid_biosparam, /* Disk BIOS Parameters */\ - 1, /* # of cmds that can be\ + MAX_COMMANDS, /* # of cmds that can be\ outstanding at any time */\ 7, /* HBA Target ID */\ MAX_SGLIST, /* Scatter/Gather Table Size */\ - 1, /* SCSI Commands per LUN */\ + MAX_CMD_PER_LUN, /* SCSI Commands per LUN */\ 0, /* Present */\ 0, /* Default Unchecked ISA DMA */\ - ENABLE_CLUSTERING } /* Enable Clustering */ + ENABLE_CLUSTERING } /* Enable Clustering */ #else #define MEGARAID \ {\ @@ -134,10 +137,10 @@ abort: megaraid_abort, /* Abort Command Function */\ reset: megaraid_reset, /* Reset Command Function */\ bios_param: megaraid_biosparam, /* Disk BIOS Parameters */\ - can_queue: 255, /* Can Queue */\ + can_queue: MAX_COMMANDS, /* Can Queue */\ this_id: 7, /* HBA Target ID */\ sg_tablesize: MAX_SGLIST, /* Scatter/Gather Table Size */\ - cmd_per_lun: 1, /* SCSI Commands per LUN */\ + cmd_per_lun: MAX_CMD_PER_LUN, /* SCSI Commands per LUN */\ present: 0, /* Present */\ unchecked_isa_dma:0, /* Default Unchecked ISA DMA */\ use_clustering: ENABLE_CLUSTERING /* Enable Clustering */\ @@ -145,140 +148,155 @@ #endif /* Structures */ -typedef struct _mega_ADP_INFO -{ - u_char MaxConcCmds; - u_char RbldRate; - u_char MaxTargPerChan; - u_char ChanPresent; - u_char FwVer[4]; - u_short AgeOfFlash; - u_char ChipSet; - u_char DRAMSize; - u_char CacheFlushInterval; - u_char BiosVer[4]; - u_char resvd[7]; +typedef struct _mega_ADP_INFO { + u_char MaxConcCmds; + u_char RbldRate; + u_char MaxTargPerChan; + u_char ChanPresent; + u_char FwVer[4]; + u_short AgeOfFlash; + u_char ChipSet; + u_char DRAMSize; + u_char CacheFlushInterval; + u_char BiosVer[4]; + u_char resvd[7]; } mega_ADP_INFO; -typedef struct _mega_LDRV_INFO -{ - u_char NumLDrv; - u_char resvd[3]; - u_long LDrvSize[MAX_LOGICAL_DRIVES]; - u_char LDrvProp[MAX_LOGICAL_DRIVES]; - u_char LDrvState[MAX_LOGICAL_DRIVES]; +typedef struct _mega_LDRV_INFO { + u_char NumLDrv; + u_char resvd[3]; + u_long LDrvSize[MAX_LOGICAL_DRIVES]; + u_char LDrvProp[MAX_LOGICAL_DRIVES]; + u_char LDrvState[MAX_LOGICAL_DRIVES]; } mega_LDRV_INFO; -typedef struct _mega_PDRV_INFO -{ - u_char PDrvState[MAX_PHYSICAL_DRIVES]; - u_char resvd; +typedef struct _mega_PDRV_INFO { + u_char PDrvState[MAX_PHYSICAL_DRIVES]; + u_char resvd; } mega_PDRV_INFO; // RAID inquiry: Mailbox command 0x5 -typedef struct _mega_RAIDINQ -{ - mega_ADP_INFO AdpInfo; - mega_LDRV_INFO LogdrvInfo; - mega_PDRV_INFO PhysdrvInfo; +typedef struct _mega_RAIDINQ { + mega_ADP_INFO AdpInfo; + mega_LDRV_INFO LogdrvInfo; + mega_PDRV_INFO PhysdrvInfo; } mega_RAIDINQ; // Passthrough command: Mailbox command 0x3 -typedef struct mega_passthru -{ - u_char timeout:3; /* 0=6sec/1=60sec/2=10min/3=3hrs */ - u_char ars:1; - u_char reserved:3; - u_char islogical:1; - u_char logdrv; /* if islogical == 1 */ - u_char channel; /* if islogical == 0 */ - u_char target; /* if islogical == 0 */ - u_char queuetag; /* unused */ - u_char queueaction; /* unused */ - u_char cdb[MAX_CDB_LEN]; - u_char cdblen; - u_char reqsenselen; - u_char reqsensearea[MAX_REQ_SENSE_LEN]; - u_char numsgelements; - u_char scsistatus; - u_long dataxferaddr; - u_long dataxferlen; +typedef struct mega_passthru { + u_char timeout:3; /* 0=6sec/1=60sec/2=10min/3=3hrs */ + u_char ars:1; + u_char reserved:3; + u_char islogical:1; + u_char logdrv; /* if islogical == 1 */ + u_char channel; /* if islogical == 0 */ + u_char target; /* if islogical == 0 */ + u_char queuetag; /* unused */ + u_char queueaction; /* unused */ + u_char cdb[MAX_CDB_LEN]; + u_char cdblen; + u_char reqsenselen; + u_char reqsensearea[MAX_REQ_SENSE_LEN]; + u_char numsgelements; + u_char scsistatus; + u_long dataxferaddr; + u_long dataxferlen; } mega_passthru; -typedef struct _mega_mailbox -{ - /* 0x0 */ u_char cmd; - /* 0x1 */ u_char cmdid; - /* 0x2 */ u_short numsectors; - /* 0x4 */ u_long lba; - /* 0x8 */ u_long xferaddr; - /* 0xC */ u_char logdrv; - /* 0xD */ u_char numsgelements; - /* 0xE */ u_char resvd; - /* 0xF */ u_char busy; - /* 0x10*/ u_char numstatus; - /* 0x11*/ u_char status; - /* 0x12*/ u_char completed[46]; - u_char mraid_poll; - u_char mraid_ack; - u_char pad[16]; +typedef struct _mega_mailbox { + /* 0x0 */ u_char cmd; + /* 0x1 */ u_char cmdid; + /* 0x2 */ u_short numsectors; + /* 0x4 */ u_long lba; + /* 0x8 */ u_long xferaddr; + /* 0xC */ u_char logdrv; + /* 0xD */ u_char numsgelements; + /* 0xE */ u_char resvd; + /* 0xF */ u_char busy; + /* 0x10 */ u_char numstatus; + /* 0x11 */ u_char status; + /* 0x12 */ u_char completed[46]; + u_char mraid_poll; + u_char mraid_ack; + u_char pad[16]; } mega_mailbox; -typedef struct _mega_sglist -{ - u_long address; - u_long length; +typedef struct _mega_ioctl_mbox { + /* 0x0 */ u_char cmd; + /* 0x1 */ u_char cmdid; + /* 0x2 */ u_char channel; + /* 0x3 */ u_char param; + /* 0x4 */ u_char pad[4]; + /* 0x8 */ u_long xferaddr; + /* 0xC */ u_char logdrv; + /* 0xD */ u_char numsgelements; + /* 0xE */ u_char resvd; + /* 0xF */ u_char busy; + /* 0x10 */ u_char numstatus; + /* 0x11 */ u_char status; + /* 0x12 */ u_char completed[46]; + u_char mraid_poll; + u_char mraid_ack; + u_char malign[16]; +} mega_ioctl_mbox; + +typedef struct _mega_sglist { + u_long address; + u_long length; } mega_sglist; /* Queued command data */ typedef struct _mega_scb mega_scb; -struct _mega_scb -{ - int idx; - u_long flag; - Scsi_Cmnd *SCpnt; - u_char mboxData[16]; - mega_passthru pthru; - mega_sglist *sgList; - mega_scb *next; +struct _mega_scb { + int idx; + u_long state; + u_long isrcount; + u_char mboxData[16]; + mega_passthru pthru; + Scsi_Cmnd *SCpnt; + mega_sglist *sgList; + mega_scb *next; }; /* Per-controller data */ -typedef struct _mega_host_config -{ - u_char numldrv; - u_long flag; - u_long base; - - struct tq_struct megaTq; - - /* Host adapter parameters */ - u_char fwVer[7]; - u_char biosVer[7]; - - struct Scsi_Host *host; - - /* The following must be DMA-able!! */ - volatile mega_mailbox *mbox; - volatile mega_mailbox mailbox; - volatile u_char mega_buffer[2*1024L]; +typedef struct _mega_host_config { + u_char numldrv; + u_long flag; + u_long base; + + mega_scb *qFree; + mega_scb *qPending; + + u_long nReads[MAX_LOGICAL_DRIVES]; + u_long nWrites[MAX_LOGICAL_DRIVES]; + + /* Host adapter parameters */ + u_char fwVer[7]; + u_char biosVer[7]; + + struct Scsi_Host *host; + + /* The following must be DMA-able!! */ + volatile mega_mailbox *mbox; + volatile mega_mailbox mailbox; + volatile u_char mega_buffer[2 * 1024L]; - u_char max_cmds; - mega_scb scbList[MAX_COMMANDS]; + u_char max_cmds; + mega_scb scbList[MAX_COMMANDS]; } mega_host_config; extern struct proc_dir_entry proc_scsi_megaraid; -const char *megaraid_info( struct Scsi_Host * ); -int megaraid_detect( Scsi_Host_Template * ); -int megaraid_release(struct Scsi_Host *); -int megaraid_command( Scsi_Cmnd * ); -int megaraid_abort( Scsi_Cmnd * ); -int megaraid_reset( Scsi_Cmnd *, unsigned int); -int megaraid_queue( Scsi_Cmnd *, void (*done)(Scsi_Cmnd *) ); -int megaraid_biosparam( Disk *, kdev_t, int * ); -int megaraid_proc_info( char *buffer, char **start, off_t offset, - int length, int hostno, int inout ); +const char *megaraid_info(struct Scsi_Host *); +int megaraid_detect(Scsi_Host_Template *); +int megaraid_release(struct Scsi_Host *); +int megaraid_command(Scsi_Cmnd *); +int megaraid_abort(Scsi_Cmnd *); +int megaraid_reset(Scsi_Cmnd *, unsigned int); +int megaraid_queue(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *)); +int megaraid_biosparam(Disk *, kdev_t, int *); +int megaraid_proc_info(char *buffer, char **start, off_t offset, + int length, int hostno, int inout); #endif diff -ur --new-file old/linux/drivers/scsi/ncr53c8xx.c new/linux/drivers/scsi/ncr53c8xx.c --- old/linux/drivers/scsi/ncr53c8xx.c Mon Jan 18 03:28:06 1999 +++ new/linux/drivers/scsi/ncr53c8xx.c Mon Apr 12 18:51:04 1999 @@ -73,7 +73,7 @@ */ /* -** January 16 1998, version 3.1f +** March 7 1999, version 3.2 ** ** Supported SCSI-II features: ** Synchronous negotiation @@ -98,6 +98,11 @@ ** Shared IRQ (since linux-1.3.72) */ +/* +** Name and version of the driver +*/ +#define SCSI_NCR_DRIVER_NAME "ncr53c8xx - version 3.2" + #define SCSI_NCR_DEBUG_FLAGS (0) /*========================================================== @@ -717,12 +722,12 @@ ** /proc directory entry and proc_info function */ -struct proc_dir_entry proc_scsi_ncr53c8xx = { +static struct proc_dir_entry proc_scsi_ncr53c8xx = { PROC_SCSI_NCR53C8XX, 9, "ncr53c8xx", S_IFDIR | S_IRUGO | S_IXUGO, 2 }; #ifdef SCSI_NCR_PROC_INFO_SUPPORT -int ncr53c8xx_proc_info(char *buffer, char **start, off_t offset, +static int ncr53c8xx_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int func); #endif @@ -732,6 +737,7 @@ ** This structure is initialized from linux config options. ** It can be overridden at boot-up by the boot command line. */ +#define SCSI_NCR_MAX_EXCLUDES 8 struct ncr_driver_setup { u_char master_parity; u_char scsi_parity; @@ -753,6 +759,9 @@ u_char diff_support; u_char irqm; u_char bus_check; + u_char optimize; + u_char recovery; + u_int excludes[SCSI_NCR_MAX_EXCLUDES]; char tag_ctrl[100]; }; @@ -2081,6 +2090,7 @@ ncrcmd msg_ext_3 [ 10]; ncrcmd msg_sdtr [ 14]; ncrcmd send_sdtr [ 7]; + ncrcmd nego_bad_phase [ 4]; ncrcmd msg_out_abort [ 10]; ncrcmd hdata_in [MAX_SCATTERH * 4]; ncrcmd hdata_in2 [ 2]; @@ -3185,16 +3195,15 @@ /* ** If a negotiation was in progress, ** negotiation failed. + ** Otherwise, let the C code print + ** some message. */ SCR_FROM_REG (HS_REG), 0, - SCR_INT ^ IFTRUE (DATA (HS_NEGOTIATE)), - SIR_NEGO_FAILED, - /* - ** else make host log this message - */ SCR_INT ^ IFFALSE (DATA (HS_NEGOTIATE)), SIR_REJECT_RECEIVED, + SCR_INT ^ IFTRUE (DATA (HS_NEGOTIATE)), + SIR_NEGO_FAILED, SCR_JUMP, PADDR (clrack), @@ -3304,10 +3313,9 @@ 0, SCR_CLR (SCR_ACK), 0, + SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_OUT)), + PADDRH (nego_bad_phase), -/* CHECK THE SOURCE FOR 'send_wdtr' IF YOU INTEND TO CHANGE SOMETHING HERE */ - SCR_INT ^ IFFALSE (WHEN (SCR_MSG_OUT)), - SIR_NEGO_PROTO, }/*-------------------------< SEND_WDTR >----------------*/,{ /* ** Send the M_X_WIDE_REQ @@ -3360,10 +3368,9 @@ 0, SCR_CLR (SCR_ACK), 0, + SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_OUT)), + PADDRH (nego_bad_phase), -/* CHECK THE SOURCE FOR 'send_sdtr' IF YOU INTEND TO CHANGE SOMETHING HERE */ - SCR_INT ^ IFFALSE (WHEN (SCR_MSG_OUT)), - SIR_NEGO_PROTO, }/*-------------------------< SEND_SDTR >-------------*/,{ /* ** Send the M_X_SYNC_REQ @@ -3376,6 +3383,12 @@ SCR_JUMP, PADDR (msg_out_done), +}/*-------------------------< NEGO_BAD_PHASE >------------*/,{ + SCR_INT, + SIR_NEGO_PROTO, + SCR_JUMP, + PADDR (dispatch), + }/*-------------------------< MSG_OUT_ABORT >-------------*/,{ /* ** After ABORT message, @@ -4274,7 +4287,7 @@ /* ** Set irq mode. */ - switch(driver_setup.irqm) { + switch(driver_setup.irqm & 3) { case 2: np->rv_dcntl |= IRQM; break; @@ -4665,21 +4678,15 @@ /* ** Install the interrupt handler. */ -#ifdef SCSI_NCR_SHARE_IRQ -#define NCR_SA_INTERRUPT_FLAGS (SA_INTERRUPT | SA_SHIRQ) - if (bootverbose > 1) -#ifdef __sparc__ - printk(KERN_INFO "%s: requesting shared irq %s (dev_id=0x%lx)\n", - ncr_name(np), __irq_itoa(device->slot.irq), (u_long) np); -#else - printk(KERN_INFO "%s: requesting shared irq %d (dev_id=0x%lx)\n", - ncr_name(np), device->slot.irq, (u_long) np); -#endif + + if (request_irq(device->slot.irq, ncr53c8xx_intr, + ((driver_setup.irqm & 0x10) ? 0 : SA_SHIRQ) | +#if LINUX_VERSION_CODE < LinuxVersionCode(2,2,0) + ((driver_setup.irqm & 0x20) ? 0 : SA_INTERRUPT), #else -#define NCR_SA_INTERRUPT_FLAGS SA_INTERRUPT + 0, #endif - if (request_irq(device->slot.irq, ncr53c8xx_intr, - NCR_SA_INTERRUPT_FLAGS, "ncr53c8xx", np)) { + "ncr53c8xx", np)) { #ifdef __sparc__ printk(KERN_ERR "%s: request irq %s failure\n", ncr_name(np), __irq_itoa(device->slot.irq)); @@ -4689,6 +4696,7 @@ #endif goto attach_error; } + np->irq = device->slot.irq; /* @@ -4836,7 +4844,7 @@ ** **========================================================== */ -int ncr_queue_command (ncb_p np, Scsi_Cmnd *cmd) +static int ncr_queue_command (ncb_p np, Scsi_Cmnd *cmd) { /* Scsi_Device *device = cmd->device; */ tcb_p tp = &np->target[cmd->target]; @@ -4956,9 +4964,8 @@ nego = NS_SYNC; } else { tp->period =0xffff; - tp->sval = 0xe0; PRINT_TARGET(np, cmd->target); - printk ("SYNC transfers not supported.\n"); + printk ("device did not report SYNC.\n"); }; }; @@ -5401,7 +5408,7 @@ ** **========================================================== */ -int ncr_reset_bus (ncb_p np, Scsi_Cmnd *cmd, int sync_reset) +static int ncr_reset_bus (ncb_p np, Scsi_Cmnd *cmd, int sync_reset) { /* Scsi_Device *device = cmd->device; */ ccb_p cp; @@ -5824,7 +5831,7 @@ ** announced capabilities (we need the 1rst 7 bytes). */ if (cmd->cmnd[0] == 0x12 && !(cmd->cmnd[1] & 0x3) && - cmd->cmnd[4] >= 7) { + cmd->cmnd[4] >= 7 && !cmd->use_sg) { ncr_setup_lcb (np, cmd->target, cmd->lun, (char *) cmd->request_buffer); } @@ -5971,7 +5978,7 @@ ** This CCB has been skipped by the NCR. ** Queue it in the correponding unit queue. */ -void ncr_ccb_skipped(ncb_p np, ccb_p cp) +static void ncr_ccb_skipped(ncb_p np, ccb_p cp) { tcb_p tp = &np->target[cp->target]; lcb_p lp = tp->lp[cp->lun]; @@ -7051,7 +7058,7 @@ OUTONB (nc_ctest3, CLF); if ((sist & (SGE)) || - (dstat & (MDPE|BF|ABORT|IID))) { + (dstat & (MDPE|BF|ABRT|IID))) { ncr_start_reset(np); return; }; @@ -7528,7 +7535,7 @@ } else if (dsp == NCB_SCRIPTH_PHYS (np, send_wdtr) || dsp == NCB_SCRIPTH_PHYS (np, send_sdtr)) { - nxtdsp = dsp - 8; /* Should raise SIR_NEGO_PROTO */ + nxtdsp = NCB_SCRIPTH_PHYS (np, nego_bad_phase); } break; #if 0 @@ -7882,9 +7889,7 @@ np->msgin [0] = M_NOOP; np->msgout[0] = M_NOOP; cp->nego_status = 0; - OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, dispatch)); - return; -/* break; */ + break; case SIR_NEGO_SYNC: /* @@ -8657,10 +8662,15 @@ ** Evaluate trustable target/unit capabilities. ** We only believe device version >= SCSI-2 that ** use appropriate response data format (2). + ** But it seems that some CCS devices also + ** support SYNC and I donnot want to frustrate + ** anybody. ;-) */ inq_byte7 = 0; - if ((inq_data[2] & 0x7) >= 2 && (inq_data[3] & 0xf) == 2) + if ((inq_data[2] & 0x7) >= 2 && (inq_data[3] & 0xf) == 2) inq_byte7 = inq_data[7]; + else if ((inq_data[2] & 0x7) == 1 && (inq_data[3] & 0xf) == 1) + inq_byte7 = INQ7_SYNC; /* ** Throw away announced LUN capabilities if we are told @@ -9238,6 +9248,7 @@ int val; int base; int c; + int xi = 0; while (cur != NULL && (pc = strchr(cur, ':')) != NULL) { char *pe; @@ -9309,6 +9320,10 @@ else if (!strncmp(cur, "safe:", 5) && val) memcpy(&driver_setup, &driver_safe_setup, sizeof(driver_setup)); + else if (!strncmp(cur, "excl:", 5)) { + if (xi < SCSI_NCR_MAX_EXCLUDES) + driver_setup.excludes[xi++] = val; + } else printk("ncr53c8xx_setup: unexpected boot option '%.*s' ignored\n", (int)(pc-cur+1), cur); @@ -9586,6 +9601,50 @@ } /* +** Generically read a base address from the PCI configuration space. +** Return the offset immediately after the base address that has +** been read. Btw, we blindly assume that the high 32 bits of 64 bit +** base addresses are set to zero on 32 bit architectures. +** +*/ +#if LINUX_VERSION_CODE <= LinuxVersionCode(2,1,92) +__initfunc( +static int +pci_read_base_address(u_char bus, u_char device_fn, int offset, u_long *base) +) +{ + u_int32 tmp; + + pcibios_read_config_dword(bus, device_fn, offset, &tmp); + *base = tmp; + offset += sizeof(u_int32); + if ((tmp & 0x7) == 0x4) { +#if BITS_PER_LONG > 32 + pcibios_read_config_dword(bus, device_fn, offset, &tmp); + *base |= (((u_long)tmp) << 32); +#endif + offset += sizeof(u_int32); + } + return offset; +} +#else /* LINUX_VERSION_CODE > LinuxVersionCode(2,1,92) */ +__initfunc( +static int +pci_get_base_address(struct pci_dev *pdev, int index, u_long *base) +) +{ + *base = pdev->base_address[index++]; + if ((*base & 0x7) == 0x4) { +#if BITS_PER_LONG > 32 + *base |= (((u_long)pdev->base_address[index]) << 32); +#endif + ++index; + } + return index; +} +#endif + +/* ** Read and check the PCI configuration for any detected NCR ** boards and save data for attaching after all boards have ** been detected. @@ -9601,60 +9660,55 @@ uchar revision; #if LINUX_VERSION_CODE > LinuxVersionCode(2,1,92) struct pci_dev *pdev; - ulong base, base_2, io_port; uint irq; #else uchar irq; - uint base, base_2, io_port; #endif + ulong base, base_2, io_port; int i; - #ifdef SCSI_NCR_NVRAM_SUPPORT ncr_nvram *nvram = device->nvram; #endif ncr_chip *chip; /* - * Read info from the PCI config space. - * pcibios_read_config_xxx() functions are assumed to be used for - * successfully detected PCI devices. - * Expecting error conditions from them is just paranoia, - * thus void cast. - */ - (void) pcibios_read_config_word(bus, device_fn, - PCI_VENDOR_ID, &vendor_id); - (void) pcibios_read_config_word(bus, device_fn, - PCI_DEVICE_ID, &device_id); - (void) pcibios_read_config_word(bus, device_fn, - PCI_COMMAND, &command); + ** Read info from the PCI config space. + ** pcibios_read_config_xxx() functions are assumed to be used for + ** successfully detected PCI devices. + */ #if LINUX_VERSION_CODE > LinuxVersionCode(2,1,92) pdev = pci_find_slot(bus, device_fn); - io_port = pdev->base_address[0]; - base = pdev->base_address[1]; - base_2 = pdev->base_address[2]; + vendor_id = pdev->vendor; + device_id = pdev->device; irq = pdev->irq; -#else - (void) pcibios_read_config_dword(bus, device_fn, - PCI_BASE_ADDRESS_0, &io_port); - (void) pcibios_read_config_dword(bus, device_fn, - PCI_BASE_ADDRESS_1, &base); - (void) pcibios_read_config_dword(bus, device_fn, - PCI_BASE_ADDRESS_2, &base_2); - - /* Handle 64bit base addresses for 53C896. */ - if ((base & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == PCI_BASE_ADDRESS_MEM_TYPE_64) - (void) pcibios_read_config_dword(bus, device_fn, - PCI_BASE_ADDRESS_3, &base_2); - (void) pcibios_read_config_byte(bus, device_fn, - PCI_INTERRUPT_LINE, &irq); -#endif - (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); - + i = 0; + i = pci_get_base_address(pdev, i, &io_port); + i = pci_get_base_address(pdev, i, &base); + (void) pci_get_base_address(pdev, i, &base_2); +#else + pcibios_read_config_word(bus, device_fn, PCI_VENDOR_ID, &vendor_id); + pcibios_read_config_word(bus, device_fn, PCI_DEVICE_ID, &device_id); + pcibios_read_config_byte(bus, device_fn, PCI_INTERRUPT_LINE, &irq); + i = PCI_BASE_ADDRESS_0; + i = pci_read_base_address(bus, device_fn, i, &io_port); + i = pci_read_base_address(bus, device_fn, i, &base); + (void) pci_read_base_address(bus, device_fn, i, &base_2); +#endif + pcibios_read_config_word(bus, device_fn, PCI_COMMAND, &command); + pcibios_read_config_byte(bus, device_fn, PCI_CLASS_REVISION, &revision); + pcibios_read_config_byte(bus, device_fn, PCI_CACHE_LINE_SIZE, + &cache_line_size); + pcibios_read_config_byte(bus, device_fn, PCI_LATENCY_TIMER, + &latency_timer); + + /* + ** If user excludes this chip, donnot initialize it. + */ + for (i = 0 ; i < SCSI_NCR_MAX_EXCLUDES ; i++) { + if (driver_setup.excludes[i] == + (io_port & PCI_BASE_ADDRESS_IO_MASK)) + return -1; + } /* * Check if the chip is supported */ @@ -10141,6 +10195,14 @@ } /* +** Linux entry point for info() function +*/ +const char *ncr53c8xx_info (struct Scsi_Host *host) +{ + return SCSI_NCR_DRIVER_NAME; +} + +/* ** Linux entry point of queuecommand() function */ @@ -10764,7 +10826,7 @@ ** - func = 1 means write (parse user control command) */ -int ncr53c8xx_proc_info(char *buffer, char **start, off_t offset, +static int ncr53c8xx_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int func) { struct Scsi_Host *host; diff -ur --new-file old/linux/drivers/scsi/ncr53c8xx.h new/linux/drivers/scsi/ncr53c8xx.h --- old/linux/drivers/scsi/ncr53c8xx.h Thu Jan 28 21:42:08 1999 +++ new/linux/drivers/scsi/ncr53c8xx.h Tue May 11 19:36:58 1999 @@ -42,215 +42,7 @@ #ifndef NCR53C8XX_H #define NCR53C8XX_H -/* -** Name and revision of the driver -*/ -#define SCSI_NCR_DRIVER_NAME "ncr53c8xx - revision 3.1f" - -/* -** Check supported Linux versions -*/ - -#if !defined(LINUX_VERSION_CODE) -#include -#endif -#include - -#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s)) - -/* - * No more an option, enabled by default. - */ -#ifndef CONFIG_SCSI_NCR53C8XX_NVRAM_DETECT -#define CONFIG_SCSI_NCR53C8XX_NVRAM_DETECT -#endif - -/* -** These options are not tunable from 'make config' -*/ -#define SCSI_NCR_PROC_INFO_SUPPORT -#define SCSI_NCR_SHARE_IRQ - -/* -** If you want a driver as small as possible, donnot define the -** following options. -*/ -#define SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT -#define SCSI_NCR_DEBUG_INFO_SUPPORT -#define SCSI_NCR_PCI_FIX_UP_SUPPORT -#ifdef SCSI_NCR_PROC_INFO_SUPPORT -# ifdef CONFIG_SCSI_NCR53C8XX_PROFILE -# define SCSI_NCR_PROFILE_SUPPORT -# endif -# define SCSI_NCR_USER_COMMAND_SUPPORT -# define SCSI_NCR_USER_INFO_SUPPORT -#endif - -/*========================================================== -** -** nvram settings - #define SCSI_NCR_NVRAM_SUPPORT to enable -** -**========================================================== -*/ - -#ifdef CONFIG_SCSI_NCR53C8XX_NVRAM_DETECT -#define SCSI_NCR_NVRAM_SUPPORT -/* #define SCSI_NCR_DEBUG_NVRAM */ -#endif - -/* --------------------------------------------------------------------- -** Take into account kernel configured parameters. -** Most of these options can be overridden at startup by a command line. -** --------------------------------------------------------------------- -*/ - -/* - * For Ultra2 SCSI support option, use special features and allow 40Mhz - * synchronous data transfers. - */ -#define SCSI_NCR_SETUP_SPECIAL_FEATURES (3) -#define SCSI_NCR_SETUP_ULTRA_SCSI (2) -#define SCSI_NCR_MAX_SYNC (40) - -/* - * Allow tags from 2 to 64, default 8 - */ -#ifdef CONFIG_SCSI_NCR53C8XX_MAX_TAGS -#if CONFIG_SCSI_NCR53C8XX_MAX_TAGS < 2 -#define SCSI_NCR_MAX_TAGS (2) -#elif CONFIG_SCSI_NCR53C8XX_MAX_TAGS > 64 -#define SCSI_NCR_MAX_TAGS (64) -#else -#define SCSI_NCR_MAX_TAGS CONFIG_SCSI_NCR53C8XX_MAX_TAGS -#endif -#else -#define SCSI_NCR_MAX_TAGS (8) -#endif - -/* - * Allow tagged command queuing support if configured with default number - * of tags set to max (see above). - */ -#ifdef CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS -#define SCSI_NCR_SETUP_DEFAULT_TAGS CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS -#elif defined CONFIG_SCSI_NCR53C8XX_TAGGED_QUEUE -#define SCSI_NCR_SETUP_DEFAULT_TAGS SCSI_NCR_MAX_TAGS -#else -#define SCSI_NCR_SETUP_DEFAULT_TAGS (0) -#endif - -/* - * Use normal IO if configured. Forced for alpha and ppc. - */ -#if defined(CONFIG_SCSI_NCR53C8XX_IOMAPPED) -#define SCSI_NCR_IOMAPPED -#elif defined(__alpha__) || defined(__powerpc__) -#define SCSI_NCR_IOMAPPED -#elif defined(__sparc__) -#undef SCSI_NCR_IOMAPPED -#endif - -/* - * Sync transfer frequency at startup. - * Allow from 5Mhz to 40Mhz default 20 Mhz. - */ -#ifndef CONFIG_SCSI_NCR53C8XX_SYNC -#define CONFIG_SCSI_NCR53C8XX_SYNC (20) -#elif CONFIG_SCSI_NCR53C8XX_SYNC > SCSI_NCR_MAX_SYNC -#undef CONFIG_SCSI_NCR53C8XX_SYNC -#define CONFIG_SCSI_NCR53C8XX_SYNC SCSI_NCR_MAX_SYNC -#endif - -#if CONFIG_SCSI_NCR53C8XX_SYNC == 0 -#define SCSI_NCR_SETUP_DEFAULT_SYNC (255) -#elif CONFIG_SCSI_NCR53C8XX_SYNC <= 5 -#define SCSI_NCR_SETUP_DEFAULT_SYNC (50) -#elif CONFIG_SCSI_NCR53C8XX_SYNC <= 20 -#define SCSI_NCR_SETUP_DEFAULT_SYNC (250/(CONFIG_SCSI_NCR53C8XX_SYNC)) -#elif CONFIG_SCSI_NCR53C8XX_SYNC <= 33 -#define SCSI_NCR_SETUP_DEFAULT_SYNC (11) -#else -#define SCSI_NCR_SETUP_DEFAULT_SYNC (10) -#endif - -/* - * Disallow disconnections at boot-up - */ -#ifdef CONFIG_SCSI_NCR53C8XX_NO_DISCONNECT -#define SCSI_NCR_SETUP_DISCONNECTION (0) -#else -#define SCSI_NCR_SETUP_DISCONNECTION (1) -#endif - -/* - * Force synchronous negotiation for all targets - */ -#ifdef CONFIG_SCSI_NCR53C8XX_FORCE_SYNC_NEGO -#define SCSI_NCR_SETUP_FORCE_SYNC_NEGO (1) -#else -#define SCSI_NCR_SETUP_FORCE_SYNC_NEGO (0) -#endif - -/* - * Disable master parity checking (flawed hardwares need that) - */ -#ifdef CONFIG_SCSI_NCR53C8XX_DISABLE_MPARITY_CHECK -#define SCSI_NCR_SETUP_MASTER_PARITY (0) -#else -#define SCSI_NCR_SETUP_MASTER_PARITY (1) -#endif - -/* - * Disable scsi parity checking (flawed devices may need that) - */ -#ifdef CONFIG_SCSI_NCR53C8XX_DISABLE_PARITY_CHECK -#define SCSI_NCR_SETUP_SCSI_PARITY (0) -#else -#define SCSI_NCR_SETUP_SCSI_PARITY (1) -#endif - -/* - * Vendor specific stuff - */ -#ifdef CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT -#define SCSI_NCR_SETUP_LED_PIN (1) -#define SCSI_NCR_SETUP_DIFF_SUPPORT (3) -#else -#define SCSI_NCR_SETUP_LED_PIN (0) -#define SCSI_NCR_SETUP_DIFF_SUPPORT (0) -#endif - -/* - * Settle time after reset at boot-up - */ -#define SCSI_NCR_SETUP_SETTLE_TIME (2) - -/* -** Other parameters not configurable with "make config" -** Avoid to change these constants, unless you know what you are doing. -*/ - -#define SCSI_NCR_ALWAYS_SIMPLE_TAG -#define SCSI_NCR_MAX_SCATTER (127) -#define SCSI_NCR_MAX_TARGET (16) - -/* No need to use a too large adapter queue */ -#if SCSI_NCR_MAX_TAGS <= 32 -#define SCSI_NCR_CAN_QUEUE (7*SCSI_NCR_MAX_TAGS) -#else -#define SCSI_NCR_CAN_QUEUE (250) -#endif - -#define SCSI_NCR_CMD_PER_LUN (SCSI_NCR_MAX_TAGS) -#define SCSI_NCR_SG_TABLESIZE (SCSI_NCR_MAX_SCATTER) - -#define SCSI_NCR_TIMER_INTERVAL (HZ) - -#if 1 /* defined CONFIG_SCSI_MULTI_LUN */ -#define SCSI_NCR_MAX_LUN (8) -#else -#define SCSI_NCR_MAX_LUN (1) -#endif +#include "sym53c8xx_defs.h" /* ** Define Scsi_Host_Template parameters @@ -264,6 +56,7 @@ int ncr53c8xx_abort(Scsi_Cmnd *); int ncr53c8xx_detect(Scsi_Host_Template *tpnt); +const char *ncr53c8xx_info(struct Scsi_Host *host); int ncr53c8xx_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); int ncr53c8xx_reset(Scsi_Cmnd *, unsigned int); @@ -273,11 +66,13 @@ #define ncr53c8xx_release NULL #endif + #if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,75) -#define NCR53C8XX { name: SCSI_NCR_DRIVER_NAME, \ +#define NCR53C8XX { name: "", \ detect: ncr53c8xx_detect, \ release: ncr53c8xx_release, \ + info: ncr53c8xx_info, \ queuecommand: ncr53c8xx_queue_command,\ abort: ncr53c8xx_abort, \ reset: ncr53c8xx_reset, \ @@ -291,8 +86,8 @@ #else #define NCR53C8XX { NULL, NULL, NULL, NULL, \ - SCSI_NCR_DRIVER_NAME, ncr53c8xx_detect, \ - ncr53c8xx_release, NULL, NULL, \ + NULL, ncr53c8xx_detect, \ + ncr53c8xx_release, ncr53c8xx_info, NULL, \ ncr53c8xx_queue_command,ncr53c8xx_abort, \ ncr53c8xx_reset, NULL, scsicam_bios_param, \ SCSI_NCR_CAN_QUEUE, 7, \ @@ -303,867 +98,4 @@ #endif /* defined(HOSTS_C) || defined(MODULE) */ -#ifndef HOSTS_C - -/* -** IO functions definition for big/little endian support. -** For now, the NCR is only supported in little endian addressing mode, -** and big endian byte ordering is only supported for the PPC. -** MMIO is not used on PPC. -*/ - -#ifdef __BIG_ENDIAN - -#if LINUX_VERSION_CODE < LinuxVersionCode(2,1,0) -#error "BIG ENDIAN byte ordering needs kernel version >= 2.1.0" -#endif - -#if defined(__powerpc__) -#define inw_l2b inw -#define inl_l2b inl -#define outw_b2l outw -#define outl_b2l outl -#elif defined(__sparc__) -#define readw_l2b readw -#define readl_l2b readl -#define writew_b2l writew -#define writel_b2l writel -#else -#error "Support for BIG ENDIAN is only available for PowerPC and SPARC" -#endif - -#else /* Assumed x86 or alpha */ - -#define inw_raw inw -#define inl_raw inl -#define outw_raw outw -#define outl_raw outl -#define readw_raw readw -#define readl_raw readl -#define writew_raw writew -#define writel_raw writel - -#endif - -#ifdef SCSI_NCR_BIG_ENDIAN -#error "The NCR in BIG ENDIAN addressing mode is not (yet) supported" -#endif - -/* -** NCR53C8XX Device Ids -*/ - -#ifndef PCI_DEVICE_ID_NCR_53C810 -#define PCI_DEVICE_ID_NCR_53C810 1 -#endif - -#ifndef PCI_DEVICE_ID_NCR_53C810AP -#define PCI_DEVICE_ID_NCR_53C810AP 5 -#endif - -#ifndef PCI_DEVICE_ID_NCR_53C815 -#define PCI_DEVICE_ID_NCR_53C815 4 -#endif - -#ifndef PCI_DEVICE_ID_NCR_53C820 -#define PCI_DEVICE_ID_NCR_53C820 2 -#endif - -#ifndef PCI_DEVICE_ID_NCR_53C825 -#define PCI_DEVICE_ID_NCR_53C825 3 -#endif - -#ifndef PCI_DEVICE_ID_NCR_53C860 -#define PCI_DEVICE_ID_NCR_53C860 6 -#endif - -#ifndef PCI_DEVICE_ID_NCR_53C875 -#define PCI_DEVICE_ID_NCR_53C875 0xf -#endif - -#ifndef PCI_DEVICE_ID_NCR_53C875J -#define PCI_DEVICE_ID_NCR_53C875J 0x8f -#endif - -#ifndef PCI_DEVICE_ID_NCR_53C885 -#define PCI_DEVICE_ID_NCR_53C885 0xd -#endif - -#ifndef PCI_DEVICE_ID_NCR_53C895 -#define PCI_DEVICE_ID_NCR_53C895 0xc -#endif - -#ifndef PCI_DEVICE_ID_NCR_53C896 -#define PCI_DEVICE_ID_NCR_53C896 0xb -#endif - -/* -** NCR53C8XX devices features table. -*/ -typedef struct { - unsigned short device_id; - unsigned short revision_id; - char *name; - unsigned char burst_max; - unsigned char offset_max; - unsigned char nr_divisor; - unsigned int features; -#define FE_LED0 (1<<0) -#define FE_WIDE (1<<1) -#define FE_ULTRA (1<<2) -#define FE_ULTRA2 (1<<3) -#define FE_DBLR (1<<4) -#define FE_QUAD (1<<5) -#define FE_ERL (1<<6) -#define FE_CLSE (1<<7) -#define FE_WRIE (1<<8) -#define FE_ERMP (1<<9) -#define FE_BOF (1<<10) -#define FE_DFS (1<<11) -#define FE_PFEN (1<<12) -#define FE_LDSTR (1<<13) -#define FE_RAM (1<<14) -#define FE_CLK80 (1<<15) -#define FE_RAM8K (1<<16) -#define FE_64BIT (1<<17) -#define FE_IO256 (1<<18) -#define FE_NOPM (1<<19) -#define FE_CACHE_SET (FE_ERL|FE_CLSE|FE_WRIE|FE_ERMP) -#define FE_SCSI_SET (FE_WIDE|FE_ULTRA|FE_ULTRA2|FE_DBLR|FE_QUAD|F_CLK80) -#define FE_SPECIAL_SET (FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM) -} ncr_chip; - -/* -** DEL 397 - 53C875 Rev 3 - Part Number 609-0392410 - ITEM 3. -** Memory Read transaction terminated by a retry followed by -** Memory Read Line command. -*/ -#define FE_CACHE0_SET (FE_CACHE_SET & ~FE_ERL) - -/* -** DEL 397 - 53C875 Rev 3 - Part Number 609-0392410 - ITEM 5. -** On paper, this errata is harmless. But it is a good reason for -** using a shorter programmed burst length (64 DWORDS instead of 128). -*/ - -#define SCSI_NCR_CHIP_TABLE \ -{ \ - {PCI_DEVICE_ID_NCR_53C810, 0x0f, "810", 4, 8, 4, \ - FE_ERL} \ - , \ - {PCI_DEVICE_ID_NCR_53C810, 0xff, "810a", 4, 8, 4, \ - FE_CACHE_SET|FE_LDSTR|FE_PFEN|FE_BOF} \ - , \ - {PCI_DEVICE_ID_NCR_53C815, 0xff, "815", 4, 8, 4, \ - FE_ERL|FE_BOF} \ - , \ - {PCI_DEVICE_ID_NCR_53C820, 0xff, "820", 4, 8, 4, \ - FE_WIDE|FE_ERL} \ - , \ - {PCI_DEVICE_ID_NCR_53C825, 0x0f, "825", 4, 8, 4, \ - FE_WIDE|FE_ERL|FE_BOF} \ - , \ - {PCI_DEVICE_ID_NCR_53C825, 0xff, "825a", 6, 8, 4, \ - FE_WIDE|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM} \ - , \ - {PCI_DEVICE_ID_NCR_53C860, 0xff, "860", 4, 8, 5, \ - FE_ULTRA|FE_CLK80|FE_CACHE_SET|FE_BOF|FE_LDSTR|FE_PFEN} \ - , \ - {PCI_DEVICE_ID_NCR_53C875, 0x01, "875", 6, 16, 5, \ - FE_WIDE|FE_ULTRA|FE_CLK80|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}\ - , \ - {PCI_DEVICE_ID_NCR_53C875, 0x0f, "875", 6, 16, 5, \ - FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}\ - , \ - {PCI_DEVICE_ID_NCR_53C875, 0xff, "876", 6, 16, 5, \ - FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}\ - , \ - {PCI_DEVICE_ID_NCR_53C875J,0xff, "875J", 6, 16, 5, \ - FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}\ - , \ - {PCI_DEVICE_ID_NCR_53C885, 0xff, "885", 6, 16, 5, \ - FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}\ - , \ - {PCI_DEVICE_ID_NCR_53C895, 0xff, "895", 7, 31, 7, \ - FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}\ - , \ - {PCI_DEVICE_ID_NCR_53C896, 0xff, "896", 7, 31, 7, \ - FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM|\ - FE_RAM8K|FE_64BIT|FE_IO256|FE_NOPM}\ -} - -/* - * List of supported NCR chip ids - */ -#define SCSI_NCR_CHIP_IDS \ -{ \ - PCI_DEVICE_ID_NCR_53C810, \ - PCI_DEVICE_ID_NCR_53C815, \ - PCI_DEVICE_ID_NCR_53C820, \ - PCI_DEVICE_ID_NCR_53C825, \ - PCI_DEVICE_ID_NCR_53C860, \ - PCI_DEVICE_ID_NCR_53C875, \ - PCI_DEVICE_ID_NCR_53C875J, \ - PCI_DEVICE_ID_NCR_53C885, \ - PCI_DEVICE_ID_NCR_53C895, \ - PCI_DEVICE_ID_NCR_53C896 \ -} - -/* -** Initial setup. -** Can be overriden at startup by a command line. -*/ -#define SCSI_NCR_DRIVER_SETUP \ -{ \ - SCSI_NCR_SETUP_MASTER_PARITY, \ - SCSI_NCR_SETUP_SCSI_PARITY, \ - SCSI_NCR_SETUP_DISCONNECTION, \ - SCSI_NCR_SETUP_SPECIAL_FEATURES, \ - SCSI_NCR_SETUP_ULTRA_SCSI, \ - SCSI_NCR_SETUP_FORCE_SYNC_NEGO, \ - 0, \ - 0, \ - 1, \ - 1, \ - SCSI_NCR_SETUP_DEFAULT_TAGS, \ - SCSI_NCR_SETUP_DEFAULT_SYNC, \ - 0x00, \ - 7, \ - SCSI_NCR_SETUP_LED_PIN, \ - 1, \ - SCSI_NCR_SETUP_SETTLE_TIME, \ - SCSI_NCR_SETUP_DIFF_SUPPORT, \ - 0, \ - 1 \ -} - -/* -** Boot fail safe setup. -** Override initial setup from boot command line: -** ncr53c8xx=safe:y -*/ -#define SCSI_NCR_DRIVER_SAFE_SETUP \ -{ \ - 0, \ - 1, \ - 0, \ - 0, \ - 0, \ - 0, \ - 0, \ - 0, \ - 1, \ - 2, \ - 0, \ - 255, \ - 0x00, \ - 255, \ - 0, \ - 0, \ - 10, \ - 1, \ - 1, \ - 1 \ -} - -/**************** ORIGINAL CONTENT of ncrreg.h from FreeBSD ******************/ - -/*----------------------------------------------------------------- -** -** The ncr 53c810 register structure. -** -**----------------------------------------------------------------- -*/ - -struct ncr_reg { -/*00*/ u_char nc_scntl0; /* full arb., ena parity, par->ATN */ - -/*01*/ u_char nc_scntl1; /* no reset */ - #define ISCON 0x10 /* connected to scsi */ - #define CRST 0x08 /* force reset */ - -/*02*/ u_char nc_scntl2; /* no disconnect expected */ - #define SDU 0x80 /* cmd: disconnect will raise error */ - #define CHM 0x40 /* sta: chained mode */ - #define WSS 0x08 /* sta: wide scsi send [W]*/ - #define WSR 0x01 /* sta: wide scsi received [W]*/ - -/*03*/ u_char nc_scntl3; /* cnf system clock dependent */ - #define EWS 0x08 /* cmd: enable wide scsi [W]*/ - #define ULTRA 0x80 /* cmd: ULTRA enable */ - -/*04*/ u_char nc_scid; /* cnf host adapter scsi address */ - #define RRE 0x40 /* r/w:e enable response to resel. */ - #define SRE 0x20 /* r/w:e enable response to select */ - -/*05*/ u_char nc_sxfer; /* ### Sync speed and count */ - -/*06*/ u_char nc_sdid; /* ### Destination-ID */ - -/*07*/ u_char nc_gpreg; /* ??? IO-Pins */ - -/*08*/ u_char nc_sfbr; /* ### First byte in phase */ - -/*09*/ u_char nc_socl; - #define CREQ 0x80 /* r/w: SCSI-REQ */ - #define CACK 0x40 /* r/w: SCSI-ACK */ - #define CBSY 0x20 /* r/w: SCSI-BSY */ - #define CSEL 0x10 /* r/w: SCSI-SEL */ - #define CATN 0x08 /* r/w: SCSI-ATN */ - #define CMSG 0x04 /* r/w: SCSI-MSG */ - #define CC_D 0x02 /* r/w: SCSI-C_D */ - #define CI_O 0x01 /* r/w: SCSI-I_O */ - -/*0a*/ u_char nc_ssid; - -/*0b*/ u_char nc_sbcl; - -/*0c*/ u_char nc_dstat; - #define DFE 0x80 /* sta: dma fifo empty */ - #define MDPE 0x40 /* int: master data parity error */ - #define BF 0x20 /* int: script: bus fault */ - #define ABRT 0x10 /* int: script: command aborted */ - #define SSI 0x08 /* int: script: single step */ - #define SIR 0x04 /* int: script: interrupt instruct. */ - #define IID 0x01 /* int: script: illegal instruct. */ - -/*0d*/ u_char nc_sstat0; - #define ILF 0x80 /* sta: data in SIDL register lsb */ - #define ORF 0x40 /* sta: data in SODR register lsb */ - #define OLF 0x20 /* sta: data in SODL register lsb */ - #define AIP 0x10 /* sta: arbitration in progress */ - #define LOA 0x08 /* sta: arbitration lost */ - #define WOA 0x04 /* sta: arbitration won */ - #define IRST 0x02 /* sta: scsi reset signal */ - #define SDP 0x01 /* sta: scsi parity signal */ - -/*0e*/ u_char nc_sstat1; - #define FF3210 0xf0 /* sta: bytes in the scsi fifo */ - -/*0f*/ u_char nc_sstat2; - #define ILF1 0x80 /* sta: data in SIDL register msb[W]*/ - #define ORF1 0x40 /* sta: data in SODR register msb[W]*/ - #define OLF1 0x20 /* sta: data in SODL register msb[W]*/ - #define DM 0x04 /* sta: DIFFSENS mismatch (895/6 only) */ - #define LDSC 0x02 /* sta: disconnect & reconnect */ - -/*10*/ u_int32 nc_dsa; /* --> Base page */ - -/*14*/ u_char nc_istat; /* --> Main Command and status */ - #define CABRT 0x80 /* cmd: abort current operation */ - #define SRST 0x40 /* mod: reset chip */ - #define SIGP 0x20 /* r/w: message from host to ncr */ - #define SEM 0x10 /* r/w: message between host + ncr */ - #define CON 0x08 /* sta: connected to scsi */ - #define INTF 0x04 /* sta: int on the fly (reset by wr)*/ - #define SIP 0x02 /* sta: scsi-interrupt */ - #define DIP 0x01 /* sta: host/script interrupt */ - -/*15*/ u_char nc_15_; -/*16*/ u_char nc_16_; -/*17*/ u_char nc_17_; - -/*18*/ u_char nc_ctest0; -/*19*/ u_char nc_ctest1; - -/*1a*/ u_char nc_ctest2; - #define CSIGP 0x40 - -/*1b*/ u_char nc_ctest3; - #define FLF 0x08 /* cmd: flush dma fifo */ - #define CLF 0x04 /* cmd: clear dma fifo */ - #define FM 0x02 /* mod: fetch pin mode */ - #define WRIE 0x01 /* mod: write and invalidate enable */ - -/*1c*/ u_int32 nc_temp; /* ### Temporary stack */ - -/*20*/ u_char nc_dfifo; -/*21*/ u_char nc_ctest4; - #define BDIS 0x80 /* mod: burst disable */ - #define MPEE 0x08 /* mod: master parity error enable */ - -/*22*/ u_char nc_ctest5; - #define DFS 0x20 /* mod: dma fifo size */ -/*23*/ u_char nc_ctest6; - -/*24*/ u_int32 nc_dbc; /* ### Byte count and command */ -/*28*/ u_int32 nc_dnad; /* ### Next command register */ -/*2c*/ u_int32 nc_dsp; /* --> Script Pointer */ -/*30*/ u_int32 nc_dsps; /* --> Script pointer save/opcode#2 */ - -/*34*/ u_char nc_scratcha; /* Temporary register a */ -/*35*/ u_char nc_scratcha1; -/*36*/ u_char nc_scratcha2; -/*37*/ u_char nc_scratcha3; - -/*38*/ u_char nc_dmode; - #define BL_2 0x80 /* mod: burst length shift value +2 */ - #define BL_1 0x40 /* mod: burst length shift value +1 */ - #define ERL 0x08 /* mod: enable read line */ - #define ERMP 0x04 /* mod: enable read multiple */ - #define BOF 0x02 /* mod: burst op code fetch */ - -/*39*/ u_char nc_dien; -/*3a*/ u_char nc_dwt; - -/*3b*/ u_char nc_dcntl; /* --> Script execution control */ - - #define CLSE 0x80 /* mod: cache line size enable */ - #define PFF 0x40 /* cmd: pre-fetch flush */ - #define PFEN 0x20 /* mod: pre-fetch enable */ - #define SSM 0x10 /* mod: single step mode */ - #define IRQM 0x08 /* mod: irq mode (1 = totem pole !) */ - #define STD 0x04 /* cmd: start dma mode */ - #define IRQD 0x02 /* mod: irq disable */ - #define NOCOM 0x01 /* cmd: protect sfbr while reselect */ - -/*3c*/ u_int32 nc_adder; - -/*40*/ u_short nc_sien; /* -->: interrupt enable */ -/*42*/ u_short nc_sist; /* <--: interrupt status */ - #define SBMC 0x1000/* sta: SCSI Bus Mode Change (895/6 only) */ - #define STO 0x0400/* sta: timeout (select) */ - #define GEN 0x0200/* sta: timeout (general) */ - #define HTH 0x0100/* sta: timeout (handshake) */ - #define MA 0x80 /* sta: phase mismatch */ - #define CMP 0x40 /* sta: arbitration complete */ - #define SEL 0x20 /* sta: selected by another device */ - #define RSL 0x10 /* sta: reselected by another device*/ - #define SGE 0x08 /* sta: gross error (over/underflow)*/ - #define UDC 0x04 /* sta: unexpected disconnect */ - #define RST 0x02 /* sta: scsi bus reset detected */ - #define PAR 0x01 /* sta: scsi parity error */ - -/*44*/ u_char nc_slpar; -/*45*/ u_char nc_swide; -/*46*/ u_char nc_macntl; -/*47*/ u_char nc_gpcntl; -/*48*/ u_char nc_stime0; /* cmd: timeout for select&handshake*/ -/*49*/ u_char nc_stime1; /* cmd: timeout user defined */ -/*4a*/ u_short nc_respid; /* sta: Reselect-IDs */ - -/*4c*/ u_char nc_stest0; - -/*4d*/ u_char nc_stest1; - #define DBLEN 0x08 /* clock doubler running */ - #define DBLSEL 0x04 /* clock doubler selected */ - - -/*4e*/ u_char nc_stest2; - #define ROF 0x40 /* reset scsi offset (after gross error!) */ - #define EXT 0x02 /* extended filtering */ - -/*4f*/ u_char nc_stest3; - #define TE 0x80 /* c: tolerAnt enable */ - #define HSC 0x20 /* c: Halt SCSI Clock */ - #define CSF 0x02 /* c: clear scsi fifo */ - -/*50*/ u_short nc_sidl; /* Lowlevel: latched from scsi data */ -/*52*/ u_char nc_stest4; - #define SMODE 0xc0 /* SCSI bus mode (895/6 only) */ - #define SMODE_HVD 0x40 /* High Voltage Differential */ - #define SMODE_SE 0x80 /* Single Ended */ - #define SMODE_LVD 0xc0 /* Low Voltage Differential */ - #define LCKFRQ 0x20 /* Frequency Lock (895/6 only) */ - -/*53*/ u_char nc_53_; -/*54*/ u_short nc_sodl; /* Lowlevel: data out to scsi data */ -/*56*/ u_char nc_ccntl0; /* Chip Control 0 (896) */ - #define ENPMJ 0x80 /* Enable Phase Mismatch Jump */ - #define PMJCTL 0x40 /* Phase Mismatch Jump Control */ - #define ENNDJ 0x20 /* Enable Non Data PM Jump */ - #define DISFC 0x10 /* Disable Auto FIFO Clear */ - #define DILS 0x02 /* Disable Internal Load/Store */ - #define DPR 0x01 /* Disable Pipe Req */ - -/*57*/ u_char nc_ccntl1; /* Chip Control 1 (896) */ - #define ZMOD 0x80 /* High Impedance Mode */ - #define DDAC 0x08 /* Disable Dual Address Cycle */ - #define XTIMOD 0x04 /* 64-bit Table Ind. Indexing Mode */ - #define EXTIBMV 0x02 /* Enable 64-bit Table Ind. BMOV */ - #define EXDBMV 0x01 /* Enable 64-bit Direct BMOV */ -/*58*/ u_short nc_sbdl; /* Lowlevel: data from scsi data */ -/*5a*/ u_short nc_5a_; -/*5c*/ u_char nc_scr0; /* Working register B */ -/*5d*/ u_char nc_scr1; /* */ -/*5e*/ u_char nc_scr2; /* */ -/*5f*/ u_char nc_scr3; /* */ -/*60*/ -}; - -/*----------------------------------------------------------- -** -** Utility macros for the script. -** -**----------------------------------------------------------- -*/ - -#define REGJ(p,r) (offsetof(struct ncr_reg, p ## r)) -#define REG(r) REGJ (nc_, r) - -#ifndef TARGET_MODE -#define TARGET_MODE 0 -#endif - -typedef u_int32 ncrcmd; - -/*----------------------------------------------------------- -** -** SCSI phases -** -**----------------------------------------------------------- -*/ - -#define SCR_DATA_OUT 0x00000000 -#define SCR_DATA_IN 0x01000000 -#define SCR_COMMAND 0x02000000 -#define SCR_STATUS 0x03000000 -#define SCR_ILG_OUT 0x04000000 -#define SCR_ILG_IN 0x05000000 -#define SCR_MSG_OUT 0x06000000 -#define SCR_MSG_IN 0x07000000 - -/*----------------------------------------------------------- -** -** Data transfer via SCSI. -** -**----------------------------------------------------------- -** -** MOVE_ABS (LEN) -** <> -** -** MOVE_IND (LEN) -** <> -** -** MOVE_TBL -** <> -** -**----------------------------------------------------------- -*/ - -#define SCR_MOVE_ABS(l) ((0x08000000 ^ (TARGET_MODE << 1ul)) | (l)) -#define SCR_MOVE_IND(l) ((0x28000000 ^ (TARGET_MODE << 1ul)) | (l)) -#define SCR_MOVE_TBL (0x18000000 ^ (TARGET_MODE << 1ul)) - -struct scr_tblmove { - u_int32 size; - u_int32 addr; -}; - -/*----------------------------------------------------------- -** -** Selection -** -**----------------------------------------------------------- -** -** SEL_ABS | SCR_ID (0..7) [ | REL_JMP] -** <> -** -** SEL_TBL | << dnad_offset>> [ | REL_JMP] -** <> -** -**----------------------------------------------------------- -*/ - -#define SCR_SEL_ABS 0x40000000 -#define SCR_SEL_ABS_ATN 0x41000000 -#define SCR_SEL_TBL 0x42000000 -#define SCR_SEL_TBL_ATN 0x43000000 - -struct scr_tblsel { - u_char sel_0; - u_char sel_sxfer; - u_char sel_id; - u_char sel_scntl3; -}; - -#define SCR_JMP_REL 0x04000000 -#define SCR_ID(id) (((u_int32)(id)) << 16) - -/*----------------------------------------------------------- -** -** Waiting for Disconnect or Reselect -** -**----------------------------------------------------------- -** -** WAIT_DISC -** dummy: <> -** -** WAIT_RESEL -** <> -** -**----------------------------------------------------------- -*/ - -#define SCR_WAIT_DISC 0x48000000 -#define SCR_WAIT_RESEL 0x50000000 - -/*----------------------------------------------------------- -** -** Bit Set / Reset -** -**----------------------------------------------------------- -** -** SET (flags {|.. }) -** -** CLR (flags {|.. }) -** -**----------------------------------------------------------- -*/ - -#define SCR_SET(f) (0x58000000 | (f)) -#define SCR_CLR(f) (0x60000000 | (f)) - -#define SCR_CARRY 0x00000400 -#define SCR_TRG 0x00000200 -#define SCR_ACK 0x00000040 -#define SCR_ATN 0x00000008 - - - - -/*----------------------------------------------------------- -** -** Memory to memory move -** -**----------------------------------------------------------- -** -** COPY (bytecount) -** << source_address >> -** << destination_address >> -** -** SCR_COPY sets the NO FLUSH option by default. -** SCR_COPY_F does not set this option. -** -** For chips which do not support this option, -** ncr_copy_and_bind() will remove this bit. -**----------------------------------------------------------- -*/ - -#define SCR_NO_FLUSH 0x01000000 - -#define SCR_COPY(n) (0xc0000000 | SCR_NO_FLUSH | (n)) -#define SCR_COPY_F(n) (0xc0000000 | (n)) - -/*----------------------------------------------------------- -** -** Register move and binary operations -** -**----------------------------------------------------------- -** -** SFBR_REG (reg, op, data) reg = SFBR op data -** << 0 >> -** -** REG_SFBR (reg, op, data) SFBR = reg op data -** << 0 >> -** -** REG_REG (reg, op, data) reg = reg op data -** << 0 >> -** -**----------------------------------------------------------- -*/ - -#define SCR_REG_OFS(ofs) ((ofs) << 16ul) - -#define SCR_SFBR_REG(reg,op,data) \ - (0x68000000 | (SCR_REG_OFS(REG(reg))) | (op) | ((data)<<8ul)) - -#define SCR_REG_SFBR(reg,op,data) \ - (0x70000000 | (SCR_REG_OFS(REG(reg))) | (op) | ((data)<<8ul)) - -#define SCR_REG_REG(reg,op,data) \ - (0x78000000 | (SCR_REG_OFS(REG(reg))) | (op) | ((data)<<8ul)) - - -#define SCR_LOAD 0x00000000 -#define SCR_SHL 0x01000000 -#define SCR_OR 0x02000000 -#define SCR_XOR 0x03000000 -#define SCR_AND 0x04000000 -#define SCR_SHR 0x05000000 -#define SCR_ADD 0x06000000 -#define SCR_ADDC 0x07000000 - -/*----------------------------------------------------------- -** -** FROM_REG (reg) SFBR = reg -** << 0 >> -** -** TO_REG (reg) reg = SFBR -** << 0 >> -** -** LOAD_REG (reg, data) reg = -** << 0 >> -** -** LOAD_SFBR(data) SFBR = -** << 0 >> -** -**----------------------------------------------------------- -*/ - -#define SCR_FROM_REG(reg) \ - SCR_REG_SFBR(reg,SCR_OR,0) - -#define SCR_TO_REG(reg) \ - SCR_SFBR_REG(reg,SCR_OR,0) - -#define SCR_LOAD_REG(reg,data) \ - SCR_REG_REG(reg,SCR_LOAD,data) - -#define SCR_LOAD_SFBR(data) \ - (SCR_REG_SFBR (gpreg, SCR_LOAD, data)) - -/*----------------------------------------------------------- -** -** LOAD from memory to register. -** STORE from register to memory. -** -**----------------------------------------------------------- -** -** LOAD_ABS (LEN) -** <> -** -** LOAD_REL (LEN) (DSA relative) -** <> -** -**----------------------------------------------------------- -*/ - -#define SCR_NO_FLUSH2 0x02000000 -#define SCR_DSA_REL2 0x10000000 - -#define SCR_LOAD_R(reg, how, n) \ - (0xe1000000 | how | (SCR_REG_OFS(REG(reg))) | (n)) - -#define SCR_STORE_R(reg, how, n) \ - (0xe0000000 | how | (SCR_REG_OFS(REG(reg))) | (n)) - -#define SCR_LOAD_ABS(reg, n) SCR_LOAD_R(reg, SCR_NO_FLUSH2, n) -#define SCR_LOAD_REL(reg, n) SCR_LOAD_R(reg, SCR_NO_FLUSH2|SCR_DSA_REL2, n) -#define SCR_LOAD_ABS_F(reg, n) SCR_LOAD_R(reg, 0, n) -#define SCR_LOAD_REL_F(reg, n) SCR_LOAD_R(reg, SCR_DSA_REL2, n) - -#define SCR_STORE_ABS(reg, n) SCR_STORE_R(reg, SCR_NO_FLUSH2, n) -#define SCR_STORE_REL(reg, n) SCR_STORE_R(reg, SCR_NO_FLUSH2|SCR_DSA_REL2,n) -#define SCR_STORE_ABS_F(reg, n) SCR_STORE_R(reg, 0, n) -#define SCR_STORE_REL_F(reg, n) SCR_STORE_R(reg, SCR_DSA_REL2, n) - - -/*----------------------------------------------------------- -** -** Waiting for Disconnect or Reselect -** -**----------------------------------------------------------- -** -** JUMP [ | IFTRUE/IFFALSE ( ... ) ] -** <
> -** -** JUMPR [ | IFTRUE/IFFALSE ( ... ) ] -** <> -** -** CALL [ | IFTRUE/IFFALSE ( ... ) ] -** <
> -** -** CALLR [ | IFTRUE/IFFALSE ( ... ) ] -** <> -** -** RETURN [ | IFTRUE/IFFALSE ( ... ) ] -** <> -** -** INT [ | IFTRUE/IFFALSE ( ... ) ] -** <> -** -** INT_FLY [ | IFTRUE/IFFALSE ( ... ) ] -** <> -** -** Conditions: -** WHEN (phase) -** IF (phase) -** CARRY -** DATA (data, mask) -** -**----------------------------------------------------------- -*/ - -#define SCR_NO_OP 0x80000000 -#define SCR_JUMP 0x80080000 -#define SCR_JUMPR 0x80880000 -#define SCR_CALL 0x88080000 -#define SCR_CALLR 0x88880000 -#define SCR_RETURN 0x90080000 -#define SCR_INT 0x98080000 -#define SCR_INT_FLY 0x98180000 - -#define IFFALSE(arg) (0x00080000 | (arg)) -#define IFTRUE(arg) (0x00000000 | (arg)) - -#define WHEN(phase) (0x00030000 | (phase)) -#define IF(phase) (0x00020000 | (phase)) - -#define DATA(D) (0x00040000 | ((D) & 0xff)) -#define MASK(D,M) (0x00040000 | (((M ^ 0xff) & 0xff) << 8ul)|((D) & 0xff)) - -#define CARRYSET (0x00200000) - -/*----------------------------------------------------------- -** -** SCSI constants. -** -**----------------------------------------------------------- -*/ - -/* -** Messages -*/ - -#define M_COMPLETE (0x00) -#define M_EXTENDED (0x01) -#define M_SAVE_DP (0x02) -#define M_RESTORE_DP (0x03) -#define M_DISCONNECT (0x04) -#define M_ID_ERROR (0x05) -#define M_ABORT (0x06) -#define M_REJECT (0x07) -#define M_NOOP (0x08) -#define M_PARITY (0x09) -#define M_LCOMPLETE (0x0a) -#define M_FCOMPLETE (0x0b) -#define M_RESET (0x0c) -#define M_ABORT_TAG (0x0d) -#define M_CLEAR_QUEUE (0x0e) -#define M_INIT_REC (0x0f) -#define M_REL_REC (0x10) -#define M_TERMINATE (0x11) -#define M_SIMPLE_TAG (0x20) -#define M_HEAD_TAG (0x21) -#define M_ORDERED_TAG (0x22) -#define M_IGN_RESIDUE (0x23) -#define M_IDENTIFY (0x80) - -#define M_X_MODIFY_DP (0x00) -#define M_X_SYNC_REQ (0x01) -#define M_X_WIDE_REQ (0x03) - -/* -** Status -*/ - -#define S_GOOD (0x00) -#define S_CHECK_COND (0x02) -#define S_COND_MET (0x04) -#define S_BUSY (0x08) -#define S_INT (0x10) -#define S_INT_COND_MET (0x14) -#define S_CONFLICT (0x18) -#define S_TERMINATED (0x20) -#define S_QUEUE_FULL (0x28) -#define S_ILLEGAL (0xff) -#define S_SENSE (0x80) - -/* - * End of ncrreg from FreeBSD - */ - -#endif /* !defined HOSTS_C */ - -#endif /* defined NCR53C8XX_H */ +#endif /* NCR53C8XX_H */ diff -ur --new-file old/linux/drivers/scsi/pci2000.c new/linux/drivers/scsi/pci2000.c --- old/linux/drivers/scsi/pci2000.c Wed Sep 9 17:56:58 1998 +++ new/linux/drivers/scsi/pci2000.c Tue Apr 13 16:54:02 1999 @@ -1,26 +1,36 @@ -/*+M************************************************************************* - * Perceptive Solutions, Inc. PCI-2000 device driver proc support for Linux. +/**************************************************************************** + * Perceptive Solutions, Inc. PCI-2000 device driver for Linux. * - * Copyright (c) 1997 Perceptive Solutions, Inc. + * pci2000.c - Linux Host Driver for PCI-2000 IntelliCache SCSI Adapters * - * 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. + * Copyright (c) 1997-1999 Perceptive Solutions, Inc. + * All Rights Reserved. * - * 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. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that redistributions of source + * code retain the above copyright notice and this comment without + * modification. * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * Technical updates and product information at: + * http://www.psidisk.com * + * Please send questions, comments, bug reports to: + * tech@psidisk.com Technical Support * - * File Name: pci2000i.c * - *-M*************************************************************************/ + * Revisions 1.10 Jan-21-1999 + * - Fixed sign on message to reflect proper controller name. + * - Added support for RAID status monitoring and control. + * + * Revisions 1.11 Mar-22-1999 + * - Fixed control timeout to not lock up the entire system if + * controller goes offline completely. + * + * Revisions 1.12 Mar-26-1999 + * - Fixed spinlock and PCI configuration. + * + ****************************************************************************/ +#define PCI2000_VERSION "1.12" #include @@ -34,16 +44,21 @@ #include #include #include -#include #include #include #include "scsi.h" #include "hosts.h" +#include #include "pci2000.h" #include "psi_roy.h" -#include +#if LINUX_VERSION_CODE >= LINUXVERSION(2,1,95) +#include +#endif +#if LINUX_VERSION_CODE < LINUXVERSION(2,1,93) +#include +#endif struct proc_dir_entry Proc_Scsi_Pci2000 = { PROC_SCSI_PCI2000, 7, "pci2000", S_IFDIR | S_IRUGO | S_IXUGO, 2 }; @@ -81,6 +96,7 @@ USHORT mb4; USHORT cmd; USHORT tag; + ULONG irqOwned; DEV2000 dev[MAX_BUS][MAX_UNITS]; } ADAPTER2000, *PADAPTER2000; @@ -89,7 +105,6 @@ static struct Scsi_Host *PsiHost[MAXADAPTER] = {NULL,}; // One for each adapter static int NumAdapters = 0; - /**************************************************************** * Name: WaitReady :LOCAL * @@ -102,13 +117,14 @@ ****************************************************************/ static int WaitReady (PADAPTER2000 padapter) { - ULONG timer; + ULONG z; - timer = jiffies + TIMEOUT_COMMAND; // calculate the timeout value - do { + for ( z = 0; z < (TIMEOUT_COMMAND * 4); z++ ) + { if ( !inb_p (padapter->cmd) ) return FALSE; - } while ( timer > jiffies ); // test for timeout + udelay (250); + }; return TRUE; } /**************************************************************** @@ -180,6 +196,26 @@ outl (SCpnt->request_bufflen, padapter->mb3); return TRUE; } +/********************************************************************* + * Name: PsiRaidCmd + * + * Description: Execute a simple command. + * + * Parameters: padapter - Pointer to adapter control structure. + * cmd - Roy command byte. + * + * Returns: Return error status. + * + ********************************************************************/ +static int PsiRaidCmd (PADAPTER2000 padapter, char cmd) + { + if ( WaitReady (padapter) ) // test for command register ready + return DID_TIME_OUT; + outb_p (cmd, padapter->cmd); // issue command + if ( WaitReady (padapter) ) // wait for adapter ready + return DID_TIME_OUT; + return DID_OK; + } /**************************************************************** * Name: Irq_Handler :LOCAL * @@ -204,6 +240,23 @@ int pun; int bus; int z; +#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95) + int flags; +#else /* version >= v2.1.95 */ + unsigned long flags; +#endif /* version >= v2.1.95 */ + +#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95) + /* Disable interrupts, if they aren't already disabled. */ + save_flags (flags); + cli (); +#else /* version >= v2.1.95 */ + /* + * Disable interrupts, if they aren't already disabled and acquire + * the I/O spinlock. + */ + spin_lock_irqsave (&io_request_lock, flags); +#endif /* version >= v2.1.95 */ DEB(printk ("\npci2000 recieved interrupt ")); for ( z = 0; z < NumAdapters; z++ ) // scan for interrupt to process @@ -222,7 +275,7 @@ if ( !shost ) { DEB (printk ("\npci2000: not my interrupt")); - return; + goto irq_return; } padapter = HOSTDATA(shost); @@ -246,7 +299,7 @@ outb_p (0xFF, padapter->tag); // clear the op interrupt outb_p (CMD_DONE, padapter->cmd); // complete the op - return; // done, but, with what? + goto irq_return;; // done, but, with what? irqProceed:; if ( tag & ERR08_TAGGED ) // is there an error here? @@ -254,7 +307,7 @@ if ( WaitReady (padapter) ) { OpDone (SCpnt, DID_TIME_OUT << 16); - return; + goto irq_return;; } outb_p (tag0, padapter->mb0); // get real error code @@ -262,7 +315,7 @@ if ( WaitReady (padapter) ) // wait for controller to suck up the op { OpDone (SCpnt, DID_TIME_OUT << 16); - return; + goto irq_return;; } error = inl (padapter->mb0); // get error data @@ -275,24 +328,40 @@ if ( bus ) // are we doint SCSI commands? { OpDone (SCpnt, (DID_OK << 16) | 2); - return; + goto irq_return;; } if ( *SCpnt->cmnd == SCSIOP_TEST_UNIT_READY ) OpDone (SCpnt, (DRIVER_SENSE << 24) | (DID_OK << 16) | 2); // test caller we have sense data too else OpDone (SCpnt, DID_ERROR << 16); - return; + goto irq_return;; } OpDone (SCpnt, DID_ERROR << 16); - return; + goto irq_return;; } outb_p (0xFF, padapter->tag); // clear the op interrupt outb_p (CMD_DONE, padapter->cmd); // complete the op OpDone (SCpnt, DID_OK << 16); + +irq_return:; +#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95) + /* + * Restore the original flags which will enable interrupts + * if and only if they were enabled on entry. + */ + restore_flags (flags); +#else /* version >= v2.1.95 */ + /* + * Release the I/O spinlock and restore the original flags + * which will enable interrupts if and only if they were + * enabled on entry. + */ + spin_unlock_irqrestore (&io_request_lock, flags); +#endif /* version >= v2.1.95 */ } /**************************************************************** - * Name: Pci2220i_QueueCommand + * Name: Pci2000_QueueCommand * * Description: Process a queued command from the SCSI manager. * @@ -366,7 +435,35 @@ switch ( *cdb ) { case SCSIOP_INQUIRY: // inquiry CDB - { + if ( cdb[2] == SC_MY_RAID ) + { + switch ( cdb[3] ) + { + case MY_SCSI_REBUILD: + OpDone (SCpnt, PsiRaidCmd (padapter, CMD_RAID_REBUILD) << 16); + return 0; + case MY_SCSI_ALARMMUTE: + OpDone (SCpnt, PsiRaidCmd (padapter, CMD_RAID_MUTE) << 16); + return 0; + case MY_SCSI_DEMOFAIL: + OpDone (SCpnt, PsiRaidCmd (padapter, CMD_RAID_FAIL) << 16); + return 0; + default: + if ( SCpnt->use_sg ) + { + rc = DID_ERROR; + goto finished; + } + else + outl (virt_to_bus (SCpnt->request_buffer), padapter->mb2); + outl (cdb[5], padapter->mb0); + outl (cdb[3], padapter->mb3); + cmd = CMD_DASD_RAID_RQ; + break; + } + break; + } + if ( SCpnt->use_sg ) { outl (virt_to_bus (((struct scatterlist *)(SCpnt->request_buffer))->address), padapter->mb2); @@ -378,7 +475,6 @@ outl (SCpnt->request_bufflen, padapter->mb3); cmd = CMD_DASD_SCSI_INQ; break; - } case SCSIOP_TEST_UNIT_READY: // test unit ready CDB outl (virt_to_bus (SCpnt->sense_buffer), padapter->mb2); @@ -454,7 +550,7 @@ if ( cmd ) break; default: - DEB (printk ("pci2220i_queuecommand: Unsupported command %02X\n", *cdb)); + DEB (printk ("pci2000_queuecommand: Unsupported command %02X\n", *cdb)); OpDone (SCpnt, DID_ERROR << 16); return 0; } @@ -466,14 +562,6 @@ OpDone (SCpnt, rc << 16); return 0; } -static void do_Irq_Handler (int irq, void *dev_id, struct pt_regs *regs) - { - unsigned long flags; - - spin_lock_irqsave(&io_request_lock, flags); - Irq_Handler(irq, dev_id, regs); - spin_unlock_irqrestore(&io_request_lock, flags); - } /**************************************************************** * Name: internal_done :LOCAL * @@ -489,7 +577,7 @@ SCpnt->SCp.Status++; } /**************************************************************** - * Name: Pci2220i_Command + * Name: Pci2000_Command * * Description: Process a command from the SCSI manager. * @@ -510,79 +598,121 @@ return SCpnt->result; } /**************************************************************** - * Name: Pci2220i_Detect + * Name: Pci2000_Detect * * Description: Detect and initialize our boards. * * Parameters: tpnt - Pointer to SCSI host template structure. * - * Returns: Number of adapters found. + * Returns: Number of adapters installed. * ****************************************************************/ int Pci2000_Detect (Scsi_Host_Template *tpnt) { - int pci_index = 0; + int found = 0; + int installed = 0; struct Scsi_Host *pshost; PADAPTER2000 padapter; - int z; + int z, zz; int setirq; +#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92) struct pci_dev *pdev = NULL; +#else + UCHAR pci_bus, pci_device_fn; +#endif - if ( pci_present () ) - while ((pdev = pci_find_device(VENDOR_PSI, DEVICE_ROY_1, pdev))) - { - pshost = scsi_register (tpnt, sizeof(ADAPTER2000)); - padapter = HOSTDATA(pshost); +#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92) + if ( !pci_present () ) +#else + if ( !pcibios_present () ) +#endif + { + printk ("pci2000: PCI BIOS not present\n"); + return 0; + } - padapter->basePort = pdev->base_address[1] & PCI_BASE_ADDRESS_IO_MASK; - DEB (printk ("\nBase Regs = %#04X", padapter->basePort)); // get the base I/O port address - padapter->mb0 = padapter->basePort + RTR_MAILBOX; // get the 32 bit mail boxes - padapter->mb1 = padapter->basePort + RTR_MAILBOX + 4; - padapter->mb2 = padapter->basePort + RTR_MAILBOX + 8; - padapter->mb3 = padapter->basePort + RTR_MAILBOX + 12; - padapter->mb4 = padapter->basePort + RTR_MAILBOX + 16; - padapter->cmd = padapter->basePort + RTR_LOCAL_DOORBELL; // command register - padapter->tag = padapter->basePort + RTR_PCI_DOORBELL; // tag/response register - - if ( WaitReady (padapter) ) - goto unregister; - outb_p (0x84, padapter->mb0); - outb_p (CMD_SPECIFY, padapter->cmd); - if ( WaitReady (padapter) ) - goto unregister; - - pshost->irq = pdev->irq; - setirq = 1; - for ( z = 0; z < pci_index; z++ ) // scan for shared interrupts - { - if ( PsiHost[z]->irq == pshost->irq ) // if shared then, don't posses - setirq = 0; - } - if ( setirq ) // if not shared, posses +#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92) + while ( (pdev = pci_find_device (VENDOR_PSI, DEVICE_ROY_1, pdev)) != NULL ) +#else + while ( !pcibios_find_device (VENDOR_PSI, DEVICE_ROY_1, found, &pci_bus, &pci_device_fn) ) +#endif + { + pshost = scsi_register (tpnt, sizeof(ADAPTER2000)); + padapter = HOSTDATA(pshost); + +#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92) + padapter->basePort = pdev->base_address[1] & 0xFFFE; +#else + pcibios_read_config_word (pci_bus, pci_device_fn, PCI_BASE_ADDRESS_1, &padapter->basePort); + padapter->basePort &= 0xFFFE; +#endif + DEB (printk ("\nBase Regs = %#04X", padapter->basePort)); // get the base I/O port address + padapter->mb0 = padapter->basePort + RTR_MAILBOX; // get the 32 bit mail boxes + padapter->mb1 = padapter->basePort + RTR_MAILBOX + 4; + padapter->mb2 = padapter->basePort + RTR_MAILBOX + 8; + padapter->mb3 = padapter->basePort + RTR_MAILBOX + 12; + padapter->mb4 = padapter->basePort + RTR_MAILBOX + 16; + padapter->cmd = padapter->basePort + RTR_LOCAL_DOORBELL; // command register + padapter->tag = padapter->basePort + RTR_PCI_DOORBELL; // tag/response register + + if ( WaitReady (padapter) ) + goto unregister; + outb_p (0x84, padapter->mb0); + outb_p (CMD_SPECIFY, padapter->cmd); + if ( WaitReady (padapter) ) + goto unregister; + +#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92) + pshost->irq = pdev->irq; +#else + pcibios_read_config_byte (pci_bus, pci_device_fn, PCI_INTERRUPT_LINE, &pshost->irq); +#endif + setirq = 1; + padapter->irqOwned = 0; + for ( z = 0; z < installed; z++ ) // scan for shared interrupts + { + if ( PsiHost[z]->irq == pshost->irq ) // if shared then, don't posses + setirq = 0; + } + if ( setirq ) // if not shared, posses + { + if ( request_irq (pshost->irq, Irq_Handler, SA_SHIRQ, "pci2000", padapter) < 0 ) { - if ( request_irq (pshost->irq, do_Irq_Handler, 0, "pci2000", NULL) ) + if ( request_irq (pshost->irq, Irq_Handler, SA_INTERRUPT | SA_SHIRQ, "pci2000", padapter) < 0 ) { - printk ("Unable to allocate IRQ for PSI-2000 controller.\n"); + printk ("Unable to allocate IRQ for PCI-2000 controller.\n"); goto unregister; } } - PsiHost[pci_index] = pshost; // save SCSI_HOST pointer + padapter->irqOwned = pshost->irq; // set IRQ as owned + } + PsiHost[installed] = pshost; // save SCSI_HOST pointer - pshost->unique_id = padapter->basePort; - pshost->max_id = 16; - pshost->max_channel = 1; - - printk("\nPSI-2000 EIDE CONTROLLER: at I/O = %X IRQ = %d\n", padapter->basePort, pshost->irq); - printk("(C) 1997 Perceptive Solutions, Inc. All rights reserved\n\n"); - NumAdapters++; + pshost->io_port = padapter->basePort; + pshost->n_io_port = 0xFF; + pshost->unique_id = padapter->basePort; + pshost->max_id = 16; + pshost->max_channel = 1; + + for ( zz = 0; zz < MAX_BUS; zz++ ) + for ( z = 0; z < MAX_UNITS; z++ ) + padapter->dev[zz][z].tag = 0; + + printk("\nPSI-2000 Intelligent Storage SCSI CONTROLLER: at I/O = %X IRQ = %d\n", padapter->basePort, pshost->irq); + printk("Version %s, Compiled %s %s\n\n", PCI2000_VERSION, __DATE__, __TIME__); + found++; + if ( ++installed < MAXADAPTER ) continue; + break; unregister:; - scsi_unregister (pshost); - } - return NumAdapters; + scsi_unregister (pshost); + found++; + } + NumAdapters = installed; + return installed; } /**************************************************************** - * Name: Pci2220i_Abort + * Name: Pci2000_Abort * * Description: Process the Abort command from the SCSI manager. * @@ -597,7 +727,7 @@ return SCSI_ABORT_SNOOZE; } /**************************************************************** - * Name: Pci2220i_Reset + * Name: Pci2000_Reset * * Description: Process the Reset command from the SCSI manager. * @@ -615,11 +745,34 @@ { return SCSI_RESET_PUNT; } +/**************************************************************** + * Name: Pci2000_Release + * + * Description: Release resources allocated for a single each adapter. + * + * Parameters: pshost - Pointer to SCSI command structure. + * + * Returns: zero. + * + ****************************************************************/ +int Pci2000_Release (struct Scsi_Host *pshost) + { + PADAPTER2000 padapter = HOSTDATA (pshost); + + if ( padapter->irqOwned ) +#if LINUX_VERSION_CODE < LINUXVERSION(1,3,70) + free_irq (pshost->irq); +#else /* version >= v1.3.70 */ + free_irq (pshost->irq, padapter); +#endif /* version >= v1.3.70 */ + release_region (pshost->io_port, pshost->n_io_port); + scsi_unregister(pshost); + return 0; + } #include "sd.h" - /**************************************************************** - * Name: Pci2220i_BiosParam + * Name: Pci2000_BiosParam * * Description: Process the biosparam request from the SCSI manager to * return C/H/S data. diff -ur --new-file old/linux/drivers/scsi/pci2000.h new/linux/drivers/scsi/pci2000.h --- old/linux/drivers/scsi/pci2000.h Mon Dec 28 07:19:21 1998 +++ new/linux/drivers/scsi/pci2000.h Tue May 11 19:36:37 1999 @@ -1,29 +1,23 @@ -/*+M************************************************************************* - * Perceptive Solutions, Inc. PCI-2000 device driver proc support for Linux. +/**************************************************************************** + * Perceptive Solutions, Inc. PCI-2000 device driver for Linux. * - * Copyright (c) 1997 Perceptive Solutions, Inc. + * pci2000.h - Linux Host Driver for PCI-2000 IntelliCache SCSI Adapters * - * 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. + * Copyright (c) 1997-1999 Perceptive Solutions, Inc. + * All Rights Reserved. * - * 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. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that redistributions of source + * code retain the above copyright notice and this comment without + * modification. * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * Technical updates and product information at: + * http://www.psidisk.com * + * Please send questions, comments, bug reports to: + * tech@psidisk.com Technical Support * - * File Name: pci2000.h - * - * Description: Header file for the SCSI driver for the PCI-2000 - * interface card. - * - *-M*************************************************************************/ + ****************************************************************************/ #ifndef _PCI2000_H #define _PCI2000_H @@ -33,6 +27,11 @@ #ifndef PSI_EIDE_SCSIOP #define PSI_EIDE_SCSIOP 1 +#ifndef LINUX_VERSION_CODE +#include +#endif +#define LINUXVERSION(v,p,s) (((v)<<16) + ((p)<<8) + (s)) + /************************************************/ /* definition of standard data types */ /************************************************/ @@ -194,6 +193,7 @@ int Pci2000_QueueCommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)); int Pci2000_Abort (Scsi_Cmnd *SCpnt); int Pci2000_Reset (Scsi_Cmnd *SCpnt, unsigned int flags); +int Pci2000_Release (struct Scsi_Host *pshost); int Pci2000_BiosParam (Disk *disk, kdev_t dev, int geom[]); #ifndef NULL @@ -202,18 +202,57 @@ extern struct proc_dir_entry Proc_Scsi_Pci2000; -#define PCI2000 { proc_dir: &Proc_Scsi_Pci2000,/* proc_dir_entry */ \ - name: "PCI-2000 SCSI Intelligent Disk Controller",\ - detect: Pci2000_Detect, \ - command: Pci2000_Command, \ - queuecommand: Pci2000_QueueCommand, \ - abort: Pci2000_Abort, \ - reset: Pci2000_Reset, \ - bios_param: Pci2000_BiosParam, \ - can_queue: 16, \ - this_id: -1, \ - sg_tablesize: 16, \ - cmd_per_lun: 1, \ - use_clustering: DISABLE_CLUSTERING } +#if LINUX_VERSION_CODE >= LINUXVERSION(2,1,75) +#define PCI2000 { \ + next: NULL, \ + module: NULL, \ + proc_dir: &Proc_Scsi_Pci2000, \ + proc_info: NULL, /* let's not bloat the kernel */ \ + name: "PCI-2000 SCSI Intelligent Disk Controller",\ + detect: Pci2000_Detect, \ + release: Pci2000_Release, \ + info: NULL, /* let's not bloat the kernel */ \ + command: Pci2000_Command, \ + queuecommand: Pci2000_QueueCommand, \ + eh_strategy_handler: NULL, \ + eh_abort_handler: NULL, \ + eh_device_reset_handler: NULL, \ + eh_bus_reset_handler: NULL, \ + eh_host_reset_handler: NULL, \ + abort: Pci2000_Abort, \ + reset: Pci2000_Reset, \ + slave_attach: NULL, \ + bios_param: Pci2000_BiosParam, \ + can_queue: 16, \ + this_id: -1, \ + sg_tablesize: 16, \ + cmd_per_lun: 1, \ + present: 0, \ + unchecked_isa_dma: 0, \ + use_clustering: DISABLE_CLUSTERING, \ + use_new_eh_code: 0 \ + } +#else +#define PCI2000 { NULL, NULL, \ + &Proc_Scsi_Pci2000,/* proc_dir_entry */ \ + NULL, \ + "PCI-2000 SCSI Intelligent Disk Controller",\ + Pci2000_Detect, \ + Pci2000_Release, \ + NULL, \ + Pci2000_Command, \ + Pci2000_QueueCommand, \ + Pci2000_Abort, \ + Pci2000_Reset, \ + NULL, \ + Pci2000_BiosParam, \ + 16, \ + -1, \ + 16, \ + 1, \ + 0, \ + 0, \ + DISABLE_CLUSTERING } +#endif #endif diff -ur --new-file old/linux/drivers/scsi/pci2220i.c new/linux/drivers/scsi/pci2220i.c --- old/linux/drivers/scsi/pci2220i.c Wed Sep 9 17:56:58 1998 +++ new/linux/drivers/scsi/pci2220i.c Tue Apr 13 16:54:02 1999 @@ -1,80 +1,83 @@ -/*+M************************************************************************* - * Perceptive Solutions, Inc. PCI-2000 device driver proc support for Linux. +/**************************************************************************** + * Perceptive Solutions, Inc. PCI-2220I device driver for Linux. * - * Copyright (c) 1997 Perceptive Solutions, Inc. + * pci2220i.c - Linux Host Driver for PCI-2220I EIDE RAID Adapters * - * 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. + * Copyright (c) 1997-1999 Perceptive Solutions, Inc. + * All Rights Reserved. * - * 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. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that redistributions of source + * code retain the above copyright notice and this comment without + * modification. * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * Technical updates and product information at: + * http://www.psidisk.com * + * Please send questions, comments, bug reports to: + * tech@psidisk.com Technical Support * - * File Name: pci2220i.c * - * Description: SCSI driver for the PCI2220I EIDE interface card. + * Revisions 1.10 Mar-26-1999 + * - Updated driver for RAID and hot reconstruct support. * - *-M*************************************************************************/ + * Revisions 1.11 Mar-26-1999 + * - Fixed spinlock and PCI configuration. + * + ****************************************************************************/ #include - #include #include #include +#include #include #include #include #include #include +#include +#include +#include +#include #include #include -#include #include -#include #include "scsi.h" #include "hosts.h" - #include "pci2220i.h" -#include "psi_dale.h" -#include +#if LINUX_VERSION_CODE >= LINUXVERSION(2,1,95) +#include +#endif +#if LINUX_VERSION_CODE < LINUXVERSION(2,1,93) +#include +#endif + +#define PCI2220I_VERSION "1.11" +//#define READ_CMD IDE_COMMAND_READ +//#define WRITE_CMD IDE_COMMAND_WRITE +//#define MAX_BUS_MASTER_BLOCKS 1 // This is the maximum we can bus master +#define READ_CMD IDE_CMD_READ_MULTIPLE +#define WRITE_CMD IDE_CMD_WRITE_MULTIPLE +#define MAX_BUS_MASTER_BLOCKS SECTORSXFER // This is the maximum we can bus master + struct proc_dir_entry Proc_Scsi_Pci2220i = - { PROC_SCSI_PCI2220I, 7, "pci2220i", S_IFDIR | S_IRUGO | S_IXUGO, 2 }; + { PROC_SCSI_PCI2220I, 8, "pci2220i", S_IFDIR | S_IRUGO | S_IXUGO, 2 }; //#define DEBUG 1 #ifdef DEBUG #define DEB(x) x -#define STOP_HERE {int st;for(st=0;st<100;st++){st=1;}} +#define STOP_HERE() {int st;for(st=0;st<100;st++){st=1;}} #else #define DEB(x) -#define STOP_HERE +#define STOP_HERE() #endif -#define MAXADAPTER 4 /* Increase this and the sizes of the arrays below, if you need more. */ - -#define MAX_BUS_MASTER_BLOCKS 1 // This is the maximum we can bus master for (1024 bytes) +#define MAXADAPTER 4 // Increase this and the sizes of the arrays below, if you need more. -#define PORT_DATA 0 -#define PORT_ERROR 1 -#define PORT_SECTOR_COUNT 2 -#define PORT_LBA_0 3 -#define PORT_LBA_8 4 -#define PORT_LBA_16 5 -#define PORT_LBA_24 6 -#define PORT_STAT_CMD 7 -#define PORT_STAT_SEL 8 -#define PORT_FAIL 9 -#define PORT_ALT_STAT 10 typedef struct { @@ -87,44 +90,245 @@ USHORT cylinders; // number of cylinders for this device USHORT spareword; // placeholder ULONG blocks; // number of blocks on device - } OUR_DEVICE, *POUR_DEVICE; + DISK_MIRROR DiskMirror[2]; // RAID status and control + ULONG lastsectorlba[2]; // last addressable sector on the drive + USHORT raid; // RAID active flag + USHORT mirrorRecon; + UCHAR hotRecon; + USHORT reconCount; + } OUR_DEVICE, *POUR_DEVICE; typedef struct { - USHORT ports[12]; - USHORT regDmaDesc; // address of the DMA discriptor register for direction of transfer - USHORT regDmaCmdStat; // Byte #1 of DMA command status register - USHORT regDmaAddrPci; // 32 bit register for PCI address of DMA - USHORT regDmaAddrLoc; // 32 bit register for local bus address of DMA - USHORT regDmaCount; // 32 bit register for DMA transfer count - USHORT regDmaMode; // 32 bit register for DMA mode control - USHORT regRemap; // 32 bit local space remap - USHORT regDesc; // 32 bit local region descriptor - USHORT regRange; // 32 bit local range - USHORT regIrqControl; // 16 bit Interrupt enable/disable and status - USHORT regScratchPad; // scratch pad I/O base address - USHORT regBase; // Base I/O register for data space - USHORT basePort; // PLX base I/O port - USHORT timingMode; // timing mode currently set for adapter - ULONG timingAddress; // address to use on adapter for current timing mode - OUR_DEVICE device[4]; - IDE_STRUCT ide; + USHORT regDmaDesc; // address of the DMA discriptor register for direction of transfer + USHORT regDmaCmdStat; // Byte #1 of DMA command status register + USHORT regDmaAddrPci; // 32 bit register for PCI address of DMA + USHORT regDmaAddrLoc; // 32 bit register for local bus address of DMA + USHORT regDmaCount; // 32 bit register for DMA transfer count + USHORT regDmaMode; // 32 bit register for DMA mode control + USHORT regRemap; // 32 bit local space remap + USHORT regDesc; // 32 bit local region descriptor + USHORT regRange; // 32 bit local range + USHORT regIrqControl; // 16 bit Interrupt enable/disable and status + USHORT regScratchPad; // scratch pad I/O base address + USHORT regBase; // Base I/O register for data space + USHORT regData; // data register I/O address + USHORT regError; // error register I/O address + USHORT regSectCount; // sector count register I/O address + USHORT regLba0; // least significant byte of LBA + USHORT regLba8; // next least significant byte of LBA + USHORT regLba16; // next most significan byte of LBA + USHORT regLba24; // head and most 4 significant bits of LBA + USHORT regStatCmd; // status on read and command on write register + USHORT regStatSel; // board status on read and spigot select on write register + USHORT regFail; // fail bits control register + USHORT regAltStat; // alternate status and drive control register + USHORT basePort; // PLX base I/O port + USHORT timingMode; // timing mode currently set for adapter + USHORT timingPIO; // TRUE if PIO timing is active + ULONG timingAddress; // address to use on adapter for current timing mode + ULONG irqOwned; // owned IRQ or zero if shared + OUR_DEVICE device[DALE_MAXDRIVES]; + DISK_MIRROR *raidData[8]; ULONG startSector; USHORT sectorCount; + UCHAR cmd; Scsi_Cmnd *SCpnt; VOID *buffer; + POUR_DEVICE pdev; // current device opearating on USHORT expectingIRQ; - USHORT readPhase; + USHORT reconIsStarting; // indicate hot reconstruct is starting + USHORT reconOn; // Hot reconstruct is to be done. + USHORT reconPhase; // Hot reconstruct operation is in progress. + ULONG reconSize; + USHORT demoFail; // flag for RAID failure demonstration + USHORT survivor; + USHORT failinprog; + struct timer_list reconTimer; + struct timer_list timer; + UCHAR *kBuffer; } ADAPTER2220I, *PADAPTER2220I; #define HOSTDATA(host) ((PADAPTER2220I)&host->hostdata) +#define RECON_PHASE_READY 0x01 +#define RECON_PHASE_COPY 0x02 +#define RECON_PHASE_UPDATE 0x03 +#define RECON_PHASE_LAST 0x04 +#define RECON_PHASE_END 0x07 +#define RECON_PHASE_MARKING 0x80 +#define RECON_PHASE_FAILOVER 0xFF static struct Scsi_Host *PsiHost[MAXADAPTER] = {NULL,}; // One for each adapter static int NumAdapters = 0; -static IDENTIFY_DATA identifyData; static SETUP DaleSetup; +static DISK_MIRROR DiskMirror[2]; +static ULONG ModeArray[] = {DALE_DATA_MODE2, DALE_DATA_MODE3, DALE_DATA_MODE4, DALE_DATA_MODE4P}; + +static void ReconTimerExpiry (unsigned long data); + +/**************************************************************** + * Name: MuteAlarm :LOCAL + * + * Description: Mute the audible alarm. + * + * Parameters: padapter - Pointer adapter data structure. + * + * Returns: TRUE if drive does not assert DRQ in time. + * + ****************************************************************/ +static void MuteAlarm (PADAPTER2220I padapter) + { + UCHAR old; + old = (inb_p (padapter->regStatSel) >> 3) | (inb_p (padapter->regStatSel) & 0x83); + outb_p (old | 0x40, padapter->regFail); + } +/**************************************************************** + * Name: WaitReady :LOCAL + * + * Description: Wait for device ready. + * + * Parameters: padapter - Pointer adapter data structure. + * + * Returns: TRUE if drive does not assert DRQ in time. + * + ****************************************************************/ +static int WaitReady (PADAPTER2220I padapter) + { + ULONG z; + UCHAR status; + + for ( z = 0; z < (TIMEOUT_READY * 4); z++ ) + { + status = inb_p (padapter->regStatCmd); + if ( (status & (IDE_STATUS_DRDY | IDE_STATUS_BUSY)) == IDE_STATUS_DRDY ) + return 0; + udelay (250); + } + return status; + } +/**************************************************************** + * Name: WaitReadyReset :LOCAL + * + * Description: Wait for device ready. + * + * Parameters: padapter - Pointer adapter data structure. + * + * Returns: TRUE if drive does not assert DRQ in time. + * + ****************************************************************/ +static int WaitReadyReset (PADAPTER2220I padapter) + { + ULONG z; + UCHAR status; + + for ( z = 0; z < (250 * 4); z++ ) // wait up to 1/4 second + { + status = inb_p (padapter->regStatCmd); + if ( (status & (IDE_STATUS_DRDY | IDE_STATUS_BUSY)) == IDE_STATUS_DRDY ) + { + DEB (printk ("\nPCI2220I: Reset took %ld mSec to be ready", z / 4)); + return 0; + } + udelay (250); + } + DEB (printk ("\nPCI2220I: Reset took more than 1 Second to come ready, Disk Failure")); + return status; + } +/**************************************************************** + * Name: WaitDrq :LOCAL + * + * Description: Wait for device ready for data transfer. + * + * Parameters: padapter - Pointer adapter data structure. + * + * Returns: TRUE if drive does not assert DRQ in time. + * + ****************************************************************/ +static int WaitDrq (PADAPTER2220I padapter) + { + ULONG z; + UCHAR status; + + for ( z = 0; z < (TIMEOUT_DRQ * 4); z++ ) + { + status = inb_p (padapter->regStatCmd); + if ( status & IDE_STATUS_DRQ ) + return 0; + udelay (250); + } + return status; + } +/**************************************************************** + * Name: HardReset :LOCAL + * + * Description: Wait for device ready for data transfer. + * + * Parameters: padapter - Pointer adapter data structure. + * pdev - Pointer to device. + * spigot - Spigot number. + * + * Returns: TRUE if drive does not assert DRQ in time. + * + ****************************************************************/ +static int HardReset (PADAPTER2220I padapter, POUR_DEVICE pdev, UCHAR spigot) + { + SelectSpigot (padapter, spigot | 0x80); + + outb_p (0x0E, padapter->regAltStat); // reset the suvivor + udelay (100); // wait a little + outb_p (0x08, padapter->regAltStat); // clear the reset + udelay (100); + outb_p (0xA0, padapter->regLba24); //Specify drive + + outb_p (pdev->byte6, padapter->regLba24); // select the drive + if ( WaitReadyReset (padapter) ) + return TRUE; + outb_p (SECTORSXFER, padapter->regSectCount); + WriteCommand (padapter, IDE_CMD_SET_MULTIPLE); + if ( WaitReady (padapter) ) + return TRUE; + return FALSE; + } +/**************************************************************** + * Name: BusMaster :LOCAL + * + * Description: Do a bus master I/O. + * + * Parameters: padapter - Pointer adapter data structure. + * datain - TRUE if data read. + * irq - TRUE if bus master interrupt expected. + * + * Returns: TRUE if drive does not assert DRQ in time. + * + ****************************************************************/ +static void BusMaster (PADAPTER2220I padapter, UCHAR datain, UCHAR irq) + { + ULONG zl; + + outl (padapter->timingAddress, padapter->regDmaAddrLoc); + outl (virt_to_bus (padapter->buffer), padapter->regDmaAddrPci); + zl = (padapter->sectorCount > MAX_BUS_MASTER_BLOCKS) ? MAX_BUS_MASTER_BLOCKS : padapter->sectorCount; + padapter->sectorCount -= zl; + zl *= (ULONG)BYTES_PER_SECTOR; + padapter->buffer += zl; + outl (zl, padapter->regDmaCount); + if ( datain ) + { + outb_p (8, padapter->regDmaDesc); // read operation + if ( irq && !padapter->sectorCount ) + outb_p (5, padapter->regDmaMode); // interrupt on + else + outb_p (1, padapter->regDmaMode); // no interrupt + } + else + { + outb_p (0, padapter->regDmaDesc); // write operation + outb_p (1, padapter->regDmaMode); // no interrupt + } + outb_p (0x03, padapter->regDmaCmdStat); // kick the DMA engine in gear + } /**************************************************************** * Name: WriteData :LOCAL * @@ -137,114 +341,265 @@ ****************************************************************/ static int WriteData (PADAPTER2220I padapter) { - ULONG timer; - USHORT *pports = padapter->ports; + ULONG zl; + + if ( !WaitDrq (padapter) ) + { + if ( padapter->timingPIO ) + { + zl = (padapter->sectorCount > MAX_BUS_MASTER_BLOCKS) ? MAX_BUS_MASTER_BLOCKS : padapter->sectorCount; + outsw (padapter->regData, padapter->buffer, zl * (BYTES_PER_SECTOR / 2)); + padapter->sectorCount -= zl; + padapter->buffer += zl * BYTES_PER_SECTOR; + } + else + BusMaster (padapter, 0, 0); + return 0; + } + padapter->cmd = 0; // null out the command byte + return 1; + } +/**************************************************************** + * Name: WriteDataBoth :LOCAL + * + * Description: Write data to device. + * + * Parameters: padapter - Pointer adapter data structure. + * + * Returns: TRUE if drive does not assert DRQ in time. + * + ****************************************************************/ +static int WriteDataBoth (PADAPTER2220I padapter) + { + ULONG zl; + UCHAR status0, status1; - timer = jiffies + TIMEOUT_DRQ; // calculate the timeout value - do { - if ( inb_p (pports[PORT_STAT_CMD]) & IDE_STATUS_DRQ ) - { - outb_p (0, padapter->regDmaDesc); // write operation - outl (padapter->timingAddress, padapter->regDmaAddrLoc); - outl (virt_to_bus (padapter->buffer), padapter->regDmaAddrPci); - outl ((ULONG)padapter->ide.ide.ide[2] * (ULONG)512, padapter->regDmaCount); - outb_p (1, padapter->regDmaMode); // interrupts off - outb_p (0x03, padapter->regDmaCmdStat); // kick the DMA engine in gear + SelectSpigot (padapter, 1); + status0 = WaitDrq (padapter); + if ( !status0 ) + { + SelectSpigot (padapter, 2); + status1 = WaitDrq (padapter); + if ( !status1 ) + { + SelectSpigot (padapter, 3); + if ( padapter->timingPIO ) + { + zl = (padapter->sectorCount > MAX_BUS_MASTER_BLOCKS) ? MAX_BUS_MASTER_BLOCKS : padapter->sectorCount; + outsw (padapter->regData, padapter->buffer, zl * (BYTES_PER_SECTOR / 2)); + padapter->sectorCount -= zl; + padapter->buffer += zl * BYTES_PER_SECTOR; + } + else + BusMaster (padapter, 0, 0); return 0; } - } while ( timer > jiffies ); // test for timeout - - padapter->ide.ide.ides.cmd = 0; // null out the command byte - return 1; + } + padapter->cmd = 0; // null out the command byte + if ( status0 ) + return 1; + return 2; } /**************************************************************** * Name: IdeCmd :LOCAL * - * Description: Process a queued command from the SCSI manager. + * Description: Process an IDE command. * * Parameters: padapter - Pointer adapter data structure. + * pdev - Pointer to device. * * Returns: Zero if no error or status register contents on error. * ****************************************************************/ -static UCHAR IdeCmd (PADAPTER2220I padapter) +static UCHAR IdeCmd (PADAPTER2220I padapter, POUR_DEVICE pdev) { - ULONG timer; - USHORT *pports = padapter->ports; UCHAR status; - outb_p (padapter->ide.ide.ides.spigot, pports[PORT_STAT_SEL]); // select the spigot - outb_p (padapter->ide.ide.ide[6], pports[PORT_LBA_24]); // select the drive - timer = jiffies + TIMEOUT_READY; // calculate the timeout value - DEB(printk ("\npci2220i Issueing new command: 0x%X",padapter->ide.ide.ides.cmd)); - do { - status = inb_p (padapter->ports[PORT_STAT_CMD]); - if ( status & IDE_STATUS_DRDY ) - { - outb_p (padapter->ide.ide.ide[2], pports[PORT_SECTOR_COUNT]); - outb_p (padapter->ide.ide.ide[3], pports[PORT_LBA_0]); - outb_p (padapter->ide.ide.ide[4], pports[PORT_LBA_8]); - outb_p (padapter->ide.ide.ide[5], pports[PORT_LBA_16]); - padapter->expectingIRQ = 1; - outb_p (padapter->ide.ide.ide[7], pports[PORT_STAT_CMD]); - - if ( padapter->ide.ide.ides.cmd == IDE_CMD_WRITE_MULTIPLE ) - return (WriteData (padapter)); - return 0; - } - } while ( timer > jiffies ); // test for timeout + SelectSpigot (padapter, pdev->spigot); // select the spigot + outb_p (pdev->byte6 | ((UCHAR *)(&padapter->startSector))[3], padapter->regLba24); // select the drive + status = WaitReady (padapter); + if ( !status ) + { + outb_p (padapter->sectorCount, padapter->regSectCount); + outb_p (((UCHAR *)(&padapter->startSector))[0], padapter->regLba0); + outb_p (((UCHAR *)(&padapter->startSector))[1], padapter->regLba8); + outb_p (((UCHAR *)(&padapter->startSector))[2], padapter->regLba16); + padapter->expectingIRQ = TRUE; + WriteCommand (padapter, padapter->cmd); + return 0; + } - padapter->ide.ide.ides.cmd = 0; // null out the command byte + padapter->cmd = 0; // null out the command byte return status; } /**************************************************************** - * Name: SetupTransfer :LOCAL + * Name: IdeCmdBoth :LOCAL * - * Description: Setup a data transfer command. + * Description: Process an IDE command to both drivers. * * Parameters: padapter - Pointer adapter data structure. - * drive - Drive/head register upper nibble only. * - * Returns: TRUE if no data to transfer. + * Returns: Zero if no error or spigot of error. * ****************************************************************/ -static int SetupTransfer (PADAPTER2220I padapter, UCHAR drive) +static UCHAR IdeCmdBoth (PADAPTER2220I padapter) { - if ( padapter->sectorCount ) + UCHAR status0; + UCHAR status1; + + SelectSpigot (padapter, 3); // select the spigots + outb_p (padapter->pdev->byte6 | ((UCHAR *)(&padapter->startSector))[3], padapter->regLba24);// select the drive + SelectSpigot (padapter, 1); + status0 = WaitReady (padapter); + if ( !status0 ) { - *(ULONG *)padapter->ide.ide.ides.lba = padapter->startSector; - padapter->ide.ide.ide[6] |= drive; -// padapter->ide.ide.ides.sectors = ( padapter->sectorCount > SECTORSXFER ) ? SECTORSXFER : padapter->sectorCount; - padapter->ide.ide.ides.sectors = ( padapter->sectorCount > MAX_BUS_MASTER_BLOCKS ) ? MAX_BUS_MASTER_BLOCKS : padapter->sectorCount; - padapter->sectorCount -= padapter->ide.ide.ides.sectors; // bump the start and count for next xfer - padapter->startSector += padapter->ide.ide.ides.sectors; - return 0; + SelectSpigot (padapter, 2); + status1 = WaitReady (padapter); + if ( !status1 ) + { + SelectSpigot (padapter, 3); + outb_p (padapter->sectorCount, padapter->regSectCount); + outb_p (((UCHAR *)(&padapter->startSector))[0], padapter->regLba0); + outb_p (((UCHAR *)(&padapter->startSector))[1], padapter->regLba8); + outb_p (((UCHAR *)(&padapter->startSector))[2], padapter->regLba16); + padapter->expectingIRQ = TRUE; + WriteCommand (padapter, padapter->cmd); + return 0; + } + } + padapter->cmd = 0; // null out the command byte + if ( status0 ) + return 1; + return 2; + } +/**************************************************************** + * Name: OpDone :LOCAL + * + * Description: Complete an operatoin done sequence. + * + * Parameters: padapter - Pointer to host data block. + * spigot - Spigot select code. + * device - Device byte code. + * + * Returns: Nothing. + * + ****************************************************************/ +static void OpDone (PADAPTER2220I padapter, ULONG result) + { + Scsi_Cmnd *SCpnt = padapter->SCpnt; + + if ( padapter->reconPhase ) + { + padapter->reconPhase = 0; + if ( padapter->SCpnt ) + { + Pci2220i_QueueCommand (SCpnt, SCpnt->scsi_done); + } + else + { + if ( padapter->reconOn ) + { + ReconTimerExpiry ((unsigned long)padapter); + } + } } else { - padapter->ide.ide.ides.cmd = 0; // null out the command byte - padapter->SCpnt = NULL; - return 1; + padapter->cmd = 0; + padapter->SCpnt = NULL; + SCpnt->result = result; + SCpnt->scsi_done (SCpnt); + if ( padapter->reconOn && !padapter->reconTimer.data ) + { + padapter->reconTimer.expires = jiffies + (HZ / 4); // start in 1/4 second + padapter->reconTimer.data = (unsigned long)padapter; + add_timer (&padapter->reconTimer); + } } } /**************************************************************** + * Name: InlineIdentify :LOCAL + * + * Description: Do an intline inquiry on a drive. + * + * Parameters: padapter - Pointer to host data block. + * spigot - Spigot select code. + * device - Device byte code. + * + * Returns: Last addressable sector or zero if none. + * + ****************************************************************/ +static ULONG InlineIdentify (PADAPTER2220I padapter, UCHAR spigot, UCHAR device) + { + PIDENTIFY_DATA pid = (PIDENTIFY_DATA)padapter->kBuffer; + + SelectSpigot (padapter, spigot | 0x80); // select the spigot + outb_p (device << 4, padapter->regLba24); // select the drive + if ( WaitReady (padapter) ) + return 0; + WriteCommand (padapter, IDE_COMMAND_IDENTIFY); + if ( WaitDrq (padapter) ) + return 0; + insw (padapter->regData, padapter->kBuffer, sizeof (IDENTIFY_DATA) >> 1); + return (pid->LBATotalSectors - 1); + } +/**************************************************************** + * Name: InlineReadSignature :LOCAL + * + * Description: Do an inline read RAID sigature. + * + * Parameters: padapter - Pointer adapter data structure. + * pdev - Pointer to device. + * index - index of data to read. + * + * Returns: Zero if no error or status register contents on error. + * + ****************************************************************/ +static UCHAR InlineReadSignature (PADAPTER2220I padapter, POUR_DEVICE pdev, int index) + { + UCHAR status; + UCHAR spigot = 1 << index; + ULONG zl = pdev->lastsectorlba[index]; + + SelectSpigot (padapter, spigot | 0x80); // select the spigot without interrupts + outb_p (pdev->byte6 | ((UCHAR *)&zl)[3], padapter->regLba24); + status = WaitReady (padapter); + if ( !status ) + { + outb_p (((UCHAR *)&zl)[2], padapter->regLba16); + outb_p (((UCHAR *)&zl)[1], padapter->regLba8); + outb_p (((UCHAR *)&zl)[0], padapter->regLba0); + outb_p (1, padapter->regSectCount); + WriteCommand (padapter, IDE_COMMAND_READ); + status = WaitDrq (padapter); + if ( !status ) + { + insw (padapter->regData, padapter->kBuffer, BYTES_PER_SECTOR / 2); + ((ULONG *)(&pdev->DiskMirror[index]))[0] = ((ULONG *)(&padapter->kBuffer[DISK_MIRROR_POSITION]))[0]; + ((ULONG *)(&pdev->DiskMirror[index]))[1] = ((ULONG *)(&padapter->kBuffer[DISK_MIRROR_POSITION]))[1]; + // some drives assert DRQ before IRQ so let's make sure we clear the IRQ + WaitReady (padapter); + return 0; + } + } + return status; + } +/**************************************************************** * Name: DecodeError :LOCAL * * Description: Decode and process device errors. * - * Parameters: pshost - Pointer to host data block. + * Parameters: padapter - Pointer to adapter data. * status - Status register code. * * Returns: The driver status code. * ****************************************************************/ -static ULONG DecodeError (struct Scsi_Host *pshost, UCHAR status) +static ULONG DecodeError (PADAPTER2220I padapter, UCHAR status) { - PADAPTER2220I padapter = HOSTDATA(pshost); UCHAR error; padapter->expectingIRQ = 0; - padapter->SCpnt = NULL; if ( status & IDE_STATUS_WRITE_FAULT ) { return DID_PARITY << 16; @@ -252,7 +607,7 @@ if ( status & IDE_STATUS_BUSY ) return DID_BUS_BUSY << 16; - error = inb_p (padapter->ports[PORT_ERROR]); + error = inb_p (padapter->regError); DEB(printk ("\npci2220i error register: %x", error)); switch ( error ) { @@ -268,6 +623,531 @@ return DID_ERROR << 16; } /**************************************************************** + * Name: StartTimer :LOCAL + * + * Description: Start the timer. + * + * Parameters: ipadapter - Pointer adapter data structure. + * + * Returns: Nothing. + * + ****************************************************************/ +static void StartTimer (PADAPTER2220I padapter) + { + padapter->timer.expires = jiffies + TIMEOUT_DATA; + add_timer (&padapter->timer); + } +/**************************************************************** + * Name: WriteSignature :LOCAL + * + * Description: Start the timer. + * + * Parameters: padapter - Pointer adapter data structure. + * pdev - Pointer to our device. + * spigot - Selected spigot. + * index - index of mirror signature on device. + * + * Returns: TRUE on any error. + * + ****************************************************************/ +static int WriteSignature (PADAPTER2220I padapter, POUR_DEVICE pdev, UCHAR spigot, int index) + { + ULONG zl; + + SelectSpigot (padapter, spigot); + zl = pdev->lastsectorlba[index]; + outb_p (pdev->byte6 | ((UCHAR *)&zl)[3], padapter->regLba24); + outb_p (((UCHAR *)&zl)[2], padapter->regLba16); + outb_p (((UCHAR *)&zl)[1], padapter->regLba8); + outb_p (((UCHAR *)&zl)[0], padapter->regLba0); + outb_p (1, padapter->regSectCount); + + WriteCommand (padapter, IDE_COMMAND_WRITE); + if ( WaitDrq (padapter) ) + return TRUE; + StartTimer (padapter); + padapter->expectingIRQ = TRUE; + + ((ULONG *)(&padapter->kBuffer[DISK_MIRROR_POSITION]))[0] = ((ULONG *)(&pdev->DiskMirror[index]))[0]; + ((ULONG *)(&padapter->kBuffer[DISK_MIRROR_POSITION]))[1] = ((ULONG *)(&pdev->DiskMirror[index]))[1]; + outsw (padapter->regData, padapter->kBuffer, BYTES_PER_SECTOR / 2); + return FALSE; + } +/******************************************************************************************************* + * Name: InitFailover + * + * Description: This is the beginning of the failover routine + * + * Parameters: SCpnt - Pointer to SCSI command structure. + * padapter - Pointer adapter data structure. + * pdev - Pointer to our device. + * + * Returns: TRUE on error. + * + ******************************************************************************************************/ +static int InitFailover (PADAPTER2220I padapter, POUR_DEVICE pdev) + { + UCHAR spigot; + + DEB (printk ("\npci2220i: Initialize failover process - survivor = %d", padapter->survivor)); + pdev->raid = FALSE; //initializes system for non raid mode + pdev->hotRecon = 0; + padapter->reconOn = FALSE; + spigot = (padapter->survivor) ? 2 : 1; + + if ( pdev->DiskMirror[padapter->survivor].status & UCBF_REBUILD ) + return (TRUE); + + if ( HardReset (padapter, pdev, spigot) ) + return TRUE; + + outb_p (0x3C | spigot, padapter->regFail); // sound alarm and set fail light + pdev->DiskMirror[padapter->survivor].status = UCBF_MIRRORED | UCBF_SURVIVOR; //clear present status + + if ( WriteSignature (padapter, pdev, spigot, padapter->survivor) ) + return TRUE; + padapter->failinprog = TRUE; + return FALSE; + } +/**************************************************************** + * Name: TimerExpiry :LOCAL + * + * Description: Timer expiry routine. + * + * Parameters: data - Pointer adapter data structure. + * + * Returns: Nothing. + * + ****************************************************************/ +static void TimerExpiry (unsigned long data) + { + PADAPTER2220I padapter = (PADAPTER2220I)data; + POUR_DEVICE pdev = padapter->pdev; + UCHAR status = IDE_STATUS_BUSY; + UCHAR temp, temp1; +#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95) + int flags; +#else /* version >= v2.1.95 */ + unsigned long flags; +#endif /* version >= v2.1.95 */ + +#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95) + /* Disable interrupts, if they aren't already disabled. */ + save_flags (flags); + cli (); +#else /* version >= v2.1.95 */ + /* + * Disable interrupts, if they aren't already disabled and acquire + * the I/O spinlock. + */ + spin_lock_irqsave (&io_request_lock, flags); +#endif /* version >= v2.1.95 */ + DEB (printk ("\nPCI2220I: Timeout expired ")); + + if ( padapter->failinprog ) + { + DEB (printk ("in failover process")); + OpDone (padapter, DecodeError (padapter, inb_p (padapter->regStatCmd))); + goto timerExpiryDone; + } + + while ( padapter->reconPhase ) + { + DEB (printk ("in recon phase %X", padapter->reconPhase)); + switch ( padapter->reconPhase ) + { + case RECON_PHASE_MARKING: + case RECON_PHASE_LAST: + padapter->survivor = (pdev->spigot ^ 3) >> 1; + DEB (printk ("\npci2220i: FAILURE 1")); + if ( InitFailover (padapter, pdev) ) + OpDone (padapter, DID_ERROR << 16); + goto timerExpiryDone; + + case RECON_PHASE_READY: + OpDone (padapter, DID_ERROR << 16); + goto timerExpiryDone; + + case RECON_PHASE_COPY: + padapter->survivor = (pdev->spigot) >> 1; + DEB (printk ("\npci2220i: FAILURE 2")); + DEB (printk ("\n spig/stat = %X", inb_p (padapter->regStatSel)); + if ( InitFailover (padapter, pdev) ) + OpDone (padapter, DID_ERROR << 16); + goto timerExpiryDone; + + case RECON_PHASE_UPDATE: + padapter->survivor = (pdev->spigot) >> 1; + DEB (printk ("\npci2220i: FAILURE 3"))); + if ( InitFailover (padapter, pdev) ) + OpDone (padapter, DID_ERROR << 16); + goto timerExpiryDone; + + case RECON_PHASE_END: + padapter->survivor = (pdev->spigot) >> 1; + DEB (printk ("\npci2220i: FAILURE 4")); + if ( InitFailover (padapter, pdev) ) + OpDone (padapter, DID_ERROR << 16); + goto timerExpiryDone; + + default: + goto timerExpiryDone; + } + } + + while ( padapter->cmd ) + { + outb_p (0x08, padapter->regDmaCmdStat); // cancel interrupt from DMA engine + if ( pdev->raid ) + { + if ( padapter->cmd == WRITE_CMD ) + { + DEB (printk ("in RAID write operation")); + if ( inb_p (padapter->regStatSel) & 1 ) + { + SelectSpigot (padapter, 0x81 ); // Masking the interrupt during spigot select + temp = inb_p (padapter->regStatCmd); + } + else + temp = IDE_STATUS_BUSY; + + if ( inb (padapter->regStatSel) & 2 ) + { + SelectSpigot (padapter, 0x82 ); // Masking the interrupt during spigot select + temp1 = inb_p (padapter->regStatCmd); + } + else + temp1 = IDE_STATUS_BUSY; + + if ( (temp & IDE_STATUS_BUSY) || (temp1 & IDE_STATUS_BUSY) ) + { + if ( (temp & IDE_STATUS_BUSY) && (temp1 & IDE_STATUS_BUSY) ) + { + status = temp; + break; + } + else + { + if (temp & IDE_STATUS_BUSY) + padapter->survivor = 1; + else + padapter->survivor = 0; + DEB (printk ("\npci2220i: FAILURE 5")); + if ( InitFailover (padapter, pdev) ) + { + status = inb_p (padapter->regStatCmd); + break; + } + goto timerExpiryDone; + } + } + } + else + { + DEB (printk ("in RAID read operation")); + padapter->survivor = (pdev->spigot ^ 3) >> 1; + DEB (printk ("\npci2220i: FAILURE 6")); + if ( InitFailover (padapter, pdev) ) + { + status = inb_p (padapter->regStatCmd); + break; + } + goto timerExpiryDone; + } + } + else + { + DEB (printk ("in I/O operation")); + status = inb_p (padapter->regStatCmd); + } + break; + } + + OpDone (padapter, DecodeError (padapter, status)); + +timerExpiryDone:; +#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95) + /* + * Restore the original flags which will enable interrupts + * if and only if they were enabled on entry. + */ + restore_flags (flags); +#else /* version >= v2.1.95 */ + /* + * Release the I/O spinlock and restore the original flags + * which will enable interrupts if and only if they were + * enabled on entry. + */ + spin_unlock_irqrestore (&io_request_lock, flags); +#endif /* version >= v2.1.95 */ + } +/**************************************************************** + * Name: SetReconstruct :LOCAL + * + * Description: Set the reconstruct up. + * + * Parameters: pdev - Pointer to device structure. + * index - Mirror index number. + * + * Returns: Number of sectors on new disk required. + * + ****************************************************************/ +static LONG SetReconstruct (POUR_DEVICE pdev, int index) + { + pdev->DiskMirror[index].status = UCBF_MIRRORED; // setup the flags + pdev->DiskMirror[index ^ 1].status = UCBF_MIRRORED | UCBF_REBUILD; + pdev->DiskMirror[index ^ 1].reconstructPoint = 0; // start the reconstruct + pdev->reconCount = 1990; // mark target drive early + pdev->hotRecon = 1 >> index; + return pdev->DiskMirror[index].reconstructPoint; + } +/**************************************************************** + * Name: ReconTimerExpiry :LOCAL + * + * Description: Reconstruct timer expiry routine. + * + * Parameters: data - Pointer adapter data structure. + * + * Returns: Nothing. + * + ****************************************************************/ +static void ReconTimerExpiry (unsigned long data) + { + PADAPTER2220I padapter; + POUR_DEVICE pdev; + ULONG testsize = 0; + PIDENTIFY_DATA pid; + USHORT minmode; + ULONG zl; + UCHAR zc; +#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95) + int flags; +#else /* version >= v2.1.95 */ + unsigned long flags; +#endif /* version >= v2.1.95 */ + +#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95) + /* Disable interrupts, if they aren't already disabled. */ + save_flags (flags); + cli (); +#else /* version >= v2.1.95 */ + /* + * Disable interrupts, if they aren't already disabled and acquire + * the I/O spinlock. + */ + spin_lock_irqsave (&io_request_lock, flags); +#endif /* version >= v2.1.95 */ + + padapter = (PADAPTER2220I)data; + if ( padapter->SCpnt ) + goto reconTimerExpiry; + + pdev = padapter->device; + pid = (PIDENTIFY_DATA)padapter->kBuffer; + padapter->reconTimer.data = 0; + padapter->pdev = pdev; + if ( padapter->reconIsStarting ) + { + padapter->reconIsStarting = FALSE; + padapter->reconOn = FALSE; + pdev->hotRecon = FALSE; + + if ( (pdev->DiskMirror[0].signature == SIGNATURE) && (pdev->DiskMirror[1].signature == SIGNATURE) && + (pdev->DiskMirror[0].pairIdentifier == (pdev->DiskMirror[1].pairIdentifier ^ 1)) ) + { + if ( (pdev->DiskMirror[0].status & UCBF_MATCHED) && (pdev->DiskMirror[1].status & UCBF_MATCHED) ) + { + goto reconTimerExpiry; + } + + if ( pdev->DiskMirror[0].status & UCBF_SURVIVOR ) // is first drive survivor? + testsize = SetReconstruct (pdev, 0); + else + if ( pdev->DiskMirror[1].status & UCBF_SURVIVOR ) // is second drive survivor? + testsize = SetReconstruct (pdev, 1); + + if ( (pdev->DiskMirror[0].status & UCBF_REBUILD) || (pdev->DiskMirror[1].status & UCBF_REBUILD) ) + { + if ( pdev->DiskMirror[0].status & UCBF_REBUILD ) + { + pdev->hotRecon = 1; + pdev->mirrorRecon = 0; + } + else + { + pdev->hotRecon = 2; + pdev->mirrorRecon = 1; + } + } + } + + if ( !pdev->hotRecon ) + goto reconTimerExpiry; + + zc = ((inb_p (padapter->regStatSel) >> 3) | inb_p (padapter->regStatSel)) & 0x83; // mute the alarm + outb_p (zc | pdev->hotRecon | 0x40, padapter->regFail); + + while ( 1 ) + { + if ( HardReset (padapter, pdev, pdev->hotRecon) ) + { + DEB (printk ("\npci2220i: sub 1")); + break; + } + + pdev->lastsectorlba[pdev->mirrorRecon] = InlineIdentify (padapter, pdev->hotRecon, 0); + + if ( pdev->lastsectorlba[pdev->mirrorRecon] < testsize ) + { + DEB (printk ("\npci2220i: sub 2 %ld %ld", pdev->lastsectorlba[pdev->mirrorRecon], testsize)); + break; + } + + // test LBA and multiper sector transfer compatability + if (!pid->SupportLBA || (pid->NumSectorsPerInt < SECTORSXFER) || !pid->Valid_64_70 ) + { + DEB (printk ("\npci2220i: sub 3")); + break; + } + + // test PIO/bus matering mode compatability + if ( (pid->MinPIOCycleWithoutFlow > 240) && !pid->SupportIORDYDisable && !padapter->timingPIO ) + { + DEB (printk ("\npci2220i: sub 4")); + break; + } + + if ( pid->MinPIOCycleWithoutFlow <= 120 ) // setup timing mode of drive + minmode = 5; + else + { + if ( pid->MinPIOCylceWithFlow <= 150 ) + minmode = 4; + else + { + if ( pid->MinPIOCylceWithFlow <= 180 ) + minmode = 3; + else + { + if ( pid->MinPIOCylceWithFlow <= 240 ) + minmode = 2; + else + { + DEB (printk ("\npci2220i: sub 5")); + break; + } + } + } + } + + if ( padapter->timingMode > minmode ) // set minimum timing mode + padapter->timingMode = minmode; + if ( padapter->timingMode >= 2 ) + padapter->timingAddress = ModeArray[padapter->timingMode - 2]; + else + padapter->timingPIO = TRUE; + + padapter->reconOn = TRUE; + break; + } + + if ( !padapter->reconOn ) + { + pdev->hotRecon = FALSE; + padapter->survivor = pdev->mirrorRecon ^ 1; + padapter->reconPhase = RECON_PHASE_FAILOVER; + DEB (printk ("\npci2220i: FAILURE 7")); + InitFailover (padapter, pdev); + goto reconTimerExpiry; + } + + pdev->raid = TRUE; + + if ( WriteSignature (padapter, pdev, pdev->spigot, pdev->mirrorRecon ^ 1) ) + goto reconTimerExpiry; + padapter->reconPhase = RECON_PHASE_MARKING; + goto reconTimerExpiry; + } + + //********************************** + // reconstruct copy starts here + //********************************** + if ( pdev->reconCount++ > 2000 ) + { + pdev->reconCount = 0; + if ( WriteSignature (padapter, pdev, pdev->hotRecon, pdev->mirrorRecon) ) + { + padapter->survivor = pdev->mirrorRecon ^ 1; + padapter->reconPhase = RECON_PHASE_FAILOVER; + DEB (printk ("\npci2220i: FAILURE 8")); + InitFailover (padapter, pdev); + goto reconTimerExpiry; + } + padapter->reconPhase = RECON_PHASE_UPDATE; + goto reconTimerExpiry; + } + + zl = pdev->DiskMirror[pdev->mirrorRecon].reconstructPoint; + padapter->reconSize = pdev->DiskMirror[pdev->mirrorRecon ^ 1].reconstructPoint - zl; + if ( padapter->reconSize > MAX_BUS_MASTER_BLOCKS ) + padapter->reconSize = MAX_BUS_MASTER_BLOCKS; + + if ( padapter->reconSize ) + { + SelectSpigot (padapter, 3); // select the spigots + outb_p (pdev->byte6 | ((UCHAR *)(&zl))[3], padapter->regLba24);// select the drive + SelectSpigot (padapter, pdev->spigot); + if ( WaitReady (padapter) ) + goto reconTimerExpiry; + + SelectSpigot (padapter, pdev->hotRecon); + if ( WaitReady (padapter) ) + { + padapter->survivor = pdev->mirrorRecon ^ 1; + padapter->reconPhase = RECON_PHASE_FAILOVER; + DEB (printk ("\npci2220i: FAILURE 9")); + InitFailover (padapter, pdev); + goto reconTimerExpiry; + } + + SelectSpigot (padapter, 3); + outb_p (padapter->reconSize & 0xFF, padapter->regSectCount); + outb_p (((UCHAR *)(&zl))[0], padapter->regLba0); + outb_p (((UCHAR *)(&zl))[1], padapter->regLba8); + outb_p (((UCHAR *)(&zl))[2], padapter->regLba16); + padapter->expectingIRQ = TRUE; + padapter->reconPhase = RECON_PHASE_READY; + SelectSpigot (padapter, pdev->hotRecon); + WriteCommand (padapter, WRITE_CMD); + StartTimer (padapter); + SelectSpigot (padapter, pdev->spigot); + WriteCommand (padapter, READ_CMD); + goto reconTimerExpiry; + } + + pdev->DiskMirror[pdev->mirrorRecon].status = UCBF_MIRRORED | UCBF_MATCHED; + pdev->DiskMirror[pdev->mirrorRecon ^ 1].status = UCBF_MIRRORED | UCBF_MATCHED; + if ( WriteSignature (padapter, pdev, pdev->spigot, pdev->mirrorRecon ^ 1) ) + goto reconTimerExpiry; + padapter->reconPhase = RECON_PHASE_LAST; + +reconTimerExpiry:; +#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95) + /* + * Restore the original flags which will enable interrupts + * if and only if they were enabled on entry. + */ + restore_flags (flags); +#else /* version >= v2.1.95 */ + /* + * Release the I/O spinlock and restore the original flags + * which will enable interrupts if and only if they were + * enabled on entry. + */ + spin_unlock_irqrestore (&io_request_lock, flags); +#endif /* version >= v2.1.95 */ + } +/**************************************************************** * Name: Irq_Handler :LOCAL * * Description: Interrupt handler. @@ -283,12 +1163,31 @@ { struct Scsi_Host *shost = NULL; // Pointer to host data block PADAPTER2220I padapter; // Pointer to adapter control structure - USHORT *pports; // I/O port array + POUR_DEVICE pdev; Scsi_Cmnd *SCpnt; UCHAR status; + UCHAR status1; int z; + ULONG zl; +#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95) + int flags; +#else /* version >= v2.1.95 */ + unsigned long flags; +#endif /* version >= v2.1.95 */ + +#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95) + /* Disable interrupts, if they aren't already disabled. */ + save_flags (flags); + cli (); +#else /* version >= v2.1.95 */ + /* + * Disable interrupts, if they aren't already disabled and acquire + * the I/O spinlock. + */ + spin_lock_irqsave (&io_request_lock, flags); +#endif /* version >= v2.1.95 */ -// DEB(printk ("\npci2220i recieved interrupt\n")); +// DEB (printk ("\npci2220i recieved interrupt\n")); for ( z = 0; z < NumAdapters; z++ ) // scan for interrupt to process { @@ -305,86 +1204,267 @@ if ( !shost ) { DEB (printk ("\npci2220i: not my interrupt")); - return; + goto irq_return; } padapter = HOSTDATA(shost); - pports = padapter->ports; + pdev = padapter->pdev; SCpnt = padapter->SCpnt; - if ( !padapter->expectingIRQ ) + if ( !padapter->expectingIRQ || !(SCpnt || padapter->reconPhase) ) { DEB(printk ("\npci2220i Unsolicited interrupt\n")); - return; + STOP_HERE (); + goto irq_return; } padapter->expectingIRQ = 0; + outb_p (0x08, padapter->regDmaCmdStat); // cancel interrupt from DMA engine - status = inb_p (padapter->ports[PORT_STAT_CMD]); // read the device status - if ( status & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT) ) - goto irqerror; - - switch ( padapter->ide.ide.ides.cmd ) // decide how to handle the interrupt - { - case IDE_CMD_READ_MULTIPLE: - if ( padapter->readPhase == 1 ) // is this a bus master channel complete? - { - DEB(printk ("\npci2220i processing read interrupt cleanup")); - outb_p (0x08, padapter->regDmaCmdStat); // cancel interrupt from DMA engine - padapter->buffer += padapter->ide.ide.ides.sectors * 512; - if ( SetupTransfer (padapter, padapter->ide.ide.ide[6] & 0xF0) ) - { - SCpnt->result = DID_OK << 16; - padapter->SCpnt = NULL; - SCpnt->scsi_done (SCpnt); - return; + if ( padapter->failinprog ) + { + DEB (printk ("\npci2220i interrupt failover complete")); + padapter->failinprog = FALSE; + status = inb_p (padapter->regStatCmd); // read the device status + if ( status & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT) ) + { + DEB (printk ("\npci2220i: interrupt failover error from drive %X", status)); + padapter->cmd = 0; + } + else + { + DEB (printk ("\npci2220i: restarting failed opertation.")); + pdev->spigot = (padapter->survivor) ? 2 : 1; + del_timer (&padapter->timer); + if ( padapter->reconPhase ) + OpDone (padapter, DID_OK << 16); + else + Pci2220i_QueueCommand (SCpnt, SCpnt->scsi_done); + goto irq_return; + } + } + + if ( padapter->reconPhase ) + { + switch ( padapter->reconPhase ) + { + case RECON_PHASE_MARKING: + case RECON_PHASE_LAST: + status = inb_p (padapter->regStatCmd); // read the device status + del_timer (&padapter->timer); + if ( padapter->reconPhase == RECON_PHASE_LAST ) + { + if ( status & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT) ) + { + padapter->survivor = (pdev->spigot ^ 3) >> 1; + DEB (printk ("\npci2220i: FAILURE 10")); + if ( InitFailover (padapter, pdev) ) + OpDone (padapter, DecodeError (padapter, status)); + goto irq_return; + } + if ( WriteSignature (padapter, pdev, pdev->hotRecon, pdev->mirrorRecon) ) + { + padapter->survivor = (pdev->spigot) >> 1; + DEB (printk ("\npci2220i: FAILURE 11")); + if ( InitFailover (padapter, pdev) ) + OpDone (padapter, DecodeError (padapter, status)); + goto irq_return; + } + padapter->reconPhase = RECON_PHASE_END; + goto irq_return; } - padapter->readPhase = 0; - if ( !(status = IdeCmd (padapter)) ) + OpDone (padapter, DID_OK << 16); + goto irq_return; + + case RECON_PHASE_READY: + status = inb_p (padapter->regStatCmd); // read the device status + if ( status & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT) ) { - DEB (printk ("\npci2220i interrupt complete, waiting for another")); - return; + del_timer (&padapter->timer); + OpDone (padapter, DecodeError (padapter, status)); + goto irq_return; } - } - if ( status & IDE_STATUS_DRQ ) + SelectSpigot (padapter, pdev->hotRecon); + if ( WaitDrq (padapter) ) + { + del_timer (&padapter->timer); + padapter->survivor = (pdev->spigot) >> 1; + DEB (printk ("\npci2220i: FAILURE 12")); + if ( InitFailover (padapter, pdev) ) + OpDone (padapter, DecodeError (padapter, status)); + goto irq_return; + } + SelectSpigot (padapter, pdev->spigot | 0x40); + padapter->reconPhase = RECON_PHASE_COPY; + padapter->expectingIRQ = TRUE; + if ( padapter->timingPIO ) + { + insw (padapter->regData, padapter->kBuffer, padapter->reconSize * (BYTES_PER_SECTOR / 2)); + } + else + { + outl (padapter->timingAddress, padapter->regDmaAddrLoc); + outl (virt_to_bus (padapter->kBuffer), padapter->regDmaAddrPci); + outl (padapter->reconSize * BYTES_PER_SECTOR, padapter->regDmaCount); + outb_p (8, padapter->regDmaDesc); // read operation + outb_p (1, padapter->regDmaMode); // no interrupt + outb_p (0x03, padapter->regDmaCmdStat); // kick the DMA engine in gear + } + goto irq_return; + + case RECON_PHASE_COPY: + pdev->DiskMirror[pdev->mirrorRecon].reconstructPoint += padapter->reconSize; + + case RECON_PHASE_UPDATE: + SelectSpigot (padapter, pdev->hotRecon | 0x80); + status = inb_p (padapter->regStatCmd); // read the device status + del_timer (&padapter->timer); + if ( status & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT) ) + { + padapter->survivor = (pdev->spigot) >> 1; + DEB (printk ("\npci2220i: FAILURE 13")); + if ( InitFailover (padapter, pdev) ) + OpDone (padapter, DecodeError (padapter, status)); + goto irq_return; + } + OpDone (padapter, DID_OK << 16); + goto irq_return; + + case RECON_PHASE_END: + status = inb_p (padapter->regStatCmd); // read the device status + del_timer (&padapter->timer); + if ( status & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT) ) + { + padapter->survivor = (pdev->spigot) >> 1; + DEB (printk ("\npci2220i: FAILURE 14")); + if ( InitFailover (padapter, pdev) ) + OpDone (padapter, DecodeError (padapter, status)); + goto irq_return; + } + padapter->reconOn = FALSE; + pdev->hotRecon = 0; + OpDone (padapter, DID_OK << 16); + goto irq_return; + + default: + goto irq_return; + } + } + + switch ( padapter->cmd ) // decide how to handle the interrupt + { + case READ_CMD: + if ( padapter->sectorCount ) { - DEB(printk ("\npci2220i processing read interrupt start bus master cycle")); - outb_p (8, padapter->regDmaDesc); // read operation - padapter->readPhase = 1; - padapter->expectingIRQ = 1; - outl (padapter->timingAddress, padapter->regDmaAddrLoc); - outl (virt_to_bus (padapter->buffer), padapter->regDmaAddrPci); - outl ((ULONG)padapter->ide.ide.ides.sectors * (ULONG)512, padapter->regDmaCount); - outb_p (5, padapter->regDmaMode); // interrupt enable/disable - outb_p (0x03, padapter->regDmaCmdStat); // kick the DMA engine in gear - return; + status = inb_p (padapter->regStatCmd); // read the device status + if ( status & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT) ) + { + if ( pdev->raid ) + { + padapter->survivor = (pdev->spigot ^ 3) >> 1; + del_timer (&padapter->timer); + DEB (printk ("\npci2220i: FAILURE 15")); + if ( !InitFailover (padapter, pdev) ) + goto irq_return; + } + break; + } + if ( padapter->timingPIO ) + { + zl = (padapter->sectorCount > MAX_BUS_MASTER_BLOCKS) ? MAX_BUS_MASTER_BLOCKS : padapter->sectorCount; + insw (padapter->regData, padapter->buffer, zl * (BYTES_PER_SECTOR / 2)); + padapter->sectorCount -= zl; + padapter->buffer += zl * BYTES_PER_SECTOR; + if ( !padapter->sectorCount ) + { + status = 0; + break; + } + } + else + BusMaster (padapter, 1, 1); + padapter->expectingIRQ = TRUE; + goto irq_return; } + status = 0; break; - case IDE_CMD_WRITE_MULTIPLE: - DEB(printk ("\npci2220i processing write interrupt cleanup")); - padapter->buffer += padapter->ide.ide.ides.sectors * 512; - if ( SetupTransfer (padapter, padapter->ide.ide.ide[6] & 0xF0) ) - { - SCpnt->result = DID_OK << 16; - padapter->SCpnt = NULL; - SCpnt->scsi_done (SCpnt); - return; + case WRITE_CMD: + SelectSpigot (padapter, pdev->spigot | 0x80); + status = inb_p (padapter->regStatCmd); // read the device status + if ( pdev->raid ) + { + SelectSpigot (padapter, (pdev->spigot ^ 3) | 0x80); + status1 = inb_p (padapter->regStatCmd); // read the device status } - if ( !(status = IdeCmd (padapter)) ) + else + status1 = 0; + + if ( status & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT) ) + { + if ( pdev->raid && !(status1 & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT)) ) + { + padapter->survivor = (pdev->spigot ^ 3) >> 1; + del_timer (&padapter->timer); + SelectSpigot (padapter, pdev->spigot | 0x80); + DEB (printk ("\npci2220i: FAILURE 16 status = %X error = %X", status, inb_p (padapter->regError))); + if ( !InitFailover (padapter, pdev) ) + goto irq_return; + } + break; + } + if ( pdev->raid ) { - DEB (printk ("\npci2220i interrupt complete, waiting for another")); - return; + if ( status1 & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT) ) + { + padapter->survivor = pdev->spigot >> 1; + del_timer (&padapter->timer); + DEB (printk ("\npci2220i: FAILURE 17 status = %X error = %X", status1, inb_p (padapter->regError))); + if ( !InitFailover (padapter, pdev) ) + goto irq_return; + status = status1; + break; + } + if ( padapter->sectorCount ) + { + status = WriteDataBoth (padapter); + if ( status ) + { + padapter->survivor = (status ^ 3) >> 1; + del_timer (&padapter->timer); + DEB (printk ("\npci2220i: FAILURE 18")); + if ( !InitFailover (padapter, pdev) ) + goto irq_return; + SelectSpigot (padapter, status | 0x80); + status = inb_p (padapter->regStatCmd); // read the device status + break; + } + padapter->expectingIRQ = TRUE; + goto irq_return; + } + status = 0; + break; + } + if ( padapter->sectorCount ) + { + SelectSpigot (padapter, pdev->spigot); + status = WriteData (padapter); + if ( status ) + break; + padapter->expectingIRQ = TRUE; + goto irq_return; } + status = 0; break; case IDE_COMMAND_IDENTIFY: { PINQUIRYDATA pinquiryData = SCpnt->request_buffer; + PIDENTIFY_DATA pid = (PIDENTIFY_DATA)padapter->kBuffer; - DEB(printk ("\npci2220i processing verify interrupt cleanup")); + status = inb_p (padapter->regStatCmd); if ( status & IDE_STATUS_DRQ ) { - insw (pports[PORT_DATA], &identifyData, sizeof (identifyData) >> 1); + insw (padapter->regData, pid, sizeof (IDENTIFY_DATA) >> 1); memset (pinquiryData, 0, SCpnt->request_bufflen); // Zero INQUIRY data structure. pinquiryData->DeviceType = 0; @@ -394,8 +1474,8 @@ // Fill in vendor identification fields. for ( z = 0; z < 20; z += 2 ) { - pinquiryData->VendorId[z] = ((UCHAR *)identifyData.ModelNumber)[z + 1]; - pinquiryData->VendorId[z + 1] = ((UCHAR *)identifyData.ModelNumber)[z]; + pinquiryData->VendorId[z] = ((UCHAR *)pid->ModelNumber)[z + 1]; + pinquiryData->VendorId[z + 1] = ((UCHAR *)pid->ModelNumber)[z]; } // Initialize unused portion of product id. @@ -406,38 +1486,47 @@ // product revision in INQUIRY data. for ( z = 0; z < 4; z += 2 ) { - pinquiryData->ProductRevisionLevel[z] = ((UCHAR *)identifyData.FirmwareRevision)[z + 1]; - pinquiryData->ProductRevisionLevel[z + 1] = ((UCHAR *)identifyData.FirmwareRevision)[z]; + pinquiryData->ProductRevisionLevel[z] = ((UCHAR *)pid->FirmwareRevision)[z + 1]; + pinquiryData->ProductRevisionLevel[z + 1] = ((UCHAR *)pid->FirmwareRevision)[z]; } - - SCpnt->result = DID_OK << 16; - padapter->SCpnt = NULL; - SCpnt->scsi_done (SCpnt); - return; + if ( pdev == padapter->device ) + *((USHORT *)(&pinquiryData->VendorSpecific)) = DEVICE_DALE_1; + + status = 0; } break; } default: - DEB(printk ("\npci2220i no real process here!")); - SCpnt->result = DID_OK << 16; - padapter->SCpnt = NULL; - SCpnt->scsi_done (SCpnt); - return; + status = 0; + break; } -irqerror:; - DEB(printk ("\npci2220i error Device Status: %X\n", status)); - SCpnt->result = DecodeError (shost, status); - SCpnt->scsi_done (SCpnt); - } -static void do_Irq_Handler (int irq, void *dev_id, struct pt_regs *regs) - { - unsigned long flags; + del_timer (&padapter->timer); + if ( status ) + { + DEB (printk ("\npci2220i Interupt hanlder return error")); + zl = DecodeError (padapter, status); + } + else + zl = DID_OK << 16; - spin_lock_irqsave(&io_request_lock, flags); - Irq_Handler(irq, dev_id, regs); - spin_unlock_irqrestore(&io_request_lock, flags); + OpDone (padapter, zl); +irq_return:; +#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95) + /* + * Restore the original flags which will enable interrupts + * if and only if they were enabled on entry. + */ + restore_flags (flags); +#else /* version >= v2.1.95 */ + /* + * Release the I/O spinlock and restore the original flags + * which will enable interrupts if and only if they were + * enabled on entry. + */ + spin_unlock_irqrestore (&io_request_lock, flags); +#endif /* version >= v2.1.95 */ } /**************************************************************** * Name: Pci2220i_QueueCommand @@ -456,121 +1545,182 @@ PADAPTER2220I padapter = HOSTDATA(SCpnt->host); // Pointer to adapter control structure POUR_DEVICE pdev = &padapter->device[SCpnt->target];// Pointer to device information UCHAR rc; // command return code + int z; + PDEVICE_RAID1 pdr; SCpnt->scsi_done = done; - padapter->ide.ide.ides.spigot = pdev->spigot; padapter->buffer = SCpnt->request_buffer; - if (done) + padapter->SCpnt = SCpnt; // Save this command data + if ( !done ) { - if ( !pdev->device ) - { - SCpnt->result = DID_BAD_TARGET << 16; - done (SCpnt); - return 0; - } + printk("pci2220i_queuecommand: %02X: done can't be NULL\n", *cdb); + return 0; } - else + + if ( padapter->reconPhase ) + return 0; + if ( padapter->reconTimer.data ) { - printk("pci2220i_queuecommand: %02X: done can't be NULL\n", *cdb); + del_timer (&padapter->reconTimer); + padapter->reconTimer.data = 0; + } + + if ( !pdev->device || SCpnt->lun ) + { + OpDone (padapter, DID_BAD_TARGET << 16); return 0; } - DEB (if(*cdb) printk ("\nCDB: %X- %X %X %X %X %X %X %X %X %X %X ", SCpnt->cmd_len, cdb[0], cdb[1], cdb[2], cdb[3], cdb[4], cdb[5], cdb[6], cdb[7], cdb[8], cdb[9])); + switch ( *cdb ) { case SCSIOP_INQUIRY: // inquiry CDB { - padapter->ide.ide.ide[6] = pdev->byte6; - padapter->ide.ide.ides.cmd = IDE_COMMAND_IDENTIFY; + if ( cdb[2] == SC_MY_RAID ) + { + switch ( cdb[3] ) + { + case MY_SCSI_REBUILD: + padapter->reconOn = padapter->reconIsStarting = TRUE; + OpDone (padapter, DID_OK << 16); + break; + case MY_SCSI_ALARMMUTE: + MuteAlarm (padapter); + OpDone (padapter, DID_OK << 16); + break; + case MY_SCSI_DEMOFAIL: + padapter->demoFail = TRUE; + OpDone (padapter, DID_OK << 16); + break; + default: + z = cdb[5]; // get index + pdr = (PDEVICE_RAID1)SCpnt->request_buffer; + if ( padapter->raidData[z] ) + { + memcpy (&pdr->DiskRaid1, padapter->raidData[z], sizeof (DISK_MIRROR)); + pdr->TotalSectors = padapter->device[0].blocks; + } + else + memset (pdr, 0, sizeof (DEVICE_RAID1)); + OpDone (padapter, DID_OK << 16); + break; + } + return 0; + } + padapter->cmd = IDE_COMMAND_IDENTIFY; break; } case SCSIOP_TEST_UNIT_READY: // test unit ready CDB - SCpnt->result = DID_OK << 16; - done (SCpnt); + OpDone (padapter, DID_OK << 16); return 0; - case SCSIOP_READ_CAPACITY: // read capctiy CDB { PREAD_CAPACITY_DATA pdata = (PREAD_CAPACITY_DATA)SCpnt->request_buffer; pdata->blksiz = 0x20000; XANY2SCSI ((UCHAR *)&pdata->blks, pdev->blocks); - SCpnt->result = DID_OK << 16; - done (SCpnt); + OpDone (padapter, DID_OK << 16); return 0; } - case SCSIOP_VERIFY: // verify CDB - *(ULONG *)padapter->ide.ide.ides.lba = XSCSI2LONG (&cdb[2]); - padapter->ide.ide.ide[6] |= pdev->byte6; - padapter->ide.ide.ide[2] = (UCHAR)((USHORT)cdb[8] | ((USHORT)cdb[7] << 8)); - padapter->ide.ide.ides.cmd = IDE_COMMAND_VERIFY; + padapter->startSector = XSCSI2LONG (&cdb[2]); + padapter->sectorCount = (UCHAR)((USHORT)cdb[8] | ((USHORT)cdb[7] << 8)); + padapter->cmd = IDE_COMMAND_VERIFY; break; - case SCSIOP_READ: // read10 CDB padapter->startSector = XSCSI2LONG (&cdb[2]); padapter->sectorCount = (USHORT)cdb[8] | ((USHORT)cdb[7] << 8); - SetupTransfer (padapter, pdev->byte6); - padapter->ide.ide.ides.cmd = IDE_CMD_READ_MULTIPLE; - padapter->readPhase = 0; + padapter->cmd = READ_CMD; break; - case SCSIOP_READ6: // read6 CDB padapter->startSector = SCSI2LONG (&cdb[1]); padapter->sectorCount = cdb[4]; - SetupTransfer (padapter, pdev->byte6); - padapter->ide.ide.ides.cmd = IDE_CMD_READ_MULTIPLE; - padapter->readPhase = 0; + padapter->cmd = READ_CMD; break; - case SCSIOP_WRITE: // write10 CDB padapter->startSector = XSCSI2LONG (&cdb[2]); padapter->sectorCount = (USHORT)cdb[8] | ((USHORT)cdb[7] << 8); - SetupTransfer (padapter, pdev->byte6); - padapter->ide.ide.ides.cmd = IDE_CMD_WRITE_MULTIPLE; + padapter->cmd = WRITE_CMD; break; case SCSIOP_WRITE6: // write6 CDB padapter->startSector = SCSI2LONG (&cdb[1]); padapter->sectorCount = cdb[4]; - SetupTransfer (padapter, pdev->byte6); - padapter->ide.ide.ides.cmd = IDE_CMD_WRITE_MULTIPLE; + padapter->cmd = WRITE_CMD; break; - default: DEB (printk ("pci2220i_queuecommand: Unsupported command %02X\n", *cdb)); - SCpnt->result = DID_ERROR << 16; - done (SCpnt); + OpDone (padapter, DID_ERROR << 16); return 0; } - padapter->SCpnt = SCpnt; // Save this command data + if ( padapter->reconPhase ) + return 0; + + padapter->pdev = pdev; - rc = IdeCmd (padapter); - if ( rc ) + while ( padapter->demoFail ) { - padapter->expectingIRQ = 0; - DEB (printk ("pci2220i_queuecommand: %02X, %02X: Device failed to respond for command\n", *cdb, padapter->ide.ide.ides.cmd)); - SCpnt->result = DID_ERROR << 16; - done (SCpnt); + padapter->demoFail = FALSE; + if ( !pdev->raid || + (pdev->DiskMirror[0].status & UCBF_SURVIVOR) || + (pdev->DiskMirror[1].status & UCBF_SURVIVOR) ) + { + break; + } + if ( pdev->DiskMirror[0].status & UCBF_REBUILD ) + padapter->survivor = 1; + else + padapter->survivor = 0; + DEB (printk ("\npci2220i: FAILURE 19")); + if ( InitFailover (padapter, pdev ) ) + break; return 0; } - if ( padapter->ide.ide.ides.cmd == IDE_CMD_WRITE_MULTIPLE ) + + StartTimer (padapter); + if ( pdev->raid && (padapter->cmd == WRITE_CMD) ) + { + rc = IdeCmdBoth (padapter); + if ( !rc ) + rc = WriteDataBoth (padapter); + if ( rc ) + { + del_timer (&padapter->timer); + padapter->expectingIRQ = 0; + padapter->survivor = (rc ^ 3) >> 1; + DEB (printk ("\npci2220i: FAILURE 20")); + if ( InitFailover (padapter, pdev) ) + { + OpDone (padapter, DID_ERROR << 16); + return 0; + } + } + } + else { - if ( WriteData (padapter) ) + rc = IdeCmd (padapter, pdev); + if ( (padapter->cmd == WRITE_CMD) && !rc ) + rc = WriteData (padapter); + if ( rc ) { + del_timer (&padapter->timer); padapter->expectingIRQ = 0; - DEB (printk ("pci2220i_queuecommand: %02X, %02X: Device failed to accept data\n", *cdb, padapter->ide.ide.ides.cmd)); - SCpnt->result = DID_ERROR << 16; - done (SCpnt); + if ( pdev->raid ) + { + padapter->survivor = (pdev->spigot ^ 3) >> 1; + DEB (printk ("\npci2220i: FAILURE 21")); + if ( !InitFailover (padapter, pdev) ) + return 0; + } + OpDone (padapter, DID_ERROR << 16); return 0; } } - DEB (printk(" now waiting for initial interrupt ")); return 0; } -static void internal_done(Scsi_Cmnd * SCpnt) +static void internal_done(Scsi_Cmnd *SCpnt) { SCpnt->SCp.Status++; } @@ -586,10 +1736,7 @@ ****************************************************************/ int Pci2220i_Command (Scsi_Cmnd *SCpnt) { - DEB(printk("pci2220i_command: ..calling pci2220i_queuecommand\n")); - Pci2220i_QueueCommand (SCpnt, internal_done); - SCpnt->SCp.Status = 0; while (!SCpnt->SCp.Status) barrier (); @@ -600,7 +1747,7 @@ * * Description: Read information from controller Flash memory. * - * Parameters: hostdata - Pointer to host interface data structure. + * Parameters: padapter - Pointer to host interface data structure. * pdata - Pointer to data structures. * base - base address in Flash. * length - lenght of data space in bytes. @@ -608,25 +1755,24 @@ * Returns: Nothing. * ****************************************************************/ -VOID ReadFlash (PADAPTER2220I hostdata, VOID *pdata, ULONG base, ULONG length) +VOID ReadFlash (PADAPTER2220I padapter, VOID *pdata, ULONG base, ULONG length) { ULONG oldremap; UCHAR olddesc; ULONG z; UCHAR *pd = (UCHAR *)pdata; - oldremap = inl (hostdata->regRemap); // save values to restore later - olddesc = inb_p (hostdata->regDesc); + oldremap = inl (padapter->regRemap); // save values to restore later + olddesc = inb_p (padapter->regDesc); - outl (base | 1, hostdata->regRemap); // remap to Flash space as specified - outb_p (0x40, hostdata->regDesc); // describe remap region as 8 bit + outl (base | 1, padapter->regRemap); // remap to Flash space as specified + outb_p (0x40, padapter->regDesc); // describe remap region as 8 bit for ( z = 0; z < length; z++) // get "length" data count - *pd++ = inb_p (hostdata->regBase + z); // read in the data + *pd++ = inb_p (padapter->regBase + z); // read in the data - outl (oldremap, hostdata->regRemap); // restore remap register values - outb_p (olddesc, hostdata->regDesc); + outl (oldremap, padapter->regRemap); // restore remap register values + outb_p (olddesc, padapter->regDesc); } - /**************************************************************** * Name: Pci2220i_Detect * @@ -634,115 +1780,239 @@ * * Parameters: tpnt - Pointer to SCSI host template structure. * - * Returns: Number of adapters found. + * Returns: Number of adapters installed. * ****************************************************************/ int Pci2220i_Detect (Scsi_Host_Template *tpnt) { - struct pci_dev *pdev = NULL; + int found = 0; + int installed = 0; struct Scsi_Host *pshost; - PADAPTER2220I hostdata; - ULONG modearray[] = {DALE_DATA_MODE2, DALE_DATA_MODE3, DALE_DATA_MODE4, DALE_DATA_MODE4P}; + PADAPTER2220I padapter; int unit; int z; + USHORT zs; + USHORT raidon = FALSE; int setirq; + UCHAR spigot1 = FALSE; + UCHAR spigot2 = FALSE; +#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92) + struct pci_dev *pdev = NULL; +#else + UCHAR pci_bus, pci_device_fn; +#endif - if ( pci_present () ) - while ((pdev = pci_find_device(VENDOR_PSI, DEVICE_DALE_1, pdev))) - { - pshost = scsi_register (tpnt, sizeof(ADAPTER2220I)); - hostdata = HOSTDATA(pshost); +#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92) + if ( !pci_present () ) +#else + if ( !pcibios_present () ) +#endif + { + printk ("pci2220i: PCI BIOS not present\n"); + return 0; + } - hostdata->basePort = pdev->base_address[1] & PCI_BASE_ADDRESS_IO_MASK; - DEB (printk ("\nBase Regs = %#04X", hostdata->basePort)); - hostdata->regRemap = hostdata->basePort + RTR_LOCAL_REMAP; // 32 bit local space remap - DEB (printk (" %#04X", hostdata->regRemap)); - hostdata->regDesc = hostdata->basePort + RTR_REGIONS; // 32 bit local region descriptor - DEB (printk (" %#04X", hostdata->regDesc)); - hostdata->regRange = hostdata->basePort + RTR_LOCAL_RANGE; // 32 bit local range - DEB (printk (" %#04X", hostdata->regRange)); - hostdata->regIrqControl = hostdata->basePort + RTR_INT_CONTROL_STATUS; // 16 bit interupt control and status - DEB (printk (" %#04X", hostdata->regIrqControl)); - hostdata->regScratchPad = hostdata->basePort + RTR_MAILBOX; // 16 byte scratchpad I/O base address - DEB (printk (" %#04X", hostdata->regScratchPad)); - - hostdata->regBase = pdev->base_address[2] & PCI_BASE_ADDRESS_IO_MASK; - for ( z = 0; z < 9; z++ ) // build regester address array - hostdata->ports[z] = hostdata->regBase + 0x80 + (z * 4); - hostdata->ports[PORT_FAIL] = hostdata->regBase + REG_FAIL; - hostdata->ports[PORT_ALT_STAT] = hostdata->regBase + REG_ALT_STAT; - DEB (printk ("\nPorts =")); - DEB (for (z=0;z<11;z++) printk(" %#04X", hostdata->ports[z]);); - - hostdata->regDmaDesc = hostdata->regBase + RTL_DMA1_DESC_PTR; // address of the DMA discriptor register for direction of transfer - DEB (printk ("\nDMA Regs = %#04X", hostdata->regDmaDesc)); - hostdata->regDmaCmdStat = hostdata->regBase + RTL_DMA_COMMAND_STATUS + 1; // Byte #1 of DMA command status register - DEB (printk (" %#04X", hostdata->regDmaCmdStat)); - hostdata->regDmaAddrPci = hostdata->regBase + RTL_DMA1_PCI_ADDR; // 32 bit register for PCI address of DMA - DEB (printk (" %#04X", hostdata->regDmaAddrPci)); - hostdata->regDmaAddrLoc = hostdata->regBase + RTL_DMA1_LOCAL_ADDR; // 32 bit register for local bus address of DMA - DEB (printk (" %#04X", hostdata->regDmaAddrLoc)); - hostdata->regDmaCount = hostdata->regBase + RTL_DMA1_COUNT; // 32 bit register for DMA transfer count - DEB (printk (" %#04X", hostdata->regDmaCount)); - hostdata->regDmaMode = hostdata->regBase + RTL_DMA1_MODE + 1; // 32 bit register for DMA mode control - DEB (printk (" %#04X", hostdata->regDmaMode)); - - if ( !inb_p (hostdata->regScratchPad + DALE_NUM_DRIVES) ) // if no devices on this board - goto unregister; - - pshost->irq = pdev->irq; - setirq = 1; - for ( z = 0; z < NumAdapters; z++ ) // scan for shared interrupts - { - if ( PsiHost[z]->irq == pshost->irq ) // if shared then, don't posses - setirq = 0; - } - if ( setirq ) // if not shared, posses +#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92) + while ( (pdev = pci_find_device (VENDOR_PSI, DEVICE_DALE_1, pdev)) != NULL ) +#else + while ( !pcibios_find_device (VENDOR_PSI, DEVICE_DALE_1, found, &pci_bus, &pci_device_fn) ) +#endif + { + pshost = scsi_register (tpnt, sizeof(ADAPTER2220I)); + padapter = HOSTDATA(pshost); + memset (padapter, 0, sizeof (ADAPTER2220I)); + +#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92) + zs = pdev->base_address[1] & 0xFFFE; +#else + pcibios_read_config_word (pci_bus, pci_device_fn, PCI_BASE_ADDRESS_1, &zs); + zs &= 0xFFFE; +#endif + padapter->basePort = zs; + padapter->regRemap = zs + RTR_LOCAL_REMAP; // 32 bit local space remap + padapter->regDesc = zs + RTR_REGIONS; // 32 bit local region descriptor + padapter->regRange = zs + RTR_LOCAL_RANGE; // 32 bit local range + padapter->regIrqControl = zs + RTR_INT_CONTROL_STATUS; // 16 bit interupt control and status + padapter->regScratchPad = zs + RTR_MAILBOX; // 16 byte scratchpad I/O base address + +#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92) + zs = pdev->base_address[2] & 0xFFFE; +#else + pcibios_read_config_word (pci_bus, pci_device_fn, PCI_BASE_ADDRESS_2, &zs); + zs &= 0xFFFE; +#endif + padapter->regBase = zs; + padapter->regData = zs + REG_DATA; // data register I/O address + padapter->regError = zs + REG_ERROR; // error register I/O address + padapter->regSectCount = zs + REG_SECTOR_COUNT; // sector count register I/O address + padapter->regLba0 = zs + REG_LBA_0; // least significant byte of LBA + padapter->regLba8 = zs + REG_LBA_8; // next least significant byte of LBA + padapter->regLba16 = zs + REG_LBA_16; // next most significan byte of LBA + padapter->regLba24 = zs + REG_LBA_24; // head and most 4 significant bits of LBA + padapter->regStatCmd = zs + REG_STAT_CMD; // status on read and command on write register + padapter->regStatSel = zs + REG_STAT_SEL; // board status on read and spigot select on write register + padapter->regFail = zs + REG_FAIL; + padapter->regAltStat = zs + REG_ALT_STAT; + + padapter->regDmaDesc = zs + RTL_DMA1_DESC_PTR; // address of the DMA discriptor register for direction of transfer + padapter->regDmaCmdStat = zs + RTL_DMA_COMMAND_STATUS + 1; // Byte #1 of DMA command status register + padapter->regDmaAddrPci = zs + RTL_DMA1_PCI_ADDR; // 32 bit register for PCI address of DMA + padapter->regDmaAddrLoc = zs + RTL_DMA1_LOCAL_ADDR; // 32 bit register for local bus address of DMA + padapter->regDmaCount = zs + RTL_DMA1_COUNT; // 32 bit register for DMA transfer count + padapter->regDmaMode = zs + RTL_DMA1_MODE + 1; // 32 bit register for DMA mode control + + if ( !inb_p (padapter->regScratchPad + DALE_NUM_DRIVES) ) // if no devices on this board + goto unregister; + +#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92) + pshost->irq = pdev->irq; +#else + pcibios_read_config_byte (pci_bus, pci_device_fn, PCI_INTERRUPT_LINE, &pshost->irq); +#endif + setirq = 1; + for ( z = 0; z < installed; z++ ) // scan for shared interrupts + { + if ( PsiHost[z]->irq == pshost->irq ) // if shared then, don't posses + setirq = 0; + } + if ( setirq ) // if not shared, posses + { + if ( request_irq (pshost->irq, Irq_Handler, SA_SHIRQ, "pci2220i", padapter) < 0 ) { - if ( request_irq (pshost->irq, do_Irq_Handler, 0, "pci2220i", NULL) ) + if ( request_irq (pshost->irq, Irq_Handler, SA_INTERRUPT | SA_SHIRQ, "pci2220i", padapter) < 0 ) { - printk ("Unable to allocate IRQ for PSI-2220I controller.\n"); + printk ("Unable to allocate IRQ for PCI-2220I controller.\n"); goto unregister; } } - PsiHost[NumAdapters] = pshost; // save SCSI_HOST pointer - - pshost->unique_id = hostdata->regBase; - pshost->max_id = 4; + padapter->irqOwned = pshost->irq; // set IRQ as owned + } + padapter->kBuffer = kmalloc (SECTORSXFER * BYTES_PER_SECTOR, GFP_DMA | GFP_ATOMIC); + if ( !padapter->kBuffer ) + { + printk ("Unable to allocate DMA buffer for PCI-2220I controller.\n"); +#if LINUX_VERSION_CODE < LINUXVERSION(1,3,70) + free_irq (pshost->irq); +#else /* version >= v1.3.70 */ + free_irq (pshost->irq, padapter); +#endif /* version >= v1.3.70 */ + goto unregister; + } + PsiHost[installed] = pshost; // save SCSI_HOST pointer - outb_p (0x01, hostdata->regRange); // fix our range register because other drivers want to tromp on it + pshost->io_port = padapter->basePort; + pshost->n_io_port = 0xFF; + pshost->unique_id = padapter->regBase; + pshost->max_id = 4; + + outb_p (0x01, padapter->regRange); // fix our range register because other drivers want to tromp on it + + padapter->timingMode = inb_p (padapter->regScratchPad + DALE_TIMING_MODE); + if ( padapter->timingMode >= 2 ) + padapter->timingAddress = ModeArray[padapter->timingMode - 2]; + else + padapter->timingPIO = TRUE; + + ReadFlash (padapter, &DaleSetup, DALE_FLASH_SETUP, sizeof (SETUP)); + for ( z = 0; z < inb_p (padapter->regScratchPad + DALE_NUM_DRIVES); ++z ) + { + unit = inb_p (padapter->regScratchPad + DALE_CHANNEL_DEVICE_0 + z) & 0x0F; + padapter->device[z].device = inb_p (padapter->regScratchPad + DALE_SCRATH_DEVICE_0 + unit); + padapter->device[z].byte6 = (UCHAR)(((unit & 1) << 4) | 0xE0); + padapter->device[z].spigot = (UCHAR)(1 << (unit >> 1)); + padapter->device[z].sectors = DaleSetup.setupDevice[unit].sectors; + padapter->device[z].heads = DaleSetup.setupDevice[unit].heads; + padapter->device[z].cylinders = DaleSetup.setupDevice[unit].cylinders; + padapter->device[z].blocks = DaleSetup.setupDevice[unit].blocks; - hostdata->timingMode = inb_p (hostdata->regScratchPad + DALE_TIMING_MODE); - hostdata->timingAddress = modearray[hostdata->timingMode - 2]; - ReadFlash (hostdata, &DaleSetup, DALE_FLASH_SETUP, sizeof (SETUP)); - - for ( z = 0; z < inb_p (hostdata->regScratchPad + DALE_NUM_DRIVES); ++z ) - { - unit = inb_p (hostdata->regScratchPad + DALE_CHANNEL_DEVICE_0 + z) & 0x0F; - hostdata->device[unit].device = inb_p (hostdata->regScratchPad + DALE_SCRATH_DEVICE_0 + unit); - hostdata->device[unit].byte6 = (UCHAR)(((unit & 1) << 4) | 0xE0); - hostdata->device[unit].spigot = (UCHAR)(1 << (unit >> 1)); - hostdata->device[unit].sectors = DaleSetup.setupDevice[unit].sectors; - hostdata->device[unit].heads = DaleSetup.setupDevice[unit].heads; - hostdata->device[unit].cylinders = DaleSetup.setupDevice[unit].cylinders; - hostdata->device[unit].blocks = DaleSetup.setupDevice[unit].blocks; - DEB (printk ("\nHOSTDATA->device = %X", hostdata->device[unit].device)); - DEB (printk ("\n byte6 = %X", hostdata->device[unit].byte6)); - DEB (printk ("\n spigot = %X", hostdata->device[unit].spigot)); - DEB (printk ("\n sectors = %X", hostdata->device[unit].sectors)); - DEB (printk ("\n heads = %X", hostdata->device[unit].heads)); - DEB (printk ("\n cylinders = %X", hostdata->device[unit].cylinders)); - DEB (printk ("\n blocks = %lX", hostdata->device[unit].blocks)); + if ( !z ) + { + ReadFlash (padapter, &DiskMirror, DALE_FLASH_RAID, sizeof (DiskMirror)); + DiskMirror[0].status = inb_p (padapter->regScratchPad + DALE_RAID_0_STATUS); + DiskMirror[1].status = inb_p (padapter->regScratchPad + DALE_RAID_1_STATUS); + if ( (DiskMirror[0].signature == SIGNATURE) && (DiskMirror[1].signature == SIGNATURE) && + (DiskMirror[0].pairIdentifier == (DiskMirror[1].pairIdentifier ^ 1)) ) + { + raidon = TRUE; + } + + memcpy (padapter->device[z].DiskMirror, DiskMirror, sizeof (DiskMirror)); + padapter->raidData[0] = &padapter->device[z].DiskMirror[0]; + padapter->raidData[2] = &padapter->device[z].DiskMirror[1]; + + if ( raidon ) + { + padapter->device[z].lastsectorlba[0] = InlineIdentify (padapter, 1, 0); + padapter->device[z].lastsectorlba[1] = InlineIdentify (padapter, 2, 0); + + if ( !(DiskMirror[1].status & UCBF_SURVIVOR) && padapter->device[z].lastsectorlba[0] ) + spigot1 = TRUE; + if ( !(DiskMirror[0].status & UCBF_SURVIVOR) && padapter->device[z].lastsectorlba[1] ) + spigot2 = TRUE; + if ( DiskMirror[0].status & UCBF_SURVIVOR & DiskMirror[1].status & UCBF_SURVIVOR ) + spigot1 = TRUE; + + if ( spigot1 && (DiskMirror[0].status & UCBF_REBUILD) ) + InlineReadSignature (padapter, &padapter->device[z], 0); + if ( spigot2 && (DiskMirror[1].status & UCBF_REBUILD) ) + InlineReadSignature (padapter, &padapter->device[z], 1); + + if ( spigot1 && spigot2 ) + { + padapter->device[z].raid = 1; + if ( DiskMirror[0].status & UCBF_REBUILD ) + padapter->device[z].spigot = 2; + else + padapter->device[z].spigot = 1; + if ( (DiskMirror[0].status & UCBF_REBUILD) || (DiskMirror[1].status & UCBF_REBUILD) ) + { + padapter->reconOn = padapter->reconIsStarting = TRUE; + } + } + else + { + if ( spigot1 ) + { + if ( DiskMirror[0].status & UCBF_REBUILD ) + goto unregister; + DiskMirror[0].status = UCBF_MIRRORED | UCBF_SURVIVOR; + padapter->device[z].spigot = 1; + } + else + { + if ( DiskMirror[1].status & UCBF_REBUILD ) + goto unregister; + DiskMirror[1].status = UCBF_MIRRORED | UCBF_SURVIVOR; + padapter->device[z].spigot = 2; + } + if ( DaleSetup.rebootRebuil ) + padapter->reconOn = padapter->reconIsStarting = TRUE; + } + + break; + } } - - printk("\nPSI-2220I EIDE CONTROLLER: at I/O = %X/%X IRQ = %d\n", hostdata->basePort, hostdata->regBase, pshost->irq); - printk("(C) 1997 Perceptive Solutions, Inc. All rights reserved\n\n"); - continue; -unregister: - scsi_unregister (pshost); - NumAdapters++; } - return NumAdapters; + + init_timer (&padapter->timer); + padapter->timer.function = TimerExpiry; + padapter->timer.data = (unsigned long)padapter; + init_timer (&padapter->reconTimer); + padapter->reconTimer.function = ReconTimerExpiry; + padapter->reconTimer.data = (unsigned long)padapter; + printk("\nPCI-2220I EIDE CONTROLLER: at I/O = %X/%X IRQ = %d\n", padapter->basePort, padapter->regBase, pshost->irq); + printk("Version %s, Compiled %s %s\n\n", PCI2220I_VERSION, __DATE__, __TIME__); + found++; + if ( ++installed < MAXADAPTER ) + continue; + break;; +unregister:; + scsi_unregister (pshost); + found++; + } + + NumAdapters = installed; + return installed; } /**************************************************************** * Name: Pci2220i_Abort @@ -756,7 +2026,6 @@ ****************************************************************/ int Pci2220i_Abort (Scsi_Cmnd *SCpnt) { - DEB (printk ("pci2220i_abort\n")); return SCSI_ABORT_SNOOZE; } /**************************************************************** @@ -777,6 +2046,47 @@ int Pci2220i_Reset (Scsi_Cmnd *SCpnt, unsigned int reset_flags) { return SCSI_RESET_PUNT; + } +/**************************************************************** + * Name: Pci2220i_Release + * + * Description: Release resources allocated for a single each adapter. + * + * Parameters: pshost - Pointer to SCSI command structure. + * + * Returns: zero. + * + ****************************************************************/ +int Pci2220i_Release (struct Scsi_Host *pshost) + { + PADAPTER2220I padapter = HOSTDATA (pshost); + + if ( padapter->reconOn ) + { + padapter->reconOn = FALSE; // shut down the hot reconstruct + if ( padapter->reconPhase ) + udelay (300000); + if ( padapter->reconTimer.data ) // is the timer running? + { + del_timer (&padapter->reconTimer); + padapter->reconTimer.data = 0; + } + } + + // save RAID status on the board + outb_p (DiskMirror[0].status, padapter->regScratchPad + DALE_RAID_0_STATUS); + outb_p (DiskMirror[1].status, padapter->regScratchPad + DALE_RAID_1_STATUS); + + if ( padapter->irqOwned ) +#if LINUX_VERSION_CODE < LINUXVERSION(1,3,70) + free_irq (pshost->irq); +#else /* version >= v1.3.70 */ + free_irq (pshost->irq, padapter); +#endif /* version >= v1.3.70 */ + release_region (pshost->io_port, pshost->n_io_port); + kfree (padapter->kBuffer); + scsi_unregister(pshost); + return 0; } #include "sd.h" diff -ur --new-file old/linux/drivers/scsi/pci2220i.h new/linux/drivers/scsi/pci2220i.h --- old/linux/drivers/scsi/pci2220i.h Mon Dec 28 07:19:21 1998 +++ new/linux/drivers/scsi/pci2220i.h Tue May 11 19:36:37 1999 @@ -1,39 +1,34 @@ -/*+M************************************************************************* - * Perceptive Solutions, Inc. PCI-2000 device driver proc support for Linux. +/**************************************************************************** + * Perceptive Solutions, Inc. PCI-2220I device driver for Linux. * - * Copyright (c) 1997 Perceptive Solutions, Inc. + * pci2220i.h - Linux Host Driver for PCI-2220i EIDE Adapters * - * 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. + * Copyright (c) 1997-1999 Perceptive Solutions, Inc. + * All Rights Reserved. * - * 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. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that redistributions of source + * code retain the above copyright notice and this comment without + * modification. * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * Technical updates and product information at: + * http://www.psidisk.com * + * Please send questions, comments, bug reports to: + * tech@psidisk.com Technical Support * - * File Name: pci2220i.h - * - * Description: Header file for the SCSI driver for the PCI2220I - * EIDE interface card. - * - *-M*************************************************************************/ - + ****************************************************************************/ #ifndef _PCI2220I_H #define _PCI2220I_H -#include -#include - #ifndef PSI_EIDE_SCSIOP #define PSI_EIDE_SCSIOP 1 +#ifndef LINUX_VERSION_CODE +#include +#endif +#define LINUXVERSION(v,p,s) (((v)<<16) + ((p)<<8) + (s)) + /************************************************/ /* Some defines that we like */ /************************************************/ @@ -46,11 +41,14 @@ #define ULONG unsigned long #define VOID void +#include "psi_dale.h" + /************************************************/ /* Timeout konstants */ /************************************************/ -#define TIMEOUT_READY 10 // 100 mSec -#define TIMEOUT_DRQ 40 // 400 mSec +#define TIMEOUT_READY 100 // 100 mSec +#define TIMEOUT_DRQ 300 // 300 mSec +#define TIMEOUT_DATA (3 * HZ) // 3 seconds /************************************************/ /* Misc. macros */ @@ -76,6 +74,9 @@ + (((long)(((UCHAR *)up)[2])) << 8) \ + ((long)(((UCHAR *)up)[3])) ) +#define SelectSpigot(padapter,spigot) outb_p (spigot, padapter->regStatSel) +#define WriteCommand(padapter,cmd) outb_p (cmd, padapter->regStatCmd) + /************************************************/ /* SCSI CDB operation codes */ /************************************************/ @@ -163,8 +164,6 @@ #define IDE_CMD_READ_MULTIPLE 0xC4 #define IDE_CMD_WRITE_MULTIPLE 0xC5 #define IDE_CMD_SET_MULTIPLE 0xC6 -#define IDE_COMMAND_WRITE_DMA 0xCA -#define IDE_COMMAND_READ_DMA 0xC8 #define IDE_COMMAND_IDENTIFY 0xEC // IDE status definitions @@ -187,23 +186,6 @@ #define IDE_ERROR_UNC 0x40 #define IDE_ERROR_BBK 0x80 -// IDE interface structure -typedef struct _IDE_STRUCT - { - union - { - UCHAR ide[9]; - struct - { - USHORT data; - UCHAR sectors; - UCHAR lba[4]; - UCHAR cmd; - UCHAR spigot; - } ides; - } ide; - } IDE_STRUCT; - // SCSI read capacity structure typedef struct _READ_CAPACITY_DATA { @@ -238,81 +220,73 @@ } INQUIRYDATA, *PINQUIRYDATA; // IDE IDENTIFY data +#pragma pack (1) +#pragma align 1 typedef struct _IDENTIFY_DATA { - USHORT GeneralConfiguration; // 00 - USHORT NumberOfCylinders; // 02 - USHORT Reserved1; // 04 - USHORT NumberOfHeads; // 06 - USHORT UnformattedBytesPerTrack; // 08 - USHORT UnformattedBytesPerSector; // 0A - USHORT SectorsPerTrack; // 0C - USHORT VendorUnique1[3]; // 0E - USHORT SerialNumber[10]; // 14 - USHORT BufferType; // 28 - USHORT BufferSectorSize; // 2A - USHORT NumberOfEccBytes; // 2C - USHORT FirmwareRevision[4]; // 2E - USHORT ModelNumber[20]; // 36 - UCHAR MaximumBlockTransfer; // 5E - UCHAR VendorUnique2; // 5F - USHORT DoubleWordIo; // 60 - USHORT Capabilities; // 62 - USHORT Reserved2; // 64 - UCHAR VendorUnique3; // 66 - UCHAR PioCycleTimingMode; // 67 - UCHAR VendorUnique4; // 68 - UCHAR DmaCycleTimingMode; // 69 - USHORT TranslationFieldsValid:1; // 6A - USHORT Reserved3:15; - USHORT NumberOfCurrentCylinders; // 6C - USHORT NumberOfCurrentHeads; // 6E - USHORT CurrentSectorsPerTrack; // 70 - ULONG CurrentSectorCapacity; // 72 - USHORT Reserved4[197]; // 76 + USHORT GeneralConfiguration; // 0 + USHORT NumberOfCylinders; // 1 + USHORT Reserved1; // 2 + USHORT NumberOfHeads; // 3 + USHORT UnformattedBytesPerTrack; // 4 + USHORT UnformattedBytesPerSector; // 5 + USHORT SectorsPerTrack; // 6 + USHORT NumBytesISG; // 7 Byte Len - inter-sector gap + USHORT NumBytesSync; // 8 - sync field + USHORT NumWordsVUS; // 9 Len - Vendor Unique Info + USHORT SerialNumber[10]; // 10 + USHORT BufferType; // 20 + USHORT BufferSectorSize; // 21 + USHORT NumberOfEccBytes; // 22 + USHORT FirmwareRevision[4]; // 23 + USHORT ModelNumber[20]; // 27 + USHORT NumSectorsPerInt :8; // 47 Multiple Mode - Sec/Blk + USHORT Reserved2 :8; // 47 + USHORT DoubleWordMode; // 48 flag for double word mode capable + USHORT VendorUnique1 :8; // 49 + USHORT SupportDMA :1; // 49 DMA supported + USHORT SupportLBA :1; // 49 LBA supported + USHORT SupportIORDYDisable :1; // 49 IORDY can be disabled + USHORT SupportIORDY :1; // 49 IORDY supported + USHORT ReservedPsuedoDMA :1; // 49 reserved for pseudo DMA mode support + USHORT Reserved3 :3; // 49 + USHORT Reserved4; // 50 + USHORT Reserved5 :8; // 51 Transfer Cycle Timing - PIO + USHORT PIOCycleTime :8; // 51 Transfer Cycle Timing - PIO + USHORT Reserved6 :8; // 52 - DMA + USHORT DMACycleTime :8; // 52 - DMA + USHORT Valid_54_58 :1; // 53 words 54 - 58 are vaild + USHORT Valid_64_70 :1; // 53 words 64 - 70 are valid + USHORT Reserved7 :14; // 53 + USHORT LogNumCyl; // 54 Current Translation - Num Cyl + USHORT LogNumHeads; // 55 Num Heads + USHORT LogSectorsPerTrack; // 56 Sec/Trk + ULONG LogTotalSectors; // 57 Total Sec + USHORT CurrentNumSecPerInt :8; // 59 current setting for number of sectors per interrupt + USHORT ValidNumSecPerInt :1; // 59 Current setting is valid for number of sectors per interrupt + USHORT Reserved8 :7; // 59 + ULONG LBATotalSectors; // 60 LBA Mode - Sectors + USHORT DMASWordFlags; // 62 + USHORT DMAMWordFlags; // 63 + USHORT AdvancedPIOSupport :8; // 64 Flow control PIO transfer modes supported + USHORT Reserved9 :8; // 64 + USHORT MinMultiDMACycle; // 65 minimum multiword DMA transfer cycle time per word + USHORT RecomendDMACycle; // 66 Manufacturer's recommende multiword DMA transfer cycle time + USHORT MinPIOCycleWithoutFlow; // 67 Minimum PIO transfer cycle time without flow control + USHORT MinPIOCylceWithFlow; // 68 Minimum PIO transfer cycle time with IORDY flow control + USHORT ReservedSpace[256-69]; // 69 } IDENTIFY_DATA, *PIDENTIFY_DATA; - -// Identify data without the Reserved4. -typedef struct _IDENTIFY_DATA2 { - USHORT GeneralConfiguration; // 00 - USHORT NumberOfCylinders; // 02 - USHORT Reserved1; // 04 - USHORT NumberOfHeads; // 06 - USHORT UnformattedBytesPerTrack; // 08 - USHORT UnformattedBytesPerSector; // 0A - USHORT SectorsPerTrack; // 0C - USHORT VendorUnique1[3]; // 0E - USHORT SerialNumber[10]; // 14 - USHORT BufferType; // 28 - USHORT BufferSectorSize; // 2A - USHORT NumberOfEccBytes; // 2C - USHORT FirmwareRevision[4]; // 2E - USHORT ModelNumber[20]; // 36 - UCHAR MaximumBlockTransfer; // 5E - UCHAR VendorUnique2; // 5F - USHORT DoubleWordIo; // 60 - USHORT Capabilities; // 62 - USHORT Reserved2; // 64 - UCHAR VendorUnique3; // 66 - UCHAR PioCycleTimingMode; // 67 - UCHAR VendorUnique4; // 68 - UCHAR DmaCycleTimingMode; // 69 - USHORT TranslationFieldsValid:1; // 6A - USHORT Reserved3:15; - USHORT NumberOfCurrentCylinders; // 6C - USHORT NumberOfCurrentHeads; // 6E - USHORT CurrentSectorsPerTrack; // 70 - ULONG CurrentSectorCapacity; // 72 - } IDENTIFY_DATA2, *PIDENTIFY_DATA2; - +#pragma pack () +#pragma align 0 #endif // PSI_EIDE_SCSIOP // function prototypes int Pci2220i_Detect (Scsi_Host_Template *tpnt); -int Pci2220i_Command (Scsi_Cmnd *SCpnt); +int Pci2220i_Command (Scsi_Cmnd *SCpnt); int Pci2220i_QueueCommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)); int Pci2220i_Abort (Scsi_Cmnd *SCpnt); int Pci2220i_Reset (Scsi_Cmnd *SCpnt, unsigned int flags); +int Pci2220i_Release (struct Scsi_Host *pshost); int Pci2220i_BiosParam (Disk *disk, kdev_t dev, int geom[]); #ifndef NULL @@ -321,18 +295,57 @@ extern struct proc_dir_entry Proc_Scsi_Pci2220i; -#define PCI2220I { proc_dir: &Proc_Scsi_Pci2220i,/* proc_dir_entry */ \ - name: "PCI-2220I EIDE Disk Controller",\ - detect: Pci2220i_Detect, \ - command: Pci2220i_Command, \ - queuecommand: Pci2220i_QueueCommand, \ - abort: Pci2220i_Abort, \ - reset: Pci2220i_Reset, \ - bios_param: Pci2220i_BiosParam, \ - can_queue: 1, \ - this_id: -1, \ - sg_tablesize: SG_NONE, \ - cmd_per_lun: 1, \ - use_clustering: DISABLE_CLUSTERING } +#if LINUX_VERSION_CODE >= LINUXVERSION(2,1,75) +#define PCI2220I { \ + next: NULL, \ + module: NULL, \ + proc_dir: &Proc_Scsi_Pci2220i, \ + proc_info: NULL, /* let's not bloat the kernel */\ + name: "PCI-2220I EIDE Disk Controller", \ + detect: Pci2220i_Detect, \ + release: Pci2220i_Release, \ + info: NULL, /* let's not bloat the kernel */\ + command: Pci2220i_Command, \ + queuecommand: Pci2220i_QueueCommand, \ + eh_strategy_handler: NULL, \ + eh_abort_handler: NULL, \ + eh_device_reset_handler: NULL, \ + eh_bus_reset_handler: NULL, \ + eh_host_reset_handler: NULL, \ + abort: Pci2220i_Abort, \ + reset: Pci2220i_Reset, \ + slave_attach: NULL, \ + bios_param: Pci2220i_BiosParam, \ + can_queue: 1, \ + this_id: -1, \ + sg_tablesize: SG_NONE, \ + cmd_per_lun: 1, \ + present: 0, \ + unchecked_isa_dma: 0, \ + use_clustering: DISABLE_CLUSTERING, \ + use_new_eh_code: 0 \ + } +#else +#define PCI2220I { NULL, NULL, \ + &Proc_Scsi_Pci2220i,/* proc_dir_entry */\ + NULL, \ + "PCI-2220I EIDE Disk Controller", \ + Pci2220i_Detect, \ + Pci2220i_Release, \ + NULL, \ + Pci2220i_Command, \ + Pci2220i_QueueCommand, \ + Pci2220i_Abort, \ + Pci2220i_Reset, \ + NULL, \ + Pci2220i_BiosParam, \ + 1, \ + -1, \ + SG_NONE, \ + 1, \ + 0, \ + 0, \ + DISABLE_CLUSTERING } +#endif #endif diff -ur --new-file old/linux/drivers/scsi/pluto.c new/linux/drivers/scsi/pluto.c --- old/linux/drivers/scsi/pluto.c Thu Jun 25 20:04:26 1998 +++ new/linux/drivers/scsi/pluto.c Tue Mar 16 01:11:31 1999 @@ -1,6 +1,6 @@ /* pluto.c: SparcSTORAGE Array SCSI host adapter driver. * - * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * Copyright (C) 1997,1998,1999 Jakub Jelinek (jj@sunsite.mff.cuni.cz) * */ @@ -22,7 +22,7 @@ #include "scsi.h" #include "hosts.h" -#include "../fc4/fcp_scsi.h" +#include "../fc4/fcp_impl.h" #include "pluto.h" #include @@ -56,7 +56,7 @@ static struct timer_list fc_timer __initdata = { 0 }; struct semaphore fc_sem __initdata = MUTEX_LOCKED; -static int pluto_encode_addr(Scsi_Cmnd *SCpnt, u16 *addr); +static int pluto_encode_addr(Scsi_Cmnd *SCpnt, u16 *addr, fc_channel *fc, fcp_cmnd *fcmd); __initfunc(static void pluto_detect_timeout(unsigned long data)) { @@ -100,15 +100,19 @@ tpnt->proc_dir = &proc_scsi_pluto; fcscount = 0; - for_each_online_fc_channel(fc) - fcscount++; + for_each_online_fc_channel(fc) { + if (!fc->posmap) + fcscount++; + } PLND(("%d channels online\n", fcscount)) if (!fcscount) { #if defined(MODULE) && defined(CONFIG_FC4_SOC_MODULE) && defined(CONFIG_KMOD) request_module("soc"); - for_each_online_fc_channel(fc) - fcscount++; + for_each_online_fc_channel(fc) { + if (!fc->posmap) + fcscount++; + } if (!fcscount) #endif return 0; @@ -129,8 +133,9 @@ Scsi_Cmnd *SCpnt; struct Scsi_Host *host; struct pluto *pluto; - + if (i == fcscount) break; + if (fc->posmap) continue; PLD(("trying to find SSA\n")) @@ -233,9 +238,13 @@ host->max_id = inq->targets; host->max_channel = inq->channels; host->irq = fc->irq; - + +#ifdef __sparc_v9__ + host->unchecked_isa_dma = 1; +#endif + host->select_queue_depths = pluto_select_queue_depths; - + fc->channels = inq->channels + 1; fc->targets = inq->targets; fc->ages = ages; @@ -304,7 +313,7 @@ channel 0 id 0 lun 0 for CONTROLLER and channels 1 .. max_channel are normal single disks. */ -static int pluto_encode_addr(Scsi_Cmnd *SCpnt, u16 *addr) +static int pluto_encode_addr(Scsi_Cmnd *SCpnt, u16 *addr, fc_channel *fc, fcp_cmnd *fcmd) { PLND(("encode addr %d %d %d\n", SCpnt->channel, SCpnt->target, SCpnt->cmnd[1] & 0xe0)) /* We don't support LUNs - neither does SSA :) */ @@ -318,6 +327,8 @@ addr[2] = SCpnt->target; addr[3] = 0; } + /* We're Point-to-Point, so target it to the default DID */ + fcmd->did = fc->did; PLND(("trying %04x%04x%04x%04x\n", addr[0], addr[1], addr[2], addr[3])) return 0; } diff -ur --new-file old/linux/drivers/scsi/pluto.h new/linux/drivers/scsi/pluto.h --- old/linux/drivers/scsi/pluto.h Thu Dec 17 00:34:53 1998 +++ new/linux/drivers/scsi/pluto.h Tue Mar 16 01:11:31 1999 @@ -6,7 +6,7 @@ #ifndef _PLUTO_H #define _PLUTO_H -#include "../fc4/fcp_scsi.h" +#include "../fc4/fcp_impl.h" struct pluto { /* This must be first */ diff -ur --new-file old/linux/drivers/scsi/ppa.c new/linux/drivers/scsi/ppa.c --- old/linux/drivers/scsi/ppa.c Sun Jan 10 04:16:43 1999 +++ new/linux/drivers/scsi/ppa.c Fri May 7 19:57:42 1999 @@ -48,7 +48,6 @@ } #include "ppa.h" -#include #define NO_HOSTS 4 static ppa_struct ppa_hosts[NO_HOSTS] = @@ -742,6 +741,7 @@ { ppa_struct *tmp = (ppa_struct *) data; Scsi_Cmnd *cmd = tmp->cur_cmd; + unsigned long flags; if (!cmd) { printk("PPA: bug in ppa_interrupt\n"); @@ -793,7 +793,10 @@ ppa_pb_release(cmd->host->unique_id); tmp->cur_cmd = 0; + + spin_lock_irqsave(&io_request_lock, flags); cmd->scsi_done(cmd); + spin_unlock_irqrestore(&io_request_lock, flags); return; } diff -ur --new-file old/linux/drivers/scsi/ppa.h new/linux/drivers/scsi/ppa.h --- old/linux/drivers/scsi/ppa.h Thu Jan 28 21:42:30 1999 +++ new/linux/drivers/scsi/ppa.h Tue May 11 19:36:59 1999 @@ -10,7 +10,7 @@ #ifndef _PPA_H #define _PPA_H -#define PPA_VERSION "2.03 (for Linux 2.0.0)" +#define PPA_VERSION "2.03 (for Linux 2.2.x)" /* * this driver has been hacked by Matteo Frigo (athena@theory.lcs.mit.edu) diff -ur --new-file old/linux/drivers/scsi/psi240i.c new/linux/drivers/scsi/psi240i.c --- old/linux/drivers/scsi/psi240i.c Wed Sep 9 17:56:58 1998 +++ new/linux/drivers/scsi/psi240i.c Tue Apr 13 16:54:02 1999 @@ -129,7 +129,7 @@ outsw (pports[PORT_DATA], padapter->buffer, (USHORT)padapter->ide.ide.ide[2] * 256); return 0; } - } while ( timer > jiffies ); // test for timeout + } while ( time_after(timer, jiffies) ); // test for timeout padapter->ide.ide.ides.cmd = 0; // null out the command byte return 1; @@ -169,7 +169,7 @@ return 0; } - } while ( timer > jiffies ); // test for timeout + } while ( time_after(timer, jiffies) ); // test for timeout padapter->ide.ide.ides.cmd = 0; // null out the command byte return status; @@ -264,7 +264,7 @@ UCHAR status; int z; - DEB(printk ("\npsi240i recieved interrupt\n")); + DEB(printk ("\npsi240i received interrupt\n")); shost = PsiHost[irq - 10]; if ( !shost ) diff -ur --new-file old/linux/drivers/scsi/psi_dale.h new/linux/drivers/scsi/psi_dale.h --- old/linux/drivers/scsi/psi_dale.h Wed Nov 5 22:06:38 1997 +++ new/linux/drivers/scsi/psi_dale.h Tue Apr 13 16:54:02 1999 @@ -1,32 +1,23 @@ -/*+M************************************************************************* - * Perceptive Solutions, Inc. PCI-2000 device driver proc support for Linux. +/**************************************************************************** + * Perceptive Solutions, Inc. PCI-2220I device driver for Linux. * - * Copyright (c) 1997 Perceptive Solutions, Inc. + * psi_dalei.h - Linux Host Driver for PCI-2220i EIDE Adapters * - * 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. + * Copyright (c) 1997-1999 Perceptive Solutions, Inc. + * All Rights Reserved. * - * 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. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that redistributions of source + * code retain the above copyright notice and this comment without + * modification. * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * Technical updates and product information at: + * http://www.psidisk.com * + * Please send questions, comments, bug reports to: + * tech@psidisk.com Technical Support * - * File Name: psi_dale.h - * - * Description: This file contains the interface defines and - * error codes. - * - *-M*************************************************************************/ - -#ifndef PSI_DALE -#define PSI_DALE + ****************************************************************************/ /************************************************/ /* Dale PCI setup */ @@ -58,24 +49,24 @@ /************************************************/ /* DALE Register address offsets */ /************************************************/ -#define REG_DATA 0x80 -#define REG_ERROR 0x84 -#define REG_SECTOR_COUNT 0x88 -#define REG_LBA_0 0x8C -#define REG_LBA_8 0x90 -#define REG_LBA_16 0x94 -#define REG_LBA_24 0x98 -#define REG_STAT_CMD 0x9C -#define REG_STAT_SEL 0xA0 -#define REG_FAIL 0xB0 -#define REG_ALT_STAT 0xB8 -#define REG_DRIVE_ADRS 0xBC - -#define DALE_DATA_SLOW 0x00040000L -#define DALE_DATA_MODE2 0x00040000L -#define DALE_DATA_MODE3 0x00050000L -#define DALE_DATA_MODE4 0x00060000L -#define DALE_DATA_MODE4P 0x00070000L +#define REG_DATA 0x80 +#define REG_ERROR 0x84 +#define REG_SECTOR_COUNT 0x88 +#define REG_LBA_0 0x8C +#define REG_LBA_8 0x90 +#define REG_LBA_16 0x94 +#define REG_LBA_24 0x98 +#define REG_STAT_CMD 0x9C +#define REG_STAT_SEL 0xA0 +#define REG_FAIL 0xB0 +#define REG_ALT_STAT 0xB8 +#define REG_DRIVE_ADRS 0xBC + +#define DALE_DATA_SLOW 0x00040000L +#define DALE_DATA_MODE2 0x00040000L +#define DALE_DATA_MODE3 0x00050000L +#define DALE_DATA_MODE4 0x00060000L +#define DALE_DATA_MODE4P 0x00070000L #define RTR_LOCAL_RANGE 0x000 #define RTR_LOCAL_REMAP 0x004 @@ -110,52 +101,52 @@ /************************************************/ /* Dale Scratchpad locations */ /************************************************/ -#define DALE_CHANNEL_DEVICE_0 0 // device channel locations -#define DALE_CHANNEL_DEVICE_1 1 -#define DALE_CHANNEL_DEVICE_2 2 -#define DALE_CHANNEL_DEVICE_3 3 - -#define DALE_SCRATH_DEVICE_0 4 // device type codes -#define DALE_SCRATH_DEVICE_1 5 -#define DALE_SCRATH_DEVICE_2 6 -#define DALE_SCRATH_DEVICE_3 7 - -#define DALE_RAID_0_STATUS 8 -#define DALE_RAID_1_STATUS 9 - -#define DALE_TIMING_MODE 12 // bus master timing mode (2, 3, 4, 5) -#define DALE_NUM_DRIVES 13 // number of addressable drives on this board -#define DALE_RAID_ON 14 // RAID status On -#define DALE_LAST_ERROR 15 // Last error code from BIOS +#define DALE_CHANNEL_DEVICE_0 0 // device channel locations +#define DALE_CHANNEL_DEVICE_1 1 +#define DALE_CHANNEL_DEVICE_2 2 +#define DALE_CHANNEL_DEVICE_3 3 + +#define DALE_SCRATH_DEVICE_0 4 // device type codes +#define DALE_SCRATH_DEVICE_1 5 +#define DALE_SCRATH_DEVICE_2 6 +#define DALE_SCRATH_DEVICE_3 7 + +#define DALE_RAID_0_STATUS 8 +#define DALE_RAID_1_STATUS 9 + +#define DALE_TIMING_MODE 12 // bus master timing mode (2, 3, 4, 5) +#define DALE_NUM_DRIVES 13 // number of addressable drives on this board +#define DALE_RAID_ON 14 // RAID status On +#define DALE_LAST_ERROR 15 // Last error code from BIOS /************************************************/ /* Dale cable select bits */ /************************************************/ -#define SEL_NONE 0x00 -#define SEL_1 0x01 -#define SEL_2 0x02 +#define SEL_NONE 0x00 +#define SEL_1 0x01 +#define SEL_2 0x02 /************************************************/ /* Programmable Interrupt Controller */ /************************************************/ -#define PIC1 0x20 // first 8259 base port address -#define PIC2 0xA0 // second 8259 base port address -#define INT_OCW1 1 // Operation Control Word 1: IRQ mask -#define EOI 0x20 // non-specific end-of-interrupt +#define PIC1 0x20 // first 8259 base port address +#define PIC2 0xA0 // second 8259 base port address +#define INT_OCW1 1 // Operation Control Word 1: IRQ mask +#define EOI 0x20 // non-specific end-of-interrupt /************************************************/ /* Device/Geometry controls */ /************************************************/ -#define GEOMETRY_NONE 0x0 // No device -#define GEOMETRY_SET 0x1 // Geometry set -#define GEOMETRY_LBA 0x2 // Geometry set in default LBA mode -#define GEOMETRY_PHOENIX 0x3 // Geometry set in Pheonix BIOS compatibility mode - -#define DEVICE_NONE 0x0 // No device present -#define DEVICE_INACTIVE 0x1 // device present but not registered active -#define DEVICE_ATAPI 0x2 // ATAPI device (CD_ROM, Tape, Etc...) -#define DEVICE_DASD_NONLBA 0x3 // Non LBA incompatible device -#define DEVICE_DASD_LBA 0x4 // LBA compatible device +#define GEOMETRY_NONE 0x0 // No device +#define GEOMETRY_SET 0x1 // Geometry set +#define GEOMETRY_LBA 0x2 // Geometry set in default LBA mode +#define GEOMETRY_PHOENIX 0x3 // Geometry set in Pheonix BIOS compatibility mode + +#define DEVICE_NONE 0x0 // No device present +#define DEVICE_INACTIVE 0x1 // device present but not registered active +#define DEVICE_ATAPI 0x2 // ATAPI device (CD_ROM, Tape, Etc...) +#define DEVICE_DASD_NONLBA 0x3 // Non LBA incompatible device +#define DEVICE_DASD_LBA 0x4 // LBA compatible device /************************************************/ /* Setup Structure Definitions */ @@ -184,4 +175,38 @@ SETUP_DEVICE setupDevice[4]; } SETUP, *PSETUP; -#endif +/************************************************/ +/* RAID Structure Definitions */ +/************************************************/ +typedef struct + { + UCHAR signature; // 0x55 our mirror signature + UCHAR status; // current status bits + UCHAR pairIdentifier; // unique identifier for pair + ULONG reconstructPoint; // recontruction point for hot reconstruct + } DISK_MIRROR; + +typedef struct DEVICE_RAID1 + { + long TotalSectors; + DISK_MIRROR DiskRaid1; + } DEVICE_RAID1, *PDEVICE_RAID1; + +#define DISK_MIRROR_POSITION 0x01A8 +#define SIGNATURE 0x55 + +#define MASK_SERIAL_NUMBER 0x0FFE // mask for serial number matching +#define MASK_SERIAL_UNIT 0x0001 // mask for unit portion of serial number + +// Status bits +#define UCBF_MIRRORED 0x0010 // drive has a pair +#define UCBF_MATCHED 0x0020 // drive pair is matched +#define UCBF_SURVIVOR 0x0040 // this unit is a survivor of a pair +#define UCBF_REBUILD 0x0080 // rebuild in progress on this device + +// SCSI controls for RAID +#define SC_MY_RAID 0xBF // our special CDB command byte for Win95... interface +#define MY_SCSI_QUERY1 0x32 // byte 1 subcommand to query driver for RAID 1 informatation +#define MY_SCSI_REBUILD 0x40 // byte 1 subcommand to reconstruct a mirrored pair +#define MY_SCSI_DEMOFAIL 0x54 // byte 1 subcommand for RAID failure demonstration +#define MY_SCSI_ALARMMUTE 0x60 // byte 1 subcommand to mute any alarm currently on diff -ur --new-file old/linux/drivers/scsi/psi_roy.h new/linux/drivers/scsi/psi_roy.h --- old/linux/drivers/scsi/psi_roy.h Wed Nov 5 22:00:30 1997 +++ new/linux/drivers/scsi/psi_roy.h Tue Apr 13 16:54:02 1999 @@ -1,29 +1,23 @@ -/*+M************************************************************************* - * Perceptive Solutions, Inc. PCI-2000 device driver proc support for Linux. +/**************************************************************************** + * Perceptive Solutions, Inc. PCI-2000 device driver for Linux. * - * Copyright (c) 1997 Perceptive Solutions, Inc. + * psi_roy.h - Linux Host Driver for PCI-2000 IntelliCache SCSI Adapters * - * 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. + * Copyright (c) 1997-1999 Perceptive Solutions, Inc. + * All Rights Reserved. * - * 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. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that redistributions of source + * code retain the above copyright notice and this comment without + * modification. * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * Technical updates and product information at: + * http://www.psidisk.com * + * Please send questions, comments, bug reports to: + * tech@psidisk.com Technical Support * - * File Name: psi_roy.h - * - * Description: This file contains the host interface command and - * error codes. - * - *-M*************************************************************************/ + ****************************************************************************/ #ifndef ROY_HOST #define ROY_HOST @@ -40,7 +34,7 @@ #define MAXADAPTER 4 // Increase this and the sizes of the arrays below, if you need more. #define MAX_BUS 2 #define MAX_UNITS 16 -#define TIMEOUT_COMMAND 30 // number of jiffies for command busy timeout +#define TIMEOUT_COMMAND 400 // number of milliSecondos for command busy timeout /************************************************/ /* I/O address offsets */ @@ -64,6 +58,8 @@ #define CMD_WRITE_CHS_SG 0x08 /* write sectors using scatter/gather list (CHS mode) */ #define CMD_VERIFY_CHS 0x09 /* verify data on sectors as specified (CHS mode) */ #define CMD_VERIFY 0x0A /* verify data on sectors as specified (RBA mode) */ +#define CMD_DASD_CDB 0x0B /* process CDB for a DASD device */ +#define CMD_DASD_CDB_SG 0x0C /* process CDB for a DASD device with scatter/gather */ #define CMD_READ_ABS 0x10 /* read absolute disk */ #define CMD_WRITE_ABS 0x11 /* write absolute disk */ @@ -80,9 +76,14 @@ #define CMD_SCSI_THRU_SG 0x31 /* SCSI pass through CDB with scatter/gather */ #define CMD_SCSI_REQ_SENSE 0x32 /* SCSI pass through request sense after check condition */ -#define CMD_DASD_SCSI_INQ 0x36 /* to DASD inquire for DASD info in SCSI inquiry format */ +#define CMD_DASD_RAID_RQ 0x35 /* request DASD RAID drive data */ +#define CMD_DASD_RAID_RQ0 0x31 /* byte 1 subcommand to query for RAID 0 informatation */ +#define CMD_DASD_RAID_RQ1 0x32 /* byte 1 subcommand to query for RAID 1 informatation */ +#define CMD_DASD_RAID_RQ5 0x33 /* byte 1 subcommand to query for RAID 5 informatation */ + +#define CMD_DASD_SCSI_INQ 0x36 /* do DASD inquire and return in SCSI format */ #define CMD_DASD_CAP 0x37 /* read DASD capacity */ -#define CMD_DASD_INQ 0x38 /* do DASD inquire for type data */ +#define CMD_DASD_INQ 0x38 /* do DASD inquire for type data and return SCSI/EIDE inquiry */ #define CMD_SCSI_INQ 0x39 /* do SCSI inquire */ #define CMD_READ_SETUP 0x3A /* Get setup structures from controller */ #define CMD_WRITE_SETUP 0x3B /* Put setup structures in controller and burn in flash */ @@ -121,6 +122,12 @@ #define CMD_RAID_STATUS 0x57 /* get status of RAID pair */ #define CMD_RAID_STOP 0x58 /* stop any reconstruct in progress */ #define CMD_RAID_START 0x59 /* start reconstruct */ +#define CMD_RAID0_READ 0x5A /* read RAID 0 parameter block */ +#define CMD_RAID0_WRITE 0x5B /* write RAID 0 parameter block */ +#define CMD_RAID5_READ 0x5C /* read RAID 5 parameter block */ +#define CMD_RAID5_WRITE 0x5D /* write RAID 5 parameter block */ + +#define CMD_ERASE_TABLES 0x5F /* erase partition table and RAID signatutures */ #define CMD_SCSI_GET 0x60 /* get SCSI pass through devices */ #define CMD_SCSI_TIMEOUT 0x61 /* set SCSI pass through timeout */ @@ -223,13 +230,13 @@ /* Host Operating System specification codes */ /* */ /************************************************/ - #define SPEC_INTERRUPT 0x80 /* specification requires host interrupt */ #define SPEC_BACKWARD_SG 0x40 /* specification requires scatter/gather items reversed */ #define SPEC_DOS_BLOCK 0x01 /* DOS DASD blocking on pass through */ #define SPEC_OS2_V3 0x02 /* OS/2 Warp */ #define SPCE_SCO_3242 0x04 /* SCO 3.4.2.2 */ - +#define SPEC_QNX_4X 0x05 /* QNX 4.XX */ +#define SPEC_NOVELL_NWPA 0x08 /* Novell NWPA scatter/gather support */ /************************************************/ /* */ @@ -309,6 +316,16 @@ #define DEVC_MEDCHGR 0x08 /* Medium changer device */ #define DEVC_DASD_REMOVABLE 0x80 /* Direct-access storage device, Removable */ #define DEVC_NONE 0xFF /* no device */ + +// SCSI controls for RAID +#define SC_MY_RAID 0xBF // our special CDB command byte for Win95... interface +#define MY_SCSI_QUERY0 0x31 // byte 1 subcommand to query driver for RAID 0 informatation +#define MY_SCSI_QUERY1 0x32 // byte 1 subcommand to query driver for RAID 1 informatation +#define MY_SCSI_QUERY5 0x33 // byte 1 subcommand to query driver for RAID 5 informatation +#define MY_SCSI_REBUILD 0x40 // byte 1 subcommand to reconstruct a mirrored pair +#define MY_SCSI_DEMOFAIL 0x54 // byte 1 subcommand for RAID failure demonstration +#define MY_SCSI_ALARMMUTE 0x60 // byte 1 subcommand to mute any alarm currently on + #endif diff -ur --new-file old/linux/drivers/scsi/qlogicfas.c new/linux/drivers/scsi/qlogicfas.c --- old/linux/drivers/scsi/qlogicfas.c Sat Apr 11 20:13:25 1998 +++ new/linux/drivers/scsi/qlogicfas.c Fri Feb 19 01:29:30 1999 @@ -5,8 +5,8 @@ these silly disclaimers. Copyright 1994, Tom Zerucha. - zerucha@shell.portal.com - + tz@execpc.com + Additional Code, and much appreciated help by Michael A. Griffith grif@cs.ucr.edu diff -ur --new-file old/linux/drivers/scsi/qlogicfc.c new/linux/drivers/scsi/qlogicfc.c --- old/linux/drivers/scsi/qlogicfc.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/scsi/qlogicfc.c Thu Apr 15 14:42:43 1999 @@ -0,0 +1,1921 @@ +/* + * QLogic ISP2100 SCSI-FCP + * Written by Erik H. Moe, ehm@cris.com + * Copyright 1995, Erik H. Moe + * + * 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. + */ + +/* 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 + */ + +/* + * $Date: 1995/09/22 02:23:15 $ + * $Revision: 0.5 $ + * + * $Log: isp1020.c,v $ + * Revision 0.5 1995/09/22 02:23:15 root + * do auto request sense + * + * Revision 0.4 1995/08/07 04:44:33 root + * supply firmware with driver. + * numerous bug fixes/general cleanup of code. + * + * Revision 0.3 1995/07/16 16:15:39 root + * added reset/abort code. + * + * Revision 0.2 1995/06/29 03:14:19 root + * fixed biosparam. + * added queue protocol. + * + * Revision 0.1 1995/06/25 01:55:45 root + * Initial release. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sd.h" +#include "hosts.h" +#include "qlogicfc.h" + +/* Configuration section **************************************************** */ + +/* Set the following macro to 1 to reload the ISP2100's firmware. This is + version 1.15.19 of the firmware. */ + +#define RELOAD_FIRMWARE 1 + +#define USE_NVRAM_DEFAULTS 1 + +#define ISP2100_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 + +/* 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_ISP2100_FABRIC 1 +*/ +/* #define TRACE_ISP 1 */ + + +#define DEFAULT_LOOP_COUNT 10000000 + +/* End Configuration section ************************************************ */ + +#include + +#if TRACE_ISP + +#define TRACE_BUF_LEN (32*1024) + +struct { + u_long next; + struct { + u_long time; + u_int index; + u_int addr; + u_char *name; + } buf[TRACE_BUF_LEN]; +} trace; + +#define TRACE(w, i, a) \ +{ \ + unsigned long flags; \ + \ + save_flags(flags); \ + cli(); \ + trace.buf[trace.next].name = (w); \ + trace.buf[trace.next].time = jiffies; \ + trace.buf[trace.next].index = (i); \ + trace.buf[trace.next].addr = (long) (a); \ + trace.next = (trace.next + 1) & (TRACE_BUF_LEN - 1); \ + restore_flags(flags); \ +} + +#else +#define TRACE(w, i, a) +#endif + +#if DEBUG_ISP2100_FABRIC +#define DEBUG_FABRIC(x) x +#else +#define DEBUG_FABRIC(x) +#endif /* DEBUG_ISP2100_FABRIC */ + + +#if DEBUG_ISP2100 +#define ENTER(x) printk("isp2100 : entering %s()\n", x); +#define LEAVE(x) printk("isp2100 : leaving %s()\n", x); +#define DEBUG(x) x +#else +#define ENTER(x) +#define LEAVE(x) +#define DEBUG(x) +#endif /* DEBUG_ISP2100 */ + +#if DEBUG_ISP2100_INTR +#define ENTER_INTR(x) printk("isp2100 : entering %s()\n", x); +#define LEAVE_INTR(x) printk("isp2100 : 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 */ + + +#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__) +#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))) +#endif + +#define ISP2100_REV_ID 1 +#define ISP2100_REV_ID3 3 + +#define MAX_TARGETS 16 +#define MAX_LUNS 8 + +/* host configuration and control registers */ +#define HOST_HCCR 0xc0 /* host command and control */ + +/* pci bus interface registers */ +#define FLASH_BIOS_ADDR 0x00 +#define FLASH_BIOS_DATA 0x02 +#define ISP_CTRL_STATUS 0x06 /* configuration register #1 */ +#define PCI_INTER_CTL 0x08 /* pci interupt control */ +#define PCI_INTER_STS 0x0a /* pci interupt status */ +#define PCI_SEMAPHORE 0x0c /* pci semaphore */ +#define PCI_NVRAM 0x0e /* pci nvram interface */ + +/* mailbox registers */ +#define MBOX0 0x10 /* mailbox 0 */ +#define MBOX1 0x12 /* mailbox 1 */ +#define MBOX2 0x14 /* mailbox 2 */ +#define MBOX3 0x16 /* mailbox 3 */ +#define MBOX4 0x18 /* mailbox 4 */ +#define MBOX5 0x1a /* mailbox 5 */ +#define MBOX6 0x1c /* mailbox 6 */ +#define MBOX7 0x1e /* mailbox 7 */ + +/* mailbox command complete status codes */ +#define MBOX_COMMAND_COMPLETE 0x4000 +#define INVALID_COMMAND 0x4001 +#define HOST_INTERFACE_ERROR 0x4002 +#define TEST_FAILED 0x4003 +#define COMMAND_ERROR 0x4005 +#define COMMAND_PARAM_ERROR 0x4006 +#define PORT_ID_USED 0x4007 +#define LOOP_ID_USED 0x4008 +#define ALL_IDS_USED 0x4009 + +/* async event status codes */ +#define RESET_DETECTED 0x8001 +#define SYSTEM_ERROR 0x8002 +#define REQUEST_TRANSFER_ERROR 0x8003 +#define RESPONSE_TRANSFER_ERROR 0x8004 +#define REQUEST_QUEUE_WAKEUP 0x8005 +#define LIP_OCCURED 0x8010 +#define LOOP_UP 0x8011 +#define LOOP_DOWN 0x8012 +#define LIP_RECEIVED 0x8013 +#define PORT_DB_CHANGED 0x8014 +#define CHANGE_NOTIFICATION 0x8015 +#define SCSI_COMMAND_COMPLETE 0x8020 + +struct Entry_header { + u_char entry_type; + u_char entry_cnt; + u_char sys_def_1; + u_char flags; +}; + +/* entry header type commands */ +#define ENTRY_COMMAND 0x19 +#define ENTRY_CONTINUATION 0x0a +#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 + +struct dataseg { + u_int d_base_lo; + u_int d_base_high; + u_int d_count; +}; + +struct Command_Entry { + struct Entry_header hdr; + u_int handle; + u_char target_lun; + u_char target_id; + u_short rsvd1; + 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]; +}; + +/* command entry control flag definitions */ +#define CFLAG_NODISC 0x01 +#define CFLAG_HEAD_TAG 0x02 +#define CFLAG_ORDERED_TAG 0x04 +#define CFLAG_SIMPLE_TAG 0x08 +#define CFLAG_TAR_RTN 0x10 +#define CFLAG_READ 0x20 +#define CFLAG_WRITE 0x40 + +struct Ext_Command_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 Continuation_Entry { + struct Entry_header hdr; + struct dataseg dataseg[5]; +}; + +struct Marker_Entry { + struct Entry_header hdr; + u_int reserved; + u_char target_lun; + u_char target_id; + u_char modifier; + u_char rsvd; + u_char rsvds[52]; +}; + +/* marker entry modifier definitions */ +#define SYNC_DEVICE 0 +#define SYNC_TARGET 1 +#define SYNC_ALL 2 + +struct Status_Entry { + struct Entry_header hdr; + u_int handle; + u_short scsi_status; + u_short completion_status; + u_short state_flags; + u_short status_flags; + u_short res_info_len; + u_short req_sense_len; + u_int residual; + u_char res_info[8]; + u_char req_sense_data[32]; +}; + +/* status entry completion status definitions */ +#define CS_COMPLETE 0x0000 +#define CS_DMA_ERROR 0x0002 +#define CS_RESET_OCCURRED 0x0004 +#define CS_ABORTED 0x0005 +#define CS_TIMEOUT 0x0006 +#define CS_DATA_OVERRUN 0x0007 +#define CS_DATA_UNDERRUN 0x0015 +#define CS_QUEUE_FULL 0x001c +#define CS_PORT_UNAVAILABLE 0x0028 +#define CS_PORT_LOGGED_OUT 0x0029 +#define CS_PORT_CONFIG_CHANGED 0x002a + +/* status entry state flag definitions */ +#define SF_SENT_CDB 0x0400 +#define SF_TRANSFERRED_DATA 0x0800 +#define SF_GOT_STATUS 0x1000 + +/* status entry status flag definitions */ +#define STF_BUS_RESET 0x0008 +#define STF_DEVICE_RESET 0x0010 +#define STF_ABORTED 0x0020 +#define STF_TIMEOUT 0x0040 + +/* interupt control commands */ +#define ISP_EN_INT 0x8000 +#define ISP_EN_RISC 0x0008 + +/* host control commands */ +#define HCCR_NOP 0x0000 +#define HCCR_RESET 0x1000 +#define HCCR_PAUSE 0x2000 +#define HCCR_RELEASE 0x3000 +#define HCCR_SINGLE_STEP 0x4000 +#define HCCR_SET_HOST_INTR 0x5000 +#define HCCR_CLEAR_HOST_INTR 0x6000 +#define HCCR_CLEAR_RISC_INTR 0x7000 +#define HCCR_BP_ENABLE 0x8000 +#define HCCR_BIOS_DISABLE 0x9000 +#define HCCR_TEST_MODE 0xf000 + +#define RISC_BUSY 0x0004 + +/* mailbox commands */ +#define MBOX_NO_OP 0x0000 +#define MBOX_LOAD_RAM 0x0001 +#define MBOX_EXEC_FIRMWARE 0x0002 +#define MBOX_DUMP_RAM 0x0003 +#define MBOX_WRITE_RAM_WORD 0x0004 +#define MBOX_READ_RAM_WORD 0x0005 +#define MBOX_MAILBOX_REG_TEST 0x0006 +#define MBOX_VERIFY_CHECKSUM 0x0007 +#define MBOX_ABOUT_FIRMWARE 0x0008 +#define MBOX_LOAD_RISC_RAM 0x0009 +#define MBOX_DUMP_RISC_RAM 0x000a +#define MBOX_CHECK_FIRMWARE 0x000e +#define MBOX_INIT_REQ_QUEUE 0x0010 +#define MBOX_INIT_RES_QUEUE 0x0011 +#define MBOX_EXECUTE_IOCB 0x0012 +#define MBOX_WAKE_UP 0x0013 +#define MBOX_STOP_FIRMWARE 0x0014 +#define MBOX_ABORT_IOCB 0x0015 +#define MBOX_ABORT_DEVICE 0x0016 +#define MBOX_ABORT_TARGET 0x0017 +#define MBOX_BUS_RESET 0x0018 +#define MBOX_STOP_QUEUE 0x0019 +#define MBOX_START_QUEUE 0x001a +#define MBOX_SINGLE_STEP_QUEUE 0x001b +#define MBOX_ABORT_QUEUE 0x001c +#define MBOX_GET_DEV_QUEUE_STATUS 0x001d +#define MBOX_GET_FIRMWARE_STATUS 0x001f +#define MBOX_GET_INIT_SCSI_ID 0x0020 +#define MBOX_GET_RETRY_COUNT 0x0022 +#define MBOX_GET_TARGET_PARAMS 0x0028 +#define MBOX_GET_DEV_QUEUE_PARAMS 0x0029 +#define MBOX_SET_RETRY_COUNT 0x0032 +#define MBOX_SET_TARGET_PARAMS 0x0038 +#define MBOX_SET_DEV_QUEUE_PARAMS 0x0039 +#define MBOX_EXECUTE_IOCB64 0x0054 +#define MBOX_INIT_FIRMWARE 0x0060 +#define MBOX_GET_INIT_CB 0x0061 +#define MBOX_INIT_LIP 0x0062 +#define MBOX_GET_POS_MAP 0x0063 +#define MBOX_GET_PORT_DB 0x0064 +#define MBOX_CLEAR_ACA 0x0065 +#define MBOX_TARGET_RESET 0x0066 +#define MBOX_CLEAR_TASK_SET 0x0067 +#define MBOX_ABORT_TASK_SET 0x0068 +#define MBOX_GET_FIRMWARE_STATE 0x0069 +#define MBOX_GET_PORT_NAME 0x006a +#define MBOX_SEND_SNS 0x006e +#define MBOX_PORT_LOGIN 0x006f +#define MBOX_SEND_CHANGE_REQUEST 0x0070 +#define MBOX_PORT_LOGOUT 0x0071 + +#include "qlogicfc_asm.c" + +/* Each element in mbox_param is an 8 bit bitmap where each bit indicates + if that mbox should be copied as input. For example 0x2 would mean + only copy mbox1. */ + +const u_char mbox_param[] = +{ + 0x01, /* MBOX_NO_OP */ + 0x1f, /* MBOX_LOAD_RAM */ + 0x03, /* MBOX_EXEC_FIRMWARE */ + 0x1f, /* MBOX_DUMP_RAM */ + 0x07, /* MBOX_WRITE_RAM_WORD */ + 0x03, /* MBOX_READ_RAM_WORD */ + 0xff, /* MBOX_MAILBOX_REG_TEST */ + 0x03, /* MBOX_VERIFY_CHECKSUM */ + 0x01, /* MBOX_ABOUT_FIRMWARE */ + 0xff, /* MBOX_LOAD_RISC_RAM */ + 0xff, /* MBOX_DUMP_RISC_RAM */ + 0x00, /* 0x000b */ + 0x00, /* 0x000c */ + 0x00, /* 0x000d */ + 0x01, /* MBOX_CHECK_FIRMWARE */ + 0x00, /* 0x000f */ + 0x1f, /* MBOX_INIT_REQ_QUEUE */ + 0x2f, /* MBOX_INIT_RES_QUEUE */ + 0x0f, /* MBOX_EXECUTE_IOCB */ + 0x03, /* MBOX_WAKE_UP */ + 0x01, /* MBOX_STOP_FIRMWARE */ + 0x0f, /* MBOX_ABORT_IOCB */ + 0x03, /* MBOX_ABORT_DEVICE */ + 0x07, /* MBOX_ABORT_TARGET */ + 0x03, /* MBOX_BUS_RESET */ + 0x03, /* MBOX_STOP_QUEUE */ + 0x03, /* MBOX_START_QUEUE */ + 0x03, /* MBOX_SINGLE_STEP_QUEUE */ + 0x03, /* MBOX_ABORT_QUEUE */ + 0x03, /* MBOX_GET_DEV_QUEUE_STATUS */ + 0x00, /* 0x001e */ + 0x01, /* MBOX_GET_FIRMWARE_STATUS */ + 0x01, /* MBOX_GET_INIT_SCSI_ID */ + 0x00, /* 0x0021 */ + 0x01, /* MBOX_GET_RETRY_COUNT */ + 0x00, /* 0x0023 */ + 0x00, /* 0x0024 */ + 0x00, /* 0x0025 */ + 0x00, /* 0x0026 */ + 0x00, /* 0x0027 */ + 0x03, /* MBOX_GET_TARGET_PARAMS */ + 0x03, /* MBOX_GET_DEV_QUEUE_PARAMS */ + 0x00, /* 0x002a */ + 0x00, /* 0x002b */ + 0x00, /* 0x002c */ + 0x00, /* 0x002d */ + 0x00, /* 0x002e */ + 0x00, /* 0x002f */ + 0x00, /* 0x0030 */ + 0x00, /* 0x0031 */ + 0x07, /* MBOX_SET_RETRY_COUNT */ + 0x00, /* 0x0033 */ + 0x00, /* 0x0034 */ + 0x00, /* 0x0035 */ + 0x00, /* 0x0036 */ + 0x00, /* 0x0037 */ + 0x0f, /* MBOX_SET_TARGET_PARAMS */ + 0x0f, /* MBOX_SET_DEV_QUEUE_PARAMS */ + 0x00, /* 0x003a */ + 0x00, /* 0x003b */ + 0x00, /* 0x003c */ + 0x00, /* 0x003d */ + 0x00, /* 0x003e */ + 0x00, /* 0x003f */ + 0x00, /* 0x0040 */ + 0x00, /* 0x0041 */ + 0x00, /* 0x0042 */ + 0x00, /* 0x0043 */ + 0x00, /* 0x0044 */ + 0x00, /* 0x0045 */ + 0x00, /* 0x0046 */ + 0x00, /* 0x0047 */ + 0x00, /* 0x0048 */ + 0x00, /* 0x0049 */ + 0x00, /* 0x004a */ + 0x00, /* 0x004b */ + 0x00, /* 0x004c */ + 0x00, /* 0x004d */ + 0x00, /* 0x004e */ + 0x00, /* 0x004f */ + 0x00, /* 0x0050 */ + 0x00, /* 0x0051 */ + 0x00, /* 0x0052 */ + 0x00, /* 0x0053 */ + 0xcf, /* MBOX_EXECUTE_IOCB64 */ + 0x00, /* 0x0055 */ + 0x00, /* 0x0056 */ + 0x00, /* 0x0057 */ + 0x00, /* 0x0058 */ + 0x00, /* 0x0059 */ + 0x00, /* 0x005a */ + 0x00, /* 0x005b */ + 0x00, /* 0x005c */ + 0x00, /* 0x005d */ + 0x00, /* 0x005e */ + 0x00, /* 0x005f */ + 0xff, /* MBOX_INIT_FIRMWARE */ + 0xcd, /* MBOX_GET_INIT_CB */ + 0x01, /* MBOX_INIT_LIP */ + 0xcd, /* MBOX_GET_POS_MAP */ + 0xcf, /* MBOX_GET_PORT_DB */ + 0x03, /* MBOX_CLEAR_ACA */ + 0x03, /* MBOX_TARGET_RESET */ + 0x03, /* MBOX_CLEAR_TASK_SET */ + 0x03, /* MBOX_ABORT_TASK_SET */ + 0x01, /* MBOX_GET_FIRMWARE_STATE */ + 0x03, /* MBOX_GET_PORT_NAME */ + 0x00, /* 0x006b */ + 0x00, /* 0x006c */ + 0x00, /* 0x006d */ + 0xcf, /* MBOX_SEND_SNS */ + 0x0f, /* MBOX_PORT_LOGIN */ + 0x03, /* MBOX_SEND_CHANGE_REQUEST */ + 0x03, /* MBOX_PORT_LOGOUT */ +}; + +#define MAX_MBOX_COMMAND (sizeof(mbox_param)/sizeof(u_short)) + + +struct id_name_map { + u64 wwn; + u_char loop_id; +}; + +struct sns_cb { + u_short len; + u_short res1; + u_int response_low; + u_int response_high; + u_short sub_len; + u_short res2; + u_short data[22]; +}; + +/* address of instance of this struct is passed to adapter to initialize things + */ +struct init_cb { + u_char version; + u_char reseverd1[1]; + u_short firm_opts; + u_short max_frame_len; + u_short max_iocb; + u_short exec_throttle; + u_char retry_cnt; + u_char retry_delay; + u_short node_name[4]; + u_short hard_addr; + u_char reserved2[10]; + u_short req_queue_out; + u_short res_queue_in; + u_short req_queue_len; + u_short res_queue_len; + u_int req_queue_addr_lo; + u_int req_queue_addr_high; + u_int res_queue_addr_lo; + u_int res_queue_addr_high; +}; + +/* + * The result queue can be quite a bit smaller since continuation entries + * do not show up there: + */ +#define RES_QUEUE_LEN ((QLOGICFC_REQ_QUEUE_LEN + 1) / 8 - 1) +#define QUEUE_ENTRY_LEN 64 + +#if ISP2100_FABRIC +#define QLOGICFC_MAX_ID 0xff +#else +#define QLOGICFC_MAX_ID 0x80 +#endif + +struct isp2100_hostdata { + u_char revision; + struct pci_dev *pci_dev; + /* result and request queues (shared with isp2100): */ + u_int req_in_ptr; /* index of next request slot */ + u_int res_out_ptr; /* index of next result slot */ + + /* this is here so the queues are nicely aligned */ + long send_marker; /* do we need to send a marker? */ + + 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; + unsigned long int tag_ages[126]; + Scsi_Cmnd *handle_ptrs[QLOGICFC_REQ_QUEUE_LEN + 1]; + unsigned long handle_serials[QLOGICFC_REQ_QUEUE_LEN + 1]; + struct id_name_map port_db[QLOGICFC_MAX_ID + 1]; + u_char mbox_done; + u64 wwn; + u_int port_id; + u_char queued; +}; + + +/* queue length's _must_ be power of two: */ +#define QUEUE_DEPTH(in, out, ql) ((in - out) & (ql)) +#define REQ_QUEUE_DEPTH(in, out) QUEUE_DEPTH(in, out, \ + 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 *); + +#if ISP2100_FABRIC +static int isp2100_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); +#endif + +#if DEBUG_ISP2100 +static void isp2100_print_scsi_cmd(Scsi_Cmnd *); +#endif + +static void isp2100_print_status_entry(struct Status_Entry *); + +static struct proc_dir_entry proc_scsi_isp2100 = +{ + PROC_SCSI_QLOGICFC, 7, "isp2100", + S_IFDIR | S_IRUGO | S_IXUGO, 2 +}; + + +static inline void isp2100_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) +{ + outw(0x0, host->io_port + PCI_INTER_CTL); +} + + +int isp2100_detect(Scsi_Host_Template * tmpt) +{ + int hosts = 0; + int wait_time; + struct Scsi_Host *host = NULL; + struct isp2100_hostdata *hostdata; + struct pci_dev *pdev = NULL; + + ENTER("isp2100_detect"); + + tmpt->proc_dir = &proc_scsi_isp2100; + + 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; + + 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"); + + 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 (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; + } + hosts++; + } + + + /* this busy loop should not be needed but the isp2100 seems to need + some time before recognizing it is attached to a fabric */ + +#if ISP2100_FABRIC + for (wait_time = jiffies + 5 * HZ; wait_time > jiffies;) + barrier(); +#endif + + LEAVE("isp2100_detect"); + + return hosts; +} + + +static int isp2100_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; + + isp2100_disable_irqs(host); + + memset(temp, 0, sizeof(temp)); + hostdata = (struct isp2100_hostdata *) host->hostdata; + +#if ISP2100_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); + + if (param[0] != MBOX_COMMAND_COMPLETE) { + printk("logout failed %x %x\n", i, param[0]); + } + } +#endif + + + param[0] = MBOX_GET_INIT_SCSI_ID; + + isp2100_mbox_command(host, param); + + if (param[0] == MBOX_COMMAND_COMPLETE) { + hostdata->port_id = ((u_int) param[3]) << 16; + hostdata->port_id |= param[2]; + temp[0].loop_id = param[1]; + temp[0].wwn = hostdata->wwn; + } + else { + printk("qlogicfc: error getting scsi id.\n"); + } + + for (i = 1, j = 1; i <= QLOGICFC_MAX_ID; i++) { + temp[i].loop_id = temp[0].loop_id; + + param[0] = MBOX_GET_PORT_NAME; + param[1] = (i << 8) & 0xff00; + + isp2100_mbox_command(host, param); + + if (param[0] == MBOX_COMMAND_COMPLETE) { + temp[j].loop_id = i; + temp[j].wwn = ((u64) (param[2] & 0xff)) << 56; + temp[j].wwn |= ((u64) ((param[2] >> 8) & 0xff)) << 48; + temp[j].wwn |= ((u64) (param[3] & 0xff)) << 40; + temp[j].wwn |= ((u64) ((param[3] >> 8) & 0xff)) << 32; + temp[j].wwn |= ((u64) (param[6] & 0xff)) << 24; + temp[j].wwn |= ((u64) ((param[6] >> 8) & 0xff)) << 16; + temp[j].wwn |= ((u64) (param[7] & 0xff)) << 8; + temp[j].wwn |= ((u64) ((param[7] >> 8) & 0xff)); + + j++; + + } + } + + +#if ISP2100_FABRIC + isp2100_init_fabric(host, temp, j); +#endif + + for (i = 0; i <= QLOGICFC_MAX_ID; i++) { + if (temp[i].wwn != hostdata->port_db[i].wwn) { + for (j = 0; j <= QLOGICFC_MAX_ID; j++) { + if (temp[j].wwn == hostdata->port_db[i].wwn) { + hostdata->port_db[i].loop_id = temp[j].loop_id; + break; + } + } + if (j == QLOGICFC_MAX_ID + 1) + hostdata->port_db[i].loop_id = temp[0].loop_id; + + for (j = 0; j <= QLOGICFC_MAX_ID; j++) { + if (hostdata->port_db[j].wwn == temp[i].wwn || !hostdata->port_db[j].wwn) { + break; + } + } + if (j == QLOGICFC_MAX_ID + 1) + printk("qlogicfc.c: Too many scsi devices, no more room in port map.\n"); + if (!hostdata->port_db[j].wwn) { + hostdata->port_db[j].loop_id = temp[i].loop_id; + hostdata->port_db[j].wwn = temp[i].wwn; + } + } else + hostdata->port_db[i].loop_id = temp[i].loop_id; + + } + + isp2100_enable_irqs(host); + + return 0; +} + + +#if ISP2100_FABRIC + +int isp2100_init_fabric(struct Scsi_Host *host, struct id_name_map *port_db, int j) +{ + + u_short param[8]; + u64 wwn; + int done = 0; + u_short loop_id = 0x81; + u_short scsi_id = j; + u_int port_id; + struct sns_cb req; + u_char sns_response[608]; + struct isp2100_hostdata *hostdata; + + hostdata = (struct isp2100_hostdata *) host->hostdata; + + DEBUG_FABRIC(printk("qlogicfc.c: Checking for a fabric.\n")); + param[0] = MBOX_GET_PORT_NAME; + param[1] = 0x7E00; + + isp2100_mbox_command(host, param); + + if (param[0] != MBOX_COMMAND_COMPLETE) { + DEBUG_FABRIC(printk("fabric check result %x\n", param[0])); + return 0; + } + printk("qlogicfc.c: Fabric found.\n"); + + + port_id = hostdata->port_id; + while (!done) { + memset(&req, 0, sizeof(req)); + + req.len = 304; + 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); + + param[0] = MBOX_SEND_SNS; + param[1] = 14; + 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); + + isp2100_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(" 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; + port_id |= ((u_int) sns_response[19]); + wwn = ((u64) sns_response[20]) << 56; + wwn |= ((u64) sns_response[21]) << 48; + wwn |= ((u64) sns_response[22]) << 40; + wwn |= ((u64) sns_response[23]) << 32; + wwn |= ((u64) sns_response[24]) << 24; + wwn |= ((u64) sns_response[25]) << 16; + 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)); + 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); + + if (param[0] == MBOX_COMMAND_COMPLETE) { + port_db[scsi_id].wwn = wwn; + port_db[scsi_id].loop_id = loop_id; + 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)); + } + + } + if (hostdata->port_id == port_id) + done = 1; + } else { + printk("qlogicfc.c: Get All Next failed %x.\n", param[0]); + return 0; + } + } + + return 1; +} + +#endif /* ISP2100_FABRIC */ + + +int isp2100_release(struct Scsi_Host *host) +{ + struct isp2100_hostdata *hostdata; + + ENTER("isp2100_release"); + + hostdata = (struct isp2100_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"); + + return 0; +} + + +const char *isp2100_info(struct Scsi_Host *host) +{ + static char buf[80]; + struct isp2100_hostdata *hostdata; + ENTER("isp2100_info"); + + hostdata = (struct isp2100_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, + host->io_port); + + + LEAVE("isp2100_info"); + + return buf; +} + + +/* + * The middle SCSI layer ensures that queuecommand never gets invoked + * concurrently with itself or the interrupt handler (though the + * interrupt handler may call this routine as part of + * request-completion handling). + */ +int isp2100_queuecommand(Scsi_Cmnd * Cmnd, void (*done) (Scsi_Cmnd *)) +{ + int i, sg_count, n, num_free; + u_int in_ptr, out_ptr; + struct dataseg *ds; + struct scatterlist *sg; + struct Command_Entry *cmd; + struct Continuation_Entry *cont; + struct Scsi_Host *host; + struct isp2100_hostdata *hostdata; + + ENTER("isp2100_queuecommand"); + + host = Cmnd->host; + hostdata = (struct isp2100_hostdata *) host->hostdata; + Cmnd->scsi_done = done; + + DEBUG(isp2100_print_scsi_cmd(Cmnd)); + + if (hostdata->loop_up == 2) { + hostdata->loop_up = 1; + isp2100_make_portdb(host); + 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)); + } + } + if (hostdata->loop_up == -1) { + printk("qlogicfc.c: The firmware is dead, just return.\n"); + host->max_id = 0; + return 0; + } + + out_ptr = inw(host->io_port + MBOX4); + in_ptr = hostdata->req_in_ptr; + + DEBUG(printk("qlogicfc : request queue depth %d\n", + 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")); + return 1; + } + if (hostdata->send_marker) { + struct Marker_Entry *marker; + + TRACE("queue marker", in_ptr, 0); + + DEBUG(printk("qlogicfc : adding marker entry\n")); + marker = (struct Marker_Entry *) cmd; + memset(marker, 0, sizeof(struct Marker_Entry)); + + marker->hdr.entry_type = ENTRY_MARKER; + marker->hdr.entry_cnt = 1; + marker->modifier = SYNC_ALL; + + hostdata->send_marker = 0; + + 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")); + return 1; + } + cmd = (struct Command_Entry *) &hostdata->req[in_ptr][0]; + in_ptr = (in_ptr + 1) & QLOGICFC_REQ_QUEUE_LEN; + } + TRACE("queue command", in_ptr, Cmnd); + + memset(cmd, 0, sizeof(struct Command_Entry)); + + /* find a free handle mapping slot */ + for (i = in_ptr; i != (in_ptr - 1) && hostdata->handle_ptrs[i]; i = ((i + 1) % (QLOGICFC_REQ_QUEUE_LEN + 1))); + + if (!hostdata->handle_ptrs[i]) { + 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"); + + cmd->hdr.entry_type = ENTRY_COMMAND; + cmd->hdr.entry_cnt = 1; + cmd->target_lun = Cmnd->lun; +#if ISP2100_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; + memcpy(cmd->cdb, Cmnd->cmnd, Cmnd->cmd_len); + + if (Cmnd->use_sg) { + cmd->segment_cnt = sg_count = Cmnd->use_sg; + sg = (struct scatterlist *) Cmnd->request_buffer; + ds = cmd->dataseg; + /* fill in first two sg entries: */ + n = sg_count; + if (n > 2) + n = 2; + 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_count = sg->length; + ++sg; + } + sg_count -= 2; + + while (sg_count > 0) { + ++cmd->hdr.entry_cnt; + cont = (struct Continuation_Entry *) + &hostdata->req[in_ptr][0]; + 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")); + 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; + 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_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->segment_cnt = 1; + } + + switch (Cmnd->cmnd[0]) { + case WRITE_10: + case WRITE_6: + case WRITE_BUFFER: + 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->segment_cnt = 1; + cmd->control_flags = CFLAG_READ; + break; + default: + cmd->control_flags = CFLAG_READ; + break; + } + + + if (Cmnd->device->tagged_supported) { + if ((jiffies - hostdata->tag_ages[Cmnd->target]) > (2 * SCSI_TIMEOUT)) { + cmd->control_flags |= CFLAG_ORDERED_TAG; + hostdata->tag_ages[Cmnd->target] = jiffies; + } else + switch (Cmnd->tag) { + case HEAD_OF_QUEUE_TAG: + cmd->control_flags |= CFLAG_HEAD_TAG; + break; + case ORDERED_QUEUE_TAG: + cmd->control_flags |= CFLAG_ORDERED_TAG; + break; + default: + cmd->control_flags |= CFLAG_SIMPLE_TAG; + break; + } + } + outw(in_ptr, host->io_port + MBOX4); + 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; + if (host->can_queue > QLOGICFC_REQ_QUEUE_LEN) + host->can_queue = QLOGICFC_REQ_QUEUE_LEN; + host->sg_tablesize = QLOGICFC_MAX_SG(num_free); + + /* 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")); + host->can_queue = host->host_busy + 1; + } + + LEAVE("isp2100_queuecommand"); + + return 0; +} + + +#define ASYNC_EVENT_INTERRUPT 0x01 + + +void do_isp2100_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); + spin_unlock_irqrestore(&io_request_lock, flags); +} + +void isp2100_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; + u_int in_ptr, out_ptr, handle, num_free; + u_short status; + + ENTER_INTR("isp2100_intr_handler"); + + hostdata = (struct isp2100_hostdata *) host->hostdata; + + DEBUG_INTR(printk("qlogicfc : interrupt on line %d\n", irq)); + + if (!(inw(host->io_port + PCI_INTER_STS) & 0x08)) { + /* spurious interrupts can happen legally */ + DEBUG_INTR(printk("qlogicfc: got spurious interrupt\n")); + return; + } + in_ptr = inw(host->io_port + MBOX5); + out_ptr = hostdata->res_out_ptr; + + 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)); + + switch (status) { + case LOOP_UP: + hostdata->loop_up = 2; + break; + case LOOP_DOWN: + hostdata->loop_up = 0; + break; + case LIP_OCCURED: + case CHANGE_NOTIFICATION: + case PORT_DB_CHANGED: + case LIP_RECEIVED: + if (hostdata->loop_up == 1) + hostdata->loop_up = 2; + break; + case SYSTEM_ERROR: + printk("The firmware just choked.\n"); + hostdata->loop_up = -1; + break; + case SCSI_COMMAND_COMPLETE: + handle = inw(host->io_port + MBOX1) | (inw(host->io_port + MBOX2) << 16); + Cmnd = hostdata->handle_ptrs[handle]; + hostdata->handle_ptrs[handle] = NULL; + hostdata->handle_serials[handle] = 0; + hostdata->queued--; + if (Cmnd != NULL) { + Cmnd->result = 0x0; + (*Cmnd->scsi_done) (Cmnd); + } else + printk("qlogicfc.c: got a null value out of handle_ptrs, this sucks\n"); + break; + case MBOX_COMMAND_COMPLETE: + case INVALID_COMMAND: + case HOST_INTERFACE_ERROR: + case TEST_FAILED: + case COMMAND_ERROR: + case COMMAND_PARAM_ERROR: + case PORT_ID_USED: + case LOOP_ID_USED: + case ALL_IDS_USED: + hostdata->mbox_done = 1; + outw(HCCR_CLEAR_RISC_INTR, host->io_port + HOST_HCCR); + return; + default: + printk("qlogicfc: got an unknown status? %x\n", 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))); + + 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); + hostdata->handle_ptrs[sts->handle] = NULL; + hostdata->queued--; + if (hostdata->handle_serials[sts->handle] != Cmnd->serial_number) { + hostdata->handle_serials[sts->handle] = 0; + outw(out_ptr, host->io_port + MBOX5); + continue; + } + hostdata->handle_serials[sts->handle] = 0; + } 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; + + memset(Cmnd->sense_buffer, 0, sizeof(Cmnd->sense_buffer)); + if (sts->scsi_status & 0x0200) + memcpy(Cmnd->sense_buffer, sts->req_sense_data, + sizeof(Cmnd->sense_buffer)); + + outw(out_ptr, host->io_port + MBOX5); + + if (Cmnd->scsi_done != NULL) { + (*Cmnd->scsi_done) (Cmnd); + } else + printk("Ouch, scsi done is NULL\n"); + } + hostdata->res_out_ptr = out_ptr; + } + + + out_ptr = inw(host->io_port + MBOX4); + in_ptr = hostdata->req_in_ptr; + + 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; + if (host->can_queue > QLOGICFC_REQ_QUEUE_LEN) + host->can_queue = QLOGICFC_REQ_QUEUE_LEN; + host->sg_tablesize = QLOGICFC_MAX_SG(num_free); + + if (host->can_queue <= host->host_busy){ + if (host->can_queue+2 < host->host_busy) + DEBUG(printk("qlogicfc crosses its fingers.\n")); + host->can_queue = host->host_busy + 1; + } + + outw(HCCR_CLEAR_RISC_INTR, host->io_port + HOST_HCCR); + LEAVE_INTR("isp2100_intr_handler"); +} + + +static int isp2100_return_status(struct Status_Entry *sts) +{ + int host_status = DID_ERROR; +#if DEBUG_ISP2100_INTR + static char *reason[] = + { + "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" + }; +#endif /* DEBUG_ISP2100_INTR */ + + ENTER("isp2100_return_status"); + + DEBUG(printk("qlogicfc : completion status = 0x%04x\n", + sts->completion_status)); + + switch (sts->completion_status) { + case CS_COMPLETE: + host_status = DID_OK; + break; + case CS_DMA_ERROR: + host_status = DID_ERROR; + break; + case CS_RESET_OCCURRED: + host_status = DID_RESET; + break; + case CS_ABORTED: + host_status = DID_ABORT; + break; + case CS_TIMEOUT: + host_status = DID_TIME_OUT; + break; + case CS_DATA_OVERRUN: + host_status = DID_ERROR; + break; + case CS_DATA_UNDERRUN: + host_status = DID_OK; + break; + case CS_PORT_UNAVAILABLE: + case CS_PORT_LOGGED_OUT: + case CS_PORT_CONFIG_CHANGED: + host_status = DID_BAD_TARGET; + break; + case CS_QUEUE_FULL: + host_status = DID_ERROR; + break; + default: + printk("qlogicfc : unknown completion status 0x%04x\n", + sts->completion_status); + host_status = DID_ERROR; + break; + } + + DEBUG_INTR(printk("qlogicfc : host status (%s) scsi status %x\n", + reason[host_status], sts->scsi_status)); + + LEAVE("isp2100_return_status"); + + return (sts->scsi_status & STATUS_MASK) | (host_status << 16); +} + + +int isp2100_abort(Scsi_Cmnd * Cmnd) +{ + u_short param[8]; + int i; + struct Scsi_Host *host; + struct isp2100_hostdata *hostdata; + int return_status = SCSI_ABORT_SUCCESS; + + ENTER("isp2100_abort"); + + host = Cmnd->host; + hostdata = (struct isp2100_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; + + isp2100_disable_irqs(host); + + param[0] = MBOX_ABORT_IOCB; + param[1] = (((u_short) Cmnd->target) << 8) | Cmnd->lun; + param[2] = i >> 16; + param[3] = i & 0xffff; + + isp2100_mbox_command(host, param); + + if (param[0] != MBOX_COMMAND_COMPLETE) { + printk("qlogicfc : scsi abort failure: %x\n", 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; + } + isp2100_enable_irqs(host); + + LEAVE("isp2100_abort"); + + return return_status; +} + + +int isp2100_reset(Scsi_Cmnd * Cmnd, unsigned int reset_flags) +{ + u_short param[8]; + struct Scsi_Host *host; + struct isp2100_hostdata *hostdata; + int return_status = SCSI_RESET_SUCCESS; + + ENTER("isp2100_reset"); + + host = Cmnd->host; + hostdata = (struct isp2100_hostdata *) host->hostdata; + param[0] = MBOX_BUS_RESET; + param[1] = 3; + + isp2100_disable_irqs(host); + + isp2100_mbox_command(host, param); + + if (param[0] != MBOX_COMMAND_COMPLETE) { + printk("qlogicfc : scsi bus reset failure: %x\n", param[0]); + return_status = SCSI_RESET_ERROR; + } + isp2100_enable_irqs(host); + + LEAVE("isp2100_reset"); + + return return_status;; +} + + +int isp2100_biosparam(Disk * disk, kdev_t n, int ip[]) +{ + int size = disk->capacity; + + ENTER("isp2100_biosparam"); + + ip[0] = 64; + ip[1] = 32; + ip[2] = size >> 11; + if (ip[2] > 1024) { + ip[0] = 255; + ip[1] = 63; + ip[2] = size / (ip[0] * ip[1]); + } + LEAVE("isp2100_biosparam"); + + return 0; +} + + +static int isp2100_reset_hardware(struct Scsi_Host *host) +{ + u_short param[8]; + struct isp2100_hostdata *hostdata; + int loop_count; + + ENTER("isp2100_reset_hardware"); + + outw(0x01, host->io_port + ISP_CTRL_STATUS); + outw(HCCR_RESET, host->io_port + HOST_HCCR); + outw(HCCR_RELEASE, host->io_port + HOST_HCCR); + outw(HCCR_BIOS_DISABLE, host->io_port + HOST_HCCR); + + loop_count = DEFAULT_LOOP_COUNT; + while (--loop_count && inw(host->io_port + HOST_HCCR) == RISC_BUSY) + barrier(); + if (!loop_count) + printk("qlogicfc: reset_hardware loop timeout\n"); + + + +#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 */ + + DEBUG(printk("qlogicfc : verifying checksum\n")); + +#if RELOAD_FIRMWARE + { + int i; + for (i = 0; i < risc_code_length01; i++) { + param[0] = MBOX_WRITE_RAM_WORD; + param[1] = risc_code_addr01 + i; + param[2] = risc_code01[i]; + + isp2100_mbox_command(host, param); + + if (param[0] != MBOX_COMMAND_COMPLETE) { + printk("qlogicfc : firmware load failure\n"); + return 1; + } + } + } +#endif /* RELOAD_FIRMWARE */ + + param[0] = MBOX_VERIFY_CHECKSUM; + param[1] = risc_code_addr01; + + isp2100_mbox_command(host, param); + + if (param[0] != MBOX_COMMAND_COMPLETE) { + printk("qlogicfc : ram checksum failure\n"); + return 1; + } + DEBUG(printk("qlogicfc : executing firmware\n")); + + param[0] = MBOX_EXEC_FIRMWARE; + param[1] = risc_code_addr01; + + isp2100_mbox_command(host, param); + + param[0] = MBOX_ABOUT_FIRMWARE; + + isp2100_mbox_command(host, param); + + if (param[0] != MBOX_COMMAND_COMPLETE) { + printk("qlogicfc : about firmware failure\n"); + 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; + +#ifdef USE_NVRAM_DEFAULTS + + if (isp2100_get_nvram_defaults(host, &hostdata->control_block) != 0) { + printk("qlogicfc: Could not read from NVRAM\n"); + } +#endif + + hostdata->wwn = (u64) (hostdata->control_block.node_name[0]) << 56; + hostdata->wwn |= (u64) (hostdata->control_block.node_name[0] & 0xff00) << 48; + hostdata->wwn |= (u64) (hostdata->control_block.node_name[1] & 0xff00) << 24; + hostdata->wwn |= (u64) (hostdata->control_block.node_name[1] & 0x00ff) << 48; + hostdata->wwn |= (u64) (hostdata->control_block.node_name[2] & 0x00ff) << 24; + hostdata->wwn |= (u64) (hostdata->control_block.node_name[2] & 0xff00) << 8; + hostdata->wwn |= (u64) (hostdata->control_block.node_name[3] & 0x00ff) << 8; + hostdata->wwn |= (u64) (hostdata->control_block.node_name[3] & 0xff00) >> 8; + + param[0] = MBOX_INIT_FIRMWARE; + param[2] = (u_short) (virt_to_bus_low32(&hostdata->control_block) >> 16); + param[3] = (u_short) (virt_to_bus_low32(&hostdata->control_block) & 0xffff); + param[4] = 0; + 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); + if (param[0] != MBOX_COMMAND_COMPLETE) { + printk("qlogicfc.c: Ouch 0x%04x\n", param[0]); + return 1; + } + param[0] = MBOX_GET_FIRMWARE_STATE; + isp2100_mbox_command(host, param); + if (param[0] != MBOX_COMMAND_COMPLETE) { + printk("qlogicfc.c: 0x%04x\n", param[0]); + return 1; + } + + LEAVE("isp2100_reset_hardware"); + + return 0; +} + +#ifdef USE_NVRAM_DEFAULTS + +static int isp2100_get_nvram_defaults(struct Scsi_Host *host, struct init_cb *control_block) +{ + + u_short value; + if (isp2100_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); + + return 0; + +} + +#endif + +static int isp2100_init(struct Scsi_Host *sh) +{ + u_int io_base; + struct isp2100_hostdata *hostdata; + u_char revision; + u_int irq; + u_short command; + struct pci_dev *pdev; + + + ENTER("isp2100_init"); + + hostdata = (struct isp2100_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"); + 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", + pdev->vendor); + return 1; + } + if (pdev->device != PCI_DEVICE_ID_QLOGIC_ISP2100) { + printk("qlogicfc : 0x%04x does not match ISP2100 device id\n", + 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"); + return 1; + } + + if (!(command & PCI_COMMAND_MASTER)) { + printk("qlogicfc : bus mastering is disabled\n"); + return 1; + } + if (revision != ISP2100_REV_ID && revision != ISP2100_REV_ID3) + printk("qlogicfc : new isp2100 revision ID (%d)\n", revision); + + + hostdata->revision = revision; + + sh->irq = irq; + sh->io_port = io_base; + + LEAVE("isp2100_init"); + + return 0; +} + +#if USE_NVRAM_DEFAULTS + +#define NVRAM_DELAY() udelay(10) /* 10 microsecond delay */ + + +u_short isp2100_read_nvram_word(struct Scsi_Host * host, u_short byte) +{ + int i; + u_short value, output, input; + + outw(0x2, host->io_port + PCI_NVRAM); + NVRAM_DELAY(); + outw(0x3, host->io_port + PCI_NVRAM); + NVRAM_DELAY(); + + byte &= 0xff; + byte |= 0x0600; + for (i = 10; i >= 0; i--) { + output = ((byte >> i) & 0x1) ? 0x4 : 0x0; + outw(output | 0x2, host->io_port + PCI_NVRAM); + NVRAM_DELAY(); + outw(output | 0x3, host->io_port + PCI_NVRAM); + NVRAM_DELAY(); + outw(output | 0x2, host->io_port + PCI_NVRAM); + NVRAM_DELAY(); + } + + for (i = 0xf, value = 0; i >= 0; i--) { + value <<= 1; + outw(0x3, host->io_port + PCI_NVRAM); + NVRAM_DELAY(); + input = inw(host->io_port + PCI_NVRAM); + NVRAM_DELAY(); + outw(0x2, host->io_port + PCI_NVRAM); + NVRAM_DELAY(); + if (input & 0x8) + value |= 1; + } + + outw(0x0, host->io_port + PCI_NVRAM); + NVRAM_DELAY(); + + return value; +} + + +#endif /* USE_NVRAM_DEFAULTS */ + + + +/* + * 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[]) +{ + int loop_count; + struct isp2100_hostdata *hostdata = (struct isp2100_hostdata *) host->hostdata; + + if (mbox_param[param[0]] == 0) + 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"); + param[0] = 0x4006; + return 1; + } + hostdata->mbox_done = 0; + + if (mbox_param[param[0]] == 0) + printk("qlogicfc: invalid mbox command\n"); + + if (mbox_param[param[0]] & 0x80) + outw(param[7], host->io_port + MBOX7); + if (mbox_param[param[0]] & 0x40) + outw(param[6], host->io_port + MBOX6); + if (mbox_param[param[0]] & 0x20) + outw(param[5], host->io_port + MBOX5); + if (mbox_param[param[0]] & 0x10) + outw(param[4], host->io_port + MBOX4); + if (mbox_param[param[0]] & 0x08) + outw(param[3], host->io_port + MBOX3); + if (mbox_param[param[0]] & 0x04) + outw(param[2], host->io_port + MBOX2); + if (mbox_param[param[0]] & 0x02) + outw(param[1], host->io_port + MBOX1); + if (mbox_param[param[0]] & 0x01) + outw(param[0], host->io_port + MBOX0); + + + outw(HCCR_SET_HOST_INTR, host->io_port + HOST_HCCR); + + while (1) { + loop_count = DEFAULT_LOOP_COUNT; + while (--loop_count && !(inw(host->io_port + PCI_INTER_STS) & 0x08)) { + barrier(); + } + + if (!loop_count) { + printk("qlogicfc: mbox_command loop timeout #2\n"); + break; + } + isp2100_intr_handler(host->irq, host, NULL); + + if (hostdata->mbox_done == 1) + break; + + } + + loop_count = DEFAULT_LOOP_COUNT; + while (--loop_count && inw(host->io_port + MBOX0) == 0x04) { + barrier(); + } + if (!loop_count) + printk("qlogicfc: mbox_command loop timeout #3\n"); + + param[7] = inw(host->io_port + MBOX7); + param[6] = inw(host->io_port + MBOX6); + param[5] = inw(host->io_port + MBOX5); + param[4] = inw(host->io_port + MBOX4); + param[3] = inw(host->io_port + MBOX3); + param[2] = inw(host->io_port + MBOX2); + param[1] = inw(host->io_port + MBOX1); + param[0] = inw(host->io_port + MBOX0); + + + outw(0x0, host->io_port + PCI_SEMAPHORE); + + if (inw(host->io_port + HOST_HCCR) & 0x0080) { + printk("mbox op is still pending\n"); + } + return 0; +} + + +void isp2100_print_status_entry(struct Status_Entry *status) +{ + 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", + 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); + printk("qlogicfc : residual transfer length = 0x%08x, response = 0x%02x\n", status->residual, status->res_info[3]); + +} + + + +#if DEBUG_ISP2100 + +void isp2100_print_scsi_cmd(Scsi_Cmnd * cmd) +{ + int i; + + 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++) + printk("0x%02x ", cmd->cmnd[i]); + printk("\n"); +} + +#endif /* DEBUG_ISP2100 */ + + +#ifdef MODULE + +Scsi_Host_Template driver_template = QLOGICFC; + +#include "scsi_module.c" + +#endif diff -ur --new-file old/linux/drivers/scsi/qlogicfc.h new/linux/drivers/scsi/qlogicfc.h --- old/linux/drivers/scsi/qlogicfc.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/scsi/qlogicfc.h Thu Feb 25 01:27:54 1999 @@ -0,0 +1,102 @@ +/* + * QLogic ISP2100 SCSI-FCP + * + * Written by Erik H. Moe, ehm@cris.com + * Copyright 1995, Erik H. Moe + * + * 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. + */ + +/* 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 + */ + + +/* + * $Date: 1995/09/22 02:32:56 $ + * $Revision: 0.5 $ + * + * $Log: isp1020.h,v $ + * Revision 0.5 1995/09/22 02:32:56 root + * do auto request sense + * + * Revision 0.4 1995/08/07 04:48:28 root + * supply firmware with driver. + * numerous bug fixes/general cleanup of code. + * + * Revision 0.3 1995/07/16 16:17:16 root + * added reset/abort code. + * + * Revision 0.2 1995/06/29 03:19:43 root + * fixed biosparam. + * added queue protocol. + * + * Revision 0.1 1995/06/25 01:56:13 root + * Initial release. + * + */ + +#ifndef _QLOGICFC_H +#define _QLOGICFC_H + +/* + * With the qlogic interface, every queue slot can hold a SCSI + * command with up to 2 scatter/gather entries. If we need more + * than 2 entries, continuation entries can be used that hold + * another 5 entries each. Unlike for other drivers, this means + * that the maximum number of scatter/gather entries we can + * support at any given time is a function of the number of queue + * slots available. That is, host->can_queue and host->sg_tablesize + * are dynamic and _not_ independent. This all works fine because + * 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)) +#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[]); + +#ifndef NULL +#define NULL (0) +#endif + +extern struct proc_dir_entry proc_scsi_isp2100; + +#define QLOGICFC { \ + detect: isp2100_detect, \ + release: isp2100_release, \ + info: isp2100_info, \ + queuecommand: isp2100_queuecommand, \ + abort: isp2100_abort, \ + reset: isp2100_reset, \ + bios_param: isp2100_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, \ + present: 0, \ + unchecked_isa_dma: 0, \ + use_clustering: DISABLE_CLUSTERING \ +} + +#endif /* _QLOGICFC_H */ + + + diff -ur --new-file old/linux/drivers/scsi/qlogicfc_asm.c new/linux/drivers/scsi/qlogicfc_asm.c --- old/linux/drivers/scsi/qlogicfc_asm.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/scsi/qlogicfc_asm.c Thu Apr 15 14:42:43 1999 @@ -0,0 +1,3292 @@ +/************************************************************************ + * * + * --- ISP2100 Fabric Initiator/Target Firmware --- * + * * + * * + ************************************************************************ + * * + * NOTICE * + * * + * COPYRIGHT 1998 QLOGIC CORPORATION * + * ALL RIGHTS RESERVED * + * * + ************************************************************************ + */ + +/* + * Firmware Version 1.15.19 (14:58 Jan 19, 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_code01[] = { + 0x0078, 0x1029, 0x0000, 0x65e6, 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, + 0x2a70, 0x705b, 0x9500, 0x705f, 0xffff, 0x7057, 0x94f9, 0x7063, + 0x0300, 0x1078, 0x1282, 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, + 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, + 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, + 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, + 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, + 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, + 0x0010, 0x2019, 0x61a8, 0x7854, 0x0005, 0x0005, 0xd08c, 0x0040, + 0x122d, 0x7824, 0xd0ac, 0x00c0, 0x1236, 0x8319, 0x00c0, 0x1223, + 0x2001, 0x0001, 0x1078, 0x202b, 0x0078, 0x123d, 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, + 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, + 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, + 0xa084, 0xfffc, 0xa205, 0x20c0, 0x007c, 0x2091, 0x8000, 0x0068, + 0x12d7, 0x007e, 0x017e, 0x2079, 0x0000, 0x7818, 0xa084, 0x0000, + 0x00c0, 0x12dd, 0x017f, 0x792e, 0x007f, 0x782a, 0x007f, 0x7826, + 0x3900, 0x783a, 0x7823, 0x8002, 0x781b, 0x0001, 0x2091, 0x5000, + 0x2091, 0x4080, 0x2079, 0x7600, 0x7803, 0x0005, 0x0078, 0x12f6, + 0x007c, 0x2071, 0x7600, 0x7158, 0x712e, 0x2021, 0x0001, 0xa190, + 0x002d, 0xa298, 0x002d, 0x0048, 0x130f, 0x705c, 0xa302, 0x00c8, + 0x130f, 0x220a, 0x2208, 0x2310, 0x8420, 0x0078, 0x1301, 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, + 0x206b, 0x0000, 0x6807, 0x0000, 0x127f, 0x0e7f, 0x007c, 0x0e7e, + 0x2071, 0x7600, 0x127e, 0x2091, 0x8000, 0x70a0, 0x8001, 0x00c8, + 0x133c, 0xa06e, 0x0078, 0x1345, 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, + 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, + 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, + 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, + 0x700e, 0x22a8, 0x53a6, 0x8203, 0x7822, 0x7803, 0x0020, 0x7803, + 0x0001, 0x3300, 0x7016, 0x157f, 0x147f, 0x137f, 0x027f, 0x017f, + 0x007c, 0x137e, 0x147e, 0x157e, 0x2099, 0x76e5, 0x20a1, 0x0018, + 0x20a9, 0x0008, 0x53a3, 0x7803, 0x0020, 0x127e, 0x2091, 0x8000, + 0x7803, 0x0041, 0x7007, 0x0003, 0x7000, 0xc084, 0x7002, 0x700b, + 0x76e0, 0x127f, 0x157f, 0x147f, 0x137f, 0x007c, 0x137e, 0x147e, + 0x157e, 0x2001, 0x7714, 0x209c, 0x20a1, 0x0014, 0x7803, 0x0026, + 0x2001, 0x7715, 0x20ac, 0x53a6, 0x2099, 0x7716, 0x20a1, 0x0018, + 0x20a9, 0x0008, 0x53a3, 0x7803, 0x0020, 0x127e, 0x2091, 0x8000, + 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, + 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, + 0x2068, 0x7830, 0x6826, 0x7834, 0x682a, 0x7838, 0x682e, 0x783c, + 0x6832, 0x680b, 0x0100, 0x0d7f, 0x7007, 0x0000, 0x1078, 0x13a8, + 0x007c, 0x137e, 0x147e, 0x157e, 0x2001, 0x76e3, 0x2004, 0xa080, + 0x000d, 0x20a0, 0x2099, 0x0014, 0x7803, 0x0040, 0x20a9, 0x0020, + 0x53a5, 0x2001, 0x76e5, 0x2004, 0xd0bc, 0x0040, 0x14e0, 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, + 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, + 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, + 0x6808, 0x8000, 0x680a, 0x0d7f, 0x127e, 0x047e, 0x037e, 0x027e, + 0x2091, 0x2100, 0x027f, 0x037f, 0x047f, 0x7000, 0xa005, 0x00c0, + 0x15a0, 0x7206, 0x2001, 0x15b4, 0x007e, 0x2260, 0x0078, 0x16cc, + 0x710c, 0x220a, 0x8108, 0x230a, 0x8108, 0x240a, 0x8108, 0xa182, + 0x788b, 0x0048, 0x15ad, 0x2009, 0x7870, 0x710e, 0x7000, 0xa005, + 0x00c0, 0x15b4, 0x1078, 0x16b5, 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, + 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, + 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, + 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, + 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, + 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, + 0x686e, 0xa31a, 0x7824, 0x6872, 0xa213, 0x6b2a, 0x6a2e, 0x7820, + 0x6910, 0xa100, 0x6812, 0x7824, 0x6914, 0xa101, 0x6816, 0x037f, + 0x027f, 0x7830, 0x681e, 0x7834, 0x6822, 0x1078, 0x1c59, 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, + 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, + 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, + 0xa213, 0x7810, 0xa100, 0x7812, 0x690c, 0x7814, 0xa101, 0x7816, + 0x0078, 0x18d6, 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 0x007c, 0x707b, 0x0000, 0x608b, 0xbc85, 0x608f, 0xb5b5, 0x6043, + 0x0001, 0x2009, 0x07d0, 0x2011, 0x3542, 0x1078, 0x4561, 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, + 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, + 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, + 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, + 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, + 0x0000, 0x601f, 0x0000, 0x2061, 0x7600, 0x6003, 0x0001, 0x2061, + 0x0100, 0x6043, 0x0090, 0x6043, 0x0010, 0x2009, 0x001e, 0x2011, + 0x35a0, 0x1078, 0x4561, 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, + 0x20a1, 0x7cc0, 0x2099, 0x7b8e, 0x3304, 0x8007, 0x20a2, 0x9398, + 0x94a0, 0x00f0, 0x35c4, 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, + 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, + 0x007c, 0x0d7e, 0x037e, 0x157e, 0x137e, 0x147e, 0x2069, 0x7651, + 0xa006, 0x6002, 0x6007, 0x0707, 0x600a, 0x600e, 0x6012, 0xa198, + 0x232f, 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, + 0x6082, 0x6086, 0x608a, 0x608e, 0x6092, 0x6096, 0x609a, 0x609e, + 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, + 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, + 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, + 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, + 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, + 0x157e, 0x137e, 0x147e, 0x600b, 0x0000, 0x600f, 0x0000, 0x6000, + 0xc08c, 0x6002, 0x2069, 0x7b8e, 0x6808, 0x605e, 0x6810, 0x6062, + 0x6138, 0xa10a, 0x0048, 0x384d, 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, + 0x007c, 0x0e7e, 0x2071, 0x7b8d, 0x2e04, 0x6896, 0x2071, 0x7b8e, + 0x7004, 0x689a, 0x701c, 0x689e, 0x0e7f, 0x007c, 0x2001, 0x75d5, + 0xa600, 0x2004, 0x127e, 0x2091, 0x8000, 0x6178, 0xa10d, 0x617a, + 0x127f, 0x007c, 0x2001, 0x75d5, 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 0x7070, 0xa081, 0x0000, 0x7072, 0x7132, 0x700c, 0x8001, 0x700e, + 0x00c0, 0x3c08, 0x127e, 0x2091, 0x8000, 0x0068, 0x3c0b, 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, + 0x7053, 0x0000, 0x127e, 0x2091, 0x8000, 0x2009, 0x7859, 0x2104, + 0xc08d, 0x200a, 0x127f, 0x1078, 0x1399, 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, + 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, + 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, + 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, + 0x007c, 0x007c, 0x7007, 0x0001, 0x6838, 0xa084, 0x00ff, 0xc0d5, + 0x683a, 0x127e, 0x2091, 0x8000, 0x1078, 0x3a7a, 0x127f, 0x007c, + 0x7007, 0x0001, 0x6838, 0xa084, 0x00ff, 0xc0e5, 0x683a, 0x127e, + 0x2091, 0x8000, 0x1078, 0x3a7a, 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 0x0000, 0x7076, 0xa085, 0x0001, 0x7932, 0x7132, 0x007c, 0x0d7e, + 0x1078, 0x460c, 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, + 0xa080, 0x001f, 0xa084, 0x03f8, 0x80ac, 0x20e1, 0x1000, 0x2ea0, + 0x2099, 0x020a, 0x53a5, 0x007c, 0x20a9, 0x000c, 0x20e1, 0x1000, + 0x2ea0, 0x2099, 0x020a, 0x53a5, 0xa085, 0x0001, 0x0078, 0x41f3, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 0x711a, 0x721e, 0x700b, 0x0009, 0x0e7f, 0x007c, 0x0e7e, 0x007e, + 0x2071, 0x7849, 0x701c, 0xa206, 0x00c0, 0x4578, 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, + 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, + 0x0e7e, 0x2071, 0x7849, 0x7027, 0x07d0, 0x7023, 0x0009, 0x703b, + 0x0002, 0x0e7f, 0x007c, 0x2001, 0x7852, 0x2003, 0x0000, 0x007c, + 0x0e7e, 0x2071, 0x7849, 0x7033, 0x07d0, 0x702f, 0x0009, 0x0e7f, + 0x007c, 0x2011, 0x7855, 0x2013, 0x0000, 0x007c, 0x0e7e, 0x2071, + 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, + 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, + 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, + 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, + 0x127e, 0x2091, 0x8000, 0x600f, 0x0000, 0x2c08, 0x2061, 0x7836, + 0x6020, 0x8000, 0x6022, 0x6010, 0xa005, 0x0040, 0x4840, 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, + 0x605b, 0x0000, 0x007e, 0x2c00, 0x681a, 0x0d7f, 0x685a, 0x2069, + 0x7836, 0x0078, 0x484b, 0x6056, 0x605a, 0x2c00, 0x681a, 0x681e, + 0x0078, 0x484b, 0x007e, 0x017e, 0x0c7e, 0x127e, 0x2091, 0x8000, + 0x600f, 0x0000, 0x2c08, 0x2061, 0x7836, 0x6020, 0x8000, 0x6022, + 0x6008, 0xa005, 0x0040, 0x488d, 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, + 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, + 0x007f, 0x027f, 0x067f, 0x0c7f, 0x0d7f, 0x0e7f, 0x0f7f, 0x007c, + 0x601c, 0xa086, 0x0006, 0x00c0, 0x48f2, 0x1078, 0x74fd, 0x0078, + 0x48fd, 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, + 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, 0x0f7e, 0x127e, 0x2079, 0x7836, 0x2091, 0x8000, 0x1078, + 0x4aa6, 0x1078, 0x4b0e, 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, + 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, + 0x067f, 0x0c7f, 0x0d7f, 0x0e7f, 0x0f7f, 0x007c, 0x601c, 0xa086, + 0x0006, 0x00c0, 0x49e7, 0x1078, 0x74fd, 0x0078, 0x49f2, 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, + 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, + 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, + 0x0d7f, 0x0c7f, 0x067f, 0x007f, 0x007c, 0x601c, 0xa086, 0x0006, + 0x00c0, 0x4aee, 0x1078, 0x74fd, 0x0078, 0x4af7, 0x007e, 0x067e, + 0x0c7e, 0x0d7e, 0x7818, 0xa065, 0x0040, 0x4b7a, 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, + 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, + 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, + 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, + 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, + 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, + 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, + 0x733e, 0x6112, 0x2e10, 0x621a, 0xa180, 0x0015, 0x2004, 0xa08a, + 0x199a, 0x0048, 0x4ced, 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, + 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, + 0x0d7f, 0x007c, 0x0f7e, 0x0d7e, 0x2069, 0x7836, 0x6830, 0xa086, + 0x0000, 0x00c0, 0x4d58, 0x6838, 0xa07d, 0x0040, 0x4d58, 0x6833, + 0x0001, 0x683e, 0x6847, 0x0000, 0x127e, 0x0f7e, 0x2091, 0x2200, + 0x027f, 0x1078, 0x1a4c, 0x00c0, 0x4d5b, 0x127f, 0x1078, 0x5457, + 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, + 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, + 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, + 0x20a3, 0x0300, 0x20a3, 0x0000, 0x7818, 0xa080, 0x0028, 0x2004, + 0xa086, 0x007e, 0x00c0, 0x4e83, 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, + 0x2099, 0x7828, 0x33a6, 0x20a9, 0x0007, 0x20a3, 0x0000, 0x00f0, + 0x4e7d, 0x0078, 0x4ea3, 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, + 0x20a9, 0x0008, 0x53a6, 0x20a9, 0x0008, 0x20a3, 0x0000, 0x00f0, + 0x4ea5, 0x20a9, 0x000a, 0x20a3, 0x0000, 0x00f0, 0x4eab, 0x60c3, + 0x0074, 0x1078, 0x556e, 0x007c, 0x20a1, 0x020b, 0x1078, 0x4fdc, + 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, + 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, + 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0004, + 0x1078, 0x556e, 0x007c, 0x20a1, 0x020b, 0x1078, 0x5053, 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, + 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, + 0x20a2, 0x20a2, 0x20a2, 0x0f7e, 0x2079, 0x7651, 0x7904, 0x0f7f, + 0xd1ac, 0x00c0, 0x4f7d, 0xa085, 0x0020, 0xd1a4, 0x0040, 0x4f82, + 0xa085, 0x0010, 0xa085, 0x0002, 0x20a2, 0x20a2, 0x20a2, 0x60c3, + 0x0014, 0x1078, 0x556e, 0x0d7f, 0x007c, 0x20a1, 0x020b, 0x1078, + 0x5053, 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, + 0x0100, 0x20a3, 0x0000, 0x20a3, 0x000b, 0x20a3, 0x0000, 0x60c3, + 0x0008, 0x1078, 0x556e, 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, + 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, + 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, + 0x20a3, 0x0000, 0x007c, 0x027e, 0x20e1, 0x9080, 0x20e1, 0x4000, + 0x7818, 0xa080, 0x0028, 0x2004, 0xa092, 0x007e, 0x0048, 0x5072, + 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, + 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, + 0x20a2, 0x2fa2, 0x20a3, 0x0000, 0x20a3, 0xffff, 0x20a3, 0x0000, + 0x20a3, 0x0000, 0x60c3, 0x000c, 0x1078, 0x556e, 0x147f, 0x007c, + 0x147e, 0x20a1, 0x020b, 0x1078, 0x5155, 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, + 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, + 0x027e, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028, + 0x2004, 0xa092, 0x007e, 0x0048, 0x5147, 0x0d7e, 0xa0e8, 0x7720, + 0x2d6c, 0x6810, 0xa085, 0x8400, 0x20a2, 0x6814, 0x20a2, 0x2069, + 0x7619, 0x2da6, 0x8d68, 0x2da6, 0x0d7f, 0x0078, 0x514f, 0x20a3, + 0x8400, 0x6298, 0x22a2, 0x20a3, 0x0000, 0x6230, 0x22a2, 0x20a3, + 0x00d1, 0x20a3, 0x0000, 0x0078, 0x507e, 0x027e, 0x20e1, 0x9080, + 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028, 0x2004, 0xa092, 0x007e, + 0x0048, 0x5174, 0x0d7e, 0xa0e8, 0x7720, 0x2d6c, 0x6810, 0xa085, + 0x8500, 0x20a2, 0x6814, 0x20a2, 0x2069, 0x7619, 0x2da6, 0x8d68, + 0x2da6, 0x0d7f, 0x0078, 0x517c, 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, + 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, + 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, + 0x4000, 0x7a18, 0xa280, 0x0023, 0x2014, 0x8210, 0xa294, 0x00ff, + 0x2202, 0x8217, 0x7818, 0xa080, 0x0028, 0x2004, 0xd0bc, 0x0040, + 0x523b, 0x0d7e, 0xa0e8, 0x7720, 0x2d6c, 0x6810, 0xa085, 0x0600, + 0x20a2, 0x6814, 0x20a2, 0x2069, 0x7619, 0x2da6, 0x8d68, 0x2da6, + 0x0d7f, 0x0078, 0x5243, 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, + 0x6880, 0x20a2, 0x687c, 0x20a2, 0xa006, 0x20a2, 0x20a2, 0x20a2, + 0x20a2, 0x60c3, 0x000c, 0x1078, 0x556e, 0x147f, 0x137f, 0x157f, + 0x0d7f, 0x007c, 0x027e, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, + 0xa080, 0x0028, 0x2004, 0xd0bc, 0x0040, 0x5290, 0x0d7e, 0xa0e8, + 0x7720, 0x2d6c, 0x6810, 0xa085, 0x0500, 0x20a2, 0x6814, 0x20a2, + 0x2069, 0x7619, 0x2da6, 0x8d68, 0x2da6, 0x0d7f, 0x0078, 0x5298, + 0x20a3, 0x0500, 0x6298, 0x22a2, 0x20a3, 0x0000, 0x6230, 0x22a2, + 0x20a3, 0x0889, 0x20a3, 0x0000, 0x1078, 0x555d, 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, + 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, + 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, + 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, + 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, + 0x7720, 0x2d6c, 0x6810, 0xa085, 0x0700, 0x20a2, 0x6814, 0x20a2, + 0x2069, 0x7619, 0x2da6, 0x8d68, 0x2da6, 0x0d7f, 0x0078, 0x53c0, + 0x20a3, 0x0700, 0x6298, 0x22a2, 0x20a3, 0x0000, 0x6230, 0x22a2, + 0x20a3, 0x0898, 0x20a3, 0x0000, 0x1078, 0x555d, 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, + 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, + 0x9080, 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028, 0x2004, 0xd0bc, + 0x0040, 0x543c, 0x0d7e, 0xa0e8, 0x7720, 0x2d6c, 0x6810, 0xa085, + 0x0100, 0x20a2, 0x6814, 0x20a2, 0x2069, 0x7619, 0x2da6, 0x8d68, + 0x2da6, 0x0d7f, 0x0078, 0x5444, 0x20a3, 0x0100, 0x6298, 0x22a2, + 0x20a3, 0x0000, 0x6230, 0x22a2, 0x20a3, 0x0888, 0xa18d, 0x0008, + 0x21a2, 0x1078, 0x555d, 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, + 0x6910, 0x6a14, 0x7364, 0x7468, 0x781c, 0xa086, 0x0006, 0x0040, + 0x54c8, 0xd5bc, 0x0040, 0x5484, 0xa185, 0x0100, 0x6062, 0x6266, + 0x636a, 0x646e, 0x0078, 0x548a, 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, + 0x7810, 0x2070, 0x704c, 0xa084, 0x0003, 0xa086, 0x0002, 0x0040, + 0x5517, 0xd5bc, 0x0040, 0x54dc, 0xa185, 0x0100, 0x6062, 0x6266, + 0x636a, 0x646e, 0x0078, 0x54e2, 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, + 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, + 0x2014, 0x8210, 0xa294, 0x00ff, 0x2202, 0x8217, 0x007c, 0x0d7e, + 0x2069, 0x7836, 0x6843, 0x0001, 0x0d7f, 0x007c, 0x20e1, 0x9080, + 0x60a3, 0x0056, 0x60a7, 0x9575, 0x1078, 0x5579, 0x1078, 0x45e0, + 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, + 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, + 0x047e, 0x007e, 0x127e, 0x2091, 0x8000, 0x6018, 0x2068, 0x6ca0, + 0x2071, 0x7836, 0x7018, 0x2068, 0x8dff, 0x0040, 0x5637, 0x68a0, + 0xa406, 0x0040, 0x5627, 0x6854, 0x2068, 0x0078, 0x561c, 0x6010, + 0x2060, 0x643c, 0x6540, 0x6644, 0xa6b4, 0x000f, 0x2d60, 0x1078, + 0x38f9, 0x0040, 0x5637, 0x1078, 0x5902, 0xa085, 0x0001, 0x127f, + 0x007f, 0x047f, 0x057f, 0x067f, 0x0c7f, 0x0d7f, 0x0e7f, 0x007c, + 0x157e, 0x147e, 0x20a1, 0x020b, 0x1078, 0x4fdc, 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, + 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, + 0xa088, 0x0002, 0x21a8, 0x53a6, 0xa080, 0x0004, 0x8003, 0x60c2, + 0x007f, 0xa080, 0x0001, 0x2004, 0x7812, 0x1078, 0x556e, 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 0xa18c, 0x00ff, 0x8107, 0x6130, 0xa18c, 0x00ff, 0xa10d, 0x6088, + 0x628c, 0x608b, 0xbc91, 0x618e, 0x6043, 0x0001, 0x6043, 0x0000, + 0x608a, 0x628e, 0x6a04, 0xa294, 0x4000, 0x00c0, 0x58f2, 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, + 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, + 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, + 0x067f, 0x077f, 0x0c7f, 0x0d7f, 0x0e7f, 0x0f7f, 0x007c, 0x6017, + 0x0000, 0x0c7f, 0xa8c5, 0x0001, 0x0078, 0x59a6, 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, + 0x0e7f, 0x0f7f, 0x007c, 0x6017, 0x0000, 0x0c7f, 0xa8c5, 0x0001, + 0x0078, 0x5a22, 0x0e7e, 0x2071, 0x7836, 0x2001, 0x7600, 0x2004, + 0xa086, 0x0002, 0x00c0, 0x5a40, 0x7007, 0x0005, 0x0078, 0x5a42, + 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, + 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, + 0x20a9, 0x0020, 0x2198, 0xa110, 0x22a0, 0x22c8, 0x53a3, 0x147f, + 0x137f, 0x157f, 0x037f, 0x007c, 0x0d7e, 0x20a1, 0x020b, 0x1078, + 0x5053, 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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 +}; +unsigned short risc_code_length01 = 0x65e6; + diff -ur --new-file old/linux/drivers/scsi/qlogicisp.c new/linux/drivers/scsi/qlogicisp.c --- old/linux/drivers/scsi/qlogicisp.c Wed Nov 25 23:52:22 1998 +++ new/linux/drivers/scsi/qlogicisp.c Fri Apr 23 04:30:08 1999 @@ -27,6 +27,7 @@ #include #include #include +#include #include "sd.h" #include "hosts.h" @@ -49,7 +50,7 @@ /* Macros used for debugging */ #define DEBUG_ISP1020 0 -#define DEBUG_ISP1020_INT 0 +#define DEBUG_ISP1020_INTR 0 #define DEBUG_ISP1020_SETUP 0 #define TRACE_ISP 0 @@ -730,17 +731,17 @@ cmd->hdr.entry_type = ENTRY_COMMAND; cmd->hdr.entry_cnt = 1; - cmd->handle = (u_int) virt_to_bus(Cmnd); + cmd->handle = cpu_to_le32((u_int) virt_to_bus(Cmnd)); cmd->target_lun = Cmnd->lun; cmd->target_id = Cmnd->target; - cmd->cdb_length = Cmnd->cmd_len; - cmd->control_flags = CFLAG_READ | CFLAG_WRITE; - cmd->time_out = 30; + cmd->cdb_length = cpu_to_le16(Cmnd->cmd_len); + cmd->control_flags = cpu_to_le16(CFLAG_READ | CFLAG_WRITE); + cmd->time_out = cpu_to_le16(30); memcpy(cmd->cdb, Cmnd->cmnd, Cmnd->cmd_len); if (Cmnd->use_sg) { - cmd->segment_cnt = sg_count = Cmnd->use_sg; + cmd->segment_cnt = cpu_to_le16(sg_count = Cmnd->use_sg); sg = (struct scatterlist *) Cmnd->request_buffer; ds = cmd->dataseg; @@ -749,8 +750,8 @@ if (n > 4) n = 4; for (i = 0; i < n; i++) { - ds[i].d_base = (u_int) virt_to_bus(sg->address); - ds[i].d_count = sg->length; + ds[i].d_base = cpu_to_le32((u_int) virt_to_bus(sg->address)); + ds[i].d_count = cpu_to_le32(sg->length); ++sg; } sg_count -= 4; @@ -776,18 +777,18 @@ if (n > 7) n = 7; for (i = 0; i < n; ++i) { - ds[i].d_base = (u_int)virt_to_bus(sg->address); - ds[i].d_count = sg->length; + ds[i].d_base = cpu_to_le32((u_int)virt_to_bus(sg->address)); + ds[i].d_count = cpu_to_le32(sg->length); ++sg; } sg_count -= n; } } else { cmd->dataseg[0].d_base = - (u_int) virt_to_bus(Cmnd->request_buffer); + cpu_to_le32((u_int) virt_to_bus(Cmnd->request_buffer)); cmd->dataseg[0].d_count = - (u_int) Cmnd->request_bufflen; - cmd->segment_cnt = 1; + cpu_to_le32((u_int) Cmnd->request_bufflen); + cmd->segment_cnt = cpu_to_le16(1); } outw(in_ptr, host->io_port + MBOX4); @@ -861,22 +862,22 @@ DEBUG_INTR(printk("qlogicisp : response queue update\n")); DEBUG_INTR(printk("qlogicisp : response queue depth %d\n", - QUEUE_DEPTH(in_ptr, out_ptr))); + QUEUE_DEPTH(in_ptr, out_ptr, RES_QUEUE_LEN))); while (out_ptr != in_ptr) { sts = (struct Status_Entry *) &hostdata->res[out_ptr][0]; out_ptr = (out_ptr + 1) & RES_QUEUE_LEN; - Cmnd = (Scsi_Cmnd *) bus_to_virt(sts->handle); + Cmnd = (Scsi_Cmnd *) bus_to_virt(le32_to_cpu(sts->handle)); TRACE("done", out_ptr, Cmnd); - if (sts->completion_status == CS_RESET_OCCURRED - || sts->completion_status == CS_ABORTED - || (sts->status_flags & STF_BUS_RESET)) + if (le16_to_cpu(sts->completion_status) == CS_RESET_OCCURRED + || le16_to_cpu(sts->completion_status) == CS_ABORTED + || (le16_to_cpu(sts->status_flags) & STF_BUS_RESET)) hostdata->send_marker = 1; - if (sts->state_flags & SF_GOT_SENSE) + if (le16_to_cpu(sts->state_flags) & SF_GOT_SENSE) memcpy(Cmnd->sense_buffer, sts->req_sense_data, sizeof(Cmnd->sense_buffer)); @@ -917,24 +918,24 @@ ENTER("isp1020_return_status"); DEBUG(printk("qlogicisp : completion status = 0x%04x\n", - sts->completion_status)); + le16_to_cpu(sts->completion_status))); - switch(sts->completion_status) { + switch(le16_to_cpu(sts->completion_status)) { case CS_COMPLETE: host_status = DID_OK; break; case CS_INCOMPLETE: - if (!(sts->state_flags & SF_GOT_BUS)) + if (!(le16_to_cpu(sts->state_flags) & SF_GOT_BUS)) host_status = DID_NO_CONNECT; - else if (!(sts->state_flags & SF_GOT_TARGET)) + else if (!(le16_to_cpu(sts->state_flags) & SF_GOT_TARGET)) host_status = DID_BAD_TARGET; - else if (!(sts->state_flags & SF_SENT_CDB)) + else if (!(le16_to_cpu(sts->state_flags) & SF_SENT_CDB)) host_status = DID_ERROR; - else if (!(sts->state_flags & SF_TRANSFERRED_DATA)) + else if (!(le16_to_cpu(sts->state_flags) & SF_TRANSFERRED_DATA)) host_status = DID_ERROR; - else if (!(sts->state_flags & SF_GOT_STATUS)) + else if (!(le16_to_cpu(sts->state_flags) & SF_GOT_STATUS)) host_status = DID_ERROR; - else if (!(sts->state_flags & SF_GOT_SENSE)) + else if (!(le16_to_cpu(sts->state_flags) & SF_GOT_SENSE)) host_status = DID_ERROR; break; case CS_DMA_ERROR: @@ -970,17 +971,17 @@ break; default: printk("qlogicisp : unknown completion status 0x%04x\n", - sts->completion_status); + le16_to_cpu(sts->completion_status)); host_status = DID_ERROR; break; } DEBUG_INTR(printk("qlogicisp : host status (%s) scsi status %x\n", - reason[host_status], sts->scsi_status)); + reason[host_status], le16_to_cpu(sts->scsi_status))); LEAVE("isp1020_return_status"); - return (sts->scsi_status & STATUS_MASK) | (host_status << 16); + return (le16_to_cpu(sts->scsi_status) & STATUS_MASK) | (host_status << 16); } @@ -1082,7 +1083,9 @@ ENTER("isp1020_reset_hardware"); outw(ISP_RESET, host->io_port + PCI_INTF_CTL); + udelay(100); outw(HCCR_RESET, host->io_port + HOST_HCCR); + udelay(100); outw(HCCR_RELEASE, host->io_port + HOST_HCCR); outw(HCCR_BIOS_DISABLE, host->io_port + HOST_HCCR); @@ -1103,27 +1106,25 @@ printk("qlogicisp : mbox 5 0x%04x \n", inw(host->io_port + MBOX5)); #endif /* DEBUG_ISP1020 */ + param[0] = MBOX_NO_OP; + isp1020_mbox_command(host, param); + if (param[0] != MBOX_COMMAND_COMPLETE) { + printk("qlogicisp : NOP test failed\n"); + return 1; + } + DEBUG(printk("qlogicisp : loading risc ram\n")); #if RELOAD_FIRMWARE - /* Do not reload firmware if 1040B, i.e. revision 5 chip. */ - if (((struct isp1020_hostdata *) host->hostdata)->revision >= 5) - printk("qlogicisp : 1040B or later chip," - " firmware not (re)loaded\n"); - else - { - int i; - for (i = 0; i < risc_code_length01; i++) { - param[0] = MBOX_WRITE_RAM_WORD; - param[1] = risc_code_addr01 + i; - param[2] = risc_code01[i]; - - isp1020_mbox_command(host, param); - - if (param[0] != MBOX_COMMAND_COMPLETE) { - printk("qlogicisp : firmware load failure\n"); - return 1; - } + for (loop_count = 0; loop_count < risc_code_length01; loop_count++) { + param[0] = MBOX_WRITE_RAM_WORD; + param[1] = risc_code_addr01 + loop_count; + param[2] = risc_code01[loop_count]; + isp1020_mbox_command(host, param); + if (param[0] != MBOX_COMMAND_COMPLETE) { + printk("qlogicisp : firmware load failure at %d\n", + loop_count); + return 1; } } #endif /* RELOAD_FIRMWARE */ @@ -1200,6 +1201,15 @@ return 1; } +#ifdef __sparc__ + command |= (PCI_COMMAND_MASTER|PCI_COMMAND_IO|PCI_COMMAND_MEMORY| + PCI_COMMAND_INVALIDATE|PCI_COMMAND_SERR); + pci_write_config_word(pdev, PCI_COMMAND, command); + pci_read_config_word(pdev, PCI_COMMAND, &command); + pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 16); + pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64); +#endif + if (command & PCI_COMMAND_IO && (io_base & 3) == 1) io_base &= PCI_BASE_ADDRESS_IO_MASK; else { @@ -1227,6 +1237,8 @@ sh->irq = irq; sh->io_port = io_base; + sh->max_id = MAX_TARGETS; + sh->max_lun = MAX_LUNS; LEAVE("isp1020_init"); @@ -1691,14 +1703,15 @@ printk("qlogicisp : entry count = 0x%02x, type = 0x%02x, flags = 0x%02x\n", status->hdr.entry_cnt, status->hdr.entry_type, status->hdr.flags); printk("qlogicisp : scsi status = 0x%04x, completion status = 0x%04x\n", - status->scsi_status, status->completion_status); + le16_to_cpu(status->scsi_status), le16_to_cpu(status->completion_status)); printk("qlogicisp : state flags = 0x%04x, status flags = 0x%04x\n", - status->state_flags, status->status_flags); + le16_to_cpu(status->state_flags), le16_to_cpu(status->status_flags)); printk("qlogicisp : time = 0x%04x, request sense length = 0x%04x\n", - status->time, status->req_sense_len); - printk("qlogicisp : residual transfer length = 0x%08x\n", status->residual); + le16_to_cpu(status->time), le16_to_cpu(status->req_sense_len)); + printk("qlogicisp : residual transfer length = 0x%08x\n", + le32_to_cpu(status->residual)); - for (i = 0; i < status->req_sense_len; i++) + for (i = 0; i < le16_to_cpu(status->req_sense_len); i++) printk("qlogicisp : sense data = 0x%02x\n", status->req_sense_data[i]); } diff -ur --new-file old/linux/drivers/scsi/qlogicisp_asm.c new/linux/drivers/scsi/qlogicisp_asm.c --- old/linux/drivers/scsi/qlogicisp_asm.c Sun Feb 2 14:34:32 1997 +++ new/linux/drivers/scsi/qlogicisp_asm.c Fri Apr 23 04:30:08 1999 @@ -1,1304 +1,2034 @@ /* - * Version 2.10 Initiator Firmware (16:13 Oct 18, 1995) + * Firmware Version 7.63.00 (12:07 Jan 27, 1999) */ - -static const unsigned short risc_code_version = 2*1024+10; +static const unsigned short risc_code_version = 7*1024+63; static const unsigned short risc_code_addr01 = 0x1000 ; #if RELOAD_FIRMWARE -static const unsigned short risc_code01[] = { - 0x0078, 0x1041, 0x0000, 0x283a, 0x0000, 0x2043, 0x4f50, 0x5952, - 0x4947, 0x4854, 0x2031, 0x3939, 0x312c, 0x3139, 0x3932, 0x2c31, - 0x3939, 0x332c, 0x3139, 0x3934, 0x2051, 0x4c4f, 0x4749, 0x4320, - 0x434f, 0x5250, 0x4f52, 0x4154, 0x494f, 0x4e00, 0x2049, 0x5350, - 0x3130, 0x3230, 0x2046, 0x6972, 0x6d77, 0x6172, 0x6520, 0x2056, - 0x6572, 0x7369, 0x6f6e, 0x2030, 0x322e, 0x3130, 0x2020, 0x2043, - 0x7573, 0x746f, 0x6d65, 0x7220, 0x4e6f, 0x2e20, 0x3030, 0x2050, - 0x726f, 0x6475, 0x6374, 0x204e, 0x6f2e, 0x2020, 0x3030, 0x2020, - 0x2400, 0x20b9, 0x1212, 0x2071, 0x0010, 0x70c3, 0x0004, 0x20c9, - 0x43ff, 0x2089, 0x115b, 0x70c7, 0x4953, 0x70cb, 0x5020, 0x70cf, - 0x2020, 0x70d3, 0x0002, 0x3f00, 0x70d6, 0x20c1, 0x0008, 0x2019, - 0x0000, 0x2009, 0xfeff, 0x2100, 0x200b, 0xa5a5, 0xa1ec, 0x7fff, - 0x2d64, 0x206b, 0x0a0a, 0xaddc, 0x3fff, 0x2b54, 0x205b, 0x5050, - 0x2114, 0xa286, 0xa5a5, 0x0040, 0x10b3, 0xa386, 0x000f, 0x0040, - 0x1079, 0x2c6a, 0x2a5a, 0x20c1, 0x0000, 0x2019, 0x000f, 0x0078, - 0x1059, 0x2c6a, 0x2a5a, 0x20c1, 0x0008, 0x2009, 0x7fff, 0x2148, - 0x2944, 0x204b, 0x0a0a, 0xa9bc, 0x3fff, 0x2734, 0x203b, 0x5050, - 0x2114, 0xa286, 0x0a0a, 0x0040, 0x109d, 0x284a, 0x263a, 0x20c1, - 0x0004, 0x2009, 0x3fff, 0x2134, 0x200b, 0x5050, 0x2114, 0xa286, - 0x5050, 0x0040, 0x109e, 0x0078, 0x1163, 0x284a, 0x263a, 0x98c0, - 0xa188, 0x1000, 0x212c, 0x200b, 0xa5a5, 0x2114, 0xa286, 0xa5a5, - 0x0040, 0x10b0, 0x250a, 0xa18a, 0x1000, 0x98c1, 0x0078, 0x10b5, - 0x250a, 0x0078, 0x10b5, 0x2c6a, 0x2a5a, 0x2130, 0xa18a, 0x0040, - 0x2128, 0xa1a2, 0x3900, 0x8424, 0x8424, 0x8424, 0x8424, 0x8424, - 0x8424, 0xa192, 0x4400, 0x2009, 0x0000, 0x2001, 0x002f, 0x1078, - 0x1a70, 0x2218, 0x2079, 0x3900, 0x2fa0, 0x2408, 0x2011, 0x0000, - 0x20a9, 0x0040, 0x42a4, 0x8109, 0x00c0, 0x10d0, 0x7eea, 0x7dde, - 0x8528, 0x7dda, 0x7ce2, 0x7be6, 0x787b, 0x0000, 0x2031, 0x0030, - 0x78c3, 0x0101, 0x780b, 0x0002, 0x780f, 0x0002, 0x784f, 0x0003, - 0x2069, 0x3940, 0x681b, 0x0028, 0x6807, 0x0007, 0x680b, 0x00fa, - 0x680f, 0x0008, 0x6813, 0x0005, 0x681f, 0x0000, 0x6823, 0x0006, - 0x6817, 0x0008, 0x6827, 0x0000, 0x2069, 0x3a00, 0x2011, 0x0020, - 0x2009, 0x0010, 0x680b, 0x0c19, 0x680f, 0x0019, 0x6803, 0xfd00, +static const unsigned short risc_code01[] = { + 0x0078, 0x103a, 0x0000, 0x3f14, 0x0000, 0x2043, 0x4f50, 0x5952, + 0x4947, 0x4854, 0x2031, 0x3939, 0x3520, 0x514c, 0x4f47, 0x4943, + 0x2043, 0x4f52, 0x504f, 0x5241, 0x5449, 0x4f4e, 0x2049, 0x5350, + 0x3130, 0x3230, 0x2049, 0x2f54, 0x2046, 0x6972, 0x6d77, 0x6172, + 0x6520, 0x2056, 0x6572, 0x7369, 0x6f6e, 0x2030, 0x372e, 0x3633, + 0x2020, 0x2043, 0x7573, 0x746f, 0x6d65, 0x7220, 0x4e6f, 0x2e20, + 0x3030, 0x2050, 0x726f, 0x6475, 0x6374, 0x204e, 0x6f2e, 0x2020, + 0x3031, 0x2024, 0x2001, 0x04fd, 0x2004, 0xa082, 0x0005, 0x0048, + 0x1045, 0x0038, 0x104b, 0x0078, 0x1047, 0x0028, 0x104b, 0x20b9, + 0x1212, 0x0078, 0x104d, 0x20b9, 0x2222, 0x20c1, 0x0008, 0x2071, + 0x0010, 0x70c3, 0x0004, 0x20c9, 0x76ff, 0x2089, 0x1186, 0x70c7, + 0x4953, 0x70cb, 0x5020, 0x70cf, 0x2020, 0x70d3, 0x0007, 0x3f00, + 0x70d6, 0x20c1, 0x0008, 0x2019, 0x0000, 0x2009, 0xfeff, 0x2100, + 0x200b, 0xa5a5, 0xa1ec, 0x7fff, 0x2d64, 0x206b, 0x0a0a, 0xaddc, + 0x3fff, 0x2b54, 0x205b, 0x5050, 0x2114, 0xa286, 0xa5a5, 0x0040, + 0x10bf, 0xa386, 0x000f, 0x0040, 0x1085, 0x2c6a, 0x2a5a, 0x20c1, + 0x0000, 0x2019, 0x000f, 0x0078, 0x1065, 0x2c6a, 0x2a5a, 0x20c1, + 0x0008, 0x2009, 0x7fff, 0x2148, 0x2944, 0x204b, 0x0a0a, 0xa9bc, + 0x3fff, 0x2734, 0x203b, 0x5050, 0x2114, 0xa286, 0x0a0a, 0x0040, + 0x10a9, 0x284a, 0x263a, 0x20c1, 0x0004, 0x2009, 0x3fff, 0x2134, + 0x200b, 0x5050, 0x2114, 0xa286, 0x5050, 0x0040, 0x10aa, 0x0078, + 0x118e, 0x284a, 0x263a, 0x98c0, 0xa188, 0x1000, 0x212c, 0x200b, + 0xa5a5, 0x2114, 0xa286, 0xa5a5, 0x0040, 0x10bc, 0x250a, 0xa18a, + 0x1000, 0x98c1, 0x0078, 0x10c1, 0x250a, 0x0078, 0x10c1, 0x2c6a, + 0x2a5a, 0x2130, 0xa18a, 0x0040, 0x2128, 0xa1a2, 0x5000, 0x8424, + 0x8424, 0x8424, 0x8424, 0x8424, 0x8424, 0xa192, 0x7700, 0x2009, + 0x0000, 0x2001, 0x0031, 0x1078, 0x1c9d, 0x2218, 0x2079, 0x5000, + 0x2fa0, 0x2408, 0x2011, 0x0000, 0x20a9, 0x0040, 0x42a4, 0x8109, + 0x00c0, 0x10dc, 0x7ef2, 0x8528, 0x7de6, 0x7cea, 0x7bee, 0x7883, + 0x0000, 0x2031, 0x0030, 0x78cf, 0x0101, 0x780b, 0x0002, 0x780f, + 0x0002, 0x784f, 0x0003, 0x2069, 0x5040, 0x2001, 0x04fd, 0x2004, + 0xa082, 0x0005, 0x0048, 0x1104, 0x0038, 0x1100, 0x0078, 0x1108, + 0x681b, 0x003c, 0x0078, 0x110a, 0x00a8, 0x1108, 0x681b, 0x003c, + 0x681b, 0x0028, 0x6807, 0x0007, 0x680b, 0x00fa, 0x680f, 0x0008, + 0x6813, 0x0005, 0x6823, 0x0000, 0x6827, 0x0006, 0x6817, 0x0008, + 0x682b, 0x0000, 0x681f, 0x0019, 0x2069, 0x5280, 0x2011, 0x0020, + 0x2009, 0x0010, 0x680b, 0x080c, 0x680f, 0x0019, 0x6803, 0xfd00, 0x6807, 0x0018, 0x6a1a, 0x2d00, 0xa0e8, 0x0008, 0xa290, 0x0004, - 0x8109, 0x00c0, 0x1102, 0x2069, 0x3a80, 0x20a9, 0x0080, 0x680b, - 0x0040, 0x7be8, 0xa386, 0xfeff, 0x00c0, 0x1124, 0x6817, 0x0100, - 0x681f, 0x0064, 0x0078, 0x1128, 0x6817, 0x0064, 0x681f, 0x0002, - 0xade8, 0x0010, 0x0070, 0x112e, 0x0078, 0x1117, 0x1078, 0x1d15, - 0x1078, 0x3366, 0x1078, 0x18a4, 0x1078, 0x37fc, 0x3200, 0xa085, - 0x000d, 0x2090, 0x70c3, 0x0000, 0x0090, 0x1145, 0x70c0, 0xa086, - 0x0002, 0x00c0, 0x1145, 0x1078, 0x1274, 0x1078, 0x1186, 0x78c0, - 0xa005, 0x00c0, 0x1151, 0x1078, 0x1a99, 0x0068, 0x1155, 0x1078, - 0x1c6f, 0x0068, 0x1155, 0x1078, 0x1997, 0x00e0, 0x1145, 0x1078, - 0x369a, 0x0078, 0x1145, 0x1163, 0x1165, 0x1ebb, 0x1ebb, 0x33d7, - 0x33d7, 0x1ebb, 0x1ebb, 0x0078, 0x1163, 0x0078, 0x1165, 0x0078, - 0x1167, 0x0078, 0x1169, 0x2009, 0x0022, 0x2104, 0xa086, 0x4000, - 0x0040, 0x1181, 0x7008, 0x800b, 0x00c8, 0x1181, 0x7007, 0x0002, - 0xa08c, 0x0060, 0x00c0, 0x1182, 0xa084, 0x0008, 0x0040, 0x1181, - 0x087a, 0x097a, 0x70c3, 0x4002, 0x0078, 0x1277, 0x0068, 0x11f1, - 0x2061, 0x0000, 0x6018, 0xa084, 0x0001, 0x00c0, 0x11f1, 0x7814, - 0xa005, 0x00c0, 0x1197, 0x0010, 0x11f2, 0x0078, 0x11f1, 0x2009, - 0x3968, 0x2104, 0xa005, 0x00c0, 0x11f1, 0x2009, 0x3971, 0x200b, - 0x0000, 0x7914, 0xa186, 0x0042, 0x00c0, 0x11bc, 0x7816, 0x2009, - 0x396f, 0x2164, 0x200b, 0x0000, 0x6018, 0x70c6, 0x6014, 0x70ca, + 0x8109, 0x00c0, 0x1122, 0x2069, 0x5300, 0x2009, 0x0002, 0x20a9, + 0x0100, 0x6837, 0x0000, 0x680b, 0x0040, 0x7bf0, 0xa386, 0xfeff, + 0x00c0, 0x1148, 0x6817, 0x0100, 0x681f, 0x0064, 0x0078, 0x114c, + 0x6817, 0x0064, 0x681f, 0x0002, 0xade8, 0x0010, 0x0070, 0x1152, + 0x0078, 0x1139, 0x8109, 0x00c0, 0x1137, 0x1078, 0x21e9, 0x1078, + 0x46e9, 0x1078, 0x1946, 0x1078, 0x4bdf, 0x3200, 0xa085, 0x000d, + 0x2090, 0x70c3, 0x0000, 0x0090, 0x116c, 0x70c0, 0xa086, 0x0002, + 0x00c0, 0x116c, 0x1078, 0x1284, 0x1078, 0x1196, 0x78cc, 0xa005, + 0x00c0, 0x117a, 0x1078, 0x1cc6, 0x0010, 0x1180, 0x0068, 0x1180, + 0x1078, 0x20c8, 0x0010, 0x1180, 0x0068, 0x1180, 0x1078, 0x1a2b, + 0x00e0, 0x116c, 0x1078, 0x4a66, 0x0078, 0x116c, 0x118e, 0x1190, + 0x23ea, 0x23ea, 0x476a, 0x476a, 0x23ea, 0x23ea, 0x0078, 0x118e, + 0x0078, 0x1190, 0x0078, 0x1192, 0x0078, 0x1194, 0x0068, 0x1201, + 0x2061, 0x0000, 0x6018, 0xa084, 0x0001, 0x00c0, 0x1201, 0x7814, + 0xa005, 0x00c0, 0x11a7, 0x0010, 0x1202, 0x0078, 0x1201, 0x2009, + 0x505b, 0x2104, 0xa005, 0x00c0, 0x1201, 0x2009, 0x5064, 0x200b, + 0x0000, 0x7914, 0xa186, 0x0042, 0x00c0, 0x11cc, 0x7816, 0x2009, + 0x5062, 0x2164, 0x200b, 0x0000, 0x6018, 0x70c6, 0x6014, 0x70ca, 0x611c, 0xa18c, 0xff00, 0x6020, 0xa084, 0x00ff, 0xa105, 0x70ce, - 0x1078, 0x1896, 0x0078, 0x11ef, 0x7814, 0xa086, 0x0018, 0x00c0, - 0x11c3, 0x1078, 0x1622, 0x7817, 0x0000, 0x2009, 0x396f, 0x2104, - 0xa065, 0x0040, 0x11df, 0x0c7e, 0x609c, 0x2060, 0x1078, 0x18f6, - 0x0c7f, 0x609f, 0x0000, 0x1078, 0x16e9, 0x2009, 0x001c, 0x6087, - 0x0103, 0x1078, 0x181d, 0x00c0, 0x11eb, 0x1078, 0x1896, 0x2009, - 0x396f, 0x200b, 0x0000, 0x2009, 0x3969, 0x2104, 0x200b, 0x0000, - 0xa005, 0x0040, 0x11ef, 0x2001, 0x4005, 0x0078, 0x1276, 0x0078, - 0x1274, 0x007c, 0x70c3, 0x0000, 0x70c7, 0x0000, 0x70cb, 0x0000, - 0x70cf, 0x0000, 0x70c0, 0xa0bc, 0xffc0, 0x00c0, 0x1242, 0x2038, - 0x0079, 0x1202, 0x1274, 0x12cf, 0x1293, 0x12cf, 0x1338, 0x1338, - 0x128a, 0x16fd, 0x1343, 0x1282, 0x1297, 0x1299, 0x129b, 0x129d, - 0x1702, 0x1282, 0x1355, 0x1380, 0x163a, 0x16f7, 0x129f, 0x1569, - 0x158b, 0x15a1, 0x15be, 0x1526, 0x1534, 0x1548, 0x155c, 0x13f3, - 0x1282, 0x13a1, 0x13a7, 0x13ac, 0x13b1, 0x13b7, 0x13bc, 0x13c1, - 0x13c6, 0x13cb, 0x13cf, 0x13e4, 0x13f0, 0x1282, 0x1282, 0x1282, - 0x1282, 0x13ff, 0x1408, 0x1417, 0x143d, 0x1447, 0x144e, 0x1474, - 0x1483, 0x1492, 0x14a4, 0x1506, 0x1516, 0x1282, 0x1282, 0x1282, - 0x1282, 0x151b, 0xa0bc, 0xffa0, 0x00c0, 0x1282, 0x2038, 0xa084, - 0x001f, 0x0079, 0x124b, 0x1719, 0x171c, 0x172c, 0x17a8, 0x17e1, - 0x1282, 0x1282, 0x1282, 0x1282, 0x1282, 0x1282, 0x1282, 0x1282, - 0x1282, 0x1282, 0x1282, 0x12c5, 0x132e, 0x134b, 0x1376, 0x1630, - 0x1282, 0x1282, 0x1282, 0x1282, 0x1282, 0x17f9, 0x1803, 0x1807, - 0x1815, 0x1282, 0x1282, 0x72ca, 0x71c6, 0x2001, 0x4006, 0x0078, - 0x1276, 0x73ce, 0x72ca, 0x71c6, 0x2001, 0x4000, 0x70c2, 0x0068, - 0x1277, 0x2061, 0x0000, 0x601b, 0x0001, 0x2091, 0x5000, 0x2091, - 0x4080, 0x007c, 0x70c3, 0x4001, 0x0078, 0x1277, 0x70c3, 0x4006, - 0x0078, 0x1277, 0x2099, 0x0041, 0x20a1, 0x0041, 0x20a9, 0x0005, - 0x53a3, 0x0078, 0x1274, 0x70c4, 0x70c3, 0x0004, 0x007a, 0x0078, - 0x1274, 0x0078, 0x1274, 0x0078, 0x1274, 0x0078, 0x1274, 0x2091, - 0x8000, 0x70c3, 0x0000, 0x70c7, 0x4953, 0x70cb, 0x5020, 0x70cf, - 0x2020, 0x70d3, 0x0002, 0x3f00, 0x70d6, 0x2079, 0x0000, 0x781b, - 0x0001, 0x2031, 0x0030, 0x2059, 0x1000, 0x2029, 0x0457, 0x2051, - 0x0470, 0x2061, 0x0472, 0x20b9, 0xffff, 0x20c1, 0x0000, 0x2091, - 0x5000, 0x2091, 0x4080, 0x0078, 0x0455, 0x1078, 0x1a04, 0x00c0, - 0x1286, 0x75d8, 0x74dc, 0x75da, 0x74de, 0x0078, 0x12d2, 0x2029, - 0x0000, 0x2520, 0x71d0, 0x72c8, 0x73cc, 0x70c4, 0x20a0, 0x2098, - 0x2031, 0x0030, 0x81ff, 0x0040, 0x1274, 0x7007, 0x0004, 0x731a, - 0x721e, 0x7422, 0x7526, 0x2051, 0x0012, 0x2049, 0x130d, 0x2041, - 0x1274, 0x7003, 0x0002, 0xa786, 0x0001, 0x0040, 0x12f5, 0xa786, - 0x0050, 0x0040, 0x12f5, 0x0078, 0x12fb, 0x2049, 0x131a, 0x2041, - 0x1326, 0x7003, 0x0003, 0x7017, 0x0000, 0x810b, 0x7112, 0x00c8, - 0x1303, 0x7017, 0x0001, 0x7007, 0x0001, 0xa786, 0x0001, 0x0040, - 0x131a, 0xa786, 0x0050, 0x0040, 0x131a, 0x700c, 0xa084, 0x007f, - 0x2009, 0x0040, 0xa102, 0x8004, 0x094a, 0x20a8, 0x26a0, 0x53a6, - 0x0078, 0x116b, 0x700c, 0xa084, 0x007f, 0x0040, 0x131a, 0x80ac, - 0x0048, 0x131a, 0x2698, 0x53a5, 0x0078, 0x116b, 0x700c, 0xa084, - 0x007f, 0x80ac, 0x2698, 0x53a5, 0x0078, 0x1274, 0x1078, 0x1a04, - 0x00c0, 0x1286, 0x75d8, 0x74dc, 0x75da, 0x74de, 0x0078, 0x12d2, - 0x71c4, 0x70c8, 0x2114, 0xa79e, 0x0004, 0x00c0, 0x1340, 0x200a, - 0x72ca, 0x0078, 0x1273, 0x70c7, 0x0002, 0x70cb, 0x000a, 0x70cf, - 0x0000, 0x0078, 0x1274, 0x1078, 0x1a04, 0x00c0, 0x1286, 0x75d8, - 0x76dc, 0x75da, 0x76de, 0x0078, 0x1358, 0x2029, 0x0000, 0x2530, - 0x70c4, 0x72c8, 0x73cc, 0x74d0, 0x70c6, 0x72ca, 0x73ce, 0x74d2, - 0xa005, 0x0040, 0x1370, 0x8001, 0x788a, 0x7a92, 0x7b96, 0x7d9a, - 0x7e9e, 0x7c8e, 0x78c0, 0xa084, 0xfffc, 0x78c2, 0x0078, 0x1374, - 0x78c0, 0xa085, 0x0001, 0x78c2, 0x0078, 0x1274, 0x1078, 0x1a04, - 0x00c0, 0x1286, 0x75d8, 0x76dc, 0x75da, 0x76de, 0x0078, 0x1383, + 0x1078, 0x192b, 0x0078, 0x11ff, 0x7814, 0xa086, 0x0018, 0x00c0, + 0x11d3, 0x1078, 0x165a, 0x7817, 0x0000, 0x2009, 0x5062, 0x2104, + 0xa065, 0x0040, 0x11ef, 0x0c7e, 0x609c, 0x2060, 0x1078, 0x1996, + 0x0c7f, 0x609f, 0x0000, 0x1078, 0x1730, 0x2009, 0x000c, 0x6007, + 0x0103, 0x1078, 0x1907, 0x00c0, 0x11fb, 0x1078, 0x192b, 0x2009, + 0x5062, 0x200b, 0x0000, 0x2009, 0x505c, 0x2104, 0x200b, 0x0000, + 0xa005, 0x0040, 0x11ff, 0x2001, 0x4005, 0x0078, 0x1286, 0x0078, + 0x1284, 0x007c, 0x70c3, 0x0000, 0x70c7, 0x0000, 0x70cb, 0x0000, + 0x70cf, 0x0000, 0x70c0, 0xa0bc, 0xffc0, 0x00c0, 0x1252, 0x2038, + 0x0079, 0x1212, 0x1284, 0x12e5, 0x12a9, 0x12fe, 0x130d, 0x1313, + 0x12a0, 0x1748, 0x1317, 0x1298, 0x12ad, 0x12af, 0x12b1, 0x12b3, + 0x174d, 0x1298, 0x1329, 0x1360, 0x1672, 0x1742, 0x12b5, 0x1591, + 0x15ad, 0x15c9, 0x15f4, 0x154a, 0x1558, 0x156c, 0x1580, 0x13df, + 0x1298, 0x138d, 0x1393, 0x1398, 0x139d, 0x13a3, 0x13a8, 0x13ad, + 0x13b2, 0x13b7, 0x13bb, 0x13d0, 0x13dc, 0x1298, 0x1298, 0x1298, + 0x1298, 0x13eb, 0x13f4, 0x1403, 0x1429, 0x1433, 0x143a, 0x1480, + 0x148f, 0x149e, 0x14b0, 0x152a, 0x153a, 0x1298, 0x1298, 0x1298, + 0x1298, 0x153f, 0xa0bc, 0xffa0, 0x00c0, 0x1298, 0x2038, 0xa084, + 0x001f, 0x0079, 0x125b, 0x1786, 0x1789, 0x1799, 0x1298, 0x1298, + 0x18d8, 0x18f5, 0x1298, 0x1298, 0x1298, 0x18f9, 0x1901, 0x1298, + 0x1298, 0x1298, 0x1298, 0x12db, 0x12f4, 0x131f, 0x1356, 0x1668, + 0x1764, 0x1778, 0x1298, 0x1829, 0x1298, 0x18b4, 0x18be, 0x18c2, + 0x18d0, 0x1298, 0x1298, 0x72ca, 0x71c6, 0x2001, 0x4006, 0x0078, + 0x1286, 0x73ce, 0x72ca, 0x71c6, 0x2001, 0x4000, 0x70c2, 0x0068, + 0x1287, 0x2061, 0x0000, 0x601b, 0x0001, 0x2091, 0x5000, 0x00e0, + 0x128f, 0x00e0, 0x1291, 0x0068, 0x1291, 0x2091, 0x4080, 0x007c, + 0x70c3, 0x4001, 0x0078, 0x1287, 0x70c3, 0x4006, 0x0078, 0x1287, + 0x2099, 0x0041, 0x20a1, 0x0041, 0x20a9, 0x0005, 0x53a3, 0x0078, + 0x1284, 0x70c4, 0x70c3, 0x0004, 0x007a, 0x0078, 0x1284, 0x0078, + 0x1284, 0x0078, 0x1284, 0x0078, 0x1284, 0x2091, 0x8000, 0x70c3, + 0x0000, 0x70c7, 0x4953, 0x70cb, 0x5020, 0x70cf, 0x2020, 0x70d3, + 0x0007, 0x3f00, 0x70d6, 0x2079, 0x0000, 0x781b, 0x0001, 0x2031, + 0x0030, 0x2059, 0x1000, 0x2029, 0x0457, 0x2051, 0x0470, 0x2061, + 0x0472, 0x20b9, 0xffff, 0x20c1, 0x0000, 0x2091, 0x5000, 0x2091, + 0x4080, 0x0078, 0x0455, 0x1078, 0x1b36, 0x00c0, 0x129c, 0x75d8, + 0x74dc, 0x75da, 0x74de, 0x0078, 0x12e8, 0x2029, 0x0000, 0x2520, + 0x71d0, 0x73c8, 0x72cc, 0x70c4, 0x1078, 0x1a70, 0x0040, 0x1284, + 0x70c3, 0x4002, 0x0078, 0x1284, 0x1078, 0x1b36, 0x00c0, 0x129c, + 0x75d8, 0x74dc, 0x75da, 0x74de, 0x0078, 0x1301, 0x2029, 0x0000, + 0x2520, 0x71d0, 0x73c8, 0x72cc, 0x70c4, 0x1078, 0x1ad0, 0x0040, + 0x1284, 0x70c3, 0x4002, 0x0078, 0x1284, 0x71c4, 0x70c8, 0x2114, + 0x200a, 0x0078, 0x1282, 0x71c4, 0x2114, 0x0078, 0x1282, 0x70c7, + 0x0007, 0x70cb, 0x003f, 0x70cf, 0x0000, 0x0078, 0x1284, 0x1078, + 0x1b36, 0x00c0, 0x129c, 0x75d8, 0x76dc, 0x75da, 0x76de, 0x0078, + 0x132c, 0x2029, 0x0000, 0x2530, 0x70c4, 0x72c8, 0x73cc, 0x74d0, + 0x70c6, 0x72ca, 0x73ce, 0x74d2, 0xa005, 0x0040, 0x1350, 0x8001, + 0x7892, 0xa084, 0xfc00, 0x0040, 0x1345, 0x78cc, 0xa085, 0x0001, + 0x78ce, 0x2001, 0x4005, 0x0078, 0x1286, 0x7a9a, 0x7b9e, 0x7da2, + 0x7ea6, 0x7c96, 0x78cc, 0xa084, 0xfffc, 0x78ce, 0x0078, 0x1354, + 0x78cc, 0xa085, 0x0001, 0x78ce, 0x0078, 0x1284, 0x1078, 0x1b36, + 0x00c0, 0x129c, 0x75d8, 0x76dc, 0x75da, 0x76de, 0x0078, 0x1363, 0x2029, 0x0000, 0x2530, 0x70c4, 0x72c8, 0x73cc, 0x74d4, 0x70c6, - 0x72ca, 0x73ce, 0x74d6, 0xa005, 0x0040, 0x139b, 0x8001, 0x78a6, - 0x7aae, 0x7bb2, 0x7db6, 0x7eba, 0x7caa, 0x78c0, 0xa084, 0xfcff, - 0x78c2, 0x0078, 0x139f, 0x78c0, 0xa085, 0x0100, 0x78c2, 0x0078, - 0x1274, 0x2009, 0x395f, 0x210c, 0x7ae4, 0x0078, 0x1272, 0x2009, - 0x3941, 0x210c, 0x0078, 0x1273, 0x2009, 0x3942, 0x210c, 0x0078, - 0x1273, 0x2061, 0x3940, 0x610c, 0x6210, 0x0078, 0x1272, 0x2009, - 0x3945, 0x210c, 0x0078, 0x1273, 0x2009, 0x3946, 0x210c, 0x0078, - 0x1273, 0x2009, 0x3947, 0x210c, 0x0078, 0x1273, 0x2009, 0x3948, - 0x210c, 0x0078, 0x1273, 0x7908, 0x7a0c, 0x0078, 0x1272, 0x71c4, - 0x8107, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xa0e8, 0x3a00, - 0x6a00, 0x6804, 0xa084, 0x0008, 0x0040, 0x13e1, 0x6b08, 0x0078, - 0x13e2, 0x6b0c, 0x0078, 0x1271, 0x77c4, 0x1078, 0x18b4, 0x2091, - 0x8000, 0x6b1c, 0x6a14, 0x2091, 0x8001, 0x2708, 0x0078, 0x1271, - 0x794c, 0x0078, 0x1273, 0x77c4, 0x1078, 0x18b4, 0x2091, 0x8000, - 0x6908, 0x6a18, 0x6b10, 0x2091, 0x8001, 0x0078, 0x1271, 0x71c4, - 0xa182, 0x0010, 0x00c8, 0x126c, 0x1078, 0x1d9b, 0x0078, 0x1271, - 0x71c4, 0xa182, 0x0010, 0x00c8, 0x126c, 0x2011, 0x3941, 0x2204, - 0x007e, 0x2112, 0x1078, 0x1d54, 0x017f, 0x0078, 0x1273, 0x71c4, - 0x2011, 0x1435, 0x20a9, 0x0008, 0x2204, 0xa106, 0x0040, 0x1427, - 0x8210, 0x0070, 0x1425, 0x0078, 0x141c, 0x0078, 0x126c, 0xa292, - 0x1435, 0x027e, 0x2011, 0x3942, 0x2204, 0x2112, 0x017f, 0x007e, - 0x1078, 0x1d60, 0x017f, 0x0078, 0x1273, 0x03e8, 0x00fa, 0x01f4, - 0x02ee, 0x0064, 0x0019, 0x0032, 0x004b, 0x2061, 0x3940, 0x610c, - 0x6210, 0x70c4, 0x600e, 0x70c8, 0x6012, 0x0078, 0x1272, 0x2061, - 0x3940, 0x6114, 0x70c4, 0x6016, 0x0078, 0x1273, 0x71c4, 0x2011, - 0x0004, 0x2019, 0x1212, 0xa186, 0x0028, 0x0040, 0x1467, 0x2011, - 0x0005, 0x2019, 0x1212, 0xa186, 0x0032, 0x0040, 0x1467, 0x2011, - 0x0006, 0x2019, 0x2323, 0xa186, 0x003c, 0x00c0, 0x126c, 0x2061, - 0x3940, 0x6018, 0x007e, 0x611a, 0x23b8, 0x1078, 0x1d71, 0x1078, - 0x37fc, 0x017f, 0x0078, 0x1273, 0x71c4, 0xa184, 0xffcf, 0x00c0, - 0x126c, 0x2011, 0x3947, 0x2204, 0x2112, 0x007e, 0x1078, 0x1d93, - 0x017f, 0x0078, 0x1273, 0x71c4, 0xa182, 0x0010, 0x00c8, 0x126c, - 0x2011, 0x3948, 0x2204, 0x007e, 0x2112, 0x1078, 0x1d82, 0x017f, - 0x0078, 0x1273, 0x71c4, 0x72c8, 0xa184, 0xfffd, 0x00c0, 0x126b, - 0xa284, 0xfffd, 0x00c0, 0x126b, 0x2100, 0x7908, 0x780a, 0x2200, - 0x7a0c, 0x780e, 0x0078, 0x1272, 0x71c4, 0x8107, 0xa084, 0x000f, - 0x8003, 0x8003, 0x8003, 0xa0e8, 0x3a00, 0x2019, 0x0000, 0x72c8, - 0x6800, 0x007e, 0xa226, 0x0040, 0x14d3, 0x6a02, 0xa484, 0x2000, - 0x0040, 0x14bc, 0xa39d, 0x0010, 0xa484, 0x1000, 0x0040, 0x14c2, - 0xa39d, 0x0008, 0xa484, 0x4000, 0x0040, 0x14d3, 0x810f, 0xa284, - 0x4000, 0x0040, 0x14cf, 0x1078, 0x1db5, 0x0078, 0x14d3, 0x1078, - 0x1da7, 0x0078, 0x14d3, 0x72cc, 0x82ff, 0x0040, 0x14ff, 0x6808, - 0xa206, 0x0040, 0x14ff, 0xa2a4, 0x00ff, 0x2061, 0x3940, 0x6118, - 0xa186, 0x0028, 0x0040, 0x14ec, 0xa186, 0x0032, 0x0040, 0x14f2, - 0xa186, 0x003c, 0x0040, 0x14f8, 0xa482, 0x0064, 0x00c8, 0x126d, - 0x0078, 0x14fc, 0xa482, 0x0050, 0x00c8, 0x126d, 0x0078, 0x14fc, - 0xa482, 0x0043, 0x00c8, 0x126d, 0x6a0a, 0xa39d, 0x000a, 0x6804, - 0xa305, 0x6806, 0x027f, 0x6b0c, 0x0078, 0x1271, 0x77c4, 0x1078, - 0x18b4, 0x2091, 0x8000, 0x6a14, 0x6b1c, 0x2091, 0x8001, 0x70c8, - 0x6816, 0x70cc, 0x681e, 0x2708, 0x0078, 0x1271, 0x70c4, 0x794c, - 0x784e, 0x0078, 0x1273, 0x71c4, 0x72c8, 0x73cc, 0xa182, 0x0010, - 0x00c8, 0x126c, 0x1078, 0x1dc3, 0x0078, 0x1271, 0x77c4, 0x1078, - 0x18b4, 0x2091, 0x8000, 0x6a08, 0xa295, 0x0002, 0x6a0a, 0x2091, - 0x8001, 0x2708, 0x0078, 0x1272, 0x77c4, 0x1078, 0x18b4, 0x2091, - 0x8000, 0x6a08, 0xa294, 0xfff9, 0x6a0a, 0x6804, 0xa005, 0x0040, - 0x1543, 0x1078, 0x1cf6, 0x2091, 0x8001, 0x2708, 0x0078, 0x1272, - 0x77c4, 0x1078, 0x18b4, 0x2091, 0x8000, 0x6a08, 0xa295, 0x0004, - 0x6a0a, 0x6804, 0xa005, 0x0040, 0x1557, 0x1078, 0x1cf6, 0x2091, - 0x8001, 0x2708, 0x0078, 0x1272, 0x77c4, 0x2041, 0x0001, 0x2049, - 0x0005, 0x2051, 0x0020, 0x1078, 0x18c1, 0x2708, 0x6a08, 0x0078, - 0x1272, 0x77c4, 0x73c8, 0x72cc, 0x77c6, 0x73ca, 0x72ce, 0x1078, - 0x193c, 0x00c0, 0x1587, 0x6818, 0xa005, 0x0040, 0x1581, 0x2708, - 0x1078, 0x1dd3, 0x00c0, 0x1581, 0x7817, 0x0015, 0x2091, 0x8001, - 0x007c, 0x2091, 0x8001, 0x2001, 0x4005, 0x0078, 0x1276, 0x2091, - 0x8001, 0x0078, 0x1274, 0x77c4, 0x77c6, 0x2061, 0x3940, 0x60a3, - 0x0003, 0x67b6, 0x60c7, 0x000f, 0x2041, 0x0021, 0x2049, 0x0005, - 0x2051, 0x0020, 0x1078, 0x18c1, 0x7817, 0x0016, 0x1078, 0x1cf6, - 0x007c, 0x77c4, 0x77c6, 0xa7bc, 0xff00, 0x2061, 0x3940, 0x60a3, - 0x0002, 0x67b6, 0x60c7, 0x000f, 0x7817, 0x0017, 0x1078, 0x1cf6, - 0x2041, 0x0021, 0x2049, 0x0004, 0x2051, 0x0010, 0x1078, 0x18c1, - 0x8738, 0xa784, 0x0007, 0x00c0, 0x15b6, 0x007c, 0x78c0, 0xa084, - 0x0003, 0x00c0, 0x15e2, 0x2039, 0x0000, 0x2041, 0x0021, 0x2049, - 0x0004, 0x2051, 0x0008, 0x1078, 0x18b4, 0x2091, 0x8000, 0x6808, - 0xa80d, 0x690a, 0x2091, 0x8001, 0x8738, 0xa784, 0x0007, 0x00c0, - 0x15cb, 0xa7bc, 0xff00, 0x873f, 0x8738, 0x873f, 0xa784, 0x0f00, - 0x00c0, 0x15cb, 0x2091, 0x8000, 0x2069, 0x0100, 0x6830, 0xa084, - 0x0040, 0x0040, 0x160b, 0x684b, 0x0004, 0x20a9, 0x0014, 0x6848, - 0xa084, 0x0004, 0x0040, 0x15f8, 0x0070, 0x15f8, 0x0078, 0x15ef, - 0x684b, 0x0009, 0x20a9, 0x0014, 0x6848, 0xa084, 0x0001, 0x0040, - 0x1605, 0x0070, 0x1605, 0x0078, 0x15fc, 0x20a9, 0x00fa, 0x0070, - 0x160b, 0x0078, 0x1607, 0x2079, 0x3900, 0x7817, 0x0018, 0x2061, - 0x3940, 0x60a3, 0x0001, 0x60c7, 0x000f, 0x78c0, 0xa085, 0x0002, - 0x78c2, 0x6808, 0xa084, 0xfffd, 0x680a, 0x681b, 0x0047, 0x2091, - 0x8001, 0x007c, 0x78c0, 0xa084, 0xfffd, 0x78c2, 0xa084, 0x0001, - 0x00c0, 0x162c, 0x1078, 0x197e, 0x71c4, 0x71c6, 0x794a, 0x007c, - 0x1078, 0x1a04, 0x00c0, 0x1286, 0x75d8, 0x74dc, 0x75da, 0x74de, - 0x0078, 0x163d, 0x2029, 0x0000, 0x2520, 0x71c4, 0x73c8, 0x72cc, - 0x71c6, 0x73ca, 0x72ce, 0x2079, 0x3900, 0x1078, 0x188d, 0x0040, - 0x16e5, 0x20a9, 0x0005, 0x20a1, 0x3916, 0x41a1, 0x2009, 0x0040, - 0x1078, 0x1857, 0x0040, 0x1658, 0x1078, 0x1896, 0x0078, 0x16e5, - 0x6004, 0xa084, 0xff00, 0x8007, 0x8009, 0x0040, 0x16b9, 0x0c7e, - 0x2c68, 0x1078, 0x188d, 0x0040, 0x1688, 0x2c00, 0x689e, 0x8109, - 0x00c0, 0x1660, 0x609f, 0x0000, 0x0c7f, 0x0c7e, 0x7218, 0x731c, - 0x7420, 0x7524, 0x2c68, 0x689c, 0xa065, 0x0040, 0x16b8, 0x2009, - 0x0040, 0x1078, 0x1857, 0x00c0, 0x16a1, 0x6004, 0xa084, 0x00ff, - 0xa086, 0x0002, 0x00c0, 0x1688, 0x2d00, 0x6002, 0x0078, 0x166e, - 0x0c7f, 0x0c7e, 0x609c, 0x2060, 0x1078, 0x18f6, 0x0c7f, 0x609f, - 0x0000, 0x1078, 0x16e9, 0x2009, 0x001c, 0x6008, 0xa085, 0x0200, - 0x600a, 0x6004, 0x6086, 0x1078, 0x181d, 0x1078, 0x1896, 0x0078, - 0x16e5, 0x0c7f, 0x0c7e, 0x609c, 0x2060, 0x1078, 0x18f6, 0x0c7f, - 0x609f, 0x0000, 0x1078, 0x16e9, 0x2009, 0x001c, 0x6087, 0x0103, - 0x601b, 0x0003, 0x1078, 0x181d, 0x1078, 0x1896, 0x0078, 0x16e5, - 0x0c7f, 0x74c4, 0x73c8, 0x72cc, 0x6014, 0x7817, 0x0012, 0x0e7e, - 0x2071, 0x3940, 0x70a3, 0x0005, 0x70a7, 0x0000, 0x73aa, 0x72ae, - 0x74b2, 0x70b6, 0x70bb, 0x0000, 0x2c00, 0x70be, 0x70c3, 0x0000, - 0xa02e, 0x2530, 0x611c, 0xa184, 0x0060, 0x0040, 0x16d9, 0x1078, - 0x330a, 0x0e7f, 0x6596, 0x65a6, 0x669a, 0x669a, 0x60af, 0x0000, - 0x60b3, 0x0000, 0x1078, 0x1cf6, 0x007c, 0x70c3, 0x4005, 0x0078, - 0x1277, 0x20a9, 0x0005, 0x2099, 0x3916, 0x530a, 0x2100, 0xa210, - 0xa399, 0x0000, 0xa4a1, 0x0000, 0xa5a9, 0x0000, 0x007c, 0x71c4, - 0x70c7, 0x0000, 0x7906, 0x0078, 0x1274, 0x71c4, 0x71c6, 0x2168, - 0x0078, 0x1704, 0x2069, 0x1000, 0x690c, 0xa016, 0x2d04, 0xa210, - 0x8d68, 0x8109, 0x00c0, 0x1706, 0xa285, 0x0000, 0x00c0, 0x1714, - 0x70c3, 0x4000, 0x0078, 0x1716, 0x70c3, 0x4003, 0x70ca, 0x0078, - 0x1277, 0x79d8, 0x0078, 0x1273, 0x71c4, 0x71c6, 0x2198, 0x20a1, - 0x0042, 0x20a9, 0x0004, 0x53a3, 0x21a0, 0x2099, 0x0042, 0x20a9, - 0x0004, 0x53a3, 0x0078, 0x1274, 0x70c4, 0x2068, 0x2079, 0x3900, - 0x1078, 0x188d, 0x0040, 0x17a4, 0x6007, 0x0001, 0x600b, 0x0000, - 0x602b, 0x0000, 0x601b, 0x0006, 0x6a10, 0xa28c, 0x0007, 0xa284, - 0x00f0, 0x8003, 0x8003, 0x8003, 0x8003, 0xa105, 0x6016, 0xa284, - 0x0800, 0x0040, 0x174f, 0x601b, 0x000a, 0x0078, 0x1755, 0xa284, - 0x1000, 0x0040, 0x1755, 0x601b, 0x000c, 0xa284, 0x0300, 0x0040, - 0x175e, 0x602b, 0x0001, 0x8004, 0x8004, 0x8004, 0xa085, 0x0001, - 0x601e, 0x6023, 0x0000, 0x6027, 0x000a, 0xa284, 0x0400, 0x0040, - 0x176b, 0x602b, 0x0000, 0x20a9, 0x0006, 0xac80, 0x000b, 0x20a0, - 0xad80, 0x0005, 0x2098, 0x53a3, 0xa284, 0x0300, 0x00c0, 0x1780, - 0x6046, 0x604a, 0x604e, 0x6052, 0x6096, 0x609a, 0x0078, 0x178a, - 0x6800, 0x6046, 0x6804, 0x604a, 0x6e08, 0x664e, 0x6d0c, 0x6552, - 0x6596, 0x669a, 0x6014, 0x7817, 0x0042, 0x2c08, 0x2061, 0x3940, - 0x60a3, 0x0005, 0x60a7, 0x0000, 0x60ab, 0x0000, 0x60af, 0x0000, - 0x60b3, 0x0000, 0x60b6, 0x61be, 0xa284, 0x0400, 0x60c2, 0x1078, - 0x32f5, 0x1078, 0x1cf6, 0x007c, 0x70c3, 0x4005, 0x0078, 0x1277, - 0x78f0, 0xa005, 0x0040, 0x1282, 0x2091, 0x8000, 0x70c4, 0x800a, - 0x2011, 0x0010, 0x810c, 0x0048, 0x17ba, 0x3a00, 0xa084, 0xfff7, - 0x0078, 0x17bd, 0x3a00, 0xa085, 0x0008, 0x20d0, 0x0005, 0x0005, - 0xa084, 0xfffb, 0x20d0, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, - 0x0005, 0x0005, 0x0005, 0xa085, 0x0004, 0x20d0, 0x0005, 0x0005, - 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x8211, 0x00c0, - 0x17b2, 0x3a00, 0xa085, 0x0008, 0x20d0, 0x2091, 0x8001, 0x0078, - 0x1274, 0x2011, 0x04fd, 0x2204, 0xa082, 0x0004, 0x0048, 0x17f5, - 0x78f3, 0x0001, 0x2009, 0xff01, 0x200a, 0x2001, 0x000c, 0x20d8, - 0x2001, 0x000c, 0x20d0, 0x0078, 0x1274, 0x2001, 0x4005, 0x0078, - 0x1276, 0x7978, 0x71c6, 0x71c4, 0xa182, 0x0003, 0x00c8, 0x126c, - 0x797a, 0x0078, 0x1274, 0x7978, 0x71c6, 0x0078, 0x1274, 0x796c, - 0x71c6, 0x71c4, 0x796e, 0x7970, 0x71ca, 0x71c8, 0x7972, 0x7974, - 0x71ce, 0x71cc, 0x7976, 0x0078, 0x1274, 0x796c, 0x71c6, 0x7970, - 0x71ca, 0x7974, 0x71ce, 0x0078, 0x1274, 0x700c, 0xa084, 0x00ff, - 0x0040, 0x1829, 0x7007, 0x0004, 0x7004, 0xa084, 0x0004, 0x00c0, - 0x1824, 0x7017, 0x0000, 0x7112, 0x721a, 0x731e, 0x7422, 0x7526, - 0xac80, 0x0001, 0x8108, 0x810c, 0x81a9, 0x8098, 0x20a1, 0x0030, - 0x6084, 0x20a2, 0x53a6, 0x780c, 0xa085, 0x0000, 0x7002, 0x7007, - 0x0001, 0x2009, 0x0022, 0x2104, 0xa084, 0x4000, 0x00c0, 0x1841, - 0x7108, 0x8103, 0x00c8, 0x1841, 0x7014, 0xa005, 0x0040, 0x1841, - 0x7007, 0x0002, 0xa184, 0x0060, 0x7003, 0x0000, 0x007c, 0x700c, - 0xa084, 0x00ff, 0x0040, 0x1863, 0x7007, 0x0004, 0x7004, 0xa084, - 0x0004, 0x00c0, 0x185e, 0x7017, 0x0000, 0x7112, 0x721a, 0x7422, - 0x7526, 0x731e, 0x2099, 0x0030, 0x8108, 0x81ac, 0x780c, 0xa085, - 0x0001, 0x7002, 0x7007, 0x0001, 0x2009, 0x0022, 0x2104, 0xa084, - 0x4000, 0x00c0, 0x1874, 0x7008, 0x800b, 0x00c8, 0x1874, 0x7007, - 0x0002, 0xa08c, 0x0060, 0x00c0, 0x188a, 0xac80, 0x0001, 0x20a0, - 0x53a5, 0xa006, 0x7003, 0x0000, 0x007c, 0x7850, 0xa065, 0x0040, - 0x1895, 0x2c04, 0x7852, 0x2063, 0x0000, 0x007c, 0x0f7e, 0x2079, - 0x3900, 0x7850, 0x2062, 0x2c00, 0xa005, 0x00c0, 0x18a1, 0x1078, - 0x1eac, 0x7852, 0x0f7f, 0x007c, 0x2011, 0x4400, 0x7a52, 0x7be4, - 0x8319, 0x0040, 0x18b1, 0xa280, 0x002f, 0x2012, 0x2010, 0x0078, - 0x18a8, 0x2013, 0x0000, 0x007c, 0xa784, 0x0f00, 0x800c, 0xa784, - 0x0007, 0x8003, 0x8003, 0x8003, 0x8003, 0xa105, 0xa0e8, 0x3a80, - 0x007c, 0x1078, 0x18b4, 0x2900, 0x682a, 0x2a00, 0x682e, 0x6808, - 0xa084, 0xffef, 0xa80d, 0x690a, 0x2091, 0x8000, 0x2009, 0x394f, - 0x210c, 0x6804, 0xa005, 0x0040, 0x18de, 0xa116, 0x00c0, 0x18de, - 0x2060, 0x6000, 0x6806, 0x017e, 0x0078, 0x18e1, 0x2009, 0x0000, - 0x017e, 0x6804, 0xa065, 0x0040, 0x18f0, 0x6000, 0x6806, 0x1078, - 0x1903, 0x1078, 0x1a14, 0x6810, 0x8001, 0x6812, 0x00c0, 0x18e1, - 0x017f, 0x6902, 0x6906, 0x2091, 0x8001, 0x007c, 0xa065, 0x0040, - 0x1902, 0x609c, 0x609f, 0x0000, 0x2008, 0x1078, 0x1896, 0x2100, - 0x0078, 0x18f6, 0x007c, 0x6007, 0x0103, 0x20a9, 0x001c, 0xac80, - 0x0005, 0x20a0, 0x2001, 0x0000, 0x40a4, 0x6828, 0x601a, 0x682c, - 0x6022, 0x007c, 0x0e7e, 0x2071, 0x3940, 0x7040, 0xa08c, 0x0080, - 0x00c0, 0x1920, 0xa088, 0x3980, 0x2d0a, 0x8000, 0x7042, 0xa006, - 0x0e7f, 0x007c, 0x0e7e, 0x2071, 0x3940, 0x2009, 0x3980, 0x7240, - 0x8221, 0x8211, 0x0048, 0x193a, 0x2104, 0x8108, 0xad06, 0x00c0, - 0x1929, 0x8119, 0x211e, 0x8108, 0x8318, 0x8211, 0x00c8, 0x1932, - 0x7442, 0xa006, 0x0e7f, 0x007c, 0x1078, 0x18b4, 0x2091, 0x8000, - 0x6804, 0x781e, 0xa065, 0x0040, 0x197d, 0x0078, 0x194d, 0x2c00, - 0x781e, 0x6000, 0xa065, 0x0040, 0x197d, 0x6010, 0xa306, 0x00c0, - 0x1947, 0x600c, 0xa206, 0x00c0, 0x1947, 0x2c28, 0x6804, 0xac06, - 0x00c0, 0x1964, 0x6000, 0x2060, 0x6806, 0xa005, 0x00c0, 0x1964, - 0x6803, 0x0000, 0x0078, 0x196e, 0x6400, 0x781c, 0x2060, 0x6402, - 0xa486, 0x0000, 0x00c0, 0x196e, 0x2c00, 0x6802, 0x2560, 0x1078, - 0x1903, 0x601b, 0x0005, 0x6023, 0x0020, 0x1078, 0x1a14, 0x6810, - 0x8001, 0x6812, 0x2001, 0xffff, 0xa005, 0x007c, 0x2039, 0x0000, - 0x2041, 0x0021, 0x2049, 0x0004, 0x2051, 0x0008, 0x1078, 0x18c1, - 0x8738, 0xa784, 0x0007, 0x00c0, 0x1986, 0xa7bc, 0xff00, 0x873f, - 0x8738, 0x873f, 0xa784, 0x0f00, 0x00c0, 0x1986, 0x007c, 0x2061, - 0x0000, 0x6018, 0xa084, 0x0001, 0x00c0, 0x19a8, 0x2091, 0x8000, - 0x78d4, 0x78d7, 0x0000, 0x2091, 0x8001, 0xa005, 0x00c0, 0x19a9, - 0x007c, 0xa08c, 0xfff0, 0x0040, 0x19af, 0x1078, 0x1eac, 0x0079, - 0x19b1, 0x19c1, 0x19c3, 0x19c9, 0x19cd, 0x19c1, 0x19d1, 0x19c1, - 0x19d8, 0x19dc, 0x19e0, 0x1a0a, 0x1a0e, 0x19c1, 0x19c1, 0x19c1, - 0x19c1, 0x1078, 0x1eac, 0x1078, 0x197e, 0x2001, 0x8001, 0x0078, - 0x1276, 0x2001, 0x8003, 0x0078, 0x1276, 0x2001, 0x8004, 0x0078, - 0x1276, 0x1078, 0x197e, 0x2001, 0x8006, 0x007c, 0x0078, 0x1276, - 0x2001, 0x8008, 0x0078, 0x1276, 0x2001, 0x8009, 0x0078, 0x1276, - 0x2091, 0x8000, 0x2069, 0x3940, 0x6800, 0xa086, 0x0000, 0x0040, - 0x19ee, 0x2091, 0x8001, 0x78d7, 0x0009, 0x007c, 0x68b4, 0xa0bc, - 0xff00, 0x2091, 0x8000, 0x2041, 0x0021, 0x2049, 0x0004, 0x2051, - 0x0010, 0x1078, 0x18c1, 0x8738, 0xa784, 0x0007, 0x00c0, 0x19f9, - 0x2001, 0x800a, 0x0078, 0x1276, 0x2001, 0x04fd, 0x2004, 0xa086, - 0x0004, 0x007c, 0x2001, 0x800c, 0x0078, 0x1276, 0x1078, 0x197e, - 0x2001, 0x800d, 0x0078, 0x1276, 0x6004, 0x6086, 0x2c08, 0x2063, - 0x0000, 0x787c, 0x8000, 0x787e, 0x7880, 0xa005, 0x7982, 0x0040, - 0x1a24, 0x2c02, 0x0078, 0x1a25, 0x7986, 0x007c, 0x0c7e, 0x2061, - 0x3900, 0x6887, 0x0103, 0x2d08, 0x206b, 0x0000, 0x607c, 0x8000, - 0x607e, 0x6080, 0xa005, 0x6182, 0x0040, 0x1a39, 0x2d02, 0x0078, - 0x1a3a, 0x6186, 0x0c7f, 0x007c, 0x1078, 0x1a4d, 0x0040, 0x1a4c, - 0x0c7e, 0x609c, 0xa065, 0x0040, 0x1a47, 0x1078, 0x18f6, 0x0c7f, - 0x609f, 0x0000, 0x1078, 0x1896, 0x007c, 0x7884, 0xa065, 0x0040, - 0x1a5f, 0x2091, 0x8000, 0x787c, 0x8001, 0x787e, 0x2c04, 0x7886, - 0xa005, 0x00c0, 0x1a5d, 0x7882, 0x8000, 0x2091, 0x8001, 0x007c, - 0x20a9, 0x0010, 0xa006, 0x8004, 0x8086, 0x818e, 0x00c8, 0x1a69, - 0xa200, 0x0070, 0x1a6d, 0x0078, 0x1a64, 0x8086, 0x818e, 0x007c, - 0x157e, 0x20a9, 0x0010, 0xa005, 0x0040, 0x1a93, 0xa11a, 0x00c8, - 0x1a93, 0x8213, 0x818d, 0x0048, 0x1a84, 0xa11a, 0x00c8, 0x1a85, - 0x0070, 0x1a8b, 0x0078, 0x1a79, 0xa11a, 0x2308, 0x8210, 0x0070, - 0x1a8b, 0x0078, 0x1a79, 0x007e, 0x3200, 0xa084, 0xf7ff, 0x2080, - 0x007f, 0x157f, 0x007c, 0x007e, 0x3200, 0xa085, 0x0800, 0x0078, - 0x1a8f, 0x798c, 0x70d0, 0x007e, 0x007f, 0xa106, 0x0040, 0x1ae9, - 0x2091, 0x8000, 0x2071, 0x0020, 0x7004, 0xa005, 0x00c0, 0x1ae9, - 0x7008, 0x7208, 0xa206, 0x00c0, 0x1ae9, 0xa286, 0x0008, 0x00c0, - 0x1ae9, 0x2071, 0x0010, 0x1078, 0x188d, 0x0040, 0x1ae9, 0x7a94, - 0x7b90, 0x7c9c, 0x7d98, 0x8107, 0x8004, 0x8004, 0xa210, 0xa399, - 0x0000, 0x2009, 0x0040, 0x1078, 0x1857, 0x2091, 0x8001, 0x0040, - 0x1ae0, 0x1078, 0x1896, 0x78a0, 0x8000, 0x78a2, 0xa086, 0x0002, - 0x00c0, 0x1ae9, 0x2091, 0x8000, 0x78d7, 0x0002, 0x78a3, 0x0000, - 0x78c0, 0xa085, 0x0003, 0x78c2, 0x2091, 0x8001, 0x0078, 0x1ae9, - 0x78a3, 0x0000, 0x1078, 0x1c38, 0x6004, 0xa084, 0x000f, 0x0079, - 0x1aee, 0x2071, 0x0010, 0x2091, 0x8001, 0x007c, 0x1afe, 0x1b20, - 0x1b46, 0x1afe, 0x1b58, 0x1b0d, 0x1afe, 0x1afe, 0x1afe, 0x1b1a, - 0x1b40, 0x1afe, 0x1afe, 0x1afe, 0x1afe, 0x1afe, 0x2039, 0x0400, - 0x78d0, 0xa705, 0x78d2, 0x6008, 0xa705, 0x600a, 0x1078, 0x1b96, - 0x609c, 0x78ce, 0x1078, 0x1c20, 0x007c, 0x78d0, 0xa084, 0x0100, - 0x0040, 0x1b14, 0x0078, 0x1afe, 0x601c, 0xa085, 0x0080, 0x601e, - 0x0078, 0x1b27, 0x1078, 0x1a04, 0x00c0, 0x1afe, 0x1078, 0x1c52, - 0x78d0, 0xa084, 0x0100, 0x0040, 0x1b27, 0x0078, 0x1afe, 0x78d3, - 0x0000, 0x6004, 0x8007, 0xa084, 0x00ff, 0x78c6, 0x8001, 0x609f, - 0x0000, 0x0040, 0x1b3d, 0x1078, 0x1b96, 0x0040, 0x1b3d, 0x78d0, - 0xa085, 0x0100, 0x78d2, 0x0078, 0x1b3f, 0x1078, 0x1bba, 0x007c, - 0x1078, 0x1a04, 0x00c0, 0x1afe, 0x1078, 0x1c4e, 0x78d0, 0xa08c, - 0x0e00, 0x00c0, 0x1b4f, 0xa084, 0x0100, 0x00c0, 0x1b51, 0x0078, - 0x1afe, 0x1078, 0x1b96, 0x00c0, 0x1b57, 0x1078, 0x1bba, 0x007c, - 0x78d0, 0xa084, 0x0100, 0x0040, 0x1b5f, 0x0078, 0x1afe, 0x78d3, - 0x0000, 0x6714, 0x20a9, 0x0001, 0x6018, 0xa005, 0x0040, 0x1b7a, - 0xa7bc, 0xff00, 0x20a9, 0x0008, 0xa08e, 0x0001, 0x0040, 0x1b7a, - 0x2039, 0x0000, 0x20a9, 0x0080, 0xa08e, 0x0002, 0x0040, 0x1b7a, - 0x0078, 0x1b93, 0x1078, 0x18b4, 0x2d00, 0xa088, 0x0002, 0x2091, - 0x8000, 0x2168, 0x682b, 0x0000, 0x682f, 0x0000, 0x2104, 0xa084, - 0xffde, 0x200a, 0x2100, 0xa088, 0x0010, 0x2091, 0x8001, 0x0070, - 0x1b93, 0x0078, 0x1b7f, 0x1078, 0x1896, 0x007c, 0x78c8, 0xa06d, - 0x00c0, 0x1ba1, 0x2c00, 0x78ca, 0x78ce, 0x609f, 0x0000, 0x0078, - 0x1bad, 0x2c00, 0x689e, 0x609f, 0x0000, 0x78ca, 0x2d00, 0x6002, - 0x78cc, 0xad06, 0x00c0, 0x1bad, 0x6002, 0x78c4, 0x8001, 0x78c6, - 0x00c0, 0x1bb9, 0x78d0, 0xa084, 0x0000, 0x78d2, 0x78cc, 0x2060, - 0xa006, 0x007c, 0xa02e, 0x2530, 0x611c, 0x61a2, 0xa184, 0xc1ff, - 0x601e, 0xa184, 0x0060, 0x0040, 0x1bc9, 0x0e7e, 0x1078, 0x330a, - 0x0e7f, 0x6596, 0x669a, 0x6714, 0x1078, 0x18b4, 0x2091, 0x8000, - 0x6808, 0xa084, 0x0001, 0x0040, 0x1be5, 0x2091, 0x8001, 0x1078, - 0x1903, 0x2091, 0x8000, 0x1078, 0x1a14, 0x2091, 0x8001, 0x78cb, - 0x0000, 0x78cf, 0x0000, 0x0078, 0x1c1f, 0x6024, 0xa096, 0x0001, - 0x00c0, 0x1bec, 0x8000, 0x6026, 0x6a10, 0x6814, 0x2091, 0x8001, - 0xa202, 0x0048, 0x1bfb, 0x0040, 0x1bfb, 0x2039, 0x0200, 0x1078, - 0x1c20, 0x0078, 0x1c1f, 0x2c08, 0x2091, 0x8000, 0x6800, 0xa065, - 0x0040, 0x1c03, 0x6102, 0x6902, 0x00c0, 0x1c07, 0x6906, 0x2160, - 0x6003, 0x0000, 0x6810, 0x8000, 0x6812, 0x2091, 0x8001, 0x6808, - 0xa08c, 0x0040, 0x0040, 0x1c19, 0xa086, 0x0040, 0x680a, 0x1078, - 0x1912, 0x1078, 0x1cf6, 0x78cf, 0x0000, 0x78cb, 0x0000, 0x007c, - 0x6008, 0xa705, 0x600a, 0x2091, 0x8000, 0x1078, 0x1a14, 0x2091, - 0x8001, 0x78cc, 0xa065, 0x0040, 0x1c33, 0x609c, 0x78ce, 0x609f, - 0x0000, 0x0078, 0x1c23, 0x78cb, 0x0000, 0x78cf, 0x0000, 0x007c, - 0x7988, 0x788c, 0x8000, 0xa10a, 0x00c8, 0x1c3f, 0xa006, 0x788e, - 0x70d2, 0x7804, 0xa005, 0x0040, 0x1c4d, 0x8001, 0x7806, 0x00c0, - 0x1c4d, 0x0068, 0x1c4d, 0x2091, 0x4080, 0x007c, 0x2039, 0x1c66, - 0x0078, 0x1c54, 0x2039, 0x1c6c, 0x2704, 0xa005, 0x0040, 0x1c65, - 0xac00, 0x2068, 0x6b08, 0x6c0c, 0x6910, 0x6a14, 0x690a, 0x6a0e, - 0x6b12, 0x6c16, 0x8738, 0x0078, 0x1c54, 0x007c, 0x0003, 0x0009, - 0x000f, 0x0015, 0x001b, 0x0000, 0x0015, 0x001b, 0x0000, 0x0068, - 0x1c87, 0x2029, 0x0000, 0x7884, 0xa065, 0x0040, 0x1c82, 0x1078, - 0x1c88, 0x0040, 0x1c82, 0x1078, 0x1c99, 0x00c0, 0x1c82, 0x8528, - 0x0078, 0x1c73, 0x85ff, 0x0040, 0x1c87, 0x2091, 0x4080, 0x007c, - 0x7ba4, 0x79a8, 0x70d4, 0x007e, 0x007f, 0xa102, 0x00c0, 0x1c93, - 0x2300, 0xa005, 0x007c, 0x0048, 0x1c97, 0xa302, 0x007c, 0x8002, - 0x007c, 0x2091, 0x8000, 0x2071, 0x0020, 0x7004, 0xa005, 0x00c0, - 0x1cdd, 0x7008, 0x7208, 0xa206, 0x00c0, 0x1cdd, 0xa286, 0x0008, - 0x00c0, 0x1cdd, 0x2071, 0x0010, 0x1078, 0x1ce2, 0x2009, 0x001c, - 0x6028, 0xa005, 0x0040, 0x1cb6, 0x2009, 0x0040, 0x1078, 0x181d, - 0x0040, 0x1ccf, 0x78bc, 0x8000, 0x78be, 0xa086, 0x0002, 0x00c0, - 0x1cdd, 0x2091, 0x8000, 0x78d7, 0x0003, 0x78bf, 0x0000, 0x78c0, - 0xa085, 0x0300, 0x78c2, 0x2091, 0x8001, 0x0078, 0x1cdd, 0x78bf, - 0x0000, 0x1078, 0x1a3c, 0x79a4, 0x78a8, 0x8000, 0xa10a, 0x00c8, - 0x1cda, 0xa006, 0x78aa, 0x70d6, 0xa006, 0x2071, 0x0010, 0x2091, - 0x8001, 0x007c, 0x8107, 0x8004, 0x8004, 0x7ab0, 0x7bac, 0x7cb8, - 0x7db4, 0xa210, 0xa399, 0x0000, 0xa4a1, 0x0000, 0xa5a9, 0x0000, - 0x007c, 0x2009, 0x3968, 0x2091, 0x8000, 0x200a, 0x0f7e, 0x2079, - 0x0100, 0x2009, 0x3940, 0x2091, 0x8000, 0x2104, 0xa086, 0x0000, - 0x00c0, 0x1d11, 0x2009, 0x3912, 0x2104, 0xa005, 0x00c0, 0x1d11, - 0x7830, 0xa084, 0x00c0, 0x00c0, 0x1d11, 0x0018, 0x1d11, 0x781b, - 0x0045, 0x2091, 0x8001, 0x0f7f, 0x007c, 0x127e, 0x2091, 0x2300, - 0x2071, 0x3940, 0x2079, 0x0100, 0x784b, 0x000f, 0x2019, 0x3205, - 0x20a1, 0x012b, 0x2304, 0xa005, 0x0040, 0x1d2f, 0x789a, 0x8318, - 0x23ac, 0x8318, 0x2398, 0x53a6, 0x3318, 0x0078, 0x1d22, 0x789b, - 0x0020, 0x20a9, 0x0010, 0x78af, 0x0000, 0x78af, 0x0020, 0x0070, - 0x1d3b, 0x0078, 0x1d33, 0x7003, 0x0000, 0x1078, 0x1e40, 0x7004, - 0xa084, 0x000f, 0xa085, 0x6280, 0x7806, 0x780f, 0x9200, 0x7843, - 0x00d8, 0x7853, 0x0080, 0x780b, 0x0008, 0x7047, 0x397f, 0x7043, - 0x0000, 0x127f, 0x2000, 0x007c, 0xa18c, 0x000f, 0x2011, 0x0101, - 0x2204, 0xa084, 0xfff0, 0xa105, 0x2012, 0x1078, 0x1e40, 0x007c, - 0x2011, 0x0101, 0x20a9, 0x0009, 0x810b, 0x0070, 0x1d69, 0x0078, - 0x1d64, 0xa18c, 0x0e00, 0x2204, 0xa084, 0xf1ff, 0xa105, 0x2012, - 0x007c, 0x2009, 0x0101, 0x20a9, 0x0005, 0x8213, 0x0070, 0x1d7a, - 0x0078, 0x1d75, 0xa294, 0x00e0, 0x2104, 0xa084, 0xff1f, 0xa205, - 0x200a, 0x007c, 0x2011, 0x0101, 0x20a9, 0x000c, 0x810b, 0x0070, - 0x1d8b, 0x0078, 0x1d86, 0xa18c, 0xf000, 0x2204, 0xa084, 0x0fff, - 0xa105, 0x2012, 0x007c, 0x2011, 0x0102, 0x2204, 0xa084, 0xffcf, - 0xa105, 0x2012, 0x007c, 0x8103, 0x8003, 0xa080, 0x0020, 0x0c7e, - 0x2061, 0x0100, 0x609a, 0x62ac, 0x63ac, 0x0c7f, 0x007c, 0x8103, - 0x8003, 0xa080, 0x0022, 0x0c7e, 0x2061, 0x0100, 0x609a, 0x60a4, - 0xa084, 0xffdf, 0x60ae, 0x0c7f, 0x007c, 0x8103, 0x8003, 0xa080, - 0x0022, 0x0c7e, 0x2061, 0x0100, 0x609a, 0x60a4, 0xa085, 0x0020, - 0x60ae, 0x0c7f, 0x007c, 0x8103, 0x8003, 0xa080, 0x0020, 0x0c7e, - 0x2061, 0x0100, 0x609a, 0x60a4, 0x62ae, 0x2010, 0x60a4, 0x63ae, - 0x2018, 0x0c7f, 0x007c, 0x0c7e, 0x0e7e, 0x6818, 0xa005, 0x0040, - 0x1e1c, 0x2061, 0x4380, 0x1078, 0x1e22, 0x0040, 0x1e06, 0x20a9, - 0x0000, 0x2061, 0x4280, 0x0c7e, 0x1078, 0x1e22, 0x0040, 0x1df0, - 0x0c7f, 0x8c60, 0x0070, 0x1dee, 0x0078, 0x1de3, 0x0078, 0x1e1c, - 0x007f, 0xa082, 0x4280, 0x2071, 0x3940, 0x70ba, 0x6020, 0xa085, - 0x0800, 0x6022, 0x2091, 0x8001, 0x71b6, 0x2001, 0x0004, 0x70a2, - 0x70c7, 0x000f, 0x1078, 0x1cf1, 0x0078, 0x1e18, 0x2071, 0x3940, - 0x6020, 0xa085, 0x0800, 0x6022, 0x2091, 0x8001, 0x71b6, 0x2c00, - 0x70be, 0x2001, 0x0006, 0x70a2, 0x70c7, 0x000f, 0x1078, 0x1cf1, - 0x2001, 0x0000, 0x0078, 0x1e1e, 0x2001, 0x0001, 0xa005, 0x0e7f, - 0x0c7f, 0x007c, 0x2091, 0x8000, 0x2c04, 0xa005, 0x0040, 0x1e3b, - 0x2060, 0x6010, 0xa306, 0x00c0, 0x1e38, 0x600c, 0xa206, 0x00c0, - 0x1e38, 0x6014, 0xa106, 0x00c0, 0x1e38, 0xa006, 0x0078, 0x1e3f, - 0x6000, 0x0078, 0x1e25, 0xa085, 0x0001, 0x2091, 0x8001, 0x007c, - 0x2011, 0x3941, 0x220c, 0xa18c, 0x000f, 0x2011, 0x013b, 0x2204, - 0xa084, 0x0100, 0x0040, 0x1e56, 0x2021, 0xff04, 0x2122, 0x810b, - 0x810b, 0x810b, 0x810b, 0xa18d, 0x0f00, 0x2104, 0x007c, 0x0e7e, - 0x68e4, 0xa08c, 0x0020, 0x0040, 0x1eaa, 0xa084, 0x0006, 0x00c0, - 0x1eaa, 0x6014, 0x8007, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, - 0xa0f0, 0x3a00, 0x7004, 0xa084, 0x000a, 0x00c0, 0x1eaa, 0x7108, - 0xa194, 0xff00, 0x0040, 0x1eaa, 0xa18c, 0x00ff, 0x2001, 0x000c, - 0xa106, 0x0040, 0x1e91, 0x2001, 0x0012, 0xa106, 0x0040, 0x1e95, - 0x2001, 0x0014, 0xa106, 0x0040, 0x1e99, 0x2001, 0x0019, 0xa106, - 0x0040, 0x1e9d, 0x2001, 0x0032, 0xa106, 0x0040, 0x1ea1, 0x0078, - 0x1ea5, 0x2009, 0x0012, 0x0078, 0x1ea7, 0x2009, 0x0014, 0x0078, - 0x1ea7, 0x2009, 0x0019, 0x0078, 0x1ea7, 0x2009, 0x0020, 0x0078, - 0x1ea7, 0x2009, 0x003f, 0x0078, 0x1ea7, 0x2011, 0x0000, 0x2100, - 0xa205, 0x700a, 0x0e7f, 0x007c, 0x2071, 0x0010, 0x70ca, 0x007f, - 0x70c6, 0x70c3, 0x8002, 0x2071, 0x0000, 0x701b, 0x0001, 0x2091, - 0x4080, 0x0078, 0x1eb9, 0x107e, 0x007e, 0x127e, 0x2091, 0x2300, - 0x7f3c, 0x7e58, 0x7c30, 0x7d38, 0x2009, 0x3974, 0x78a0, 0x200a, - 0x8108, 0x250a, 0x8108, 0x240a, 0x8108, 0x260a, 0x8108, 0x270a, - 0xa594, 0x003f, 0xa484, 0x4000, 0x0040, 0x1edc, 0xa784, 0x007c, - 0x00c0, 0x318f, 0x1078, 0x1eac, 0xa49c, 0x000f, 0xa382, 0x0004, - 0x0050, 0x1ee4, 0x1078, 0x1eac, 0x8507, 0xa084, 0x000f, 0x0079, - 0x1ee9, 0x236e, 0x240d, 0x242e, 0x2699, 0x28dd, 0x293b, 0x2984, - 0x29f0, 0x2a8d, 0x2b1a, 0x1f11, 0x1ef9, 0x21c3, 0x2288, 0x28bc, - 0x1ef9, 0x1078, 0x1eac, 0x0018, 0x1ec0, 0x127f, 0x2091, 0x8001, - 0x007f, 0x107f, 0x007c, 0x7003, 0x0000, 0x703f, 0x0000, 0x7030, - 0xa005, 0x0040, 0x1f0d, 0x7033, 0x0000, 0x1078, 0x316a, 0x0018, - 0x1ec0, 0x2009, 0x390f, 0x200b, 0x0000, 0x705c, 0xa005, 0x00c0, - 0x1fe2, 0x70a0, 0xa084, 0x0007, 0x0079, 0x1f1e, 0x2005, 0x1f26, - 0x1f34, 0x1f51, 0x1f73, 0x1fc0, 0x1f99, 0x1f26, 0x7808, 0xa084, - 0xfffd, 0x780a, 0x2009, 0x0047, 0x1078, 0x27c1, 0x00c0, 0x1f32, - 0x7003, 0x0004, 0x0078, 0x1efb, 0x1078, 0x3151, 0x00c0, 0x1f4f, - 0x70b4, 0x8007, 0x7882, 0x789b, 0x0010, 0x78ab, 0x000c, 0x789b, - 0x0060, 0x78ab, 0x0001, 0x785b, 0x0004, 0x2009, 0x00fb, 0x1078, - 0x27bf, 0x00c0, 0x1f4f, 0x7003, 0x0004, 0x70c7, 0x000f, 0x0078, - 0x1efb, 0x1078, 0x3151, 0x00c0, 0x1f71, 0x71b4, 0x8107, 0x7882, - 0x789b, 0x0010, 0xa18c, 0x0007, 0xa18d, 0x00c0, 0x79aa, 0x78ab, - 0x0006, 0x789b, 0x0060, 0x78ab, 0x0002, 0x785b, 0x0004, 0x2009, - 0x00fb, 0x1078, 0x27bf, 0x00c0, 0x1f71, 0x7003, 0x0004, 0x70c7, - 0x000f, 0x0078, 0x1efb, 0x1078, 0x3151, 0x00c0, 0x1f97, 0x71b4, - 0x8107, 0x7882, 0x789b, 0x0010, 0xa18c, 0x0007, 0xa18d, 0x00c0, - 0x79aa, 0x78ab, 0x0020, 0x71b8, 0x79aa, 0x78ab, 0x000d, 0x789b, - 0x0060, 0x78ab, 0x0004, 0x785b, 0x0004, 0x2009, 0x00fb, 0x1078, - 0x27bf, 0x00c0, 0x1f97, 0x7003, 0x0004, 0x70c7, 0x000f, 0x0078, - 0x1efb, 0x1078, 0x3151, 0x00c0, 0x1fbe, 0x71b4, 0x8107, 0x7882, - 0x789b, 0x0010, 0xa18c, 0x0007, 0xa18d, 0x00c0, 0x79aa, 0x78ab, - 0x0006, 0x789b, 0x0060, 0x78ab, 0x0002, 0x785b, 0x0004, 0x2009, - 0x00fb, 0x1078, 0x27bf, 0x00c0, 0x1fbe, 0x70bc, 0x70bf, 0x0000, - 0x2068, 0x703e, 0x7003, 0x0002, 0x70c7, 0x000f, 0x0078, 0x1efb, - 0x1078, 0x3151, 0x00c0, 0x1efb, 0x70bc, 0x2068, 0x1078, 0x31f3, - 0x789b, 0x0010, 0x6814, 0xa084, 0x0007, 0xa085, 0x0080, 0x007e, - 0x007f, 0x78aa, 0x6e1c, 0x067e, 0x067f, 0x2041, 0x0001, 0x70c0, - 0xa084, 0x0400, 0x2001, 0x0004, 0x0040, 0x1fe0, 0x2001, 0x0006, - 0x0078, 0x20e1, 0x1078, 0x3151, 0x00c0, 0x1efb, 0x789b, 0x0010, - 0x705c, 0x2068, 0x1078, 0x31f3, 0x6f14, 0x1078, 0x3099, 0x6008, - 0xa085, 0x0010, 0x600a, 0xad80, 0x0009, 0x2003, 0x0005, 0x6814, - 0xa084, 0x0007, 0xa085, 0x0080, 0x78aa, 0x2031, 0x0020, 0x2041, - 0x0001, 0x2001, 0x0003, 0x0078, 0x20e1, 0x0018, 0x1ec0, 0x7440, - 0xa485, 0x0000, 0x0040, 0x201f, 0xa080, 0x3980, 0x2030, 0x7144, - 0x8108, 0xa12a, 0x0048, 0x2016, 0x2009, 0x3980, 0x2164, 0x6504, - 0x85ff, 0x00c0, 0x202c, 0x8421, 0x00c0, 0x2010, 0x7146, 0x7003, - 0x0000, 0x703f, 0x0000, 0x0078, 0x1efb, 0x7640, 0xa6b0, 0x3980, - 0x7144, 0x2600, 0x0078, 0x201b, 0x7146, 0x2568, 0x2558, 0x753e, - 0x2c50, 0x6708, 0x7736, 0xa784, 0x013f, 0x0040, 0x2059, 0xa784, - 0x0021, 0x00c0, 0x2029, 0xa784, 0x0002, 0x0040, 0x2046, 0xa784, - 0x0004, 0x0040, 0x2029, 0xa7bc, 0xfffb, 0x670a, 0xa784, 0x0008, - 0x00c0, 0x2029, 0xa784, 0x0010, 0x00c0, 0x2029, 0xa784, 0x0100, - 0x0040, 0x2059, 0x6018, 0xa005, 0x00c0, 0x2029, 0xa7bc, 0xfeff, - 0x670a, 0x6823, 0x0000, 0x6e1c, 0xa684, 0x000e, 0x6118, 0x0040, - 0x2069, 0x601c, 0xa102, 0x0048, 0x206c, 0x0040, 0x206c, 0x0078, - 0x2025, 0x81ff, 0x00c0, 0x2025, 0xa784, 0x0080, 0x00c0, 0x2072, - 0x700c, 0x6022, 0x1078, 0x31f3, 0x0018, 0x1ec0, 0x789b, 0x0010, - 0xa046, 0x1078, 0x3151, 0x00c0, 0x1efb, 0x6b14, 0xa39c, 0x0007, - 0xa39d, 0x00c0, 0x704c, 0xa084, 0x8000, 0x0040, 0x208b, 0xa684, - 0x0001, 0x0040, 0x208d, 0xa39c, 0xffbf, 0xa684, 0x0010, 0x0040, - 0x2093, 0xa39d, 0x0020, 0x7baa, 0x8840, 0xa684, 0x000e, 0x00c0, - 0x209e, 0xa7bd, 0x0010, 0x670a, 0x0078, 0x20df, 0x714c, 0xa18c, - 0x0800, 0x0040, 0x2cfc, 0x2011, 0x0021, 0x8004, 0x8004, 0x0048, - 0x20b5, 0x2011, 0x0022, 0x8004, 0x0048, 0x20b5, 0x2011, 0x0020, - 0x8004, 0x0048, 0x20b5, 0x0040, 0x20df, 0x7aaa, 0x8840, 0x1078, - 0x316a, 0x6a14, 0x610c, 0x8108, 0xa18c, 0x00ff, 0xa1e0, 0x4280, - 0x2c64, 0x8cff, 0x0040, 0x20d6, 0x6014, 0xa206, 0x00c0, 0x20c0, - 0x60b8, 0x8001, 0x60ba, 0x00c0, 0x20bb, 0x0c7e, 0x2a60, 0x6008, - 0xa085, 0x0100, 0x600a, 0x0c7f, 0x0078, 0x2005, 0x1078, 0x3151, - 0x00c0, 0x1efb, 0x2a60, 0x610e, 0x79aa, 0x8840, 0x712e, 0x2001, - 0x0001, 0x007e, 0x7150, 0xa184, 0x0018, 0x0040, 0x20fc, 0xa184, - 0x0010, 0x0040, 0x20ef, 0x1078, 0x2ee3, 0x00c0, 0x211f, 0xa184, - 0x0008, 0x0040, 0x20fc, 0x69a0, 0xa184, 0x0600, 0x00c0, 0x20fc, - 0x1078, 0x2ddf, 0x0078, 0x211f, 0x69a0, 0xa184, 0x0800, 0x0040, - 0x2113, 0x0c7e, 0x027e, 0x2960, 0x6000, 0xa085, 0x2000, 0x6002, - 0x6104, 0xa18d, 0x0010, 0x6106, 0x027f, 0x0c7f, 0x1078, 0x2ee3, - 0x00c0, 0x211f, 0x69a0, 0xa184, 0x0200, 0x0040, 0x211b, 0x1078, - 0x2e2e, 0x0078, 0x211f, 0xa184, 0x0400, 0x00c0, 0x20f8, 0x69a0, - 0xa184, 0x1000, 0x0040, 0x212a, 0x6914, 0xa18c, 0xff00, 0x810f, - 0x1078, 0x1da7, 0x007f, 0x7002, 0xa68c, 0x00e0, 0xa684, 0x0060, - 0x0040, 0x2138, 0xa086, 0x0060, 0x00c0, 0x2138, 0xa18d, 0x4000, - 0x88ff, 0x0040, 0x213d, 0xa18d, 0x0004, 0x795a, 0x69b6, 0x789b, - 0x0060, 0x2800, 0x78aa, 0x789b, 0x0061, 0x6818, 0xa08d, 0x8000, - 0xa084, 0x7fff, 0x691a, 0xa68c, 0x0080, 0x0040, 0x215c, 0x70cb, - 0x0000, 0xa08a, 0x000d, 0x0050, 0x215a, 0xa08a, 0x000c, 0x71ca, - 0x2001, 0x000c, 0x800c, 0x71ce, 0x78aa, 0x8008, 0x810c, 0x0040, - 0x2d07, 0xa18c, 0x00f8, 0x00c0, 0x2d07, 0x157e, 0x137e, 0x147e, - 0x20a1, 0x012b, 0x789b, 0x0000, 0x8000, 0x80ac, 0xad80, 0x000b, - 0x2098, 0x53a6, 0x147f, 0x137f, 0x157f, 0x6814, 0x8007, 0x7882, - 0x6d94, 0x7dd6, 0x7dde, 0x6e98, 0x7ed2, 0x7eda, 0x7830, 0xa084, - 0x00c0, 0x00c0, 0x2185, 0x0098, 0x218d, 0x6008, 0xa084, 0xffef, - 0x600a, 0x1078, 0x316a, 0x0078, 0x1f03, 0x7200, 0xa284, 0x0007, - 0xa086, 0x0001, 0x00c0, 0x219a, 0x781b, 0x004a, 0x1078, 0x316a, - 0x0078, 0x21ab, 0x6ab4, 0xa295, 0x2000, 0x7a5a, 0x781b, 0x004a, - 0x1078, 0x316a, 0x7200, 0x2500, 0xa605, 0x0040, 0x21ab, 0xa284, - 0x0007, 0x1079, 0x21b9, 0xa284, 0x0007, 0xa086, 0x0001, 0x00c0, - 0x1efb, 0x6018, 0x8000, 0x601a, 0xad80, 0x0009, 0x7032, 0x0078, - 0x1efb, 0x21c1, 0x3571, 0x3571, 0x3560, 0x3571, 0x21c1, 0x3560, - 0x21c1, 0x1078, 0x1eac, 0x7808, 0xa084, 0xfffd, 0x780a, 0x0f7e, - 0x2079, 0x3900, 0x78c0, 0x0f7f, 0xa084, 0x0001, 0x0040, 0x21e9, - 0x70a0, 0xa086, 0x0001, 0x00c0, 0x21d8, 0x70a2, 0x0078, 0x226c, - 0x70a0, 0xa086, 0x0005, 0x00c0, 0x21e7, 0x70bc, 0x2068, 0x681b, - 0x0004, 0x6817, 0x0000, 0x6820, 0xa085, 0x0008, 0x6822, 0x70a3, - 0x0000, 0x157e, 0x2011, 0x0004, 0x71a0, 0xa186, 0x0001, 0x0040, - 0x2207, 0xa186, 0x0007, 0x00c0, 0x21fb, 0x2009, 0x3935, 0x200b, - 0x0005, 0x0078, 0x2207, 0x2009, 0x3913, 0x2104, 0x2009, 0x3912, - 0x200a, 0x2009, 0x3935, 0x200b, 0x0001, 0x0078, 0x2209, 0x70a3, - 0x0000, 0x1078, 0x32f5, 0x20a9, 0x0010, 0x2039, 0x0000, 0x1078, - 0x2f9a, 0xa7b8, 0x0100, 0x0070, 0x2217, 0x0078, 0x220f, 0x7000, - 0x0079, 0x221a, 0x2248, 0x2231, 0x2231, 0x2224, 0x2248, 0x2248, - 0x2248, 0x2222, 0x1078, 0x1eac, 0x2021, 0x3957, 0x2404, 0xa005, - 0x0040, 0x2248, 0xad06, 0x00c0, 0x2231, 0x6800, 0x2022, 0x0078, - 0x2241, 0x6820, 0xa084, 0x0001, 0x00c0, 0x223d, 0x6f14, 0x1078, - 0x3099, 0x1078, 0x2cc9, 0x0078, 0x2241, 0x7054, 0x2060, 0x6800, - 0x6002, 0x6a1a, 0x6820, 0xa085, 0x0008, 0x6822, 0x1078, 0x1a26, - 0x2021, 0x4380, 0x1078, 0x2272, 0x2021, 0x3957, 0x1078, 0x2272, - 0x20a9, 0x0000, 0x2021, 0x4280, 0x1078, 0x2272, 0x8420, 0x0070, - 0x225b, 0x0078, 0x2254, 0x20a9, 0x0080, 0x2061, 0x3a80, 0x6018, - 0x6110, 0xa102, 0x6012, 0x601b, 0x0000, 0xace0, 0x0010, 0x0070, - 0x226b, 0x0078, 0x225f, 0x157f, 0x7003, 0x0000, 0x703f, 0x0000, - 0x0078, 0x1efb, 0x047e, 0x2404, 0xa005, 0x0040, 0x2284, 0x2068, - 0x6800, 0x007e, 0x6a1a, 0x6820, 0xa085, 0x0008, 0x6822, 0x1078, - 0x1a26, 0x007f, 0x0078, 0x2274, 0x047f, 0x2023, 0x0000, 0x007c, - 0xa282, 0x0003, 0x0050, 0x228e, 0x1078, 0x1eac, 0x2300, 0x0079, - 0x2291, 0x2294, 0x2311, 0x232e, 0xa282, 0x0002, 0x0040, 0x229a, - 0x1078, 0x1eac, 0x70a0, 0x70a3, 0x0000, 0x70c7, 0x0000, 0x0079, - 0x22a1, 0x22a9, 0x22a9, 0x22ab, 0x22e9, 0x2d0d, 0x22a9, 0x22e9, - 0x22a9, 0x1078, 0x1eac, 0x77b4, 0x1078, 0x2f9a, 0x77b4, 0xa7bc, - 0x0f00, 0x1078, 0x3099, 0x6018, 0xa005, 0x0040, 0x22e0, 0x2021, - 0x4380, 0x2009, 0x0004, 0x2011, 0x0010, 0x1078, 0x2349, 0x0040, - 0x22e0, 0x157e, 0x20a9, 0x0000, 0x2021, 0x4280, 0x047e, 0x2009, - 0x0004, 0x2011, 0x0010, 0x1078, 0x2349, 0x047f, 0x0040, 0x22d5, - 0x8420, 0x0070, 0x22d5, 0x0078, 0x22c6, 0x157f, 0x2021, 0x3957, - 0x2009, 0x0004, 0x2011, 0x0010, 0x1078, 0x2349, 0x0040, 0x22e0, - 0x8738, 0xa784, 0x0007, 0x00c0, 0x22b1, 0x0078, 0x1f03, 0x0078, - 0x1f03, 0x77b4, 0x1078, 0x3099, 0x6018, 0xa005, 0x0040, 0x230f, - 0x2021, 0x4380, 0x2009, 0x0005, 0x2011, 0x0020, 0x1078, 0x2349, - 0x0040, 0x230f, 0x157e, 0x20a9, 0x0000, 0x2021, 0x4280, 0x047e, - 0x2009, 0x0005, 0x2011, 0x0020, 0x1078, 0x2349, 0x047f, 0x0040, - 0x230e, 0x8420, 0x0070, 0x230e, 0x0078, 0x22ff, 0x157f, 0x0078, - 0x1f03, 0x2200, 0x0079, 0x2314, 0x2317, 0x2319, 0x2319, 0x1078, - 0x1eac, 0x2009, 0x0012, 0x70a0, 0xa086, 0x0002, 0x0040, 0x2322, - 0x2009, 0x000e, 0x6818, 0xa084, 0x8000, 0x0040, 0x2328, 0x691a, - 0x70a3, 0x0000, 0x70a7, 0x0001, 0x0078, 0x311c, 0x2200, 0x0079, - 0x2331, 0x2336, 0x2319, 0x2334, 0x1078, 0x1eac, 0x1078, 0x27ce, - 0x7000, 0xa086, 0x0001, 0x00c0, 0x2c9f, 0x1078, 0x2cdf, 0x6008, - 0xa084, 0xffef, 0x600a, 0x1078, 0x2c92, 0x0040, 0x2c9f, 0x0078, - 0x2005, 0x2404, 0xa005, 0x0040, 0x236a, 0x2068, 0x2d04, 0x007e, - 0x6814, 0xa706, 0x0040, 0x2358, 0x2d20, 0x007f, 0x0078, 0x234a, - 0x007f, 0x2022, 0x691a, 0x6820, 0xa205, 0x6822, 0x1078, 0x1a26, - 0x6010, 0x8001, 0x6012, 0x6008, 0xa084, 0xffef, 0x600a, 0x1078, - 0x2cdf, 0x007c, 0xa085, 0x0001, 0x0078, 0x2369, 0x2300, 0x0079, - 0x2371, 0x2376, 0x2374, 0x23c2, 0x1078, 0x1eac, 0x78e4, 0xa005, - 0x00d0, 0x238a, 0x0018, 0x238a, 0xa084, 0x0007, 0x0079, 0x2380, - 0x239b, 0x23a8, 0x238e, 0x2388, 0x3144, 0x3144, 0x2388, 0x23b5, - 0x1078, 0x1eac, 0x2001, 0x0003, 0x0078, 0x26ad, 0x6818, 0xa084, - 0x8000, 0x0040, 0x2395, 0x681b, 0x001d, 0x1078, 0x2f7d, 0x781b, - 0x0053, 0x0078, 0x1efb, 0x6818, 0xa084, 0x8000, 0x0040, 0x23a2, - 0x681b, 0x001d, 0x1078, 0x2f7d, 0x781b, 0x00de, 0x0078, 0x1efb, - 0x6818, 0xa084, 0x8000, 0x0040, 0x23af, 0x681b, 0x001d, 0x1078, - 0x2f7d, 0x781b, 0x00e5, 0x0078, 0x1efb, 0x6818, 0xa084, 0x8000, - 0x0040, 0x23bc, 0x681b, 0x001d, 0x1078, 0x2f7d, 0x781b, 0x009c, - 0x0078, 0x1efb, 0xa584, 0x000f, 0x00c0, 0x23e1, 0x1078, 0x27ce, - 0x7000, 0x0079, 0x23cb, 0x23d3, 0x23d5, 0x23d3, 0x2c9f, 0x2c9f, - 0x2c9f, 0x2c9f, 0x23d3, 0x1078, 0x1eac, 0x1078, 0x2cdf, 0x6008, - 0xa084, 0xffef, 0x600a, 0x1078, 0x2c92, 0x0040, 0x2c9f, 0x0078, - 0x2005, 0x79e4, 0xa005, 0x00d0, 0x238a, 0x0018, 0x238a, 0xa184, - 0x0007, 0x0079, 0x23eb, 0x23fb, 0x2401, 0x23f5, 0x23f3, 0x3144, - 0x3144, 0x23f3, 0x313c, 0x1078, 0x1eac, 0x1078, 0x2f85, 0x781b, - 0x0053, 0x0078, 0x1efb, 0x1078, 0x2f85, 0x781b, 0x00de, 0x0078, - 0x1efb, 0x1078, 0x2f85, 0x781b, 0x00e5, 0x0078, 0x1efb, 0x1078, - 0x2f85, 0x781b, 0x009c, 0x0078, 0x1efb, 0x2300, 0x0079, 0x2410, - 0x2415, 0x2413, 0x2417, 0x1078, 0x1eac, 0x0078, 0x29f0, 0x681b, - 0x0008, 0x78a3, 0x0000, 0x79e4, 0xa184, 0x0030, 0x0040, 0x29f0, - 0xa184, 0x0007, 0x0079, 0x2424, 0x242c, 0x2401, 0x238e, 0x311c, - 0x3144, 0x3144, 0x242c, 0x313c, 0x1078, 0x1eac, 0xa282, 0x0005, - 0x0050, 0x2434, 0x1078, 0x1eac, 0x2300, 0x0079, 0x2437, 0x243a, - 0x265e, 0x266a, 0x2200, 0x0079, 0x243d, 0x2457, 0x2444, 0x2457, - 0x2442, 0x2643, 0x1078, 0x1eac, 0x789b, 0x0018, 0x78a8, 0xa084, - 0x00ff, 0xa082, 0x0020, 0x0048, 0x2f69, 0xa08a, 0x0004, 0x00c8, - 0x2f69, 0x0079, 0x2453, 0x2f69, 0x2f69, 0x2f69, 0x2f23, 0x789b, - 0x0018, 0x79a8, 0xa184, 0x0080, 0x0040, 0x246c, 0xa184, 0x0018, - 0x0040, 0x2468, 0x0078, 0x2f69, 0x7000, 0xa005, 0x00c0, 0x2462, - 0x2011, 0x0004, 0x0078, 0x2b28, 0xa184, 0x00ff, 0xa08a, 0x0010, - 0x00c8, 0x2f69, 0x0079, 0x2474, 0x2486, 0x2484, 0x249e, 0x24a2, - 0x255a, 0x2f69, 0x2f69, 0x255c, 0x2f69, 0x2f69, 0x263f, 0x263f, - 0x2f69, 0x2f69, 0x2f69, 0x2641, 0x1078, 0x1eac, 0xa684, 0x1000, - 0x0040, 0x2493, 0x2001, 0x0300, 0x8000, 0x8000, 0x783a, 0x781b, - 0x0099, 0x0078, 0x1efb, 0x6818, 0xa084, 0x8000, 0x0040, 0x249c, - 0x681b, 0x001d, 0x0078, 0x248a, 0x0078, 0x311c, 0x681b, 0x001d, - 0x0078, 0x2f75, 0x6920, 0xa184, 0x8000, 0x00c0, 0x24ae, 0x68af, - 0x0000, 0x68b3, 0x0000, 0xa18d, 0x8000, 0x6922, 0xa684, 0x1800, - 0x00c0, 0x24ed, 0x6820, 0xa084, 0x0001, 0x00c0, 0x24f3, 0x6818, - 0xa086, 0x0008, 0x00c0, 0x24be, 0x681b, 0x0000, 0xa684, 0x0400, - 0x0040, 0x2556, 0xa684, 0x0080, 0x0040, 0x24e9, 0x70cb, 0x0000, - 0x6818, 0xa084, 0x003f, 0xa08a, 0x000d, 0x0050, 0x24e9, 0xa08a, - 0x000c, 0x71ca, 0x2001, 0x000c, 0x800c, 0x71ce, 0x789b, 0x0061, - 0x78aa, 0x157e, 0x137e, 0x147e, 0x20a1, 0x012b, 0x789b, 0x0000, - 0x8000, 0x80ac, 0xad80, 0x000b, 0x2098, 0x53a6, 0x147f, 0x137f, - 0x157f, 0x781b, 0x0056, 0x0078, 0x1efb, 0xa684, 0x1000, 0x0040, - 0x24f3, 0x0078, 0x1efb, 0xa684, 0x0060, 0x0040, 0x2552, 0xa684, - 0x0800, 0x0040, 0x2552, 0xa684, 0x8000, 0x00c0, 0x2503, 0x69b0, - 0x6aac, 0x0078, 0x251d, 0xa6b4, 0x7fff, 0x7e5a, 0x6eb6, 0x789b, - 0x0074, 0x7aac, 0x79ac, 0x78ac, 0x801b, 0x00c8, 0x2510, 0x8000, - 0xa084, 0x003f, 0xa108, 0xa291, 0x0000, 0x6b98, 0x2100, 0xa302, - 0x68b2, 0x6b94, 0x2200, 0xa303, 0x68ae, 0xa684, 0x4000, 0x0040, - 0x2525, 0xa6b4, 0xbfff, 0x7e5a, 0x6eb6, 0xa006, 0x1078, 0x362f, - 0x6ab0, 0x69ac, 0x6c98, 0x6b94, 0x2200, 0xa105, 0x0040, 0x2534, - 0x2200, 0xa422, 0x2100, 0xa31b, 0x6caa, 0x7cd2, 0x6ba6, 0x7bd6, - 0x2300, 0xa405, 0x00c0, 0x2544, 0xa6b5, 0x4000, 0x7e5a, 0x6eb6, - 0x781b, 0x0065, 0x0078, 0x1efb, 0x781b, 0x0065, 0x2200, 0xa115, - 0x00c0, 0x254e, 0x1078, 0x3571, 0x0078, 0x1efb, 0x1078, 0x35a6, - 0x0078, 0x1efb, 0x781b, 0x0068, 0x0078, 0x1efb, 0x781b, 0x0056, - 0x0078, 0x1efb, 0x1078, 0x1eac, 0x0078, 0x25b1, 0x6920, 0xa184, - 0x0100, 0x0040, 0x2570, 0xa18c, 0xfeff, 0x6922, 0x0c7e, 0x7048, - 0x2060, 0x6004, 0xa084, 0xfff5, 0x6006, 0x0c7f, 0x0078, 0x25a0, - 0xa184, 0x0200, 0x0040, 0x25a0, 0xa18c, 0xfdff, 0x6922, 0x0c7e, - 0x7048, 0x2060, 0x6004, 0xa084, 0xffef, 0x6006, 0x2008, 0x2c48, - 0x0c7f, 0xa184, 0x0008, 0x0040, 0x25a0, 0x1078, 0x3095, 0x1078, - 0x2ddf, 0x88ff, 0x0040, 0x25a0, 0x789b, 0x0060, 0x2800, 0x78aa, - 0x7e58, 0xa6b5, 0x0004, 0x7e5a, 0xa684, 0x0400, 0x00c0, 0x259c, - 0x781b, 0x0053, 0x0078, 0x1efb, 0x781b, 0x0067, 0x0078, 0x1efb, - 0x7e58, 0xa684, 0x0400, 0x00c0, 0x25a9, 0x781b, 0x0056, 0x0078, - 0x1efb, 0x781b, 0x0068, 0x0078, 0x1efb, 0x0078, 0x2f6f, 0x0078, - 0x2f6f, 0x2019, 0x0000, 0x7990, 0xa18c, 0x0007, 0x0040, 0x25af, - 0x789b, 0x0010, 0x78a8, 0xa094, 0x00ff, 0xa286, 0x0001, 0x00c0, - 0x25d4, 0x2300, 0x7ca8, 0xa400, 0x2018, 0xa102, 0x0040, 0x25cc, - 0x0048, 0x25cc, 0x0078, 0x25ce, 0x0078, 0x255e, 0x24a8, 0x7aa8, - 0x00f0, 0x25ce, 0x0078, 0x25ba, 0xa284, 0x00f0, 0xa086, 0x0020, - 0x00c0, 0x2630, 0x8318, 0x8318, 0x2300, 0xa102, 0x0040, 0x25e4, - 0x0048, 0x25e4, 0x0078, 0x262d, 0xa286, 0x0023, 0x0040, 0x25af, - 0x681c, 0xa084, 0xfff1, 0x681e, 0x7e58, 0xa684, 0xfff1, 0xa085, - 0x0010, 0x2030, 0x7e5a, 0x6008, 0xa085, 0x0010, 0x600a, 0x0c7e, - 0x7048, 0x2060, 0x6004, 0x2008, 0x2c48, 0x0c7f, 0xa184, 0x0010, - 0x0040, 0x2608, 0x1078, 0x3095, 0x1078, 0x2ee3, 0x0078, 0x2617, - 0x0c7e, 0x7048, 0x2060, 0x6004, 0x2008, 0x2c48, 0x0c7f, 0xa184, - 0x0008, 0x0040, 0x25a0, 0x1078, 0x3095, 0x1078, 0x2ddf, 0x88ff, - 0x0040, 0x25a0, 0x789b, 0x0060, 0x2800, 0x78aa, 0xa6b5, 0x0004, - 0x7e5a, 0xa684, 0x0400, 0x00c0, 0x2629, 0x781b, 0x0053, 0x0078, - 0x1efb, 0x781b, 0x0067, 0x0078, 0x1efb, 0x7aa8, 0x0078, 0x25ba, - 0x8318, 0x2300, 0xa102, 0x0040, 0x2639, 0x0048, 0x2639, 0x0078, - 0x25ba, 0xa284, 0x0080, 0x00c0, 0x2f75, 0x0078, 0x2f6f, 0x0078, - 0x2f75, 0x0078, 0x2f69, 0x789b, 0x0018, 0x78a8, 0xa084, 0x00ff, - 0xa08e, 0x0001, 0x0040, 0x264e, 0x1078, 0x1eac, 0x7aa8, 0xa294, - 0x00ff, 0x78a8, 0xa084, 0x00ff, 0xa08a, 0x0004, 0x00c8, 0x2f69, - 0x0079, 0x265a, 0x2f69, 0x2d32, 0x2f69, 0x2e7e, 0xa282, 0x0000, - 0x00c0, 0x2664, 0x1078, 0x1eac, 0x1078, 0x2f7d, 0x781b, 0x0067, - 0x0078, 0x1efb, 0xa282, 0x0003, 0x00c0, 0x2670, 0x1078, 0x1eac, - 0xa484, 0x8000, 0x00c0, 0x2693, 0x70a0, 0xa005, 0x0040, 0x267a, - 0x1078, 0x1eac, 0x6f14, 0x77b6, 0xa7bc, 0x0f00, 0x1078, 0x3099, - 0x6008, 0xa085, 0x0021, 0x600a, 0x8738, 0xa784, 0x0007, 0x00c0, - 0x267e, 0x1078, 0x2f81, 0x70a3, 0x0002, 0x2009, 0x3935, 0x200b, - 0x0009, 0x0078, 0x2695, 0x1078, 0x2f8d, 0x781b, 0x0067, 0x0078, - 0x1efb, 0xa282, 0x0004, 0x0050, 0x269f, 0x1078, 0x1eac, 0x2300, - 0x0079, 0x26a2, 0x26a5, 0x2781, 0x27a9, 0xa286, 0x0003, 0x0040, - 0x26ab, 0x1078, 0x1eac, 0x2001, 0x0000, 0x703a, 0x7000, 0xa084, - 0x0007, 0x0079, 0x26b3, 0x26bb, 0x26bd, 0x26bd, 0x2871, 0x28a2, - 0x1f03, 0x28a2, 0x26bb, 0x1078, 0x1eac, 0xa684, 0x1000, 0x00c0, - 0x26c5, 0x1078, 0x32f5, 0x0040, 0x275b, 0x7868, 0xa08c, 0x00ff, - 0x0040, 0x270d, 0xa186, 0x0008, 0x00c0, 0x26dc, 0x1078, 0x2cdf, - 0x6008, 0xa084, 0xffef, 0x600a, 0x1078, 0x2c92, 0x0040, 0x270d, - 0x1078, 0x32f5, 0x0078, 0x26f4, 0xa186, 0x0028, 0x00c0, 0x270d, - 0x1078, 0x32f5, 0x6008, 0xa084, 0xffef, 0x600a, 0x6018, 0xa005, - 0x0040, 0x26f4, 0x8001, 0x601a, 0xa005, 0x0040, 0x26f4, 0x8001, - 0xa005, 0x0040, 0x26f4, 0x601e, 0x6820, 0xa084, 0x0001, 0x0040, - 0x1f03, 0x6820, 0xa084, 0xfffe, 0x6822, 0x7054, 0x0c7e, 0x2060, - 0x6800, 0x6002, 0x0c7f, 0x6004, 0x6802, 0xa005, 0x2d00, 0x00c0, - 0x270a, 0x6002, 0x6006, 0x0078, 0x1f03, 0x017e, 0x1078, 0x27ce, - 0x017f, 0xa684, 0xdf00, 0x681e, 0x682b, 0x0000, 0x6f14, 0x81ff, - 0x0040, 0x275b, 0xa186, 0x0002, 0x00c0, 0x2753, 0xa684, 0x0800, - 0x00c0, 0x272a, 0xa684, 0x0060, 0x0040, 0x272a, 0x78d8, 0x7adc, - 0x682e, 0x6a32, 0x6820, 0xa084, 0x0800, 0x00c0, 0x275b, 0x8717, - 0xa294, 0x000f, 0x8213, 0x8213, 0x8213, 0xa290, 0x3a00, 0xa290, - 0x0000, 0x221c, 0x8210, 0x2204, 0xa085, 0x0018, 0x2012, 0x8211, - 0xa384, 0x0400, 0x0040, 0x274d, 0x68a0, 0xa084, 0x0100, 0x00c0, - 0x274d, 0x1078, 0x2830, 0x0078, 0x1f03, 0x6008, 0xa085, 0x0002, - 0x600a, 0x0078, 0x275b, 0xa186, 0x0018, 0x0040, 0x275b, 0xa186, - 0x0014, 0x0040, 0x1f03, 0x6916, 0x6818, 0xa084, 0x8000, 0x0040, - 0x2763, 0x7038, 0x681a, 0xa68c, 0xdf00, 0x691e, 0x1078, 0x2cd0, - 0x1078, 0x2cdf, 0x00c0, 0x2770, 0x6008, 0xa084, 0xffef, 0x600a, - 0x6820, 0xa084, 0x0001, 0x00c0, 0x2779, 0x1078, 0x2cc9, 0x0078, - 0x277d, 0x7054, 0x2060, 0x6800, 0x6002, 0x1078, 0x1a26, 0x0078, - 0x1f03, 0xa282, 0x0004, 0x0048, 0x2787, 0x1078, 0x1eac, 0x2200, - 0x0079, 0x278a, 0x2785, 0x278e, 0x2794, 0x278e, 0x1078, 0x2f7d, - 0x781b, 0x0067, 0x0078, 0x1efb, 0x7890, 0x8007, 0x8001, 0xa084, - 0x0007, 0xa080, 0x0018, 0x789a, 0x79a8, 0xa18c, 0x00ff, 0xa186, - 0x0003, 0x0040, 0x27a5, 0x0078, 0x2f69, 0x781b, 0x0068, 0x0078, - 0x1efb, 0x6820, 0xa085, 0x0004, 0x6822, 0x82ff, 0x00c0, 0x27b4, - 0x1078, 0x2f7d, 0x0078, 0x27bb, 0x8211, 0x0040, 0x27b9, 0x1078, - 0x1eac, 0x1078, 0x2f8d, 0x781b, 0x0067, 0x0078, 0x1efb, 0x1078, - 0x316a, 0x7830, 0xa084, 0x00c0, 0x00c0, 0x27cb, 0x0018, 0x27cb, - 0x791a, 0xa006, 0x007c, 0xa085, 0x0001, 0x007c, 0xa684, 0x0060, - 0x00c0, 0x27d8, 0x682f, 0x0000, 0x6833, 0x0000, 0x0078, 0x282f, - 0xa684, 0x0800, 0x00c0, 0x27e8, 0x6998, 0x6a94, 0x692e, 0x6a32, - 0x7000, 0xa086, 0x0006, 0x0040, 0x27e7, 0x1078, 0x32f5, 0x007c, - 0xa684, 0x0020, 0x0040, 0x2802, 0xa684, 0x4000, 0x0040, 0x27f6, - 0x682f, 0x0000, 0x6833, 0x0000, 0x0078, 0x27e0, 0x7038, 0xa005, - 0x00c0, 0x27fc, 0x703b, 0x0015, 0x79d8, 0x7adc, 0x692e, 0x6a32, - 0x0078, 0x27e0, 0xa684, 0x4000, 0x0040, 0x280c, 0x682f, 0x0000, - 0x6833, 0x0000, 0x0078, 0x27e0, 0x7038, 0xa005, 0x00c0, 0x2812, - 0x703b, 0x0015, 0x79d8, 0x7adc, 0x78d0, 0x80fb, 0x00c8, 0x2819, + 0x72ca, 0x73ce, 0x74d6, 0xa005, 0x0040, 0x1387, 0x8001, 0x78ae, + 0xa084, 0xfc00, 0x0040, 0x137c, 0x78cc, 0xa085, 0x0100, 0x78ce, + 0x2001, 0x4005, 0x0078, 0x1286, 0x7ab6, 0x7bba, 0x7dbe, 0x7ec2, + 0x7cb2, 0x78cc, 0xa084, 0xfcff, 0x78ce, 0x0078, 0x138b, 0x78cc, + 0xa085, 0x0100, 0x78ce, 0x0078, 0x1284, 0x2009, 0x5061, 0x210c, + 0x7aec, 0x0078, 0x1282, 0x2009, 0x5041, 0x210c, 0x0078, 0x1283, + 0x2009, 0x5042, 0x210c, 0x0078, 0x1283, 0x2061, 0x5040, 0x610c, + 0x6210, 0x0078, 0x1282, 0x2009, 0x5045, 0x210c, 0x0078, 0x1283, + 0x2009, 0x5046, 0x210c, 0x0078, 0x1283, 0x2009, 0x5048, 0x210c, + 0x0078, 0x1283, 0x2009, 0x5049, 0x210c, 0x0078, 0x1283, 0x7908, + 0x7a0c, 0x0078, 0x1282, 0x71c4, 0x8107, 0xa084, 0x000f, 0x8003, + 0x8003, 0x8003, 0xa0e8, 0x5280, 0x6a00, 0x6804, 0xa084, 0x0008, + 0x0040, 0x13cd, 0x6b08, 0x0078, 0x13ce, 0x6b0c, 0x0078, 0x1281, + 0x77c4, 0x1078, 0x1956, 0x2091, 0x8000, 0x6b1c, 0x6a14, 0x2091, + 0x8001, 0x2708, 0x0078, 0x1281, 0x794c, 0x0078, 0x1283, 0x77c4, + 0x1078, 0x1956, 0x2091, 0x8000, 0x6908, 0x6a18, 0x6b10, 0x2091, + 0x8001, 0x0078, 0x1281, 0x71c4, 0xa182, 0x0010, 0x00c8, 0x127c, + 0x1078, 0x22c1, 0x0078, 0x1281, 0x71c4, 0xa182, 0x0010, 0x00c8, + 0x127c, 0x2011, 0x5041, 0x2204, 0x007e, 0x2112, 0x1078, 0x227a, + 0x017f, 0x0078, 0x1283, 0x71c4, 0x2011, 0x1421, 0x20a9, 0x0008, + 0x2204, 0xa106, 0x0040, 0x1413, 0x8210, 0x0070, 0x1411, 0x0078, + 0x1408, 0x0078, 0x127c, 0xa292, 0x1421, 0x027e, 0x2011, 0x5042, + 0x2204, 0x2112, 0x017f, 0x007e, 0x1078, 0x2286, 0x017f, 0x0078, + 0x1283, 0x03e8, 0x00fa, 0x01f4, 0x02ee, 0x0064, 0x0019, 0x0032, + 0x004b, 0x2061, 0x5040, 0x610c, 0x6210, 0x70c4, 0x600e, 0x70c8, + 0x6012, 0x0078, 0x1282, 0x2061, 0x5040, 0x6114, 0x70c4, 0x6016, + 0x0078, 0x1283, 0x2061, 0x5040, 0x71c4, 0x2011, 0x0004, 0x601f, + 0x0019, 0x2019, 0x1212, 0xa186, 0x0028, 0x0040, 0x145b, 0x2011, + 0x0005, 0x601f, 0x0019, 0x2019, 0x1212, 0xa186, 0x0032, 0x0040, + 0x145b, 0x2011, 0x0006, 0x601f, 0x000c, 0x2019, 0x2222, 0xa186, + 0x003c, 0x00c0, 0x127c, 0x6018, 0x007e, 0x611a, 0x7800, 0xa084, + 0x0001, 0x00c0, 0x1476, 0x2001, 0x04fd, 0x2004, 0xa082, 0x0005, + 0x0048, 0x146e, 0x0038, 0x1472, 0x0078, 0x1476, 0x0028, 0x1472, + 0x0078, 0x1476, 0x2019, 0x2222, 0x0078, 0x1478, 0x2019, 0x1212, + 0x23b8, 0x1078, 0x2297, 0x1078, 0x4bdf, 0x017f, 0x0078, 0x1283, + 0x71c4, 0xa184, 0xffcf, 0x00c0, 0x127c, 0x2011, 0x5048, 0x2204, + 0x2112, 0x007e, 0x1078, 0x22b9, 0x017f, 0x0078, 0x1283, 0x71c4, + 0xa182, 0x0010, 0x00c8, 0x127c, 0x2011, 0x5049, 0x2204, 0x007e, + 0x2112, 0x1078, 0x22a8, 0x017f, 0x0078, 0x1283, 0x71c4, 0x72c8, + 0xa184, 0xfffd, 0x00c0, 0x127b, 0xa284, 0xfffd, 0x00c0, 0x127b, + 0x2100, 0x7908, 0x780a, 0x2200, 0x7a0c, 0x780e, 0x0078, 0x1282, + 0x71c4, 0x8107, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xa0e8, + 0x5280, 0x2019, 0x0000, 0x72c8, 0xa284, 0x0080, 0x0040, 0x14c6, + 0x6c14, 0x84ff, 0x00c0, 0x14c6, 0x6817, 0x0040, 0xa284, 0x0040, + 0x0040, 0x14d0, 0x6c10, 0x84ff, 0x00c0, 0x14d0, 0x6813, 0x0001, + 0x6800, 0x007e, 0xa226, 0x0040, 0x14f3, 0x6a02, 0xa484, 0x2000, + 0x0040, 0x14dc, 0xa39d, 0x0010, 0xa484, 0x1000, 0x0040, 0x14e2, + 0xa39d, 0x0008, 0xa484, 0x4000, 0x0040, 0x14f3, 0x810f, 0xa284, + 0x4000, 0x0040, 0x14ef, 0x1078, 0x22db, 0x0078, 0x14f3, 0x1078, + 0x22cd, 0x0078, 0x14f3, 0x72cc, 0x6808, 0xa206, 0x0040, 0x1522, + 0xa2a4, 0x00ff, 0x2061, 0x5040, 0x6118, 0xa186, 0x0028, 0x0040, + 0x1509, 0xa186, 0x0032, 0x0040, 0x150f, 0xa186, 0x003c, 0x0040, + 0x1515, 0xa482, 0x0064, 0x0048, 0x151f, 0x0078, 0x1519, 0xa482, + 0x0050, 0x0048, 0x151f, 0x0078, 0x1519, 0xa482, 0x0043, 0x0048, + 0x151f, 0x71c4, 0x71c6, 0x027f, 0x72ca, 0x0078, 0x127d, 0x6a0a, + 0xa39d, 0x000a, 0x6804, 0xa305, 0x6806, 0x027f, 0x6b0c, 0x71c4, + 0x0078, 0x1281, 0x77c4, 0x1078, 0x1956, 0x2091, 0x8000, 0x6a14, + 0x6b1c, 0x2091, 0x8001, 0x70c8, 0x6816, 0x70cc, 0x681e, 0x2708, + 0x0078, 0x1281, 0x70c4, 0x794c, 0x784e, 0x0078, 0x1283, 0x71c4, + 0x72c8, 0x73cc, 0xa182, 0x0010, 0x00c8, 0x127c, 0x1078, 0x22e9, + 0x0078, 0x1281, 0x77c4, 0x1078, 0x1956, 0x2091, 0x8000, 0x6a08, + 0xa295, 0x0002, 0x6a0a, 0x2091, 0x8001, 0x2708, 0x0078, 0x1282, + 0x77c4, 0x1078, 0x1956, 0x2091, 0x8000, 0x6a08, 0xa294, 0xfff9, + 0x6a0a, 0x6804, 0xa005, 0x0040, 0x1567, 0x1078, 0x21b1, 0x2091, + 0x8001, 0x2708, 0x0078, 0x1282, 0x77c4, 0x1078, 0x1956, 0x2091, + 0x8000, 0x6a08, 0xa295, 0x0004, 0x6a0a, 0x6804, 0xa005, 0x0040, + 0x157b, 0x1078, 0x21b1, 0x2091, 0x8001, 0x2708, 0x0078, 0x1282, + 0x77c4, 0x2041, 0x0001, 0x2049, 0x0005, 0x2051, 0x0020, 0x2091, + 0x8000, 0x1078, 0x1963, 0x2091, 0x8001, 0x2708, 0x6a08, 0x0078, + 0x1282, 0x77c4, 0x72c8, 0x73cc, 0x77c6, 0x72ca, 0x73ce, 0x1078, + 0x19c4, 0x00c0, 0x15a9, 0x6818, 0xa005, 0x0040, 0x15a9, 0x2708, + 0x1078, 0x22f9, 0x00c0, 0x15a9, 0x7817, 0x0015, 0x2091, 0x8001, + 0x007c, 0x2091, 0x8001, 0x0078, 0x1284, 0x77c4, 0x77c6, 0x2041, + 0x0021, 0x2049, 0x0005, 0x2051, 0x0020, 0x2091, 0x8000, 0x1078, + 0x1963, 0x2061, 0x5040, 0x606f, 0x0003, 0x6782, 0x6093, 0x000f, + 0x6073, 0x0000, 0x7817, 0x0016, 0x1078, 0x21b1, 0x2091, 0x8001, + 0x007c, 0x77c8, 0x77ca, 0x77c4, 0x77c6, 0xa7bc, 0xff00, 0x2091, + 0x8000, 0x2061, 0x5040, 0x606f, 0x0002, 0x6073, 0x0000, 0x6782, + 0x6093, 0x000f, 0x7817, 0x0017, 0x1078, 0x21b1, 0x2091, 0x8001, + 0x2041, 0x0021, 0x2049, 0x0004, 0x2051, 0x0010, 0x2091, 0x8000, + 0x1078, 0x1963, 0x70c8, 0x6836, 0x8738, 0xa784, 0x001f, 0x00c0, + 0x15e8, 0x2091, 0x8001, 0x007c, 0x78cc, 0xa084, 0x0003, 0x00c0, + 0x1618, 0x2039, 0x0000, 0x2041, 0x0021, 0x2049, 0x0004, 0x2051, + 0x0008, 0x1078, 0x1956, 0x2091, 0x8000, 0x6808, 0xa80d, 0x690a, + 0x2091, 0x8001, 0x8738, 0xa784, 0x001f, 0x00c0, 0x1601, 0xa7bc, + 0xff00, 0x873f, 0x8738, 0x873f, 0xa784, 0x0f00, 0x00c0, 0x1601, + 0x2091, 0x8000, 0x2069, 0x0100, 0x6830, 0xa084, 0x0040, 0x0040, + 0x1641, 0x684b, 0x0004, 0x20a9, 0x0014, 0x6848, 0xa084, 0x0004, + 0x0040, 0x162e, 0x0070, 0x162e, 0x0078, 0x1625, 0x684b, 0x0009, + 0x20a9, 0x0014, 0x6848, 0xa084, 0x0001, 0x0040, 0x163b, 0x0070, + 0x163b, 0x0078, 0x1632, 0x20a9, 0x00fa, 0x0070, 0x1641, 0x0078, + 0x163d, 0x2079, 0x5000, 0x7817, 0x0018, 0x2061, 0x5040, 0x606f, + 0x0001, 0x6073, 0x0000, 0x6093, 0x000f, 0x78cc, 0xa085, 0x0002, + 0x78ce, 0x6808, 0xa084, 0xfffd, 0x680a, 0x681b, 0x0048, 0x2091, + 0x8001, 0x007c, 0x78cc, 0xa084, 0xfffd, 0x78ce, 0xa084, 0x0001, + 0x00c0, 0x1664, 0x1078, 0x1a0e, 0x71c4, 0x71c6, 0x794a, 0x007c, + 0x1078, 0x1b36, 0x00c0, 0x129c, 0x75d8, 0x74dc, 0x75da, 0x74de, + 0x0078, 0x1675, 0x2029, 0x0000, 0x2520, 0x71c4, 0x73c8, 0x72cc, + 0x71c6, 0x73ca, 0x72ce, 0x2079, 0x5000, 0x2091, 0x8000, 0x1078, + 0x1911, 0x2091, 0x8001, 0x0040, 0x172c, 0x20a9, 0x0005, 0x20a1, + 0x5018, 0x2091, 0x8000, 0x41a1, 0x2091, 0x8001, 0x2009, 0x0020, + 0x1078, 0x190c, 0x0040, 0x1698, 0x1078, 0x192b, 0x0078, 0x172c, + 0x6004, 0xa084, 0xff00, 0x8007, 0x8009, 0x0040, 0x16fb, 0x0c7e, + 0x2c68, 0x2091, 0x8000, 0x1078, 0x1911, 0x2091, 0x8001, 0x0040, + 0x16cc, 0x2c00, 0x689e, 0x8109, 0x00c0, 0x16a0, 0x609f, 0x0000, + 0x0c7f, 0x0c7e, 0x7218, 0x731c, 0x7420, 0x7524, 0x2c68, 0x689c, + 0xa065, 0x0040, 0x16fa, 0x2009, 0x0020, 0x1078, 0x190c, 0x00c0, + 0x16e3, 0x6004, 0xa084, 0x00ff, 0xa086, 0x0002, 0x00c0, 0x16cc, + 0x2d00, 0x6002, 0x0078, 0x16b2, 0x0c7f, 0x0c7e, 0x609c, 0x2060, + 0x1078, 0x1996, 0x0c7f, 0x609f, 0x0000, 0x1078, 0x1730, 0x2009, + 0x000c, 0x6008, 0xa085, 0x0200, 0x600a, 0x1078, 0x1907, 0x1078, + 0x192b, 0x0078, 0x172c, 0x0c7f, 0x0c7e, 0x609c, 0x2060, 0x1078, + 0x1996, 0x0c7f, 0x609f, 0x0000, 0x1078, 0x1730, 0x2009, 0x000c, + 0x6007, 0x0103, 0x601b, 0x0003, 0x1078, 0x1907, 0x1078, 0x192b, + 0x0078, 0x172c, 0x0c7f, 0x74c4, 0x73c8, 0x72cc, 0x6014, 0x2091, + 0x8000, 0x7817, 0x0012, 0x0e7e, 0x2071, 0x5040, 0x706f, 0x0005, + 0x7073, 0x0000, 0x7376, 0x727a, 0x747e, 0x7082, 0x7087, 0x0000, + 0x2c00, 0x708a, 0x708f, 0x0000, 0xa02e, 0x2530, 0x611c, 0x61a2, + 0xa184, 0x0060, 0x0040, 0x171e, 0x1078, 0x467f, 0x0e7f, 0x6596, + 0x65a6, 0x669a, 0x66aa, 0x60af, 0x0000, 0x60b3, 0x0000, 0x1078, + 0x21b1, 0x2091, 0x8001, 0x007c, 0x70c3, 0x4005, 0x0078, 0x1287, + 0x20a9, 0x0005, 0x2099, 0x5018, 0x2091, 0x8000, 0x530a, 0x2091, + 0x8001, 0x2100, 0xa210, 0xa399, 0x0000, 0xa4a1, 0x0000, 0xa5a9, + 0x0000, 0x007c, 0x71c4, 0x70c7, 0x0000, 0x7906, 0x0078, 0x1284, + 0x71c4, 0x71c6, 0x2168, 0x0078, 0x174f, 0x2069, 0x1000, 0x690c, + 0xa016, 0x2d04, 0xa210, 0x8d68, 0x8109, 0x00c0, 0x1751, 0xa285, + 0x0000, 0x00c0, 0x175f, 0x70c3, 0x4000, 0x0078, 0x1761, 0x70c3, + 0x4003, 0x70ca, 0x0078, 0x1287, 0x2011, 0x5067, 0x220c, 0x70c4, + 0x8003, 0x0048, 0x1771, 0x1078, 0x3b49, 0xa184, 0x7fff, 0x0078, + 0x1775, 0x1078, 0x3b3c, 0xa185, 0x8000, 0x2012, 0x0078, 0x1283, + 0x71c4, 0x1078, 0x3b33, 0x6100, 0x2001, 0x5067, 0x2004, 0xa084, + 0x8000, 0xa10d, 0x6204, 0x6308, 0x0078, 0x1281, 0x79e4, 0x0078, + 0x1283, 0x71c4, 0x71c6, 0x2198, 0x20a1, 0x0042, 0x20a9, 0x0004, + 0x53a3, 0x21a0, 0x2099, 0x0042, 0x20a9, 0x0004, 0x53a3, 0x0078, + 0x1284, 0x70c4, 0x2068, 0x2079, 0x5000, 0x2091, 0x8000, 0x1078, + 0x1911, 0x2091, 0x8001, 0x0040, 0x1825, 0x6007, 0x0001, 0x600b, + 0x0000, 0x602b, 0x0000, 0x601b, 0x0006, 0x6a10, 0xa28c, 0x000f, + 0xa284, 0x00f0, 0x8003, 0x8003, 0x8003, 0x8003, 0xa105, 0x6016, + 0xa284, 0x0800, 0x0040, 0x17c0, 0x601b, 0x000a, 0x0078, 0x17c6, + 0xa284, 0x1000, 0x0040, 0x17c6, 0x601b, 0x000c, 0xa284, 0x0300, + 0x0040, 0x17cf, 0x602b, 0x0001, 0x8004, 0x8004, 0x8004, 0xa085, + 0x0001, 0x601e, 0x6023, 0x0000, 0x6027, 0x0000, 0xa284, 0x0400, + 0x0040, 0x17dc, 0x602b, 0x0000, 0x20a9, 0x0006, 0xac80, 0x000b, + 0x20a0, 0xad80, 0x0005, 0x2098, 0x53a3, 0xa284, 0x0300, 0x00c0, + 0x17f1, 0x6046, 0x604a, 0x604e, 0x6052, 0x6096, 0x609a, 0x0078, + 0x17fb, 0x6800, 0x6046, 0x6804, 0x604a, 0x6e08, 0x664e, 0x6d0c, + 0x6552, 0x6596, 0x669a, 0x6014, 0x2091, 0x8000, 0x7817, 0x0042, + 0x2c08, 0x2061, 0x5040, 0x606f, 0x0005, 0x6073, 0x0000, 0x6077, + 0x0000, 0x607b, 0x0000, 0x607f, 0x0000, 0x6082, 0x618a, 0xa284, + 0x0400, 0x608e, 0x2091, 0x8001, 0x0e7e, 0x2071, 0x0020, 0x7007, + 0x000a, 0x7007, 0x0002, 0x7003, 0x0000, 0x0e7f, 0x2091, 0x8000, + 0x1078, 0x21b1, 0x2091, 0x8001, 0x007c, 0x70c3, 0x4005, 0x0078, + 0x1287, 0x0c7e, 0x0d7e, 0x0e7e, 0x0f7e, 0x2091, 0x8000, 0x2071, + 0x5040, 0x2079, 0x0100, 0x2061, 0x0010, 0x70a0, 0xa06d, 0x0040, + 0x18aa, 0x6a04, 0xa294, 0x00ff, 0xa286, 0x0007, 0x0040, 0x1844, + 0xa286, 0x000f, 0x00c0, 0x18aa, 0x691c, 0xa184, 0x0080, 0x00c0, + 0x18aa, 0x6824, 0xa18c, 0xff00, 0xa085, 0x0019, 0x6826, 0x71b0, + 0x81ff, 0x0040, 0x1865, 0x0d7e, 0x2069, 0x0020, 0x6908, 0x6808, + 0xa106, 0x00c0, 0x1856, 0x690c, 0x680c, 0xa106, 0x00c0, 0x185b, + 0xa184, 0x00ff, 0x00c0, 0x185b, 0x0d7f, 0x78b8, 0xa084, 0x801f, + 0x00c0, 0x1865, 0x7848, 0xa085, 0x000c, 0x784a, 0x71b0, 0x81ff, + 0x0040, 0x1888, 0x70b3, 0x0000, 0x0d7e, 0x2069, 0x0020, 0x6807, + 0x0008, 0x6804, 0xa084, 0x0008, 0x00c0, 0x1879, 0x6807, 0x0008, + 0x6804, 0xa084, 0x0008, 0x00c0, 0x1880, 0x6807, 0x0002, 0x0d7f, + 0x61c4, 0x62c8, 0x63cc, 0x61c6, 0x62ca, 0x63ce, 0x0e7e, 0x2071, + 0x5000, 0x7266, 0x736a, 0xae80, 0x0019, 0x0e7f, 0x1078, 0x4598, + 0x78a3, 0x0000, 0x7858, 0xa084, 0xedff, 0x785a, 0x70b4, 0xa080, + 0x00da, 0x781a, 0x0f7f, 0x0e7f, 0x0d7f, 0x0c7f, 0x2091, 0x8001, + 0x0078, 0x1284, 0x0f7f, 0x0e7f, 0x0d7f, 0x0c7f, 0x2091, 0x8001, + 0x2001, 0x4005, 0x0078, 0x1286, 0x7980, 0x71c6, 0x71c4, 0xa182, + 0x0003, 0x00c8, 0x127c, 0x7982, 0x0078, 0x1284, 0x7980, 0x71c6, + 0x0078, 0x1284, 0x7974, 0x71c6, 0x71c4, 0x7976, 0x7978, 0x71ca, + 0x71c8, 0x797a, 0x797c, 0x71ce, 0x71cc, 0x797e, 0x0078, 0x1284, + 0x7974, 0x71c6, 0x7978, 0x71ca, 0x797c, 0x71ce, 0x0078, 0x1284, + 0x7900, 0x71c6, 0x71c4, 0x7902, 0x2001, 0x04fd, 0x2004, 0xa082, + 0x0005, 0x0048, 0x18e7, 0x0038, 0x18e9, 0x0078, 0x18f3, 0x00a8, + 0x18f3, 0xa18c, 0x0001, 0x00c0, 0x18f1, 0x20b9, 0x2222, 0x0078, + 0x18f3, 0x20b9, 0x1212, 0x0078, 0x1284, 0x7900, 0x71c6, 0x0078, + 0x1284, 0x2009, 0x5074, 0x2104, 0x70c6, 0x70c4, 0x200a, 0x0078, + 0x1284, 0x2009, 0x5074, 0x2104, 0x70c6, 0x0078, 0x1284, 0xac80, + 0x0001, 0x1078, 0x1af2, 0x007c, 0xac80, 0x0001, 0x1078, 0x1a92, + 0x007c, 0x7850, 0xa065, 0x0040, 0x1919, 0x2c04, 0x7852, 0x2063, + 0x0000, 0x007c, 0x0f7e, 0x2079, 0x5000, 0x7850, 0xa06d, 0x0040, + 0x1929, 0x2d04, 0x7852, 0x6803, 0x0000, 0x6807, 0x0000, 0x680b, + 0x0000, 0x0f7f, 0x007c, 0x2091, 0x8000, 0x0f7e, 0x2079, 0x5000, + 0x7850, 0x2062, 0x2c00, 0xa005, 0x00c0, 0x1938, 0x1078, 0x23ca, + 0x7852, 0x0f7f, 0x2091, 0x8001, 0x007c, 0x0f7e, 0x2079, 0x5000, + 0x7850, 0x206a, 0x2d00, 0x7852, 0x0f7f, 0x007c, 0x2011, 0x7700, + 0x7a52, 0x7bec, 0x8319, 0x0040, 0x1953, 0xa280, 0x0031, 0x2012, + 0x2010, 0x0078, 0x194a, 0x2013, 0x0000, 0x007c, 0xa784, 0x0f00, + 0x800b, 0xa784, 0x001f, 0x8003, 0x8003, 0x8003, 0x8003, 0xa105, + 0xa0e8, 0x5300, 0x007c, 0x1078, 0x1956, 0x2900, 0x682a, 0x2a00, + 0x682e, 0x6808, 0xa084, 0xffef, 0xa80d, 0x690a, 0x2009, 0x5052, + 0x210c, 0x6804, 0xa005, 0x0040, 0x1995, 0xa116, 0x00c0, 0x1980, + 0x2060, 0x6000, 0x6806, 0x017e, 0x200b, 0x0000, 0x0078, 0x1983, + 0x2009, 0x0000, 0x017e, 0x6804, 0xa065, 0x0040, 0x1992, 0x6000, + 0x6806, 0x1078, 0x19a3, 0x1078, 0x1c42, 0x6810, 0x8001, 0x6812, + 0x00c0, 0x1983, 0x017f, 0x6902, 0x6906, 0x007c, 0xa065, 0x0040, + 0x19a2, 0x609c, 0x609f, 0x0000, 0x2008, 0x1078, 0x192b, 0x2100, + 0x0078, 0x1996, 0x007c, 0x6007, 0x0103, 0x608f, 0x0000, 0x20a9, + 0x001c, 0xac80, 0x0005, 0x20a0, 0x2001, 0x0000, 0x40a4, 0x6828, + 0x601a, 0x682c, 0x6022, 0x007c, 0x0e7e, 0x2071, 0x5040, 0x704c, + 0xa08c, 0x0200, 0x00c0, 0x19c2, 0xa088, 0x5080, 0x2d0a, 0x8000, + 0x704e, 0xa006, 0x0e7f, 0x007c, 0x1078, 0x1956, 0x2091, 0x8000, + 0x6804, 0x781e, 0xa065, 0x0040, 0x1a0d, 0x0078, 0x19d5, 0x2c00, + 0x781e, 0x6000, 0xa065, 0x0040, 0x1a0d, 0x600c, 0xa306, 0x00c0, + 0x19cf, 0x6010, 0xa206, 0x00c0, 0x19cf, 0x2c28, 0x2001, 0x5052, + 0x2004, 0xac06, 0x00c0, 0x19e6, 0x0078, 0x1a0b, 0x6804, 0xac06, + 0x00c0, 0x19f3, 0x6000, 0xa065, 0x6806, 0x00c0, 0x19fd, 0x6803, + 0x0000, 0x0078, 0x19fd, 0x6400, 0x781c, 0x2060, 0x6402, 0xa486, + 0x0000, 0x00c0, 0x19fd, 0x2c00, 0x6802, 0x2560, 0x1078, 0x19a3, + 0x601b, 0x0005, 0x6023, 0x0020, 0x1078, 0x1c42, 0x6810, 0x8001, + 0x1050, 0x23ca, 0x6812, 0xa085, 0xffff, 0x007c, 0x2039, 0x0000, + 0x2041, 0x0021, 0x2049, 0x0004, 0x2051, 0x0008, 0x2091, 0x8000, + 0x1078, 0x1963, 0x8738, 0xa784, 0x001f, 0x00c0, 0x1a18, 0xa7bc, + 0xff00, 0x873f, 0x8738, 0x873f, 0xa784, 0x0f00, 0x00c0, 0x1a18, + 0x2091, 0x8001, 0x007c, 0x2061, 0x0000, 0x6018, 0xa084, 0x0001, + 0x00c0, 0x1a3c, 0x2091, 0x8000, 0x78e0, 0x78e3, 0x0000, 0x2091, + 0x8001, 0xa005, 0x00c0, 0x1a3d, 0x007c, 0xa08c, 0xfff0, 0x0040, + 0x1a43, 0x1078, 0x23ca, 0x0079, 0x1a45, 0x1a55, 0x1a58, 0x1a5e, + 0x1a62, 0x1a56, 0x1a66, 0x1a6c, 0x1a56, 0x1a56, 0x1c0c, 0x1c30, + 0x1c34, 0x1a56, 0x1a56, 0x1a56, 0x1a56, 0x007c, 0x1078, 0x23ca, + 0x1078, 0x1a0e, 0x2001, 0x8001, 0x0078, 0x1c3a, 0x2001, 0x8003, + 0x0078, 0x1c3a, 0x2001, 0x8004, 0x0078, 0x1c3a, 0x1078, 0x1a0e, + 0x2001, 0x8006, 0x0078, 0x1c3a, 0x2001, 0x8007, 0x0078, 0x1c3a, + 0x2030, 0x2138, 0xa782, 0x0021, 0x0048, 0x1a78, 0x2009, 0x0020, + 0x2600, 0x1078, 0x1a92, 0x00c0, 0x1a91, 0xa7ba, 0x0020, 0x0048, + 0x1a90, 0x0040, 0x1a90, 0x2708, 0xa6b0, 0x0020, 0xa290, 0x0040, + 0xa399, 0x0000, 0xa4a1, 0x0000, 0xa5a9, 0x0000, 0x0078, 0x1a72, + 0xa006, 0x007c, 0x81ff, 0x0040, 0x1acd, 0x2099, 0x0030, 0x20a0, + 0x700c, 0xa084, 0x00ff, 0x0040, 0x1aa4, 0x7007, 0x0004, 0x7004, + 0xa084, 0x0004, 0x00c0, 0x1a9f, 0x21a8, 0x7017, 0x0000, 0x810b, + 0x7112, 0x721a, 0x731e, 0x7422, 0x7526, 0x780c, 0xa085, 0x0001, + 0x7002, 0x7007, 0x0001, 0x2001, 0x04fd, 0x2004, 0xa082, 0x0005, + 0x00c8, 0x1ac1, 0x2009, 0x0022, 0x2104, 0xa084, 0x4000, 0x00c0, + 0x1ab3, 0x7008, 0x800b, 0x00c8, 0x1ab3, 0x7007, 0x0002, 0xa08c, + 0x01e0, 0x00c0, 0x1acd, 0x53a5, 0xa006, 0x7003, 0x0000, 0x007c, + 0x2030, 0x2138, 0xa782, 0x0021, 0x0048, 0x1ad8, 0x2009, 0x0020, + 0x2600, 0x1078, 0x1af2, 0x00c0, 0x1af1, 0xa7ba, 0x0020, 0x0048, + 0x1af0, 0x0040, 0x1af0, 0x2708, 0xa6b0, 0x0020, 0xa290, 0x0040, + 0xa399, 0x0000, 0xa4a1, 0x0000, 0xa5a9, 0x0000, 0x0078, 0x1ad2, + 0xa006, 0x007c, 0x81ff, 0x0040, 0x1b33, 0x2098, 0x20a1, 0x0030, + 0x700c, 0xa084, 0x00ff, 0x0040, 0x1b04, 0x7007, 0x0004, 0x7004, + 0xa084, 0x0004, 0x00c0, 0x1aff, 0x21a8, 0x7017, 0x0000, 0x810b, + 0x7112, 0x721a, 0x731e, 0x7422, 0x7526, 0x780c, 0xa085, 0x0000, + 0x7002, 0x53a6, 0x7007, 0x0001, 0x2001, 0x04fd, 0x2004, 0xa082, + 0x0005, 0x00c8, 0x1b22, 0x2009, 0x0022, 0x2104, 0xa084, 0x4000, + 0x00c0, 0x1b14, 0x7010, 0xa084, 0xf000, 0x0040, 0x1b2b, 0x7007, + 0x0008, 0x0078, 0x1b2f, 0x7108, 0x8103, 0x00c8, 0x1b14, 0x7007, + 0x0002, 0xa184, 0x01e0, 0x7003, 0x0000, 0x007c, 0x2001, 0x04fd, + 0x2004, 0xa082, 0x0004, 0x00c8, 0x1b3f, 0x0078, 0x1b42, 0xa006, + 0x0078, 0x1b44, 0xa085, 0x0001, 0x007c, 0x0e7e, 0x2071, 0x5000, + 0x2d08, 0x7058, 0x6802, 0xa005, 0x00c0, 0x1b4f, 0x715e, 0x715a, + 0x0e7f, 0x007c, 0x2c08, 0x7858, 0x6002, 0xa005, 0x00c0, 0x1b59, + 0x795e, 0x795a, 0x007c, 0x2091, 0x8000, 0x6003, 0x0000, 0x2c08, + 0x785c, 0xa065, 0x00c0, 0x1b67, 0x795a, 0x0078, 0x1b68, 0x6102, + 0x795e, 0x2091, 0x8001, 0x1078, 0x21ce, 0x007c, 0x0e7e, 0x2071, + 0x5000, 0x7058, 0xa06d, 0x0040, 0x1b7c, 0x6800, 0x705a, 0xa005, + 0x00c0, 0x1b7b, 0x705e, 0x8dff, 0x0e7f, 0x007c, 0x0d7e, 0x0c7e, + 0x0f7e, 0x2079, 0x5000, 0xaf80, 0x0016, 0x2060, 0x6000, 0xa005, + 0x0040, 0x1bac, 0x2068, 0x6814, 0xa306, 0x00c0, 0x1b95, 0x6828, + 0xa084, 0x00ff, 0xa406, 0x0040, 0x1b98, 0x2d60, 0x0078, 0x1b86, + 0x6800, 0xa005, 0x6002, 0x00c0, 0x1ba4, 0xaf80, 0x0016, 0xac06, + 0x0040, 0x1ba3, 0x2c00, 0x785e, 0x0d7e, 0x689c, 0xa005, 0x0040, + 0x1bab, 0x1078, 0x1996, 0x007f, 0x0f7f, 0x0c7f, 0x0d7f, 0xa005, + 0x007c, 0x0d7e, 0x0c7e, 0x0f7e, 0x2079, 0x5000, 0xaf80, 0x0016, + 0x2060, 0x6000, 0xa005, 0x0040, 0x1bdb, 0x2068, 0x6814, 0xa084, + 0x00ff, 0xa306, 0x0040, 0x1bc7, 0x2d60, 0x0078, 0x1bb9, 0x6800, + 0xa005, 0x6002, 0x00c0, 0x1bd3, 0xaf80, 0x0016, 0xac06, 0x0040, + 0x1bd2, 0x2c00, 0x785e, 0x0d7e, 0x689c, 0xa005, 0x0040, 0x1bda, + 0x1078, 0x1996, 0x007f, 0x0f7f, 0x0c7f, 0x0d7f, 0xa005, 0x007c, + 0x0d7e, 0x0c7e, 0x0f7e, 0x2079, 0x5000, 0xaf80, 0x0016, 0x2060, + 0x6000, 0xa06d, 0x0040, 0x1c07, 0x6814, 0xa306, 0x0040, 0x1bf3, + 0x2d60, 0x0078, 0x1be8, 0x6800, 0xa005, 0x6002, 0x00c0, 0x1bff, + 0xaf80, 0x0016, 0xac06, 0x0040, 0x1bfe, 0x2c00, 0x785e, 0x0d7e, + 0x689c, 0xa005, 0x0040, 0x1c06, 0x1078, 0x1996, 0x007f, 0x0f7f, + 0x0c7f, 0x0d7f, 0xa005, 0x007c, 0x2091, 0x8000, 0x2069, 0x5040, + 0x6800, 0xa086, 0x0000, 0x0040, 0x1c1a, 0x2091, 0x8001, 0x78e3, + 0x0009, 0x007c, 0x6880, 0xa0bc, 0xff00, 0x2041, 0x0021, 0x2049, + 0x0004, 0x2051, 0x0010, 0x1078, 0x1963, 0x8738, 0xa784, 0x001f, + 0x00c0, 0x1c23, 0x2091, 0x8001, 0x2001, 0x800a, 0x0078, 0x1c3a, + 0x2001, 0x800c, 0x0078, 0x1c3a, 0x1078, 0x1a0e, 0x2001, 0x800d, + 0x0078, 0x1c3a, 0x70c2, 0x2061, 0x0000, 0x601b, 0x0001, 0x2091, + 0x4080, 0x007c, 0x6004, 0x2c08, 0x2063, 0x0000, 0x7884, 0x8000, + 0x7886, 0x7888, 0xa005, 0x798a, 0x0040, 0x1c51, 0x2c02, 0x0078, + 0x1c52, 0x798e, 0x007c, 0x6807, 0x0103, 0x0c7e, 0x2061, 0x5000, + 0x2d08, 0x206b, 0x0000, 0x6084, 0x8000, 0x6086, 0x6088, 0xa005, + 0x618a, 0x0040, 0x1c66, 0x2d02, 0x0078, 0x1c67, 0x618e, 0x0c7f, + 0x007c, 0x1078, 0x1c7a, 0x0040, 0x1c79, 0x0c7e, 0x609c, 0xa065, + 0x0040, 0x1c74, 0x1078, 0x1996, 0x0c7f, 0x609f, 0x0000, 0x1078, + 0x192b, 0x007c, 0x788c, 0xa065, 0x0040, 0x1c8c, 0x2091, 0x8000, + 0x7884, 0x8001, 0x7886, 0x2c04, 0x788e, 0xa005, 0x00c0, 0x1c8a, + 0x788a, 0x8000, 0x2091, 0x8001, 0x007c, 0x20a9, 0x0010, 0xa006, + 0x8004, 0x8086, 0x818e, 0x00c8, 0x1c96, 0xa200, 0x0070, 0x1c9a, + 0x0078, 0x1c91, 0x8086, 0x818e, 0x007c, 0x157e, 0x20a9, 0x0010, + 0xa005, 0x0040, 0x1cc0, 0xa11a, 0x00c8, 0x1cc0, 0x8213, 0x818d, + 0x0048, 0x1cb1, 0xa11a, 0x00c8, 0x1cb2, 0x0070, 0x1cb8, 0x0078, + 0x1ca6, 0xa11a, 0x2308, 0x8210, 0x0070, 0x1cb8, 0x0078, 0x1ca6, + 0x007e, 0x3200, 0xa084, 0xf7ff, 0x2080, 0x007f, 0x157f, 0x007c, + 0x007e, 0x3200, 0xa085, 0x0800, 0x0078, 0x1cbc, 0x7994, 0x70d0, + 0xa106, 0x0040, 0x1d34, 0x2091, 0x8000, 0x2071, 0x0020, 0x7004, + 0xa005, 0x00c0, 0x1d34, 0x7008, 0x7208, 0xa206, 0x00c0, 0x1d34, + 0xa286, 0x0008, 0x00c0, 0x1d34, 0x2071, 0x0010, 0x1078, 0x1911, + 0x0040, 0x1d34, 0x7a9c, 0x7b98, 0x7ca4, 0x7da0, 0xa184, 0xff00, + 0x0040, 0x1d02, 0x2031, 0x0000, 0x810b, 0x86b5, 0x810b, 0x86b5, + 0x810b, 0x86b5, 0x810b, 0x86b5, 0x810b, 0x86b5, 0x810b, 0x86b5, + 0x2100, 0xa210, 0x2600, 0xa319, 0xa4a1, 0x0000, 0xa5a9, 0x0000, + 0x0078, 0x1d0c, 0x8107, 0x8004, 0x8004, 0xa210, 0xa399, 0x0000, + 0xa4a1, 0x0000, 0xa5a9, 0x0000, 0x2009, 0x0020, 0x1078, 0x190c, + 0x2091, 0x8001, 0x0040, 0x1d2b, 0x1078, 0x192b, 0x78a8, 0x8000, + 0x78aa, 0xa086, 0x0002, 0x00c0, 0x1d34, 0x2091, 0x8000, 0x78e3, + 0x0002, 0x78ab, 0x0000, 0x78cc, 0xa085, 0x0003, 0x78ce, 0x2091, + 0x8001, 0x0078, 0x1d34, 0x78ab, 0x0000, 0x1078, 0x208b, 0x6004, + 0xa084, 0x000f, 0x0079, 0x1d39, 0x2071, 0x0010, 0x2091, 0x8001, + 0x007c, 0x1d49, 0x1d6b, 0x1d91, 0x1d49, 0x1dae, 0x1d58, 0x1f0d, + 0x1f28, 0x1d49, 0x1d65, 0x1d8b, 0x1df6, 0x1e63, 0x1eb3, 0x1ec5, + 0x1f24, 0x2039, 0x0400, 0x78dc, 0xa705, 0x78de, 0x6008, 0xa705, + 0x600a, 0x1078, 0x1fa6, 0x609c, 0x78da, 0x1078, 0x2073, 0x007c, + 0x78dc, 0xa084, 0x0100, 0x0040, 0x1d5f, 0x0078, 0x1d49, 0x601c, + 0xa085, 0x0080, 0x601e, 0x0078, 0x1d72, 0x1078, 0x1b36, 0x00c0, + 0x1d49, 0x1078, 0x20a5, 0x78dc, 0xa084, 0x0100, 0x0040, 0x1d72, + 0x0078, 0x1d49, 0x78df, 0x0000, 0x6004, 0x8007, 0xa084, 0x00ff, + 0x78d2, 0x8001, 0x609f, 0x0000, 0x0040, 0x1d88, 0x1078, 0x1fa6, + 0x0040, 0x1d88, 0x78dc, 0xa085, 0x0100, 0x78de, 0x0078, 0x1d8a, + 0x1078, 0x1fca, 0x007c, 0x1078, 0x1b36, 0x00c0, 0x1d49, 0x1078, + 0x20a1, 0x78dc, 0xa08c, 0x0e00, 0x00c0, 0x1d9a, 0xa084, 0x0100, + 0x00c0, 0x1d9c, 0x0078, 0x1d49, 0x1078, 0x1fa6, 0x00c0, 0x1dad, + 0x6104, 0xa18c, 0x00ff, 0xa186, 0x0007, 0x0040, 0x1f63, 0xa186, + 0x000f, 0x0040, 0x1f63, 0x1078, 0x1fca, 0x007c, 0x78dc, 0xa084, + 0x0100, 0x0040, 0x1db5, 0x0078, 0x1d49, 0x78df, 0x0000, 0x6714, + 0x2011, 0x0001, 0x20a9, 0x0001, 0x6018, 0xa084, 0x00ff, 0xa005, + 0x0040, 0x1dd8, 0x2011, 0x0001, 0xa7bc, 0xff00, 0x20a9, 0x0020, + 0xa08e, 0x0001, 0x0040, 0x1dd8, 0x2039, 0x0000, 0x2011, 0x0002, + 0x20a9, 0x0100, 0xa08e, 0x0002, 0x0040, 0x1dd8, 0x0078, 0x1df3, + 0x1078, 0x1956, 0x2091, 0x8000, 0x682b, 0x0000, 0x682f, 0x0000, + 0x6808, 0xa084, 0xffde, 0x680a, 0xade8, 0x0010, 0x2091, 0x8001, + 0x0070, 0x1dec, 0x0078, 0x1dda, 0x8211, 0x0040, 0x1df3, 0x20a9, + 0x0100, 0x0078, 0x1dda, 0x1078, 0x192b, 0x007c, 0x2001, 0x5067, + 0x2004, 0xa084, 0x8000, 0x0040, 0x1f8b, 0x6114, 0x1078, 0x20c2, + 0x6900, 0xa184, 0x0001, 0x0040, 0x1e17, 0x6028, 0xa084, 0x00ff, + 0x00c0, 0x1f83, 0x6800, 0xa084, 0x0001, 0x0040, 0x1f8b, 0x6803, + 0x0000, 0x680b, 0x0000, 0x6807, 0x0000, 0x0078, 0x1f93, 0x2011, + 0x0001, 0x6020, 0xa084, 0x4000, 0x0040, 0x1e20, 0xa295, 0x0002, + 0x6020, 0xa084, 0x0100, 0x0040, 0x1e27, 0xa295, 0x0008, 0x601c, + 0xa084, 0x0002, 0x0040, 0x1e2e, 0xa295, 0x0004, 0x602c, 0xa08c, + 0x00ff, 0xa182, 0x0002, 0x0048, 0x1f8f, 0xa182, 0x001b, 0x00c8, + 0x1f8f, 0x0040, 0x1f8f, 0x690e, 0x602c, 0x8007, 0xa08c, 0x00ff, + 0xa182, 0x0002, 0x0048, 0x1f8f, 0xa182, 0x001b, 0x00c8, 0x1f8f, + 0x0040, 0x1f8f, 0x6912, 0x6030, 0xa005, 0x00c0, 0x1e51, 0x2001, + 0x001e, 0x8000, 0x6816, 0x6028, 0xa084, 0x00ff, 0x0040, 0x1f8b, + 0x6806, 0x6028, 0x8007, 0xa084, 0x00ff, 0x0040, 0x1f8b, 0x680a, + 0x6a02, 0x0078, 0x1f93, 0x2001, 0x5067, 0x2004, 0xa084, 0x8000, + 0x0040, 0x1f8b, 0x6114, 0x1078, 0x20c2, 0x2091, 0x8000, 0x6a04, + 0x6b08, 0x6418, 0xa484, 0x0003, 0x0040, 0x1e89, 0x6128, 0xa18c, + 0x00ff, 0x8001, 0x00c0, 0x1e82, 0x2100, 0xa210, 0x0048, 0x1eaf, + 0x0078, 0x1e89, 0x8001, 0x00c0, 0x1eaf, 0x2100, 0xa212, 0x0048, + 0x1eaf, 0xa484, 0x000c, 0x0040, 0x1ea3, 0x6128, 0x810f, 0xa18c, + 0x00ff, 0xa082, 0x0004, 0x00c0, 0x1e9b, 0x2100, 0xa318, 0x0048, + 0x1eaf, 0x0078, 0x1ea3, 0xa082, 0x0004, 0x00c0, 0x1eaf, 0x2100, + 0xa31a, 0x0048, 0x1eaf, 0x6030, 0xa005, 0x0040, 0x1ea9, 0x8000, + 0x6816, 0x6a06, 0x6b0a, 0x2091, 0x8001, 0x0078, 0x1f93, 0x2091, + 0x8001, 0x0078, 0x1f8f, 0x6114, 0x1078, 0x20c2, 0x2091, 0x8000, + 0x6b08, 0x8318, 0x0048, 0x1ec1, 0x6b0a, 0x2091, 0x8001, 0x0078, + 0x1fa2, 0x2091, 0x8001, 0x0078, 0x1f8f, 0x6024, 0x8007, 0xa084, + 0x00ff, 0x0040, 0x1ee3, 0xa086, 0x0080, 0x00c0, 0x1f0b, 0x20a9, + 0x0008, 0x2069, 0x7410, 0x2091, 0x8000, 0x6800, 0xa084, 0xfcff, + 0x6802, 0xade8, 0x0008, 0x0070, 0x1edf, 0x0078, 0x1ed5, 0x2091, + 0x8001, 0x0078, 0x1f93, 0x6028, 0xa015, 0x0040, 0x1f0b, 0x6114, + 0x1078, 0x20c2, 0x0d7e, 0xade8, 0x0007, 0x2091, 0x8000, 0x6800, + 0xa00d, 0x0040, 0x1f08, 0xa206, 0x0040, 0x1ef9, 0x2168, 0x0078, + 0x1eef, 0x0c7e, 0x2160, 0x6000, 0x6802, 0x1078, 0x192b, 0x0c7f, + 0x0d7f, 0x6808, 0x8000, 0x680a, 0x2091, 0x8001, 0x0078, 0x1fa2, + 0x2091, 0x8001, 0x0d7f, 0x0078, 0x1f8b, 0x6114, 0x1078, 0x20c2, + 0x6800, 0xa084, 0x0001, 0x0040, 0x1f7b, 0x2091, 0x8000, 0x6a04, + 0x8210, 0x0048, 0x1f20, 0x6a06, 0x2091, 0x8001, 0x0078, 0x1fa2, + 0x2091, 0x8001, 0x0078, 0x1f8f, 0x1078, 0x1b36, 0x00c0, 0x1d49, + 0x6114, 0x1078, 0x20c2, 0x60be, 0x6900, 0xa184, 0x0008, 0x0040, + 0x1f35, 0x6020, 0xa085, 0x0100, 0x6022, 0xa184, 0x0001, 0x0040, + 0x1f8b, 0xa184, 0x0100, 0x00c0, 0x1f77, 0xa184, 0x0200, 0x00c0, + 0x1f73, 0x681c, 0xa005, 0x00c0, 0x1f7f, 0x6004, 0xa084, 0x00ff, + 0xa086, 0x000f, 0x00c0, 0x1f4e, 0x1078, 0x20a5, 0x78df, 0x0000, + 0x6004, 0x8007, 0xa084, 0x00ff, 0x78d2, 0x8001, 0x609f, 0x0000, + 0x0040, 0x1f63, 0x1078, 0x1fa6, 0x0040, 0x1f63, 0x78dc, 0xa085, + 0x0100, 0x78de, 0x007c, 0x78d7, 0x0000, 0x78db, 0x0000, 0x6024, + 0xa084, 0xff00, 0x6026, 0x1078, 0x39aa, 0x0040, 0x1cc6, 0x1078, + 0x1b5b, 0x0078, 0x1cc6, 0x2009, 0x0017, 0x0078, 0x1f95, 0x2009, + 0x000e, 0x0078, 0x1f95, 0x2009, 0x0007, 0x0078, 0x1f95, 0x2009, + 0x0035, 0x0078, 0x1f95, 0x2009, 0x003e, 0x0078, 0x1f95, 0x2009, + 0x0004, 0x0078, 0x1f95, 0x2009, 0x0006, 0x0078, 0x1f95, 0x2009, + 0x0016, 0x0078, 0x1f95, 0x2009, 0x0001, 0x6024, 0xa084, 0xff00, + 0xa105, 0x6026, 0x2091, 0x8000, 0x1078, 0x1c42, 0x2091, 0x8001, + 0x0078, 0x1cc6, 0x1078, 0x192b, 0x0078, 0x1cc6, 0x78d4, 0xa06d, + 0x00c0, 0x1fb1, 0x2c00, 0x78d6, 0x78da, 0x609f, 0x0000, 0x0078, + 0x1fbd, 0x2c00, 0x689e, 0x609f, 0x0000, 0x78d6, 0x2d00, 0x6002, + 0x78d8, 0xad06, 0x00c0, 0x1fbd, 0x6002, 0x78d0, 0x8001, 0x78d2, + 0x00c0, 0x1fc9, 0x78dc, 0xa084, 0xfeff, 0x78de, 0x78d8, 0x2060, + 0xa006, 0x007c, 0xa02e, 0x2530, 0x611c, 0x61a2, 0xa184, 0xe1ff, + 0x601e, 0xa184, 0x0060, 0x0040, 0x1fd9, 0x0e7e, 0x1078, 0x467f, + 0x0e7f, 0x6596, 0x65a6, 0x669a, 0x66aa, 0x60af, 0x0000, 0x60b3, + 0x0000, 0x6714, 0x1078, 0x1956, 0x2091, 0x8000, 0x60a0, 0xa084, + 0x8000, 0x00c0, 0x2000, 0x6808, 0xa084, 0x0001, 0x0040, 0x2000, + 0x2091, 0x8001, 0x1078, 0x19a3, 0x2091, 0x8000, 0x1078, 0x1c42, + 0x2091, 0x8001, 0x78d7, 0x0000, 0x78db, 0x0000, 0x0078, 0x2072, + 0x6024, 0xa096, 0x0001, 0x00c0, 0x2007, 0x8000, 0x6026, 0x6a10, + 0x6814, 0x2091, 0x8001, 0xa202, 0x0048, 0x2016, 0x0040, 0x2016, + 0x2039, 0x0200, 0x1078, 0x2073, 0x0078, 0x2072, 0x2c08, 0x2091, + 0x8000, 0x60a0, 0xa084, 0x8000, 0x0040, 0x2043, 0x6800, 0xa065, + 0x0040, 0x2048, 0x6a04, 0x0e7e, 0x2071, 0x5040, 0x7000, 0xa084, + 0x0001, 0x0040, 0x203d, 0x7048, 0xa206, 0x00c0, 0x203d, 0x6b04, + 0x231c, 0x2160, 0x6302, 0x2300, 0xa005, 0x00c0, 0x2038, 0x6902, + 0x2260, 0x6102, 0x0e7f, 0x0078, 0x204f, 0x2160, 0x6202, 0x6906, + 0x0e7f, 0x0078, 0x204f, 0x6800, 0xa065, 0x0040, 0x2048, 0x6102, + 0x6902, 0x00c0, 0x204c, 0x6906, 0x2160, 0x6003, 0x0000, 0x2160, + 0x60a0, 0xa084, 0x8000, 0x0040, 0x2059, 0x6808, 0xa084, 0xfffc, + 0x680a, 0x6810, 0x8000, 0x6812, 0x2091, 0x8001, 0x6808, 0xa08c, + 0x0040, 0x0040, 0x2068, 0xa086, 0x0040, 0x680a, 0x1078, 0x19b4, + 0x2091, 0x8000, 0x1078, 0x21b1, 0x2091, 0x8001, 0x78db, 0x0000, + 0x78d7, 0x0000, 0x007c, 0x6008, 0xa705, 0x600a, 0x2091, 0x8000, + 0x1078, 0x1c42, 0x2091, 0x8001, 0x78d8, 0xa065, 0x0040, 0x2086, + 0x609c, 0x78da, 0x609f, 0x0000, 0x0078, 0x2076, 0x78d7, 0x0000, + 0x78db, 0x0000, 0x007c, 0x7990, 0x7894, 0x8000, 0xa10a, 0x00c8, + 0x2092, 0xa006, 0x7896, 0x70d2, 0x7804, 0xa005, 0x0040, 0x20a0, + 0x8001, 0x7806, 0x00c0, 0x20a0, 0x0068, 0x20a0, 0x2091, 0x4080, + 0x007c, 0x2039, 0x20b9, 0x0078, 0x20a7, 0x2039, 0x20bf, 0x2704, + 0xa005, 0x0040, 0x20b8, 0xac00, 0x2068, 0x6b08, 0x6c0c, 0x6910, + 0x6a14, 0x690a, 0x6a0e, 0x6b12, 0x6c16, 0x8738, 0x0078, 0x20a7, + 0x007c, 0x0003, 0x0009, 0x000f, 0x0015, 0x001b, 0x0000, 0x0015, + 0x001b, 0x0000, 0x0c7e, 0x1078, 0x3b33, 0x2c68, 0x0c7f, 0x007c, + 0x0010, 0x2139, 0x0068, 0x2139, 0x2029, 0x0000, 0x78cb, 0x0000, + 0x788c, 0xa065, 0x0040, 0x2132, 0x2009, 0x5074, 0x2104, 0xa084, + 0x0001, 0x0040, 0x2100, 0x6004, 0xa086, 0x0103, 0x00c0, 0x2100, + 0x6018, 0xa005, 0x00c0, 0x2100, 0x6014, 0xa005, 0x00c0, 0x2100, + 0x0d7e, 0x2069, 0x0000, 0x6818, 0xa084, 0x0001, 0x00c0, 0x20ff, + 0x600c, 0x70c6, 0x6010, 0x70ca, 0x70c3, 0x8020, 0x681b, 0x0001, + 0x2091, 0x4080, 0x0d7f, 0x1078, 0x1c69, 0x0078, 0x2137, 0x0d7f, + 0x1078, 0x213a, 0x0040, 0x2132, 0x6204, 0xa294, 0x00ff, 0xa296, + 0x0003, 0x0040, 0x2112, 0x6204, 0xa296, 0x0110, 0x00c0, 0x2120, + 0x78cb, 0x0001, 0x6204, 0xa294, 0xff00, 0x8217, 0x8211, 0x0040, + 0x2120, 0x85ff, 0x00c0, 0x2132, 0x8210, 0xa202, 0x00c8, 0x2132, + 0x057e, 0x1078, 0x2149, 0x057f, 0x0040, 0x212d, 0x78e0, 0xa086, + 0x0003, 0x0040, 0x2132, 0x0078, 0x2120, 0x8528, 0x78c8, 0xa005, + 0x0040, 0x20d0, 0x85ff, 0x0040, 0x2139, 0x2091, 0x4080, 0x78b0, + 0x70d6, 0x007c, 0x7bac, 0x79b0, 0x70d4, 0xa102, 0x00c0, 0x2143, + 0x2300, 0xa005, 0x007c, 0x0048, 0x2147, 0xa302, 0x007c, 0x8002, + 0x007c, 0x2001, 0x04fd, 0x2004, 0xa082, 0x0005, 0x00c8, 0x2163, + 0x2091, 0x8000, 0x2071, 0x0020, 0x7004, 0xa005, 0x00c0, 0x2198, + 0x7008, 0x7208, 0xa206, 0x00c0, 0x2198, 0xa286, 0x0008, 0x00c0, + 0x2198, 0x2071, 0x0010, 0x1078, 0x219d, 0x2009, 0x0020, 0x6004, + 0xa086, 0x0103, 0x00c0, 0x2172, 0x6028, 0xa005, 0x00c0, 0x2172, + 0x2009, 0x000c, 0x1078, 0x1907, 0x0040, 0x218b, 0x78c4, 0x8000, + 0x78c6, 0xa086, 0x0002, 0x00c0, 0x2198, 0x2091, 0x8000, 0x78e3, + 0x0003, 0x78c7, 0x0000, 0x78cc, 0xa085, 0x0300, 0x78ce, 0x2091, + 0x8001, 0x0078, 0x2198, 0x78c7, 0x0000, 0x1078, 0x1c69, 0x79ac, + 0x78b0, 0x8000, 0xa10a, 0x00c8, 0x2196, 0xa006, 0x78b2, 0xa006, + 0x2071, 0x0010, 0x2091, 0x8001, 0x007c, 0x8107, 0x8004, 0x8004, + 0x7ab8, 0x7bb4, 0x7cc0, 0x7dbc, 0xa210, 0xa399, 0x0000, 0xa4a1, + 0x0000, 0xa5a9, 0x0000, 0x007c, 0x2009, 0x505b, 0x2091, 0x8000, + 0x200a, 0x0f7e, 0x0e7e, 0x2071, 0x5040, 0x7000, 0xa086, 0x0000, + 0x00c0, 0x21cb, 0x2009, 0x5012, 0x2104, 0xa005, 0x00c0, 0x21cb, + 0x2079, 0x0100, 0x7830, 0xa084, 0x00c0, 0x00c0, 0x21cb, 0x0018, + 0x21cb, 0x781b, 0x004b, 0x0e7f, 0x0f7f, 0x007c, 0x0f7e, 0x0e7e, + 0x2071, 0x5040, 0x2091, 0x8000, 0x7000, 0xa086, 0x0000, 0x00c0, + 0x21e4, 0x2079, 0x0100, 0x7830, 0xa084, 0x00c0, 0x00c0, 0x21e4, + 0x0018, 0x21e4, 0x781b, 0x004d, 0x2091, 0x8001, 0x0e7f, 0x0f7f, + 0x007c, 0x127e, 0x2091, 0x2300, 0x2071, 0x5040, 0x2079, 0x0100, + 0x784b, 0x000f, 0x0098, 0x21f7, 0x7838, 0x0078, 0x21f0, 0x20a9, + 0x0040, 0x7800, 0xa082, 0x0004, 0x0048, 0x2200, 0x20a9, 0x0060, + 0x789b, 0x0000, 0x78af, 0x0000, 0x78af, 0x0000, 0x0070, 0x220a, + 0x0078, 0x2202, 0x7800, 0xa082, 0x0004, 0x0048, 0x2219, 0x70b7, + 0x009b, 0x2019, 0x4da4, 0x1078, 0x2255, 0x702f, 0x8001, 0x0078, + 0x2225, 0x70b7, 0x0000, 0x2019, 0x4c1c, 0x1078, 0x2255, 0x2019, + 0x4c5b, 0x1078, 0x2255, 0x702f, 0x8000, 0x7003, 0x0000, 0x1078, + 0x235e, 0x7004, 0xa084, 0x000f, 0x017e, 0x2009, 0x04fd, 0x210c, + 0xa18a, 0x0005, 0x0048, 0x223a, 0x0038, 0x2240, 0xa085, 0x6280, + 0x0078, 0x2242, 0x0028, 0x2240, 0xa085, 0x6280, 0x0078, 0x2242, + 0xa085, 0x62c0, 0x017f, 0x7806, 0x780f, 0xb204, 0x7843, 0x00d8, + 0x7853, 0x0080, 0x780b, 0x0008, 0x7047, 0x0008, 0x7053, 0x507f, + 0x704f, 0x0000, 0x127f, 0x2000, 0x007c, 0x137e, 0x147e, 0x157e, + 0x047e, 0x20a1, 0x012b, 0x2304, 0xa005, 0x789a, 0x0040, 0x2275, + 0x8318, 0x2324, 0x8318, 0x2398, 0x24a8, 0xa484, 0xff00, 0x0040, + 0x226d, 0xa482, 0x0100, 0x20a9, 0x0100, 0x2020, 0x53a6, 0xa005, + 0x00c0, 0x2264, 0x3318, 0x0078, 0x225b, 0x047f, 0x157f, 0x147f, + 0x137f, 0x007c, 0xa18c, 0x000f, 0x2011, 0x0101, 0x2204, 0xa084, + 0xfff0, 0xa105, 0x2012, 0x1078, 0x235e, 0x007c, 0x2011, 0x0101, + 0x20a9, 0x0009, 0x810b, 0x0070, 0x228f, 0x0078, 0x228a, 0xa18c, + 0x0e00, 0x2204, 0xa084, 0xf1ff, 0xa105, 0x2012, 0x007c, 0x2009, + 0x0101, 0x20a9, 0x0005, 0x8213, 0x0070, 0x22a0, 0x0078, 0x229b, + 0xa294, 0x00e0, 0x2104, 0xa084, 0xff1f, 0xa205, 0x200a, 0x007c, + 0x2011, 0x0101, 0x20a9, 0x000c, 0x810b, 0x0070, 0x22b1, 0x0078, + 0x22ac, 0xa18c, 0xf000, 0x2204, 0xa084, 0x0fff, 0xa105, 0x2012, + 0x007c, 0x2011, 0x0102, 0x2204, 0xa084, 0xffcf, 0xa105, 0x2012, + 0x007c, 0x8103, 0x8003, 0xa080, 0x0020, 0x0c7e, 0x2061, 0x0100, + 0x609a, 0x62ac, 0x63ac, 0x0c7f, 0x007c, 0x8103, 0x8003, 0xa080, + 0x0022, 0x0c7e, 0x2061, 0x0100, 0x609a, 0x60a4, 0xa084, 0xffdf, + 0x60ae, 0x0c7f, 0x007c, 0x8103, 0x8003, 0xa080, 0x0022, 0x0c7e, + 0x2061, 0x0100, 0x609a, 0x60a4, 0xa085, 0x0020, 0x60ae, 0x0c7f, + 0x007c, 0x8103, 0x8003, 0xa080, 0x0020, 0x0c7e, 0x2061, 0x0100, + 0x609a, 0x60a4, 0x62ae, 0x2010, 0x60a4, 0x63ae, 0x2018, 0x0c7f, + 0x007c, 0x2091, 0x8000, 0x0c7e, 0x0e7e, 0x6818, 0xa005, 0x0040, + 0x233c, 0x2061, 0x7400, 0x1078, 0x2344, 0x0040, 0x2328, 0x20a9, + 0x0000, 0x2061, 0x7300, 0x0c7e, 0x1078, 0x2344, 0x0040, 0x2318, + 0x0c7f, 0x8c60, 0x0070, 0x2316, 0x0078, 0x230b, 0x0078, 0x233c, + 0x007f, 0xa082, 0x7300, 0x2071, 0x5040, 0x7086, 0x7182, 0x2001, + 0x0004, 0x706e, 0x7093, 0x000f, 0x1078, 0x21ac, 0x0078, 0x2338, + 0x60c0, 0xa005, 0x00c0, 0x233c, 0x2071, 0x5040, 0x7182, 0x2c00, + 0x708a, 0x2001, 0x0006, 0x706e, 0x7093, 0x000f, 0x1078, 0x21ac, + 0x2001, 0x0000, 0x0078, 0x233e, 0x2001, 0x0001, 0x2091, 0x8001, + 0xa005, 0x0e7f, 0x0c7f, 0x007c, 0x2c04, 0xa005, 0x0040, 0x235b, + 0x2060, 0x600c, 0xa306, 0x00c0, 0x2358, 0x6010, 0xa206, 0x00c0, + 0x2358, 0x6014, 0xa106, 0x00c0, 0x2358, 0xa006, 0x0078, 0x235d, + 0x6000, 0x0078, 0x2345, 0xa085, 0x0001, 0x007c, 0x2011, 0x5041, + 0x220c, 0xa18c, 0x000f, 0x2011, 0x013b, 0x2204, 0xa084, 0x0100, + 0x0040, 0x2374, 0x2021, 0xff04, 0x2122, 0x810b, 0x810b, 0x810b, + 0x810b, 0xa18d, 0x0f00, 0x2104, 0x007c, 0x0e7e, 0x68e4, 0xa08c, + 0x0020, 0x0040, 0x23c8, 0xa084, 0x0006, 0x00c0, 0x23c8, 0x6014, + 0x8007, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xa0f0, 0x5280, + 0x7004, 0xa084, 0x000a, 0x00c0, 0x23c8, 0x7108, 0xa194, 0xff00, + 0x0040, 0x23c8, 0xa18c, 0x00ff, 0x2001, 0x000c, 0xa106, 0x0040, + 0x23af, 0x2001, 0x0012, 0xa106, 0x0040, 0x23b3, 0x2001, 0x0014, + 0xa106, 0x0040, 0x23b7, 0x2001, 0x0019, 0xa106, 0x0040, 0x23bb, + 0x2001, 0x0032, 0xa106, 0x0040, 0x23bf, 0x0078, 0x23c3, 0x2009, + 0x0012, 0x0078, 0x23c5, 0x2009, 0x0014, 0x0078, 0x23c5, 0x2009, + 0x0019, 0x0078, 0x23c5, 0x2009, 0x0020, 0x0078, 0x23c5, 0x2009, + 0x003f, 0x0078, 0x23c5, 0x2011, 0x0000, 0x2100, 0xa205, 0x700a, + 0x0e7f, 0x007c, 0x0068, 0x23ca, 0x2091, 0x8000, 0x2071, 0x0000, + 0x007e, 0x7018, 0xa084, 0x0001, 0x00c0, 0x23d1, 0x007f, 0x2071, + 0x0010, 0x70ca, 0x007f, 0x70c6, 0x70c3, 0x8002, 0x70db, 0x073f, + 0x70df, 0x0000, 0x2071, 0x0000, 0x701b, 0x0001, 0x2091, 0x4080, + 0x0078, 0x23e8, 0x107e, 0x007e, 0x127e, 0x2091, 0x2300, 0x7f3c, + 0x7e58, 0x7c30, 0x7d38, 0x77c2, 0x74c6, 0x76ca, 0x75ce, 0xa594, + 0x003f, 0xa49c, 0x0003, 0xa484, 0x000f, 0x0079, 0x23ff, 0x2411, + 0x2411, 0x2411, 0x274b, 0x3907, 0x240f, 0x2440, 0x244a, 0x240f, + 0x240f, 0x240f, 0x240f, 0x240f, 0x240f, 0x240f, 0x240f, 0x1078, + 0x23ca, 0x8507, 0xa084, 0x001f, 0x0079, 0x2416, 0x2454, 0x274b, + 0x2905, 0x2a02, 0x2a2a, 0x2cc3, 0x2f6e, 0x2fb1, 0x2ffc, 0x3081, + 0x3139, 0x31e2, 0x2440, 0x2827, 0x2f43, 0x2436, 0x3c78, 0x3c98, + 0x3e5e, 0x3e6a, 0x3f3f, 0x2436, 0x2436, 0x4012, 0x4016, 0x3c76, + 0x2436, 0x3dc9, 0x2436, 0x3b56, 0x244a, 0x2436, 0x1078, 0x23ca, + 0x0018, 0x23ef, 0x127f, 0x2091, 0x8001, 0x007f, 0x107f, 0x007c, + 0x2019, 0x4cfd, 0x1078, 0x2255, 0x702f, 0x0001, 0x781b, 0x004f, + 0x0078, 0x2438, 0x2019, 0x4c5b, 0x1078, 0x2255, 0x702f, 0x8000, + 0x781b, 0x00d5, 0x0078, 0x2438, 0x7242, 0x2009, 0x500f, 0x200b, + 0x0000, 0xa584, 0x0001, 0x00c0, 0x3b6a, 0x0040, 0x2471, 0x1078, + 0x23ca, 0x7003, 0x0000, 0x704b, 0x0000, 0x7043, 0x0000, 0x7037, + 0x0000, 0x1078, 0x38de, 0x0018, 0x23ef, 0x2009, 0x500f, 0x200b, + 0x0000, 0x7068, 0xa005, 0x00c0, 0x253c, 0x706c, 0xa084, 0x0007, + 0x0079, 0x247a, 0x2573, 0x2482, 0x248e, 0x24ab, 0x24cd, 0x251a, + 0x24f3, 0x2482, 0x1078, 0x38c6, 0x2009, 0x0048, 0x1078, 0x2e0f, + 0x00c0, 0x248c, 0x7003, 0x0004, 0x0078, 0x2438, 0x1078, 0x38c6, + 0x00c0, 0x24a9, 0x7080, 0x8007, 0x7882, 0x789b, 0x0010, 0x78ab, + 0x000c, 0x789b, 0x0060, 0x78ab, 0x0001, 0x785b, 0x0004, 0x2009, + 0x00e5, 0x1078, 0x2e03, 0x00c0, 0x24a9, 0x7003, 0x0004, 0x7093, + 0x000f, 0x0078, 0x2438, 0x1078, 0x38c6, 0x00c0, 0x24cb, 0x7180, + 0x8107, 0x7882, 0x789b, 0x0010, 0xa18c, 0x001f, 0xa18d, 0x00c0, + 0x79aa, 0x78ab, 0x0006, 0x789b, 0x0060, 0x78ab, 0x0002, 0x785b, + 0x0004, 0x2009, 0x00e5, 0x1078, 0x2e03, 0x00c0, 0x24cb, 0x7003, + 0x0004, 0x7093, 0x000f, 0x0078, 0x2438, 0x1078, 0x38c6, 0x00c0, + 0x24f1, 0x7180, 0x8107, 0x7882, 0x789b, 0x0010, 0xa18c, 0x001f, + 0xa18d, 0x00c0, 0x79aa, 0x78ab, 0x0020, 0x7184, 0x79aa, 0x78ab, + 0x000d, 0x789b, 0x0060, 0x78ab, 0x0004, 0x785b, 0x0004, 0x2009, + 0x00e5, 0x1078, 0x2e03, 0x00c0, 0x24f1, 0x7003, 0x0004, 0x7093, + 0x000f, 0x0078, 0x2438, 0x1078, 0x38c6, 0x00c0, 0x2518, 0x7180, + 0x8107, 0x7882, 0x789b, 0x0010, 0xa18c, 0x001f, 0xa18d, 0x00c0, + 0x79aa, 0x78ab, 0x0006, 0x789b, 0x0060, 0x78ab, 0x0002, 0x785b, + 0x0004, 0x2009, 0x00e5, 0x1078, 0x2e03, 0x00c0, 0x2518, 0x7088, + 0x708b, 0x0000, 0x2068, 0x704a, 0x7003, 0x0002, 0x7093, 0x000f, + 0x0078, 0x2438, 0x1078, 0x38c6, 0x00c0, 0x2438, 0x7088, 0x2068, + 0x6f14, 0x1078, 0x37bd, 0x2c50, 0x1078, 0x3978, 0x789b, 0x0010, + 0x6814, 0xa084, 0x001f, 0xa085, 0x0080, 0x78aa, 0x6e1c, 0x2041, + 0x0001, 0x708c, 0xa084, 0x0400, 0x2001, 0x0004, 0x0040, 0x253a, + 0x2001, 0x0006, 0x0078, 0x265b, 0x1078, 0x38c6, 0x00c0, 0x2438, + 0x789b, 0x0010, 0x7068, 0x2068, 0x6f14, 0x1078, 0x37bd, 0x2c50, + 0x1078, 0x3978, 0x6008, 0xa085, 0x0010, 0x600a, 0x6824, 0xa005, + 0x0040, 0x255a, 0xa082, 0x0006, 0x0048, 0x2558, 0x0078, 0x255a, + 0x6827, 0x0005, 0x6b14, 0xa39c, 0x001f, 0xa39d, 0x00c0, 0x7058, + 0xa084, 0x8000, 0x0040, 0x2568, 0xa684, 0x0001, 0x0040, 0x256a, + 0xa39c, 0xffbf, 0x7baa, 0x2031, 0x0020, 0x2041, 0x0001, 0x2001, + 0x0003, 0x0078, 0x265b, 0x0018, 0x23ef, 0x744c, 0xa485, 0x0000, + 0x0040, 0x258d, 0xa080, 0x5080, 0x2030, 0x7150, 0x8108, 0xa12a, + 0x0048, 0x2584, 0x2009, 0x5080, 0x2164, 0x6504, 0x85ff, 0x00c0, + 0x259e, 0x8421, 0x00c0, 0x257e, 0x7152, 0x7003, 0x0000, 0x704b, + 0x0000, 0x7040, 0xa005, 0x0040, 0x3b6a, 0x0078, 0x2438, 0x764c, + 0xa6b0, 0x5080, 0x7150, 0x2600, 0x0078, 0x2589, 0x7152, 0x2568, + 0x2558, 0x754a, 0x2c50, 0x6034, 0xa085, 0x0000, 0x00c0, 0x259b, + 0x6708, 0x773a, 0xa784, 0x033f, 0x0040, 0x25d4, 0xa784, 0x0021, + 0x00c0, 0x259b, 0xa784, 0x0002, 0x0040, 0x25bd, 0xa784, 0x0004, + 0x0040, 0x259b, 0xa7bc, 0xfffb, 0x670a, 0xa784, 0x0008, 0x00c0, + 0x259b, 0xa784, 0x0010, 0x00c0, 0x259b, 0xa784, 0x0200, 0x00c0, + 0x259b, 0xa784, 0x0100, 0x0040, 0x25d4, 0x6018, 0xa005, 0x00c0, + 0x259b, 0xa7bc, 0xfeff, 0x670a, 0x6823, 0x0000, 0x6e1c, 0xa684, + 0x000e, 0x6118, 0x0040, 0x25e4, 0x601c, 0xa102, 0x0048, 0x25e7, + 0x0040, 0x25e7, 0x0078, 0x2597, 0x81ff, 0x00c0, 0x2597, 0x68c3, + 0x0000, 0xa784, 0x0080, 0x00c0, 0x25ef, 0x700c, 0x6022, 0xa7bc, + 0xff7f, 0x670a, 0x1078, 0x3978, 0x0018, 0x23ef, 0x789b, 0x0010, + 0xa046, 0x1078, 0x38c6, 0x00c0, 0x2438, 0x6b14, 0xa39c, 0x001f, + 0xa39d, 0x00c0, 0x7058, 0xa084, 0x8000, 0x0040, 0x260b, 0xa684, + 0x0001, 0x0040, 0x260d, 0xa39c, 0xffbf, 0xa684, 0x0010, 0x0040, + 0x2613, 0xa39d, 0x0020, 0x7baa, 0x8840, 0xa684, 0x000e, 0x00c0, + 0x261e, 0xa7bd, 0x0010, 0x670a, 0x0078, 0x2659, 0x7158, 0xa18c, + 0x0800, 0x0040, 0x33d7, 0x2011, 0x0020, 0xa684, 0x0008, 0x00c0, + 0x262f, 0x8210, 0xa684, 0x0002, 0x00c0, 0x262f, 0x8210, 0x7aaa, + 0x8840, 0x1078, 0x38de, 0x6a14, 0x610c, 0x8108, 0xa18c, 0x00ff, + 0xa1e0, 0x7300, 0x2c64, 0x8cff, 0x0040, 0x2650, 0x6014, 0xa206, + 0x00c0, 0x263a, 0x60b8, 0x8001, 0x60ba, 0x00c0, 0x2635, 0x0c7e, + 0x2a60, 0x6008, 0xa085, 0x0100, 0x600a, 0x0c7f, 0x0078, 0x2573, + 0x1078, 0x38c6, 0x00c0, 0x2438, 0x2a60, 0x610e, 0x79aa, 0x8840, + 0x7132, 0x2001, 0x0001, 0x007e, 0x715c, 0xa184, 0x0018, 0x0040, + 0x2676, 0xa184, 0x0010, 0x0040, 0x2669, 0x1078, 0x35d6, 0x00c0, + 0x2699, 0xa184, 0x0008, 0x0040, 0x2676, 0x69a0, 0xa184, 0x0600, + 0x00c0, 0x2676, 0x1078, 0x34c7, 0x0078, 0x2699, 0x69a0, 0xa184, + 0x0800, 0x0040, 0x268d, 0x0c7e, 0x027e, 0x2960, 0x6000, 0xa085, + 0x2000, 0x6002, 0x6104, 0xa18d, 0x0010, 0x6106, 0x027f, 0x0c7f, + 0x1078, 0x35d6, 0x00c0, 0x2699, 0x69a0, 0xa184, 0x0200, 0x0040, + 0x2695, 0x1078, 0x3516, 0x0078, 0x2699, 0xa184, 0x0400, 0x00c0, + 0x2672, 0x69a0, 0xa184, 0x1000, 0x0040, 0x26a4, 0x6914, 0xa18c, + 0xff00, 0x810f, 0x1078, 0x22cd, 0x007f, 0x7002, 0xa68c, 0x00e0, + 0xa684, 0x0060, 0x0040, 0x26b2, 0xa086, 0x0060, 0x00c0, 0x26b2, + 0xa18d, 0x4000, 0x88ff, 0x0040, 0x26b7, 0xa18d, 0x0004, 0x795a, + 0x69b6, 0x789b, 0x0060, 0x2800, 0x78aa, 0x789b, 0x0061, 0x6818, + 0xa08d, 0x8000, 0xa084, 0x7fff, 0x691a, 0xa68c, 0x0080, 0x0040, + 0x26d6, 0x7097, 0x0000, 0xa08a, 0x000d, 0x0050, 0x26d4, 0xa08a, + 0x000c, 0x7196, 0x2001, 0x000c, 0x800c, 0x719a, 0x78aa, 0x8008, + 0x810c, 0x0040, 0x33dd, 0xa18c, 0x00f8, 0x00c0, 0x33dd, 0x157e, + 0x137e, 0x147e, 0x20a1, 0x012b, 0x789b, 0x0000, 0x8000, 0x80ac, + 0xad80, 0x000b, 0x2098, 0x53a6, 0x147f, 0x137f, 0x157f, 0x6814, + 0x8007, 0x7882, 0x6d94, 0x7dd6, 0x7dde, 0x6e98, 0x7ed2, 0x7eda, + 0x1078, 0x38c6, 0x00c0, 0x270d, 0x702c, 0x8003, 0x0048, 0x2706, + 0x2019, 0x4c5b, 0x1078, 0x2255, 0x702f, 0x8000, 0x7830, 0xa084, + 0x00c0, 0x00c0, 0x270d, 0x0098, 0x2715, 0x6008, 0xa084, 0xffef, + 0x600a, 0x1078, 0x38de, 0x0078, 0x2461, 0x7200, 0xa284, 0x0007, + 0xa086, 0x0001, 0x00c0, 0x2722, 0x781b, 0x004f, 0x1078, 0x38de, + 0x0078, 0x2733, 0x6ab4, 0xa295, 0x2000, 0x7a5a, 0x781b, 0x004f, + 0x1078, 0x38de, 0x7200, 0x2500, 0xa605, 0x0040, 0x2733, 0xa284, + 0x0007, 0x1079, 0x2741, 0xad80, 0x0009, 0x7036, 0xa284, 0x0007, + 0xa086, 0x0001, 0x00c0, 0x2438, 0x6018, 0x8000, 0x601a, 0x0078, + 0x2438, 0x2749, 0x48f7, 0x48f7, 0x48e6, 0x48f7, 0x2749, 0x48e6, + 0x2749, 0x1078, 0x23ca, 0x1078, 0x38c6, 0x0f7e, 0x2079, 0x5000, + 0x78cc, 0x0f7f, 0xa084, 0x0001, 0x0040, 0x276f, 0x706c, 0xa086, + 0x0001, 0x00c0, 0x275e, 0x706e, 0x0078, 0x2802, 0x706c, 0xa086, + 0x0005, 0x00c0, 0x276d, 0x7088, 0x2068, 0x681b, 0x0004, 0x6817, + 0x0000, 0x6820, 0xa085, 0x0008, 0x6822, 0x706f, 0x0000, 0x2011, + 0x0004, 0x716c, 0xa186, 0x0001, 0x0040, 0x2790, 0xa186, 0x0007, + 0x00c0, 0x2780, 0x2009, 0x5038, 0x200b, 0x0005, 0x0078, 0x2790, + 0x2009, 0x5013, 0x2104, 0x2009, 0x5012, 0x200a, 0x2009, 0x5038, + 0x200b, 0x0001, 0x706f, 0x0000, 0x7073, 0x0001, 0x0078, 0x2792, + 0x706f, 0x0000, 0x1078, 0x4633, 0x157e, 0x20a9, 0x0010, 0x2039, + 0x0000, 0x1078, 0x36b0, 0xa7b8, 0x0100, 0x0070, 0x27a1, 0x0078, + 0x2799, 0x157f, 0x7000, 0x0079, 0x27a5, 0x27d3, 0x27ba, 0x27ba, + 0x27ad, 0x27d3, 0x27d3, 0x27d3, 0x27d3, 0x2021, 0x505a, 0x2404, + 0xa005, 0x0040, 0x27d3, 0xad06, 0x00c0, 0x27ba, 0x6800, 0x2022, + 0x0078, 0x27ca, 0x6820, 0xa084, 0x0001, 0x00c0, 0x27c6, 0x6f14, + 0x1078, 0x37bd, 0x1078, 0x33ae, 0x0078, 0x27ca, 0x7060, 0x2060, + 0x6800, 0x6002, 0x6a1a, 0x6817, 0x0000, 0x6820, 0xa085, 0x0008, + 0x6822, 0x1078, 0x1c53, 0x2021, 0x7400, 0x1078, 0x280f, 0x2021, + 0x505a, 0x1078, 0x280f, 0x157e, 0x20a9, 0x0000, 0x2021, 0x7300, + 0x1078, 0x280f, 0x8420, 0x0070, 0x27e7, 0x0078, 0x27e0, 0x2061, + 0x5300, 0x2021, 0x0002, 0x20a9, 0x0100, 0x6018, 0x6110, 0x81ff, + 0x0040, 0x27f6, 0xa102, 0x0050, 0x27f6, 0x6012, 0x601b, 0x0000, + 0xace0, 0x0010, 0x0070, 0x27fe, 0x0078, 0x27ed, 0x8421, 0x00c0, + 0x27eb, 0x157f, 0x709c, 0xa084, 0x8000, 0x0040, 0x2809, 0x1078, + 0x39cc, 0x7003, 0x0000, 0x704b, 0x0000, 0x0078, 0x2438, 0x047e, + 0x2404, 0xa005, 0x0040, 0x2823, 0x2068, 0x6800, 0x007e, 0x6a1a, + 0x6817, 0x0000, 0x6820, 0xa085, 0x0008, 0x6822, 0x1078, 0x1c53, + 0x007f, 0x0078, 0x2811, 0x047f, 0x2023, 0x0000, 0x007c, 0xa282, + 0x0003, 0x0050, 0x282d, 0x1078, 0x23ca, 0x2300, 0x0079, 0x2830, + 0x2833, 0x28a6, 0x28c3, 0xa282, 0x0002, 0x0040, 0x2839, 0x1078, + 0x23ca, 0x706c, 0x706f, 0x0000, 0x7093, 0x0000, 0x0079, 0x2840, + 0x2848, 0x2848, 0x284a, 0x287e, 0x33e3, 0x2848, 0x287e, 0x2848, + 0x1078, 0x23ca, 0x7780, 0x1078, 0x36b0, 0x7780, 0xa7bc, 0x0f00, + 0x1078, 0x37bd, 0x6018, 0xa005, 0x0040, 0x2875, 0x2021, 0x7400, + 0x2009, 0x0004, 0x2011, 0x0010, 0x1078, 0x28de, 0x0040, 0x2875, + 0x157e, 0x20a9, 0x0000, 0x2021, 0x7300, 0x047e, 0x2009, 0x0004, + 0x2011, 0x0010, 0x1078, 0x28de, 0x047f, 0x0040, 0x2874, 0x8420, + 0x0070, 0x2874, 0x0078, 0x2865, 0x157f, 0x8738, 0xa784, 0x001f, + 0x00c0, 0x2850, 0x0078, 0x2461, 0x0078, 0x2461, 0x7780, 0x1078, + 0x37bd, 0x6018, 0xa005, 0x0040, 0x28a4, 0x2021, 0x7400, 0x2009, + 0x0005, 0x2011, 0x0020, 0x1078, 0x28de, 0x0040, 0x28a4, 0x157e, + 0x20a9, 0x0000, 0x2021, 0x7300, 0x047e, 0x2009, 0x0005, 0x2011, + 0x0020, 0x1078, 0x28de, 0x047f, 0x0040, 0x28a3, 0x8420, 0x0070, + 0x28a3, 0x0078, 0x2894, 0x157f, 0x0078, 0x2461, 0x2200, 0x0079, + 0x28a9, 0x28ac, 0x28ae, 0x28ae, 0x1078, 0x23ca, 0x2009, 0x0012, + 0x706c, 0xa086, 0x0002, 0x0040, 0x28b7, 0x2009, 0x000e, 0x6818, + 0xa084, 0x8000, 0x0040, 0x28bd, 0x691a, 0x706f, 0x0000, 0x7073, + 0x0001, 0x0078, 0x3854, 0x2200, 0x0079, 0x28c6, 0x28cb, 0x28ae, + 0x28c9, 0x1078, 0x23ca, 0x1078, 0x4633, 0x7000, 0xa086, 0x0001, + 0x00c0, 0x3373, 0x1078, 0x33c4, 0x6008, 0xa084, 0xffef, 0x600a, + 0x1078, 0x3366, 0x0040, 0x3373, 0x0078, 0x2573, 0x2404, 0xa005, + 0x0040, 0x2901, 0x2068, 0x2d04, 0x007e, 0x6814, 0xa706, 0x0040, + 0x28ed, 0x2d20, 0x007f, 0x0078, 0x28df, 0x007f, 0x2022, 0x691a, + 0x6817, 0x0000, 0x6820, 0xa205, 0x6822, 0x1078, 0x1c53, 0x6010, + 0x8001, 0x6012, 0x6008, 0xa084, 0xffef, 0x600a, 0x1078, 0x33c4, + 0x007c, 0xa085, 0x0001, 0x0078, 0x2900, 0x2300, 0x0079, 0x2908, + 0x290d, 0x290b, 0x29a6, 0x1078, 0x23ca, 0x78ec, 0xa084, 0x0001, + 0x00c0, 0x2921, 0x7000, 0xa086, 0x0004, 0x00c0, 0x2919, 0x0078, + 0x2944, 0x1078, 0x33c4, 0x6008, 0xa084, 0xffef, 0x600a, 0x0078, + 0x3373, 0x78e4, 0xa005, 0x00d0, 0x2944, 0x0018, 0x2438, 0x2008, + 0xa084, 0x0030, 0x00c0, 0x2930, 0x781b, 0x004f, 0x0078, 0x2438, + 0x78ec, 0xa084, 0x0003, 0x0040, 0x292c, 0x2100, 0xa084, 0x0007, + 0x0079, 0x293a, 0x297d, 0x2988, 0x296e, 0x2942, 0x38b9, 0x38b9, + 0x2942, 0x2997, 0x1078, 0x23ca, 0x7000, 0xa086, 0x0004, 0x00c0, + 0x295e, 0x706c, 0xa086, 0x0002, 0x00c0, 0x2954, 0x2011, 0x0002, + 0x2019, 0x0000, 0x0078, 0x2827, 0x706c, 0xa086, 0x0006, 0x0040, + 0x294e, 0x706c, 0xa086, 0x0004, 0x0040, 0x294e, 0x79e4, 0xa184, + 0x0030, 0x0040, 0x2968, 0x78ec, 0xa084, 0x0003, 0x00c0, 0x296a, + 0x0078, 0x2f43, 0x2001, 0x0003, 0x0078, 0x2cd7, 0x6818, 0xa084, + 0x8000, 0x0040, 0x2975, 0x681b, 0x001d, 0x1078, 0x368f, 0x782b, + 0x3008, 0x781b, 0x0056, 0x0078, 0x2438, 0x6818, 0xa084, 0x8000, + 0x0040, 0x2984, 0x681b, 0x001d, 0x1078, 0x368f, 0x0078, 0x3884, + 0x6818, 0xa084, 0x8000, 0x0040, 0x298f, 0x681b, 0x001d, 0x1078, + 0x368f, 0x782b, 0x3008, 0x781b, 0x00d2, 0x0078, 0x2438, 0x6818, + 0xa084, 0x8000, 0x0040, 0x299e, 0x681b, 0x001d, 0x1078, 0x368f, + 0x782b, 0x3008, 0x781b, 0x0093, 0x0078, 0x2438, 0xa584, 0x000f, + 0x00c0, 0x29c3, 0x7000, 0x0079, 0x29ad, 0x2461, 0x29b7, 0x29b5, + 0x3373, 0x3373, 0x3373, 0x3373, 0x29b5, 0x1078, 0x23ca, 0x1078, + 0x33c4, 0x6008, 0xa084, 0xffef, 0x600a, 0x1078, 0x3366, 0x0040, + 0x3373, 0x0078, 0x2573, 0x78e4, 0xa005, 0x00d0, 0x2944, 0x0018, + 0x2944, 0x2008, 0xa084, 0x0030, 0x00c0, 0x29d2, 0x781b, 0x004f, + 0x0078, 0x2438, 0x78ec, 0xa084, 0x0003, 0x0040, 0x29ce, 0x2100, + 0xa184, 0x0007, 0x0079, 0x29dc, 0x29ee, 0x29f2, 0x29e6, 0x29e4, + 0x38b9, 0x38b9, 0x29e4, 0x38af, 0x1078, 0x23ca, 0x1078, 0x3697, + 0x782b, 0x3008, 0x781b, 0x0056, 0x0078, 0x2438, 0x1078, 0x3697, + 0x0078, 0x3884, 0x1078, 0x3697, 0x782b, 0x3008, 0x781b, 0x00d2, + 0x0078, 0x2438, 0x1078, 0x3697, 0x782b, 0x3008, 0x781b, 0x0093, + 0x0078, 0x2438, 0x2300, 0x0079, 0x2a05, 0x2a0a, 0x2a08, 0x2a0c, + 0x1078, 0x23ca, 0x0078, 0x3081, 0x681b, 0x0008, 0x78a3, 0x0000, + 0x79e4, 0xa184, 0x0030, 0x0040, 0x3081, 0x78ec, 0xa084, 0x0003, + 0x0040, 0x3081, 0xa184, 0x0007, 0x0079, 0x2a1e, 0x2a26, 0x29f2, + 0x296e, 0x3854, 0x38b9, 0x38b9, 0x2a26, 0x38af, 0x1078, 0x3868, + 0x0078, 0x2438, 0xa282, 0x0005, 0x0050, 0x2a30, 0x1078, 0x23ca, + 0x2300, 0x0079, 0x2a33, 0x2a36, 0x2c84, 0x2c92, 0x2200, 0x0079, + 0x2a39, 0x2a53, 0x2a40, 0x2a53, 0x2a3e, 0x2c69, 0x1078, 0x23ca, + 0x789b, 0x0018, 0x78a8, 0xa084, 0x00ff, 0xa082, 0x0020, 0x0048, + 0x366b, 0xa08a, 0x0004, 0x00c8, 0x366b, 0x0079, 0x2a4f, 0x366b, + 0x366b, 0x366b, 0x3619, 0x789b, 0x0018, 0x79a8, 0xa184, 0x0080, + 0x0040, 0x2a64, 0x0078, 0x366b, 0x7000, 0xa005, 0x00c0, 0x2a5a, + 0x2011, 0x0004, 0x0078, 0x31f5, 0xa184, 0x00ff, 0xa08a, 0x0010, + 0x00c8, 0x366b, 0x0079, 0x2a6c, 0x2a7e, 0x2a7c, 0x2a96, 0x2a9a, + 0x2b55, 0x366b, 0x366b, 0x2b57, 0x366b, 0x366b, 0x2c65, 0x2c65, + 0x366b, 0x366b, 0x366b, 0x2c67, 0x1078, 0x23ca, 0xa684, 0x1000, + 0x0040, 0x2a8b, 0x2001, 0x0500, 0x8000, 0x8000, 0x783a, 0x781b, + 0x0091, 0x0078, 0x2438, 0x6818, 0xa084, 0x8000, 0x0040, 0x2a94, + 0x681b, 0x001d, 0x0078, 0x2a82, 0x0078, 0x3854, 0x681b, 0x001d, + 0x0078, 0x367b, 0x6920, 0x6922, 0xa684, 0x1800, 0x00c0, 0x2adb, + 0x6820, 0xa084, 0x0001, 0x00c0, 0x2ae1, 0x6818, 0xa086, 0x0008, + 0x00c0, 0x2aac, 0x681b, 0x0000, 0xa684, 0x0400, 0x0040, 0x2b51, + 0xa684, 0x0080, 0x0040, 0x2ad7, 0x7097, 0x0000, 0x6818, 0xa084, + 0x003f, 0xa08a, 0x000d, 0x0050, 0x2ad7, 0xa08a, 0x000c, 0x7196, + 0x2001, 0x000c, 0x800c, 0x719a, 0x789b, 0x0061, 0x78aa, 0x157e, + 0x137e, 0x147e, 0x20a1, 0x012b, 0x789b, 0x0000, 0x8000, 0x80ac, + 0xad80, 0x000b, 0x2098, 0x53a6, 0x147f, 0x137f, 0x157f, 0x781b, + 0x0058, 0x0078, 0x2438, 0xa684, 0x1000, 0x0040, 0x2ae1, 0x0078, + 0x2438, 0xa684, 0x0060, 0x0040, 0x2b4d, 0xa684, 0x0800, 0x0040, + 0x2b4d, 0xa684, 0x8000, 0x00c0, 0x2aef, 0x0078, 0x2b09, 0xa6b4, + 0x7fff, 0x7e5a, 0x6eb6, 0x789b, 0x0076, 0x7aac, 0x79ac, 0x78ac, + 0x801b, 0x00c8, 0x2afc, 0x8000, 0xa084, 0x003f, 0xa108, 0xa291, + 0x0000, 0x6b98, 0x2100, 0xa302, 0x68b2, 0x6b94, 0x2200, 0xa303, + 0x68ae, 0xa684, 0x4000, 0x0040, 0x2b11, 0xa6b4, 0xbfff, 0x7e5a, + 0x6eb6, 0x7000, 0xa086, 0x0003, 0x00c0, 0x2b1e, 0x1078, 0x46e9, + 0x1078, 0x48e6, 0x781b, 0x0064, 0x0078, 0x2438, 0xa006, 0x1078, + 0x49ed, 0x6ab0, 0x69ac, 0x6c98, 0x6b94, 0x2200, 0xa105, 0x0040, + 0x2b2d, 0x2200, 0xa422, 0x2100, 0xa31b, 0x6caa, 0x7cd2, 0x7cda, + 0x6ba6, 0x7bd6, 0x7bde, 0x2300, 0xa405, 0x00c0, 0x2b3f, 0xa6b5, + 0x4000, 0x7e5a, 0x6eb6, 0x781b, 0x0064, 0x0078, 0x2438, 0x781b, + 0x0064, 0x2200, 0xa115, 0x00c0, 0x2b49, 0x1078, 0x48f7, 0x0078, + 0x2438, 0x1078, 0x4942, 0x0078, 0x2438, 0x781b, 0x0065, 0x0078, + 0x2438, 0x781b, 0x0058, 0x0078, 0x2438, 0x1078, 0x23ca, 0x0078, + 0x2bb8, 0x6920, 0xa184, 0x0100, 0x0040, 0x2b6f, 0xa18c, 0xfeff, + 0x6922, 0x0c7e, 0x7054, 0x2060, 0x6000, 0xa084, 0xefff, 0x6002, + 0x6004, 0xa084, 0xfff5, 0x6006, 0x0c7f, 0x0078, 0x2ba7, 0xa184, + 0x0200, 0x0040, 0x2ba7, 0xa18c, 0xfdff, 0x6922, 0x0c7e, 0x7054, + 0x2060, 0x6000, 0xa084, 0xdfff, 0x6002, 0x6004, 0xa084, 0xffef, + 0x6006, 0x2008, 0x2c48, 0x0c7f, 0xa184, 0x0008, 0x0040, 0x2ba7, + 0x1078, 0x37b9, 0x1078, 0x34c7, 0x88ff, 0x0040, 0x2ba7, 0x789b, + 0x0060, 0x2800, 0x78aa, 0x7e58, 0xa6b5, 0x0004, 0x7e5a, 0xa684, + 0x0400, 0x00c0, 0x2ba1, 0x782b, 0x3008, 0x781b, 0x0056, 0x0078, + 0x2438, 0x782b, 0x3008, 0x781b, 0x0065, 0x0078, 0x2438, 0x7e58, + 0xa684, 0x0400, 0x00c0, 0x2bb0, 0x781b, 0x0058, 0x0078, 0x2438, + 0x781b, 0x0065, 0x0078, 0x2438, 0x0078, 0x3673, 0x0078, 0x3673, + 0x2019, 0x0000, 0x7990, 0xa18c, 0x0007, 0x0040, 0x2bb6, 0x789b, + 0x0010, 0x78a8, 0xa094, 0x00ff, 0xa286, 0x0001, 0x00c0, 0x2bf6, + 0x2300, 0x7ca8, 0xa400, 0x2018, 0xa102, 0x0040, 0x2bee, 0x0048, + 0x2bd3, 0x0078, 0x2bf0, 0xa380, 0x0002, 0xa102, 0x00c8, 0x2bee, + 0x6920, 0xa18c, 0xfcff, 0x6922, 0x0c7e, 0x7054, 0x2060, 0x6000, + 0xa084, 0xefef, 0x6002, 0x6004, 0xa084, 0xffe5, 0x6006, 0x0c7f, + 0x7e58, 0xa6b4, 0xfffb, 0x7e5a, 0x0078, 0x2ba8, 0x0078, 0x2b59, + 0x24a8, 0x7aa8, 0x00f0, 0x2bf0, 0x0078, 0x2bc1, 0xa284, 0x00f0, + 0xa086, 0x0020, 0x00c0, 0x2c56, 0x8318, 0x8318, 0x2300, 0xa102, + 0x0040, 0x2c06, 0x0048, 0x2c06, 0x0078, 0x2c53, 0xa286, 0x0023, + 0x0040, 0x2bb6, 0x681c, 0xa084, 0xfff1, 0x681e, 0x7e58, 0xa684, + 0xfff1, 0xa085, 0x0010, 0x2030, 0x7e5a, 0x6008, 0xa085, 0x0010, + 0x600a, 0x0c7e, 0x7054, 0x2060, 0x6004, 0x2008, 0x2c48, 0x0c7f, + 0xa184, 0x0010, 0x0040, 0x2c2a, 0x1078, 0x37b9, 0x1078, 0x35d6, + 0x0078, 0x2c39, 0x0c7e, 0x7054, 0x2060, 0x6004, 0x2008, 0x2c48, + 0x0c7f, 0xa184, 0x0008, 0x0040, 0x2ba7, 0x1078, 0x37b9, 0x1078, + 0x34c7, 0x88ff, 0x0040, 0x2ba7, 0x789b, 0x0060, 0x2800, 0x78aa, + 0xa6b5, 0x0004, 0x7e5a, 0xa684, 0x0400, 0x00c0, 0x2c4d, 0x782b, + 0x3008, 0x781b, 0x0056, 0x0078, 0x2438, 0x782b, 0x3008, 0x781b, + 0x0065, 0x0078, 0x2438, 0x7aa8, 0x0078, 0x2bc1, 0x8318, 0x2300, + 0xa102, 0x0040, 0x2c5f, 0x0048, 0x2c5f, 0x0078, 0x2bc1, 0xa284, + 0x0080, 0x00c0, 0x367b, 0x0078, 0x3673, 0x0078, 0x367b, 0x0078, + 0x366b, 0x789b, 0x0018, 0x78a8, 0xa084, 0x00ff, 0xa08e, 0x0001, + 0x0040, 0x2c74, 0x1078, 0x23ca, 0x7aa8, 0xa294, 0x00ff, 0x78a8, + 0xa084, 0x00ff, 0xa08a, 0x0004, 0x00c8, 0x366b, 0x0079, 0x2c80, + 0x366b, 0x3414, 0x366b, 0x356b, 0xa282, 0x0000, 0x00c0, 0x2c8a, + 0x1078, 0x23ca, 0x1078, 0x368f, 0x782b, 0x3008, 0x781b, 0x0065, + 0x0078, 0x2438, 0xa282, 0x0003, 0x00c0, 0x2c98, 0x1078, 0x23ca, + 0xa484, 0x8000, 0x00c0, 0x2cbb, 0x706c, 0xa005, 0x0040, 0x2ca2, + 0x1078, 0x23ca, 0x6f14, 0x7782, 0xa7bc, 0x0f00, 0x1078, 0x37bd, + 0x6008, 0xa085, 0x0021, 0x600a, 0x8738, 0xa784, 0x001f, 0x00c0, + 0x2ca6, 0x1078, 0x3693, 0x706f, 0x0002, 0x2009, 0x5038, 0x200b, + 0x0009, 0x0078, 0x2cbd, 0x1078, 0x369f, 0x782b, 0x3008, 0x781b, + 0x0065, 0x0078, 0x2438, 0xa282, 0x0004, 0x0050, 0x2cc9, 0x1078, + 0x23ca, 0x2300, 0x0079, 0x2ccc, 0x2ccf, 0x2db8, 0x2deb, 0xa286, + 0x0003, 0x0040, 0x2cd5, 0x1078, 0x23ca, 0x2001, 0x0000, 0x007e, + 0x68c0, 0xa005, 0x0040, 0x2cde, 0x7003, 0x0003, 0x68a0, 0xa084, + 0x2000, 0x0040, 0x2ce7, 0x6008, 0xa085, 0x0002, 0x600a, 0x007f, + 0x703e, 0x7000, 0xa084, 0x0007, 0x0079, 0x2cee, 0x2461, 0x2cf8, + 0x2cf8, 0x2eed, 0x2f29, 0x2461, 0x2f29, 0x2cf6, 0x1078, 0x23ca, + 0xa684, 0x1000, 0x00c0, 0x2d00, 0x1078, 0x4633, 0x0040, 0x2d92, + 0x7868, 0xa08c, 0x00ff, 0x0040, 0x2d48, 0xa186, 0x0008, 0x00c0, + 0x2d17, 0x1078, 0x33c4, 0x6008, 0xa084, 0xffef, 0x600a, 0x1078, + 0x3366, 0x0040, 0x2d48, 0x1078, 0x4633, 0x0078, 0x2d2f, 0xa186, + 0x0028, 0x00c0, 0x2d48, 0x1078, 0x4633, 0x6008, 0xa084, 0xffef, + 0x600a, 0x6018, 0xa005, 0x0040, 0x2d2f, 0x8001, 0x601a, 0xa005, + 0x0040, 0x2d2f, 0x8001, 0xa005, 0x0040, 0x2d2f, 0x601e, 0x6820, + 0xa084, 0x0001, 0x0040, 0x2461, 0x6820, 0xa084, 0xfffe, 0x6822, + 0x7060, 0x0c7e, 0x2060, 0x6800, 0x6002, 0x0c7f, 0x6004, 0x6802, + 0xa005, 0x2d00, 0x00c0, 0x2d45, 0x6002, 0x6006, 0x0078, 0x2461, + 0x017e, 0x1078, 0x2e1c, 0x017f, 0xa684, 0xdf00, 0x681e, 0x682b, + 0x0000, 0x6f14, 0x81ff, 0x0040, 0x2d92, 0xa186, 0x0002, 0x00c0, + 0x2d92, 0xa684, 0x0800, 0x00c0, 0x2d65, 0xa684, 0x0060, 0x0040, + 0x2d65, 0x78d8, 0x7adc, 0x682e, 0x6a32, 0x6820, 0xa084, 0x0800, + 0x00c0, 0x2d92, 0x8717, 0xa294, 0x000f, 0x8213, 0x8213, 0x8213, + 0xa290, 0x5280, 0xa290, 0x0000, 0x221c, 0xa384, 0x0100, 0x00c0, + 0x2d7b, 0x0078, 0x2d81, 0x8210, 0x2204, 0xa085, 0x0018, 0x2012, + 0x8211, 0xa384, 0x0400, 0x0040, 0x2d8e, 0x68a0, 0xa084, 0x0100, + 0x00c0, 0x2d8e, 0x1078, 0x2ea0, 0x0078, 0x2461, 0x6008, 0xa085, + 0x0002, 0x600a, 0x6916, 0x6818, 0xa084, 0x8000, 0x0040, 0x2d9a, + 0x703c, 0x681a, 0xa68c, 0xdf00, 0x691e, 0x1078, 0x33b5, 0x1078, + 0x33c4, 0x00c0, 0x2da7, 0x6008, 0xa084, 0xffef, 0x600a, 0x6820, + 0xa084, 0x0001, 0x00c0, 0x2db0, 0x1078, 0x33ae, 0x0078, 0x2db4, + 0x7060, 0x2060, 0x6800, 0x6002, 0x1078, 0x1c53, 0x0078, 0x2461, + 0xa282, 0x0004, 0x0048, 0x2dbe, 0x1078, 0x23ca, 0x2200, 0x0079, + 0x2dc1, 0x2dbc, 0x2dc5, 0x2dd2, 0x2dc5, 0x7000, 0xa086, 0x0005, + 0x0040, 0x2dce, 0x1078, 0x368f, 0x782b, 0x3008, 0x781b, 0x0065, + 0x0078, 0x2438, 0x7890, 0x8007, 0x8001, 0xa084, 0x0007, 0xa080, + 0x0018, 0x789a, 0x79a8, 0xa18c, 0x00ff, 0xa186, 0x0003, 0x0040, + 0x2de7, 0xa186, 0x0000, 0x0040, 0x2de7, 0x0078, 0x366b, 0x781b, + 0x0065, 0x0078, 0x2438, 0x6820, 0xa085, 0x0004, 0x6822, 0x82ff, + 0x00c0, 0x2df6, 0x1078, 0x368f, 0x0078, 0x2dfd, 0x8211, 0x0040, + 0x2dfb, 0x1078, 0x23ca, 0x1078, 0x369f, 0x782b, 0x3008, 0x781b, + 0x0065, 0x0078, 0x2438, 0x702c, 0x8003, 0x0048, 0x2e0d, 0x2019, + 0x4c5b, 0x1078, 0x2255, 0x702f, 0x8000, 0x1078, 0x38de, 0x7830, + 0xa084, 0x00c0, 0x00c0, 0x2e19, 0x0018, 0x2e19, 0x791a, 0xa006, + 0x007c, 0xa085, 0x0001, 0x007c, 0xa684, 0x0060, 0x00c0, 0x2e26, + 0x682f, 0x0000, 0x6833, 0x0000, 0x0078, 0x2e9f, 0xa684, 0x0800, + 0x00c0, 0x2e48, 0x68b4, 0xa084, 0x4800, 0xa635, 0xa684, 0x0800, + 0x00c0, 0x2e48, 0x6998, 0x6a94, 0x692e, 0x6a32, 0x703c, 0xa005, + 0x00c0, 0x2e40, 0x2200, 0xa105, 0x0040, 0x2e47, 0x703f, 0x0015, + 0x7000, 0xa086, 0x0006, 0x0040, 0x2e47, 0x1078, 0x4633, 0x007c, + 0xa684, 0x0020, 0x0040, 0x2e6a, 0xa684, 0x4000, 0x0040, 0x2e56, + 0x682f, 0x0000, 0x6833, 0x0000, 0x0078, 0x2e40, 0x68b4, 0xa084, + 0x4800, 0xa635, 0xa684, 0x4000, 0x00c0, 0x2e50, 0x703c, 0xa005, + 0x00c0, 0x2e64, 0x703f, 0x0015, 0x79d8, 0x7adc, 0x692e, 0x6a32, + 0x0078, 0x2e40, 0xa684, 0x4000, 0x0040, 0x2e74, 0x682f, 0x0000, + 0x6833, 0x0000, 0x0078, 0x2e40, 0x68b4, 0xa084, 0x4800, 0xa635, + 0xa684, 0x4000, 0x00c0, 0x2e6e, 0x703c, 0xa005, 0x00c0, 0x2e82, + 0x703f, 0x0015, 0x79d8, 0x7adc, 0x78d0, 0x80fb, 0x00c8, 0x2e89, 0x8000, 0xa084, 0x003f, 0xa108, 0xa291, 0x0000, 0x692e, 0x6a32, - 0x2100, 0xa205, 0x00c0, 0x2826, 0x0078, 0x27e0, 0x7000, 0xa086, - 0x0006, 0x0040, 0x282f, 0x1078, 0x362f, 0x0078, 0x27e0, 0x007c, - 0xa384, 0x0200, 0x0040, 0x2838, 0x6008, 0xa085, 0x0002, 0x600a, - 0x681b, 0x0006, 0x6a30, 0x692c, 0x6a3e, 0x6942, 0x682f, 0x0003, + 0x2100, 0xa205, 0x00c0, 0x2e96, 0x0078, 0x2e40, 0x7000, 0xa086, + 0x0006, 0x0040, 0x2e9f, 0x1078, 0x49ed, 0x0078, 0x2e40, 0x007c, + 0x6008, 0xa085, 0x0200, 0x600a, 0xa384, 0x0200, 0x0040, 0x2eac, + 0x6008, 0xa085, 0x0002, 0x600a, 0x681b, 0x0006, 0x688f, 0x0000, + 0x6893, 0x0000, 0x6a30, 0x692c, 0x6a3e, 0x6942, 0x682f, 0x0003, 0x6833, 0x0000, 0x6837, 0x0020, 0x6897, 0x0000, 0x689b, 0x0020, - 0x7000, 0x0079, 0x284b, 0x2853, 0x2855, 0x285e, 0x2853, 0x2853, - 0x2853, 0x2853, 0x2853, 0x1078, 0x1eac, 0x6820, 0xa084, 0x0001, - 0x00c0, 0x285e, 0x1078, 0x2cc9, 0x0078, 0x2864, 0x7054, 0x2c50, - 0x2060, 0x6800, 0x6002, 0x2a60, 0x2021, 0x3957, 0x2404, 0xa005, - 0x0040, 0x286d, 0x2020, 0x0078, 0x2866, 0x2d22, 0x206b, 0x0000, - 0x007c, 0x1078, 0x2cd0, 0x1078, 0x2cdf, 0x682b, 0x0000, 0x789b, - 0x000e, 0x6f14, 0x6817, 0x0002, 0x1078, 0x366b, 0xa684, 0x0800, - 0x0040, 0x2886, 0x691c, 0xa18d, 0x2000, 0x691e, 0x6818, 0xa084, - 0x8000, 0x0040, 0x2896, 0x7868, 0xa08c, 0x00ff, 0x0040, 0x2894, - 0x681b, 0x001e, 0x0078, 0x2896, 0x681b, 0x0000, 0x2021, 0x3957, - 0x6800, 0x2022, 0x6a3c, 0x6940, 0x6a32, 0x692e, 0x1078, 0x1a26, - 0x0078, 0x1f03, 0x1078, 0x27ce, 0x682b, 0x0000, 0x789b, 0x000e, - 0x6f14, 0x1078, 0x316f, 0xa08c, 0x00ff, 0x6916, 0x6818, 0xa084, - 0x8000, 0x0040, 0x28b5, 0x7038, 0x681a, 0xa68c, 0xdf00, 0x691e, - 0x70a3, 0x0000, 0x0078, 0x1f03, 0xa006, 0x1078, 0x32f5, 0x6817, - 0x0000, 0x681b, 0x0001, 0xa68c, 0xdf00, 0x691e, 0x682b, 0x0000, - 0x7000, 0x0079, 0x28cb, 0x28d3, 0x28d5, 0x28d5, 0x28d7, 0x28d7, - 0x28d7, 0x28d7, 0x28d3, 0x1078, 0x1eac, 0x1078, 0x2cdf, 0x6008, - 0xa084, 0xffef, 0x600a, 0x0078, 0x2caa, 0x2300, 0x0079, 0x28e0, - 0x28e3, 0x28e5, 0x2939, 0x1078, 0x1eac, 0x7000, 0x0079, 0x28e8, - 0x28f0, 0x28f2, 0x28f2, 0x290d, 0x28f2, 0x291a, 0x290d, 0x28f0, - 0x1078, 0x1eac, 0xa684, 0x0060, 0xa086, 0x0060, 0x00c0, 0x2909, - 0xa6b4, 0xffdf, 0xa6b4, 0xbfff, 0xa6b5, 0x2000, 0x7e5a, 0x681c, - 0xa084, 0xffdf, 0x681e, 0x1078, 0x32f5, 0x1078, 0x3571, 0x0078, - 0x311c, 0xa684, 0x2000, 0x0040, 0x28fc, 0x6818, 0xa084, 0x8000, - 0x0040, 0x291a, 0x681b, 0x0015, 0xa684, 0x4000, 0x0040, 0x291a, - 0x681b, 0x0007, 0x2009, 0x391e, 0x210c, 0xa186, 0x0000, 0x0040, - 0x292f, 0xa186, 0x0001, 0x0040, 0x2933, 0x2009, 0x3935, 0x200b, - 0x000b, 0x70a3, 0x0001, 0x781b, 0x0047, 0x0078, 0x1efb, 0x781b, - 0x00df, 0x0078, 0x1efb, 0x2009, 0x3935, 0x200b, 0x000a, 0x0078, - 0x1efb, 0x1078, 0x1eac, 0x2300, 0x0079, 0x293e, 0x2941, 0x2943, - 0x2976, 0x1078, 0x1eac, 0x7000, 0x0079, 0x2946, 0x294e, 0x2950, - 0x2950, 0x296b, 0x2950, 0x2972, 0x296b, 0x294e, 0x1078, 0x1eac, - 0xa684, 0x0060, 0xa086, 0x0060, 0x00c0, 0x2967, 0xa6b4, 0xffbf, - 0xa6b4, 0xbfff, 0xa6b5, 0x2000, 0x7e5a, 0x681c, 0xa084, 0xffbf, - 0x681e, 0x1078, 0x32f5, 0x1078, 0x3571, 0x0078, 0x311c, 0xa684, - 0x2000, 0x0040, 0x295a, 0x6818, 0xa084, 0x8000, 0x0040, 0x2972, - 0x681b, 0x0007, 0x781b, 0x00e6, 0x0078, 0x1efb, 0x6820, 0xa085, - 0x0004, 0x6822, 0x1078, 0x30e7, 0xa6b5, 0x0800, 0x1078, 0x2f7d, - 0x781b, 0x0067, 0x0078, 0x1efb, 0x2300, 0x0079, 0x2987, 0x298a, - 0x298c, 0x298e, 0x1078, 0x1eac, 0x1078, 0x1eac, 0xa684, 0x0400, - 0x00c0, 0x29ae, 0x782b, 0x3009, 0x6920, 0xa18c, 0xfdff, 0xa18c, - 0xfeff, 0x6922, 0x789b, 0x0060, 0x78ab, 0x0000, 0xa684, 0xfffb, - 0x785a, 0x79e4, 0xa184, 0x0020, 0x00c0, 0x29aa, 0x2001, 0x0014, - 0x0078, 0x26ad, 0xa184, 0x0007, 0x0079, 0x29e6, 0x7a90, 0xa294, - 0x0007, 0x789b, 0x0060, 0x79a8, 0x81ff, 0x0040, 0x29e4, 0x789b, - 0x0010, 0x7ba8, 0xa384, 0x0001, 0x00c0, 0x29d5, 0x7ba8, 0x7ba8, - 0xa386, 0x0001, 0x00c0, 0x29c8, 0x2009, 0xfff7, 0x0078, 0x29ce, - 0xa386, 0x0003, 0x00c0, 0x29d5, 0x2009, 0xffef, 0x0c7e, 0x7048, - 0x2060, 0x6004, 0xa104, 0x6006, 0x0c7f, 0x789b, 0x0060, 0x78ab, - 0x0000, 0xa684, 0xfffb, 0x785a, 0x782b, 0x3009, 0x6920, 0xa18c, - 0xfdff, 0xa18c, 0xfeff, 0x6922, 0x0078, 0x311c, 0x239b, 0x23a8, - 0x3124, 0x3124, 0x29ee, 0x29ee, 0x29ee, 0x3124, 0x1078, 0x1eac, - 0x79e4, 0xa184, 0x0030, 0x00c0, 0x2a06, 0x70a0, 0xa086, 0x0002, - 0x00c0, 0x29fe, 0x2011, 0x0002, 0x0078, 0x2288, 0x6818, 0xa085, - 0x8000, 0x681a, 0x2001, 0x0014, 0x0078, 0x26ad, 0xa184, 0x0007, - 0x0079, 0x2a0a, 0x311c, 0x311c, 0x2a12, 0x311c, 0x3144, 0x3144, - 0x311c, 0x311c, 0xa684, 0x0080, 0x0040, 0x2a41, 0x71c8, 0x81ff, - 0x0040, 0x2a41, 0xa182, 0x000d, 0x00d0, 0x2a22, 0x70cb, 0x0000, - 0x0078, 0x2a27, 0xa182, 0x000c, 0x70ca, 0x2009, 0x000c, 0x789b, - 0x0061, 0x79aa, 0x157e, 0x137e, 0x147e, 0x70cc, 0x8114, 0xa210, - 0x72ce, 0xa080, 0x000b, 0xad00, 0x2098, 0x20a1, 0x012b, 0x789b, - 0x0000, 0x8108, 0x81ac, 0x53a6, 0x147f, 0x137f, 0x157f, 0x0078, - 0x3124, 0xa684, 0x0400, 0x00c0, 0x2a82, 0x6820, 0xa084, 0x0001, - 0x0040, 0x3124, 0xa68c, 0x0060, 0xa684, 0x0060, 0x0040, 0x2a56, - 0xa086, 0x0060, 0x00c0, 0x2a56, 0xa18d, 0x4000, 0xa18c, 0xfffb, - 0x795a, 0x69b6, 0x789b, 0x0060, 0x78ab, 0x0000, 0x789b, 0x0061, - 0x6818, 0xa085, 0x8000, 0x681a, 0x78aa, 0x8008, 0x810c, 0x0040, - 0x2d07, 0xa18c, 0x00f8, 0x00c0, 0x2d07, 0x157e, 0x137e, 0x147e, - 0x20a1, 0x012b, 0x789b, 0x0000, 0x8000, 0x80ac, 0xad80, 0x000b, - 0x2098, 0x53a6, 0x147f, 0x137f, 0x157f, 0x6814, 0x8007, 0x7882, - 0x0078, 0x3124, 0x6818, 0xa084, 0x8000, 0x0040, 0x2a89, 0x681b, - 0x0008, 0x781b, 0x00da, 0x0078, 0x1efb, 0x2300, 0x0079, 0x2a90, - 0x2a95, 0x2b18, 0x2a93, 0x1078, 0x1eac, 0x7000, 0xa084, 0x0007, - 0x0079, 0x2a9a, 0x2aa2, 0x2aa4, 0x2ac0, 0x2aa2, 0x2aa2, 0x1f03, - 0x2aa2, 0x2aa2, 0x1078, 0x1eac, 0x6920, 0xa18d, 0x0001, 0x6922, - 0x6800, 0x6006, 0xa005, 0x00c0, 0x2aae, 0x6002, 0x681c, 0xa084, - 0x000e, 0x0040, 0x2aba, 0x7014, 0x68ba, 0x712c, 0xa188, 0x4280, - 0x0078, 0x2abc, 0x2009, 0x4380, 0x2104, 0x6802, 0x2d0a, 0x7156, - 0x6920, 0xa184, 0x8000, 0x00c0, 0x2acc, 0x68af, 0x0000, 0x68b3, - 0x0000, 0xa18d, 0x8000, 0x6922, 0x6eb6, 0xa684, 0x0060, 0x0040, - 0x2b16, 0xa684, 0x0800, 0x00c0, 0x2add, 0x6894, 0x68a6, 0x6898, - 0x68aa, 0x1078, 0x32f5, 0x0078, 0x2b16, 0xa684, 0x0020, 0x0040, - 0x2aea, 0xa006, 0x1078, 0x362f, 0x79d8, 0x7adc, 0x69aa, 0x6aa6, - 0x0078, 0x2af0, 0x1078, 0x30a6, 0x69aa, 0x6aa6, 0x1078, 0x362f, - 0xa684, 0x8000, 0x0040, 0x2b16, 0xa684, 0x7fff, 0x68b6, 0x789b, - 0x0074, 0x1078, 0x316f, 0x2010, 0x1078, 0x316f, 0x2008, 0xa684, - 0x0020, 0x00c0, 0x2b0e, 0x1078, 0x316f, 0x801b, 0x00c8, 0x2b09, + 0x68b3, 0x0000, 0x68af, 0x0000, 0x7000, 0x0079, 0x2ec7, 0x2461, + 0x2ed1, 0x2eda, 0x2ecf, 0x2ecf, 0x2ecf, 0x2ecf, 0x2ecf, 0x1078, + 0x23ca, 0x6820, 0xa084, 0x0001, 0x00c0, 0x2eda, 0x1078, 0x33ae, + 0x0078, 0x2ee0, 0x7060, 0x2c50, 0x2060, 0x6800, 0x6002, 0x2a60, + 0x2021, 0x505a, 0x2404, 0xa005, 0x0040, 0x2ee9, 0x2020, 0x0078, + 0x2ee2, 0x2d22, 0x206b, 0x0000, 0x007c, 0x1078, 0x33b5, 0x1078, + 0x33c4, 0x6008, 0xa084, 0xfdff, 0x600a, 0x682b, 0x0000, 0x789b, + 0x000e, 0x6f14, 0x6817, 0x0002, 0x1078, 0x4a35, 0xa684, 0x0800, + 0x0040, 0x2f06, 0x691c, 0xa18d, 0x2000, 0x691e, 0x6818, 0xa084, + 0x8000, 0x0040, 0x2f16, 0x7868, 0xa08c, 0x00ff, 0x0040, 0x2f14, + 0x681b, 0x001e, 0x0078, 0x2f16, 0x681b, 0x0000, 0x2021, 0x505a, + 0x2404, 0xad06, 0x0040, 0x2f1d, 0x7460, 0x6800, 0x2022, 0x68c3, + 0x0000, 0x6a3c, 0x6940, 0x6a32, 0x692e, 0x1078, 0x1c53, 0x0078, + 0x2461, 0x1078, 0x2e1c, 0x682b, 0x0000, 0x2001, 0x000e, 0x6f14, + 0x1078, 0x38e4, 0xa08c, 0x00ff, 0x6916, 0x6818, 0xa084, 0x8000, + 0x0040, 0x2f3c, 0x703c, 0x681a, 0xa68c, 0xdf00, 0x691e, 0x706f, + 0x0000, 0x0078, 0x2461, 0x7000, 0xa005, 0x00c0, 0x2f49, 0x0078, + 0x2461, 0xa006, 0x1078, 0x4633, 0x6817, 0x0000, 0x681b, 0x0014, + 0xa68c, 0xdf00, 0x691e, 0x682b, 0x0000, 0x6820, 0xa085, 0x00ff, + 0x6822, 0x7000, 0x0079, 0x2f5c, 0x2461, 0x2f66, 0x2f66, 0x2f68, + 0x2f68, 0x2f68, 0x2f68, 0x2f64, 0x1078, 0x23ca, 0x1078, 0x33c4, + 0x6008, 0xa084, 0xffef, 0x600a, 0x0078, 0x337e, 0x2300, 0x0079, + 0x2f71, 0x2f74, 0x2f76, 0x2faf, 0x1078, 0x23ca, 0x7000, 0x0079, + 0x2f79, 0x2461, 0x2f83, 0x2f83, 0x2f9e, 0x2f83, 0x2fab, 0x2f9e, + 0x2f81, 0x1078, 0x23ca, 0xa684, 0x0060, 0xa086, 0x0060, 0x00c0, + 0x2f9a, 0xa6b4, 0xffdf, 0xa6b4, 0xbfff, 0xa6b5, 0x2000, 0x7e5a, + 0x681c, 0xa084, 0xffdf, 0x681e, 0x1078, 0x4633, 0x1078, 0x48f7, + 0x0078, 0x3854, 0xa684, 0x2000, 0x0040, 0x2f8d, 0x6818, 0xa084, + 0x8000, 0x0040, 0x2fab, 0x681b, 0x0015, 0xa684, 0x4000, 0x0040, + 0x2fab, 0x681b, 0x0007, 0x1078, 0x3868, 0x0078, 0x2438, 0x1078, + 0x23ca, 0x2300, 0x0079, 0x2fb4, 0x2fb7, 0x2fb9, 0x2fec, 0x1078, + 0x23ca, 0x7000, 0x0079, 0x2fbc, 0x2461, 0x2fc6, 0x2fc6, 0x2fe1, + 0x2fc6, 0x2fe8, 0x2fe1, 0x2fc4, 0x1078, 0x23ca, 0xa684, 0x0060, + 0xa086, 0x0060, 0x00c0, 0x2fdd, 0xa6b4, 0xffbf, 0xa6b4, 0xbfff, + 0xa6b5, 0x2000, 0x7e5a, 0x681c, 0xa084, 0xffbf, 0x681e, 0x1078, + 0x4633, 0x1078, 0x48f7, 0x0078, 0x3854, 0xa684, 0x2000, 0x0040, + 0x2fd0, 0x6818, 0xa084, 0x8000, 0x0040, 0x2fe8, 0x681b, 0x0007, + 0x781b, 0x00d2, 0x0078, 0x2438, 0x6820, 0xa085, 0x0004, 0x6822, + 0x1078, 0x381f, 0xa6b5, 0x0800, 0x1078, 0x368f, 0x782b, 0x3008, + 0x781b, 0x0065, 0x0078, 0x2438, 0x2300, 0x0079, 0x2fff, 0x3002, + 0x3004, 0x3006, 0x1078, 0x23ca, 0x0078, 0x367b, 0xa684, 0x0400, + 0x00c0, 0x302f, 0x79e4, 0xa184, 0x0020, 0x0040, 0x3016, 0x78ec, + 0xa084, 0x0003, 0x0040, 0x3016, 0x782b, 0x3009, 0x789b, 0x0060, + 0x78ab, 0x0000, 0xa684, 0xfffb, 0x785a, 0x79e4, 0xa184, 0x0020, + 0x0040, 0x3027, 0x78ec, 0xa084, 0x0003, 0x00c0, 0x302b, 0x2001, + 0x0014, 0x0078, 0x2cd7, 0xa184, 0x0007, 0x0079, 0x3067, 0x7a90, + 0xa294, 0x0007, 0x789b, 0x0060, 0x79a8, 0x81ff, 0x0040, 0x3065, + 0x789b, 0x0010, 0x7ba8, 0xa384, 0x0001, 0x00c0, 0x3056, 0x7ba8, + 0x7ba8, 0xa386, 0x0001, 0x00c0, 0x3049, 0x2009, 0xfff7, 0x0078, + 0x304f, 0xa386, 0x0003, 0x00c0, 0x3056, 0x2009, 0xffef, 0x0c7e, + 0x7054, 0x2060, 0x6004, 0xa104, 0x6006, 0x0c7f, 0x789b, 0x0060, + 0x78ab, 0x0000, 0xa684, 0xfffb, 0x785a, 0x782b, 0x3009, 0x6920, + 0xa18c, 0xfdff, 0xa18c, 0xfeff, 0x6922, 0x0078, 0x3854, 0x297d, + 0x2988, 0x3071, 0x3079, 0x306f, 0x306f, 0x3854, 0x3854, 0x1078, + 0x23ca, 0x6920, 0xa18c, 0xfdff, 0xa18c, 0xfeff, 0x6922, 0x0078, + 0x385e, 0x6920, 0xa18c, 0xfdff, 0xa18c, 0xfeff, 0x6922, 0x0078, + 0x3854, 0x79e4, 0xa184, 0x0030, 0x0040, 0x308b, 0x78ec, 0xa084, + 0x0003, 0x00c0, 0x30b2, 0x7000, 0xa086, 0x0004, 0x00c0, 0x30a5, + 0x706c, 0xa086, 0x0002, 0x00c0, 0x309b, 0x2011, 0x0002, 0x2019, + 0x0000, 0x0078, 0x2827, 0x706c, 0xa086, 0x0006, 0x0040, 0x3095, + 0x706c, 0xa086, 0x0004, 0x0040, 0x3095, 0x7000, 0xa086, 0x0000, + 0x0040, 0x2438, 0x6818, 0xa085, 0x8000, 0x681a, 0x2001, 0x0014, + 0x0078, 0x2cd7, 0xa184, 0x0007, 0x0079, 0x30b6, 0x3854, 0x3854, + 0x30be, 0x3854, 0x38b9, 0x38b9, 0x3854, 0x3854, 0xa684, 0x0080, + 0x0040, 0x30ed, 0x7194, 0x81ff, 0x0040, 0x30ed, 0xa182, 0x000d, + 0x00d0, 0x30ce, 0x7097, 0x0000, 0x0078, 0x30d3, 0xa182, 0x000c, + 0x7096, 0x2009, 0x000c, 0x789b, 0x0061, 0x79aa, 0x157e, 0x137e, + 0x147e, 0x7098, 0x8114, 0xa210, 0x729a, 0xa080, 0x000b, 0xad00, + 0x2098, 0x20a1, 0x012b, 0x789b, 0x0000, 0x8108, 0x81ac, 0x53a6, + 0x147f, 0x137f, 0x157f, 0x0078, 0x385e, 0xa684, 0x0400, 0x00c0, + 0x312e, 0x6820, 0xa084, 0x0001, 0x0040, 0x385e, 0xa68c, 0x0060, + 0xa684, 0x0060, 0x0040, 0x3102, 0xa086, 0x0060, 0x00c0, 0x3102, + 0xa18d, 0x4000, 0xa18c, 0xfffb, 0x795a, 0x69b6, 0x789b, 0x0060, + 0x78ab, 0x0000, 0x789b, 0x0061, 0x6818, 0xa085, 0x8000, 0x681a, + 0x78aa, 0x8008, 0x810c, 0x0040, 0x33dd, 0xa18c, 0x00f8, 0x00c0, + 0x33dd, 0x157e, 0x137e, 0x147e, 0x20a1, 0x012b, 0x789b, 0x0000, + 0x8000, 0x80ac, 0xad80, 0x000b, 0x2098, 0x53a6, 0x147f, 0x137f, + 0x157f, 0x6814, 0x8007, 0x7882, 0x0078, 0x385e, 0x6818, 0xa084, + 0x8000, 0x0040, 0x3135, 0x681b, 0x0008, 0x781b, 0x00c8, 0x0078, + 0x2438, 0x2300, 0x0079, 0x313c, 0x3141, 0x31e0, 0x313f, 0x1078, + 0x23ca, 0x7000, 0xa084, 0x0007, 0x0079, 0x3146, 0x2461, 0x3150, + 0x3185, 0x315b, 0x314e, 0x2461, 0x314e, 0x314e, 0x1078, 0x23ca, + 0x681c, 0xa084, 0x2000, 0x0040, 0x3169, 0x6008, 0xa085, 0x0002, + 0x600a, 0x0078, 0x3169, 0x68c0, 0xa005, 0x00c0, 0x3185, 0x6920, + 0xa18d, 0x0001, 0x6922, 0x68c3, 0x0001, 0x6800, 0x706a, 0x0078, + 0x317f, 0x6920, 0xa18d, 0x0001, 0x6922, 0x6800, 0x6006, 0xa005, + 0x00c0, 0x3173, 0x6002, 0x681c, 0xa084, 0x000e, 0x0040, 0x317f, + 0x7014, 0x68ba, 0x7130, 0xa188, 0x7300, 0x0078, 0x3181, 0x2009, + 0x7400, 0x2104, 0x6802, 0x2d0a, 0x7162, 0x6eb6, 0xa684, 0x0060, + 0x0040, 0x31de, 0xa684, 0x0800, 0x00c0, 0x3199, 0xa684, 0x7fff, + 0x68b6, 0x6894, 0x68a6, 0x6898, 0x68aa, 0x1078, 0x4633, 0x0078, + 0x31de, 0xa684, 0x0020, 0x0040, 0x31ae, 0x68c0, 0xa005, 0x0040, + 0x31a5, 0x1078, 0x4a35, 0x0078, 0x31a8, 0xa006, 0x1078, 0x49ed, + 0x79d8, 0x7adc, 0x69aa, 0x6aa6, 0x0078, 0x31b4, 0x1078, 0x37ca, + 0x69aa, 0x6aa6, 0x1078, 0x49ed, 0xa684, 0x8000, 0x0040, 0x31de, + 0xa684, 0x7fff, 0x68b6, 0x2001, 0x0076, 0x1078, 0x38e4, 0x2010, + 0x2001, 0x0078, 0x1078, 0x38e4, 0x2008, 0xa684, 0x0020, 0x00c0, + 0x31d6, 0x2001, 0x007a, 0x1078, 0x38e4, 0x801b, 0x00c8, 0x31d1, 0x8000, 0xa084, 0x003f, 0xa108, 0xa291, 0x0000, 0x6b98, 0x2100, - 0xa302, 0x68b2, 0x6b94, 0x2200, 0xa303, 0x68ae, 0x0078, 0x1f03, - 0x0078, 0x2f75, 0x7033, 0x0000, 0xa282, 0x0006, 0x0050, 0x2b22, - 0x1078, 0x1eac, 0x2300, 0x0079, 0x2b25, 0x2b28, 0x2b4e, 0x2b72, - 0x2200, 0x0079, 0x2b2b, 0x2b31, 0x2f75, 0x2b33, 0x2b31, 0x2b9c, - 0x2bed, 0x1078, 0x1eac, 0x7003, 0x0005, 0x2001, 0x4390, 0x2068, - 0x703e, 0x157e, 0x20a9, 0x002f, 0x2003, 0x0000, 0x8000, 0x0070, - 0x2b43, 0x0078, 0x2b3c, 0x157f, 0x6817, 0x0000, 0x68b7, 0x0700, - 0x6823, 0x0800, 0x6827, 0x0003, 0x0078, 0x2f69, 0x7000, 0xa086, - 0x0001, 0x00c0, 0x2b5b, 0x1078, 0x2cdf, 0x1078, 0x32f5, 0x7034, - 0x600a, 0x0078, 0x2b60, 0x7000, 0xa086, 0x0003, 0x0040, 0x2b55, - 0x7003, 0x0005, 0x2001, 0x4390, 0x2068, 0x703e, 0x7032, 0x2200, - 0x0079, 0x2b6a, 0x2f75, 0x2b70, 0x2b70, 0x2b9c, 0x2b70, 0x2f75, - 0x1078, 0x1eac, 0x7000, 0xa086, 0x0001, 0x00c0, 0x2b7f, 0x1078, - 0x2cdf, 0x1078, 0x32f5, 0x7034, 0x600a, 0x0078, 0x2b84, 0x7000, - 0xa086, 0x0003, 0x0040, 0x2b79, 0x7003, 0x0005, 0x2001, 0x4390, - 0x2068, 0x703e, 0x7032, 0x2200, 0x0079, 0x2b8e, 0x2b96, 0x2b94, - 0x2b94, 0x2b96, 0x2b94, 0x2b96, 0x1078, 0x1eac, 0x1078, 0x2f8d, - 0x781b, 0x0067, 0x0078, 0x1efb, 0x7000, 0xa086, 0x0001, 0x00c0, - 0x2ba9, 0x1078, 0x2cdf, 0x1078, 0x32f5, 0x7034, 0x600a, 0x0078, - 0x2bae, 0x7000, 0xa086, 0x0003, 0x0040, 0x2ba3, 0x7003, 0x0002, - 0x7a80, 0xa294, 0x0f00, 0x789b, 0x0018, 0x7ca8, 0xa484, 0x0007, - 0xa215, 0x2069, 0x4380, 0x2d04, 0x2d08, 0x7156, 0x2068, 0xa005, - 0x0040, 0x2bc9, 0x6814, 0xa206, 0x0040, 0x2be2, 0x6800, 0x0078, - 0x2bbc, 0x7003, 0x0005, 0x2001, 0x4390, 0x2068, 0x703e, 0x7032, - 0x157e, 0x20a9, 0x002f, 0x2003, 0x0000, 0x8000, 0x0070, 0x2bda, - 0x0078, 0x2bd3, 0x157f, 0x6a16, 0x68b7, 0x0700, 0x6823, 0x0800, + 0xa302, 0x68b2, 0x6b94, 0x2200, 0xa303, 0x68ae, 0x0078, 0x2461, + 0x0078, 0x367b, 0x7037, 0x0000, 0xa282, 0x0006, 0x0050, 0x31ea, + 0x1078, 0x23ca, 0x7000, 0xa084, 0x0007, 0x10c0, 0x398a, 0x2300, + 0x0079, 0x31f2, 0x31f5, 0x321e, 0x3232, 0x2200, 0x0079, 0x31f8, + 0x321c, 0x367b, 0x31fe, 0x321c, 0x324e, 0x3290, 0x7003, 0x0005, + 0x2001, 0x7510, 0x2068, 0x704a, 0x157e, 0x20a9, 0x0031, 0x2003, + 0x0000, 0x8000, 0x0070, 0x320e, 0x0078, 0x3207, 0x157f, 0xad80, + 0x0009, 0x7036, 0x6817, 0x0000, 0x68b7, 0x0700, 0x6823, 0x0800, + 0x6827, 0x0003, 0x0078, 0x366b, 0x1078, 0x23ca, 0x7003, 0x0005, + 0x2001, 0x7510, 0x2068, 0x704a, 0xad80, 0x0009, 0x7036, 0x2200, + 0x0079, 0x322a, 0x367b, 0x3230, 0x3230, 0x324e, 0x3230, 0x367b, + 0x1078, 0x23ca, 0x7003, 0x0005, 0x2001, 0x7510, 0x2068, 0x704a, + 0xad80, 0x0009, 0x7036, 0x2200, 0x0079, 0x323e, 0x3246, 0x3244, + 0x3244, 0x3246, 0x3244, 0x3246, 0x1078, 0x23ca, 0x1078, 0x369f, + 0x782b, 0x3008, 0x781b, 0x0065, 0x0078, 0x2438, 0x7003, 0x0002, + 0x7a80, 0xa294, 0x0f00, 0x789b, 0x0018, 0x7ca8, 0xa484, 0x001f, + 0xa215, 0x2069, 0x7400, 0x2d04, 0x2d08, 0x7162, 0x2068, 0xa005, + 0x0040, 0x3269, 0x6814, 0xa206, 0x0040, 0x3285, 0x6800, 0x0078, + 0x325c, 0x7003, 0x0005, 0x2001, 0x7510, 0x2068, 0x704a, 0x7036, + 0x157e, 0x20a9, 0x0031, 0x2003, 0x0000, 0x8000, 0x0070, 0x327a, + 0x0078, 0x3273, 0x157f, 0xad80, 0x0009, 0x7036, 0x6a16, 0x68b7, + 0x0700, 0x6823, 0x0800, 0x6827, 0x0003, 0x6eb4, 0x7e5a, 0x6820, + 0xa084, 0x0c00, 0x0040, 0x32df, 0x1078, 0x3697, 0x0078, 0x32df, + 0x7003, 0x0002, 0x7a80, 0xa294, 0x0f00, 0x789b, 0x0018, 0x7ca8, + 0xa484, 0x001f, 0xa215, 0x79a8, 0x79a8, 0xa18c, 0x00ff, 0xa1e8, + 0x7300, 0x2d04, 0x2d08, 0x7162, 0x2068, 0xa005, 0x0040, 0x32af, + 0x6814, 0xa206, 0x0040, 0x32ca, 0x6800, 0x0078, 0x32a2, 0x7003, + 0x0005, 0x2001, 0x7510, 0x2068, 0x704a, 0x157e, 0x20a9, 0x0031, + 0x2003, 0x0000, 0x8000, 0x0070, 0x32bf, 0x0078, 0x32b8, 0x157f, + 0xad80, 0x0009, 0x7036, 0x6a16, 0x68b7, 0x0700, 0x6823, 0x0800, 0x6827, 0x0003, 0x6eb4, 0x7e5a, 0x6820, 0xa084, 0x0c00, 0x0040, - 0x2c4b, 0x1078, 0x2f85, 0x0078, 0x2c4b, 0x7000, 0xa086, 0x0001, - 0x00c0, 0x2bfa, 0x1078, 0x2cdf, 0x1078, 0x32f5, 0x7034, 0x600a, - 0x0078, 0x2bff, 0x7000, 0xa086, 0x0003, 0x0040, 0x2bf4, 0x7003, - 0x0002, 0x7a80, 0xa294, 0x0f00, 0x789b, 0x0018, 0x7ca8, 0xa484, - 0x0007, 0xa215, 0x79a8, 0x79a8, 0xa18c, 0x00ff, 0xa1e8, 0x4280, - 0x2d04, 0x2d08, 0x7156, 0x2068, 0xa005, 0x0040, 0x2c1e, 0x6814, - 0xa206, 0x0040, 0x2c36, 0x6800, 0x0078, 0x2c11, 0x7003, 0x0005, - 0x2001, 0x4390, 0x2068, 0x703e, 0x157e, 0x20a9, 0x002f, 0x2003, - 0x0000, 0x8000, 0x0070, 0x2c2e, 0x0078, 0x2c27, 0x157f, 0x6a16, - 0x68b7, 0x0700, 0x6823, 0x0800, 0x6827, 0x0003, 0x6eb4, 0x7e5a, - 0x6820, 0xa084, 0x0c00, 0x0040, 0x2c4b, 0xa084, 0x0800, 0x0040, - 0x2c45, 0x1078, 0x2f89, 0x0078, 0x2c4b, 0x1078, 0x2f85, 0x70bf, - 0x0000, 0x0078, 0x2c4b, 0x027e, 0x8207, 0xa084, 0x000f, 0x8003, - 0x8003, 0x8003, 0xa080, 0x3a00, 0x2060, 0x704a, 0x6000, 0x704e, - 0x6004, 0x7052, 0xa684, 0x0060, 0x0040, 0x2c64, 0x68a8, 0x78d2, - 0x78da, 0x68a4, 0x78d6, 0x78de, 0x077f, 0x1078, 0x3099, 0x2009, - 0x0068, 0xa684, 0x0008, 0x0040, 0x2c6f, 0x2009, 0x0067, 0xa6b5, - 0x2000, 0x7e5a, 0x791a, 0xa684, 0x0060, 0x0040, 0x2c85, 0xa684, - 0x0800, 0x00c0, 0x2c7f, 0x1078, 0x3571, 0x0078, 0x2c85, 0xa684, - 0x4000, 0x00c0, 0x2c85, 0x1078, 0x3502, 0x2d00, 0x703e, 0x8207, - 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xa080, 0x3a00, 0x2048, - 0x0078, 0x1efb, 0x6020, 0xa005, 0x0040, 0x2c9e, 0x8001, 0x6022, - 0x6008, 0xa085, 0x0008, 0x600a, 0x7010, 0x6026, 0x007c, 0xa006, - 0x1078, 0x32f5, 0x6817, 0x0000, 0x681b, 0x0001, 0x6823, 0x0040, - 0x681f, 0x0100, 0x7000, 0xa084, 0x0007, 0x0079, 0x2caf, 0x2cb7, - 0x2cb9, 0x2cb9, 0x2cc5, 0x2cc1, 0x2cb7, 0x2cc1, 0x2cb7, 0x1078, - 0x1eac, 0x1078, 0x2cd0, 0x1078, 0x2cc9, 0x1078, 0x1a26, 0x0078, - 0x1f03, 0x70a3, 0x0000, 0x0078, 0x1f03, 0x681b, 0x0000, 0x0078, - 0x2871, 0x6800, 0xa005, 0x00c0, 0x2cce, 0x6002, 0x6006, 0x007c, - 0x6010, 0xa005, 0x0040, 0x2cd9, 0x8001, 0x00d0, 0x2cd9, 0x1078, - 0x1eac, 0x6012, 0x6008, 0xa084, 0xffef, 0x600a, 0x007c, 0x6018, - 0xa005, 0x0040, 0x2ce5, 0x8001, 0x601a, 0x007c, 0x1078, 0x316a, - 0x6818, 0xa084, 0x8000, 0x0040, 0x2cef, 0x681b, 0x0018, 0x0078, - 0x2d26, 0x1078, 0x316a, 0x6818, 0xa084, 0x8000, 0x0040, 0x2cfa, - 0x681b, 0x0019, 0x0078, 0x2d26, 0x1078, 0x316a, 0x6818, 0xa084, - 0x8000, 0x0040, 0x2d05, 0x681b, 0x001a, 0x0078, 0x2d26, 0x1078, - 0x316a, 0x681b, 0x0003, 0x0078, 0x2d26, 0x71b8, 0xa18c, 0x00ff, - 0xa1e8, 0x4280, 0x2d04, 0x2d08, 0x2068, 0xa005, 0x00c0, 0x2d1a, - 0x0078, 0x1f03, 0x6814, 0x72b4, 0xa206, 0x0040, 0x2d22, 0x6800, - 0x0078, 0x2d13, 0x6800, 0x200a, 0x681b, 0x0005, 0x681f, 0x0000, - 0x6823, 0x0020, 0x1078, 0x2cd0, 0x1078, 0x2cc9, 0x1078, 0x1a26, - 0x0078, 0x1f03, 0xa282, 0x0003, 0x00c0, 0x2f69, 0x7da8, 0xa5ac, - 0x00ff, 0x7ea8, 0xa6b4, 0x00ff, 0x6920, 0xa18d, 0x0080, 0x6922, - 0xa184, 0x0100, 0x0040, 0x2d92, 0xa18c, 0xfeff, 0x6922, 0xa6b4, - 0x00ff, 0x0040, 0x2d7c, 0xa682, 0x000c, 0x0048, 0x2d53, 0x0040, - 0x2d53, 0x2031, 0x000c, 0x852b, 0x852b, 0x1078, 0x3018, 0x0040, - 0x2d5d, 0x1078, 0x2e4a, 0x0078, 0x2d85, 0x1078, 0x2fd3, 0x0c7e, - 0x2960, 0x6004, 0xa084, 0xfff5, 0x6006, 0x1078, 0x2e6e, 0x0c7f, - 0x6920, 0xa18d, 0x0100, 0x6922, 0x7e58, 0xa6b5, 0x0004, 0x7e5a, - 0xa684, 0x0400, 0x00c0, 0x2d78, 0x781b, 0x0053, 0x0078, 0x1efb, - 0x781b, 0x0067, 0x0078, 0x1efb, 0x0c7e, 0x2960, 0x6004, 0xa084, - 0xfff5, 0x6006, 0x1078, 0x2e6e, 0x0c7f, 0x7e58, 0xa684, 0x0400, - 0x00c0, 0x2d8e, 0x781b, 0x0056, 0x0078, 0x1efb, 0x781b, 0x0068, - 0x0078, 0x1efb, 0x0c7e, 0x7048, 0x2060, 0x6100, 0xa18c, 0x1000, - 0x0040, 0x2dd2, 0x6208, 0x8217, 0xa294, 0x00ff, 0xa282, 0x000c, - 0x0048, 0x2da6, 0x0040, 0x2da6, 0x2011, 0x000c, 0x2600, 0xa202, - 0x00c8, 0x2dab, 0x2230, 0x6208, 0xa294, 0x00ff, 0x7018, 0xa086, - 0x0028, 0x00c0, 0x2dbb, 0xa282, 0x0019, 0x00c8, 0x2dc1, 0x2011, - 0x0019, 0x0078, 0x2dc1, 0xa282, 0x000c, 0x00c8, 0x2dc1, 0x2011, - 0x000c, 0x2200, 0xa502, 0x00c8, 0x2dc6, 0x2228, 0x1078, 0x2fd7, - 0x852b, 0x852b, 0x1078, 0x3018, 0x0040, 0x2dd2, 0x1078, 0x2e4a, - 0x0078, 0x2dd6, 0x1078, 0x2fd3, 0x1078, 0x2e6e, 0x7858, 0xa085, - 0x0004, 0x785a, 0x0c7f, 0x781b, 0x0067, 0x0078, 0x1efb, 0x0c7e, - 0x2960, 0x6000, 0xa084, 0x1000, 0x00c0, 0x2df7, 0x6010, 0xa084, - 0x000f, 0x00c0, 0x2df1, 0x6104, 0xa18c, 0xfff5, 0x6106, 0x0c7f, - 0x007c, 0x2011, 0x0032, 0x2019, 0x0000, 0x0078, 0x2e1e, 0x68a0, - 0xa084, 0x0200, 0x00c0, 0x2df1, 0x6208, 0xa294, 0x00ff, 0x7018, - 0xa086, 0x0028, 0x00c0, 0x2e0c, 0xa282, 0x0019, 0x00c8, 0x2e12, - 0x2011, 0x0019, 0x0078, 0x2e12, 0xa282, 0x000c, 0x00c8, 0x2e12, + 0x32df, 0xa084, 0x0800, 0x0040, 0x32d9, 0x1078, 0x369b, 0x0078, + 0x32df, 0x1078, 0x3697, 0x708b, 0x0000, 0x0078, 0x32df, 0x027e, + 0x8207, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xa080, 0x5280, + 0x2060, 0x7056, 0x6000, 0x705a, 0x6004, 0x705e, 0xa684, 0x0060, + 0x0040, 0x3337, 0x6b98, 0x6c94, 0x69ac, 0x68b0, 0xa105, 0x00c0, + 0x3319, 0x7bd2, 0x7bda, 0x7cd6, 0x7cde, 0xa6b4, 0xb7ff, 0x7e5a, + 0xa684, 0x0060, 0xa086, 0x0060, 0x0040, 0x3337, 0x68c0, 0xa005, + 0x0040, 0x3312, 0x7003, 0x0003, 0x682b, 0x0000, 0x1078, 0x48e6, + 0x0078, 0x3314, 0x1078, 0x48f7, 0xa6b5, 0x2000, 0x7e5a, 0x0078, + 0x3337, 0x68b0, 0xa31a, 0x2100, 0xa423, 0x2400, 0xa305, 0x0040, + 0x3337, 0x7bd2, 0x7bda, 0x7cd6, 0x7cde, 0x68b0, 0xa6b4, 0xbfff, + 0x7e5a, 0x007e, 0x68c0, 0xa005, 0x007f, 0x0040, 0x3335, 0x7003, + 0x0003, 0x1078, 0x48e6, 0x0078, 0x3337, 0x1078, 0x4942, 0x077f, + 0x1078, 0x37bd, 0x2009, 0x0065, 0xa684, 0x0004, 0x0040, 0x3358, + 0x78e4, 0xa084, 0x0030, 0x0040, 0x3350, 0x78ec, 0xa084, 0x0003, + 0x0040, 0x3350, 0x782b, 0x3008, 0x2009, 0x0065, 0x0078, 0x3358, + 0x0f7e, 0x2079, 0x5000, 0x1078, 0x4633, 0x0f7f, 0x0040, 0x2461, + 0x791a, 0x2d00, 0x704a, 0x8207, 0xa084, 0x000f, 0x8003, 0x8003, + 0x8003, 0xa080, 0x5280, 0x2048, 0x0078, 0x2438, 0x6020, 0xa005, + 0x0040, 0x3372, 0x8001, 0x6022, 0x6008, 0xa085, 0x0008, 0x600a, + 0x7010, 0x6026, 0x007c, 0xa006, 0x1078, 0x4633, 0x6817, 0x0000, + 0x681b, 0x0001, 0x6823, 0x0040, 0x681f, 0x0100, 0x7000, 0xa084, + 0x0007, 0x0079, 0x3383, 0x2461, 0x338d, 0x338d, 0x33aa, 0x3395, + 0x3393, 0x3395, 0x338b, 0x1078, 0x23ca, 0x1078, 0x33b5, 0x1078, + 0x33ae, 0x1078, 0x1c53, 0x0078, 0x2461, 0x706c, 0x706f, 0x0000, + 0x7093, 0x0000, 0x0079, 0x339c, 0x33a6, 0x33a6, 0x33a4, 0x33a4, + 0x33a4, 0x33a6, 0x33a4, 0x33a6, 0x0079, 0x2840, 0x706f, 0x0000, + 0x0078, 0x2461, 0x681b, 0x0000, 0x0078, 0x2eed, 0x6800, 0xa005, + 0x00c0, 0x33b3, 0x6002, 0x6006, 0x007c, 0x6010, 0xa005, 0x0040, + 0x33be, 0x8001, 0x00d0, 0x33be, 0x1078, 0x23ca, 0x6012, 0x6008, + 0xa084, 0xffef, 0x600a, 0x007c, 0x6018, 0xa005, 0x0040, 0x33ca, + 0x8001, 0x601a, 0x007c, 0x1078, 0x38de, 0x681b, 0x0018, 0x0078, + 0x3401, 0x1078, 0x38de, 0x681b, 0x0019, 0x0078, 0x3401, 0x1078, + 0x38de, 0x681b, 0x001a, 0x0078, 0x3401, 0x1078, 0x38de, 0x681b, + 0x0003, 0x0078, 0x3401, 0x7780, 0x1078, 0x37bd, 0x7184, 0xa18c, + 0x00ff, 0xa1e8, 0x7300, 0x2d04, 0x2d08, 0x2068, 0xa005, 0x00c0, + 0x33f3, 0x0078, 0x2461, 0x6814, 0x7280, 0xa206, 0x0040, 0x33fb, + 0x6800, 0x0078, 0x33ec, 0x6800, 0x200a, 0x681b, 0x0005, 0x708b, + 0x0000, 0x1078, 0x33b5, 0x6820, 0xa084, 0x0001, 0x00c0, 0x340a, + 0x1078, 0x33ae, 0x1078, 0x33c4, 0x681f, 0x0000, 0x6823, 0x0020, + 0x1078, 0x1c53, 0x0078, 0x2461, 0xa282, 0x0003, 0x00c0, 0x366b, + 0x7da8, 0xa5ac, 0x00ff, 0x7ca8, 0xa4a4, 0x00ff, 0x6920, 0xa18d, + 0x0080, 0x6922, 0xa184, 0x0100, 0x0040, 0x3478, 0xa18c, 0xfeff, + 0x6922, 0xa4a4, 0x00ff, 0x0040, 0x3462, 0xa482, 0x000c, 0x0048, + 0x3435, 0x0040, 0x3435, 0x2021, 0x000c, 0x852b, 0x852b, 0x1078, + 0x372e, 0x0040, 0x343f, 0x1078, 0x3531, 0x0078, 0x346b, 0x1078, + 0x36e9, 0x0c7e, 0x2960, 0x6004, 0xa084, 0xfff5, 0x6006, 0x1078, + 0x3558, 0x0c7f, 0x6920, 0xa18d, 0x0100, 0x6922, 0x7e58, 0xa6b5, + 0x0004, 0x7e5a, 0xa684, 0x0400, 0x00c0, 0x345c, 0x782b, 0x3008, + 0x781b, 0x0056, 0x0078, 0x2438, 0x782b, 0x3008, 0x781b, 0x0065, + 0x0078, 0x2438, 0x0c7e, 0x2960, 0x6004, 0xa084, 0xfff5, 0x6006, + 0x1078, 0x3558, 0x0c7f, 0x7e58, 0xa684, 0x0400, 0x00c0, 0x3474, + 0x781b, 0x0058, 0x0078, 0x2438, 0x781b, 0x0065, 0x0078, 0x2438, + 0x0c7e, 0x7054, 0x2060, 0x6100, 0xa18c, 0x1000, 0x0040, 0x34b8, + 0x6208, 0x8217, 0xa294, 0x00ff, 0xa282, 0x000c, 0x0048, 0x348c, + 0x0040, 0x348c, 0x2011, 0x000c, 0x2400, 0xa202, 0x00c8, 0x3491, + 0x2220, 0x6208, 0xa294, 0x00ff, 0x7018, 0xa086, 0x0028, 0x00c0, + 0x34a1, 0xa282, 0x0019, 0x00c8, 0x34a7, 0x2011, 0x0019, 0x0078, + 0x34a7, 0xa282, 0x000c, 0x00c8, 0x34a7, 0x2011, 0x000c, 0x2200, + 0xa502, 0x00c8, 0x34ac, 0x2228, 0x1078, 0x36ed, 0x852b, 0x852b, + 0x1078, 0x372e, 0x0040, 0x34b8, 0x1078, 0x3531, 0x0078, 0x34bc, + 0x1078, 0x36e9, 0x1078, 0x3558, 0x7858, 0xa085, 0x0004, 0x785a, + 0x0c7f, 0x782b, 0x3008, 0x781b, 0x0065, 0x0078, 0x2438, 0x0c7e, + 0x2960, 0x6000, 0xa084, 0x1000, 0x00c0, 0x34df, 0x6010, 0xa084, + 0x000f, 0x00c0, 0x34d9, 0x6104, 0xa18c, 0xfff5, 0x6106, 0x0c7f, + 0x007c, 0x2011, 0x0032, 0x2019, 0x0000, 0x0078, 0x3506, 0x68a0, + 0xa084, 0x0200, 0x00c0, 0x34d9, 0x6208, 0xa294, 0x00ff, 0x7018, + 0xa086, 0x0028, 0x00c0, 0x34f4, 0xa282, 0x0019, 0x00c8, 0x34fa, + 0x2011, 0x0019, 0x0078, 0x34fa, 0xa282, 0x000c, 0x00c8, 0x34fa, 0x2011, 0x000c, 0x6308, 0x831f, 0xa39c, 0x00ff, 0xa382, 0x000c, - 0x0048, 0x2e1e, 0x0040, 0x2e1e, 0x2019, 0x000c, 0x78ab, 0x0001, + 0x0048, 0x3506, 0x0040, 0x3506, 0x2019, 0x000c, 0x78ab, 0x0001, 0x78ab, 0x0003, 0x78ab, 0x0001, 0x7aaa, 0x7baa, 0xa8c0, 0x0005, 0x6820, 0xa085, 0x0100, 0x6822, 0x0c7f, 0x007c, 0x0c7e, 0x2960, - 0x6104, 0xa18c, 0xfff5, 0x6106, 0x2011, 0x0032, 0x2019, 0x0000, - 0x0078, 0x2e3a, 0x78ab, 0x0001, 0x78ab, 0x0003, 0x78ab, 0x0001, - 0x7aaa, 0x7baa, 0xa8c0, 0x0005, 0x6820, 0xa085, 0x0100, 0x6822, - 0x0c7f, 0x007c, 0x0c7e, 0x7148, 0x2160, 0x2008, 0xa084, 0xfff0, - 0xa635, 0x7e86, 0x6018, 0x789a, 0x7eae, 0x6612, 0x78a4, 0xa084, - 0xfff8, 0xa18c, 0x0007, 0xa105, 0x78a6, 0x6016, 0x788a, 0xa6b4, - 0x000f, 0x8637, 0x8204, 0x8004, 0xa084, 0x00ff, 0xa605, 0x600e, - 0x6004, 0xa084, 0xfff5, 0x6006, 0x0c7f, 0x007c, 0x0c7e, 0x7048, - 0x2060, 0x6018, 0x789a, 0x78a4, 0xa084, 0xfff0, 0x78a6, 0x6012, - 0x7884, 0xa084, 0xfff0, 0x7886, 0x0c7f, 0x007c, 0xa282, 0x0002, - 0x00c0, 0x2f69, 0x7aa8, 0x6920, 0xa18d, 0x0080, 0x6922, 0xa184, - 0x0200, 0x0040, 0x2ec3, 0xa18c, 0xfdff, 0x6922, 0xa294, 0x00ff, - 0xa282, 0x0002, 0x00c8, 0x2f69, 0x1078, 0x2f0a, 0x1078, 0x2e6e, - 0xa980, 0x0001, 0x200c, 0x1078, 0x3095, 0x1078, 0x2ddf, 0x88ff, - 0x0040, 0x2eb6, 0x789b, 0x0060, 0x2800, 0x78aa, 0x7e58, 0xa6b5, - 0x0004, 0x7e5a, 0xa684, 0x0400, 0x00c0, 0x2eb2, 0x781b, 0x0053, - 0x0078, 0x1efb, 0x781b, 0x0067, 0x0078, 0x1efb, 0x7e58, 0xa684, - 0x0400, 0x00c0, 0x2ebf, 0x781b, 0x0056, 0x0078, 0x1efb, 0x781b, - 0x0068, 0x0078, 0x1efb, 0xa282, 0x0002, 0x00c8, 0x2ecb, 0xa284, - 0x0001, 0x0040, 0x2ed5, 0x7148, 0xa188, 0x0000, 0x210c, 0xa18c, - 0x2000, 0x00c0, 0x2ed5, 0x2011, 0x0000, 0x1078, 0x2fc5, 0x1078, - 0x2f0a, 0x1078, 0x2e6e, 0x7858, 0xa085, 0x0004, 0x785a, 0x781b, - 0x0067, 0x0078, 0x1efb, 0x0c7e, 0x027e, 0x2960, 0x6000, 0x2011, - 0x0001, 0xa084, 0x2000, 0x00c0, 0x2efa, 0x6014, 0xa084, 0x0040, - 0x00c0, 0x2ef8, 0xa18c, 0xffef, 0x6106, 0xa006, 0x0078, 0x2f07, - 0x2011, 0x0000, 0x78ab, 0x0001, 0x78ab, 0x0002, 0x78ab, 0x0003, - 0x7aaa, 0xa8c0, 0x0004, 0x6820, 0xa085, 0x0200, 0x6822, 0x027f, - 0x0c7f, 0x007c, 0x0c7e, 0x7048, 0x2060, 0x82ff, 0x0040, 0x2f12, - 0x2011, 0x0040, 0x6018, 0xa080, 0x0002, 0x789a, 0x78a4, 0xa084, - 0xffbf, 0xa205, 0x78a6, 0x6016, 0x788a, 0x6004, 0xa084, 0xffef, - 0x6006, 0x0c7f, 0x007c, 0xa684, 0x0020, 0x0040, 0x2f65, 0x7888, - 0xa084, 0x0040, 0x0040, 0x2f65, 0x7bb8, 0xa384, 0x003f, 0x831b, - 0x00c8, 0x2f33, 0x8000, 0xa005, 0x0040, 0x2f4c, 0x831b, 0x00c8, - 0x2f3c, 0x8001, 0x0040, 0x2f61, 0xa684, 0x4000, 0x0040, 0x2f4c, - 0x78b8, 0x801b, 0x00c8, 0x2f45, 0x8000, 0xa084, 0x003f, 0x00c0, - 0x2f61, 0xa6b4, 0xbfff, 0x7e5a, 0x79d8, 0x7adc, 0x2001, 0x0001, - 0xa108, 0x00c8, 0x2f55, 0xa291, 0x0000, 0x79d2, 0x79da, 0x7ad6, - 0x7ade, 0x1078, 0x362f, 0x781b, 0x0065, 0x1078, 0x3502, 0x0078, - 0x1efb, 0x781b, 0x0065, 0x0078, 0x1efb, 0x781b, 0x0068, 0x0078, - 0x1efb, 0x1078, 0x2f91, 0x781b, 0x0067, 0x0078, 0x1efb, 0x1078, - 0x2f7d, 0x781b, 0x0067, 0x0078, 0x1efb, 0x6827, 0x0002, 0x1078, - 0x2f85, 0x781b, 0x0067, 0x0078, 0x1efb, 0x2001, 0x0005, 0x0078, - 0x2f93, 0x2001, 0x000c, 0x0078, 0x2f93, 0x2001, 0x0006, 0x0078, - 0x2f93, 0x2001, 0x000d, 0x0078, 0x2f93, 0x2001, 0x0009, 0x0078, - 0x2f93, 0x2001, 0x0007, 0x789b, 0x007e, 0x78aa, 0xa6b5, 0x0008, - 0x7e5a, 0x007c, 0x077e, 0x873f, 0xa7bc, 0x000f, 0x873b, 0x873b, - 0x8703, 0xa0e0, 0x3a00, 0xa7b8, 0x0020, 0x7f9a, 0x79a4, 0xa184, - 0x000f, 0x0040, 0x2fb3, 0xa184, 0xfff0, 0x78a6, 0x6012, 0x6004, - 0xa085, 0x0008, 0x6006, 0x8738, 0x8738, 0x7f9a, 0x79a4, 0xa184, - 0x0040, 0x0040, 0x2fc3, 0xa184, 0xffbf, 0x78a6, 0x6016, 0x6004, - 0xa085, 0x0010, 0x6006, 0x077f, 0x007c, 0x789b, 0x0010, 0x78ab, - 0x0001, 0x78ab, 0x0002, 0x78ab, 0x0003, 0x7aaa, 0x789b, 0x0060, - 0x78ab, 0x0004, 0x007c, 0x2031, 0x0000, 0x2029, 0x0032, 0x789b, - 0x0010, 0x78ab, 0x0001, 0x78ab, 0x0003, 0x78ab, 0x0001, 0x7daa, - 0x7eaa, 0x789b, 0x0060, 0x78ab, 0x0005, 0x007c, 0x157e, 0x8007, - 0xa084, 0x00ff, 0x8003, 0x8003, 0xa080, 0x0020, 0x789a, 0x79a4, - 0xa18c, 0xfff0, 0x2001, 0x3946, 0x2004, 0xa082, 0x0028, 0x0040, - 0x3001, 0x2021, 0x307c, 0x2019, 0x0014, 0x20a9, 0x000c, 0x0078, - 0x3007, 0x2021, 0x3088, 0x2019, 0x0019, 0x20a9, 0x000d, 0x2011, - 0x0064, 0x2404, 0xa084, 0xfff0, 0xa106, 0x0040, 0x3016, 0x8420, - 0x2300, 0xa210, 0x0070, 0x3016, 0x0078, 0x3009, 0x157f, 0x007c, - 0x157e, 0x2011, 0x3946, 0x2214, 0xa282, 0x0032, 0x0048, 0x302c, - 0x0040, 0x3030, 0x2021, 0x306e, 0x2019, 0x0011, 0x20a9, 0x000e, - 0x2011, 0x0032, 0x0078, 0x3042, 0xa282, 0x0028, 0x0040, 0x303a, - 0x2021, 0x307c, 0x2019, 0x0014, 0x20a9, 0x000c, 0x2011, 0x0064, - 0x0078, 0x3042, 0x2021, 0x3088, 0x2019, 0x0019, 0x20a9, 0x000d, - 0x2011, 0x0064, 0x2200, 0xa502, 0x0040, 0x3052, 0x0048, 0x3052, - 0x8420, 0x2300, 0xa210, 0x0070, 0x304f, 0x0078, 0x3042, 0x157f, - 0xa006, 0x007c, 0x157f, 0x7a08, 0xa582, 0x0064, 0x00c8, 0x305d, - 0xa285, 0x0040, 0x780a, 0x0078, 0x305d, 0x78ec, 0xa084, 0x0300, - 0x0040, 0x306b, 0x2404, 0xa09e, 0x2002, 0x00c0, 0x306b, 0x2001, - 0x2101, 0x0078, 0x306c, 0x2404, 0xa015, 0x007c, 0x2002, 0x3002, - 0x3202, 0x4203, 0x4403, 0x5404, 0x5604, 0x6605, 0x6805, 0x7806, - 0x7a06, 0x0a07, 0x0c07, 0x0e07, 0x3202, 0x4202, 0x5202, 0x6202, - 0x7202, 0x6605, 0x7605, 0x7805, 0x7a05, 0x7c05, 0x7e05, 0x7f05, - 0x2202, 0x3202, 0x4202, 0x5202, 0x5404, 0x6404, 0x7404, 0x7604, - 0x7804, 0x7a04, 0x7c04, 0x7e04, 0x7f04, 0x789b, 0x0010, 0xa046, - 0x007c, 0xa784, 0x0f00, 0x800c, 0xa784, 0x0007, 0x8003, 0x8003, - 0x8003, 0x8003, 0xa105, 0xa0e0, 0x3a80, 0x007c, 0x79d8, 0x7adc, - 0x78d0, 0x801b, 0x00c8, 0x30ad, 0x8000, 0xa084, 0x003f, 0xa108, - 0xa291, 0x0000, 0x007c, 0x0f7e, 0x2079, 0x0100, 0x2009, 0x3940, - 0x2091, 0x8000, 0x2104, 0x0079, 0x30bd, 0x30e3, 0x30c7, 0x30c7, - 0x30c7, 0x30c7, 0x30c7, 0x30c7, 0x30c5, 0x1078, 0x1eac, 0x784b, - 0x0004, 0x68b4, 0xa085, 0x4000, 0x68b6, 0x7858, 0xa085, 0x4000, - 0x785a, 0x7830, 0xa084, 0x0080, 0x00c0, 0x30e3, 0x0018, 0x30e3, - 0x681c, 0xa084, 0x0020, 0x00c0, 0x30e1, 0x781b, 0x00df, 0x0078, - 0x30e3, 0x781b, 0x00e6, 0x2091, 0x8001, 0x0f7f, 0x007c, 0x0c7e, + 0xa18c, 0xfff5, 0x6106, 0x2011, 0x0032, 0x2019, 0x0000, 0x0078, + 0x3521, 0x78ab, 0x0001, 0x78ab, 0x0003, 0x78ab, 0x0001, 0x7aaa, + 0x7baa, 0xa8c0, 0x0005, 0x6820, 0xa085, 0x0100, 0x6822, 0x0c7f, + 0x007c, 0x0c7e, 0x7154, 0x2160, 0x1078, 0x3538, 0x0c7f, 0x007c, + 0x2008, 0xa084, 0xfff0, 0xa425, 0x7c86, 0x6018, 0x789a, 0x7cae, + 0x6412, 0x78a4, 0xa084, 0xfff8, 0xa18c, 0x0007, 0xa105, 0x78a6, + 0x6016, 0x788a, 0xa4a4, 0x000f, 0x8427, 0x8204, 0x8004, 0xa084, + 0x00ff, 0xa405, 0x600e, 0x6004, 0xa084, 0xfff5, 0x6006, 0x007c, + 0x0c7e, 0x7054, 0x2060, 0x1078, 0x355f, 0x0c7f, 0x007c, 0x6018, + 0x789a, 0x78a4, 0xa084, 0xfff0, 0x78a6, 0x6012, 0x7884, 0xa084, + 0xfff0, 0x7886, 0x007c, 0xa282, 0x0002, 0x00c0, 0x366b, 0x7aa8, + 0x6920, 0xa18d, 0x0080, 0x6922, 0xa184, 0x0200, 0x0040, 0x35b4, + 0xa18c, 0xfdff, 0x6922, 0xa294, 0x00ff, 0xa282, 0x0002, 0x00c8, + 0x366b, 0x1078, 0x35fd, 0x1078, 0x3558, 0xa980, 0x0001, 0x200c, + 0x1078, 0x37b9, 0x1078, 0x34c7, 0x88ff, 0x0040, 0x35a7, 0x789b, + 0x0060, 0x2800, 0x78aa, 0x7e58, 0xa6b5, 0x0004, 0x7e5a, 0xa684, + 0x0400, 0x00c0, 0x35a1, 0x782b, 0x3008, 0x781b, 0x0056, 0x0078, + 0x2438, 0x782b, 0x3008, 0x781b, 0x0065, 0x0078, 0x2438, 0x7e58, + 0xa684, 0x0400, 0x00c0, 0x35b0, 0x781b, 0x0058, 0x0078, 0x2438, + 0x781b, 0x0065, 0x0078, 0x2438, 0xa282, 0x0002, 0x00c8, 0x35bc, + 0xa284, 0x0001, 0x0040, 0x35c6, 0x7154, 0xa188, 0x0000, 0x210c, + 0xa18c, 0x2000, 0x00c0, 0x35c6, 0x2011, 0x0000, 0x1078, 0x36db, + 0x1078, 0x35fd, 0x1078, 0x3558, 0x7858, 0xa085, 0x0004, 0x785a, + 0x782b, 0x3008, 0x781b, 0x0065, 0x0078, 0x2438, 0x0c7e, 0x027e, + 0x2960, 0x6000, 0x2011, 0x0001, 0xa084, 0x2000, 0x00c0, 0x35ed, + 0x6014, 0xa084, 0x0040, 0x00c0, 0x35eb, 0xa18c, 0xffef, 0x6106, + 0xa006, 0x0078, 0x35fa, 0x2011, 0x0000, 0x78ab, 0x0001, 0x78ab, + 0x0002, 0x78ab, 0x0003, 0x7aaa, 0xa8c0, 0x0004, 0x6820, 0xa085, + 0x0200, 0x6822, 0x027f, 0x0c7f, 0x007c, 0x0c7e, 0x7054, 0x2060, + 0x1078, 0x3604, 0x0c7f, 0x007c, 0x82ff, 0x0040, 0x3609, 0x2011, + 0x0040, 0x6018, 0xa080, 0x0002, 0x789a, 0x78a4, 0xa084, 0xffbf, + 0xa205, 0x78a6, 0x788a, 0x6016, 0x6004, 0xa084, 0xffef, 0x6006, + 0x007c, 0x007e, 0x7000, 0xa086, 0x0003, 0x0040, 0x3622, 0x007f, + 0x0078, 0x3625, 0x007f, 0x0078, 0x3667, 0xa684, 0x0020, 0x0040, + 0x3667, 0x7888, 0xa084, 0x0040, 0x0040, 0x3667, 0x7bb8, 0xa384, + 0x003f, 0x831b, 0x00c8, 0x3635, 0x8000, 0xa005, 0x0040, 0x364b, + 0x831b, 0x00c8, 0x363e, 0x8001, 0x0040, 0x3663, 0xa684, 0x4000, + 0x0040, 0x364b, 0x78b8, 0x801b, 0x00c8, 0x3647, 0x8000, 0xa084, + 0x003f, 0x00c0, 0x3663, 0xa6b4, 0xbfff, 0x7e5a, 0x79d8, 0x7adc, + 0x2001, 0x0001, 0xa108, 0x00c8, 0x3657, 0xa291, 0x0000, 0x79d2, + 0x79da, 0x7ad6, 0x7ade, 0x1078, 0x49ed, 0x781b, 0x0064, 0x1078, + 0x4872, 0x0078, 0x2438, 0x781b, 0x0064, 0x0078, 0x2438, 0x781b, + 0x0065, 0x0078, 0x2438, 0x1078, 0x36a3, 0x782b, 0x3008, 0x781b, + 0x0065, 0x0078, 0x2438, 0x1078, 0x368f, 0x782b, 0x3008, 0x781b, + 0x0065, 0x0078, 0x2438, 0x6827, 0x0002, 0x1078, 0x3697, 0x78e4, + 0xa084, 0x0030, 0x0040, 0x2461, 0x78ec, 0xa084, 0x0003, 0x0040, + 0x2461, 0x782b, 0x3008, 0x781b, 0x0065, 0x0078, 0x2438, 0x2001, + 0x0005, 0x0078, 0x36a5, 0x2001, 0x000c, 0x0078, 0x36a5, 0x2001, + 0x0006, 0x0078, 0x36a5, 0x2001, 0x000d, 0x0078, 0x36a5, 0x2001, + 0x0009, 0x0078, 0x36a5, 0x2001, 0x0007, 0x789b, 0x0010, 0x78aa, + 0x789b, 0x0060, 0x78ab, 0x0001, 0xa6b5, 0x0004, 0x7e5a, 0x007c, + 0x077e, 0x873f, 0xa7bc, 0x000f, 0x873b, 0x873b, 0x8703, 0xa0e0, + 0x5280, 0xa7b8, 0x0020, 0x7f9a, 0x79a4, 0xa184, 0x000f, 0x0040, + 0x36c9, 0xa184, 0xfff0, 0x78a6, 0x6012, 0x6004, 0xa085, 0x0008, + 0x6006, 0x8738, 0x8738, 0x7f9a, 0x79a4, 0xa184, 0x0040, 0x0040, + 0x36d9, 0xa184, 0xffbf, 0x78a6, 0x6016, 0x6004, 0xa085, 0x0010, + 0x6006, 0x077f, 0x007c, 0x789b, 0x0010, 0x78ab, 0x0001, 0x78ab, + 0x0002, 0x78ab, 0x0003, 0x7aaa, 0x789b, 0x0060, 0x78ab, 0x0004, + 0x007c, 0x2021, 0x0000, 0x2029, 0x0032, 0x789b, 0x0010, 0x78ab, + 0x0001, 0x78ab, 0x0003, 0x78ab, 0x0001, 0x7daa, 0x7caa, 0x789b, + 0x0060, 0x78ab, 0x0005, 0x007c, 0x157e, 0x8007, 0xa084, 0x00ff, + 0x8003, 0x8003, 0xa080, 0x0020, 0x789a, 0x79a4, 0xa18c, 0xfff0, + 0x2001, 0x5046, 0x2004, 0xa082, 0x0028, 0x0040, 0x3717, 0x2021, + 0x37a0, 0x2019, 0x0014, 0x20a9, 0x000c, 0x0078, 0x371d, 0x2021, + 0x37ac, 0x2019, 0x0019, 0x20a9, 0x000d, 0x2011, 0x0064, 0x2404, + 0xa084, 0xfff0, 0xa106, 0x0040, 0x372c, 0x8420, 0x2300, 0xa210, + 0x0070, 0x372c, 0x0078, 0x371f, 0x157f, 0x007c, 0x157e, 0x2009, + 0x5046, 0x210c, 0xa182, 0x0032, 0x0048, 0x3742, 0x0040, 0x3746, + 0x2009, 0x3792, 0x2019, 0x0011, 0x20a9, 0x000e, 0x2011, 0x0032, + 0x0078, 0x3758, 0xa182, 0x0028, 0x0040, 0x3750, 0x2009, 0x37a0, + 0x2019, 0x0014, 0x20a9, 0x000c, 0x2011, 0x0064, 0x0078, 0x3758, + 0x2009, 0x37ac, 0x2019, 0x0019, 0x20a9, 0x000d, 0x2011, 0x0064, + 0x2200, 0xa502, 0x0040, 0x3768, 0x0048, 0x3768, 0x8108, 0x2300, + 0xa210, 0x0070, 0x3765, 0x0078, 0x3758, 0x157f, 0xa006, 0x007c, + 0x157f, 0xa582, 0x0064, 0x00c8, 0x3777, 0x7808, 0xa085, 0x0070, + 0x780a, 0x7044, 0xa085, 0x0070, 0x7046, 0x0078, 0x3777, 0x78ec, + 0xa084, 0x0300, 0x0040, 0x377f, 0x2104, 0x0078, 0x3790, 0x2104, + 0xa09e, 0x1102, 0x00c0, 0x3790, 0x2001, 0x04fd, 0x2004, 0xa082, + 0x0005, 0x0048, 0x378f, 0x2001, 0x1201, 0x0078, 0x3790, 0x2104, + 0xa005, 0x007c, 0x1102, 0x3002, 0x3202, 0x4203, 0x4403, 0x5404, + 0x5604, 0x6605, 0x6805, 0x7806, 0x7a06, 0x0c07, 0x0c07, 0x0e07, + 0x3202, 0x4202, 0x5202, 0x6202, 0x7202, 0x6605, 0x7605, 0x7805, + 0x7a05, 0x7c05, 0x7e05, 0x7f05, 0x2202, 0x3202, 0x4202, 0x5202, + 0x5404, 0x6404, 0x7404, 0x7604, 0x7804, 0x7a04, 0x7c04, 0x7e04, + 0x7f04, 0x789b, 0x0010, 0xa046, 0x007c, 0xa784, 0x0f00, 0x800b, + 0xa784, 0x001f, 0x8003, 0x8003, 0x8003, 0x8003, 0xa105, 0xa0e0, + 0x5300, 0x007c, 0x79d8, 0x7adc, 0x78d0, 0x801b, 0x00c8, 0x37d1, + 0x8000, 0xa084, 0x003f, 0xa108, 0xa291, 0x0000, 0x007c, 0x0f7e, + 0x2079, 0x0100, 0x2009, 0x5040, 0x2091, 0x8000, 0x2104, 0x0079, + 0x37e1, 0x3817, 0x37eb, 0x37eb, 0x37eb, 0x37eb, 0x37eb, 0x37eb, + 0x381b, 0x1078, 0x23ca, 0x784b, 0x0004, 0x7848, 0xa084, 0x0004, + 0x00c0, 0x37ed, 0x784b, 0x0008, 0x7848, 0xa084, 0x0008, 0x00c0, + 0x37f4, 0x68b4, 0xa085, 0x4000, 0x68b6, 0x7858, 0xa085, 0x4000, + 0x785a, 0x7830, 0xa084, 0x0080, 0x00c0, 0x3817, 0x0018, 0x3817, + 0x681c, 0xa084, 0x0020, 0x00c0, 0x3815, 0x0e7e, 0x2071, 0x5040, + 0x1078, 0x3868, 0x0e7f, 0x0078, 0x3817, 0x781b, 0x00d2, 0x2091, + 0x8001, 0x0f7f, 0x007c, 0x1078, 0x3a42, 0x0078, 0x3817, 0x0c7e, 0x6814, 0x8007, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xa0e0, - 0x3a00, 0x6004, 0xa084, 0x000a, 0x00c0, 0x311a, 0x6108, 0xa194, - 0xff00, 0x0040, 0x311a, 0xa18c, 0x00ff, 0x2001, 0x0019, 0xa106, - 0x0040, 0x3109, 0x2001, 0x0032, 0xa106, 0x0040, 0x310d, 0x0078, - 0x3111, 0x2009, 0x0020, 0x0078, 0x3113, 0x2009, 0x003f, 0x0078, - 0x3113, 0x2011, 0x0000, 0x2100, 0xa205, 0x600a, 0x6004, 0xa085, - 0x0002, 0x6006, 0x0c7f, 0x007c, 0x781b, 0x0068, 0x0078, 0x1efb, - 0x781b, 0x0067, 0x0078, 0x1efb, 0x781b, 0x0056, 0x0078, 0x1efb, - 0x781b, 0x0053, 0x0078, 0x1efb, 0x781b, 0x00df, 0x0078, 0x1efb, - 0x781b, 0x00de, 0x0078, 0x1efb, 0x781b, 0x00e6, 0x0078, 0x1efb, - 0x781b, 0x00e5, 0x0078, 0x1efb, 0x781b, 0x009d, 0x0078, 0x1efb, - 0x781b, 0x009c, 0x0078, 0x1efb, 0x6818, 0xa084, 0x8000, 0x0040, - 0x314b, 0x681b, 0x001d, 0x70a3, 0x0001, 0x781b, 0x0047, 0x0078, - 0x1efb, 0x007e, 0x7830, 0xa084, 0x00c0, 0x00c0, 0x3168, 0x7808, - 0xa084, 0xfffd, 0x780a, 0x0005, 0x0005, 0x0005, 0x0005, 0x78ec, - 0xa084, 0x0021, 0x0040, 0x3168, 0x7808, 0xa085, 0x0002, 0x780a, - 0x007f, 0x007c, 0x7808, 0xa085, 0x0002, 0x780a, 0x007c, 0x7830, - 0xa084, 0x0040, 0x00c0, 0x316f, 0x0098, 0x3178, 0x78ac, 0x007c, + 0x5280, 0x6004, 0xa084, 0x000a, 0x00c0, 0x3852, 0x6108, 0xa194, + 0xff00, 0x0040, 0x3852, 0xa18c, 0x00ff, 0x2001, 0x0019, 0xa106, + 0x0040, 0x3841, 0x2001, 0x0032, 0xa106, 0x0040, 0x3845, 0x0078, + 0x3849, 0x2009, 0x0020, 0x0078, 0x384b, 0x2009, 0x003f, 0x0078, + 0x384b, 0x2011, 0x0000, 0x2100, 0xa205, 0x600a, 0x6004, 0xa085, + 0x0002, 0x6006, 0x0c7f, 0x007c, 0x781b, 0x0065, 0x0078, 0x2438, + 0x782b, 0x3008, 0x781b, 0x0065, 0x0078, 0x2438, 0x781b, 0x0058, + 0x0078, 0x2438, 0x782b, 0x3008, 0x781b, 0x0056, 0x0078, 0x2438, + 0x2009, 0x5020, 0x210c, 0xa186, 0x0000, 0x0040, 0x387c, 0xa186, + 0x0001, 0x0040, 0x387f, 0x2009, 0x5038, 0x200b, 0x000b, 0x706f, + 0x0001, 0x781b, 0x0048, 0x007c, 0x781b, 0x00cc, 0x007c, 0x2009, + 0x5038, 0x200b, 0x000a, 0x007c, 0x2009, 0x5020, 0x210c, 0xa186, + 0x0000, 0x0040, 0x389f, 0xa186, 0x0001, 0x0040, 0x3899, 0x2009, + 0x5038, 0x200b, 0x000b, 0x706f, 0x0001, 0x781b, 0x0048, 0x0078, + 0x2438, 0x2009, 0x5038, 0x200b, 0x000a, 0x0078, 0x2438, 0x782b, + 0x3008, 0x781b, 0x00cc, 0x0078, 0x2438, 0x781b, 0x00d2, 0x0078, + 0x2438, 0x782b, 0x3008, 0x781b, 0x00d2, 0x0078, 0x2438, 0x781b, + 0x0093, 0x0078, 0x2438, 0x782b, 0x3008, 0x781b, 0x0093, 0x0078, + 0x2438, 0x6818, 0xa084, 0x8000, 0x0040, 0x38c0, 0x681b, 0x001d, + 0x706f, 0x0001, 0x781b, 0x0048, 0x0078, 0x2438, 0x007e, 0x7830, + 0xa084, 0x00c0, 0x00c0, 0x38dc, 0x7808, 0xa084, 0xfffc, 0x780a, + 0x0005, 0x0005, 0x0005, 0x0005, 0x78ec, 0xa084, 0x0021, 0x0040, + 0x38dc, 0x7044, 0x780a, 0xa005, 0x007f, 0x007c, 0x7044, 0xa085, + 0x0002, 0x7046, 0x780a, 0x007c, 0x007e, 0x7830, 0xa084, 0x0040, + 0x00c0, 0x38e5, 0x0098, 0x38f0, 0x007f, 0x789a, 0x78ac, 0x007c, 0x7808, 0xa084, 0xfffd, 0x780a, 0x0005, 0x0005, 0x0005, 0x0005, - 0x78ec, 0xa084, 0x0021, 0x0040, 0x3187, 0x0098, 0x3185, 0x78ac, - 0x007e, 0x7808, 0xa085, 0x0002, 0x780a, 0x007f, 0x007c, 0xa784, - 0x0070, 0x0040, 0x319b, 0x0c7e, 0x2d60, 0x2f68, 0x1078, 0x1e57, - 0x2d78, 0x2c68, 0x0c7f, 0xa784, 0x0008, 0x0040, 0x31a8, 0x784b, - 0x0008, 0x78ec, 0xa084, 0x0003, 0x0040, 0x1f03, 0x0078, 0x311c, - 0xa784, 0x0004, 0x0040, 0x31db, 0x78b8, 0xa084, 0x4001, 0x0040, - 0x31db, 0x784b, 0x0008, 0x78ec, 0xa084, 0x0003, 0x0040, 0x1f03, - 0x78e4, 0xa084, 0x0007, 0xa086, 0x0001, 0x00c0, 0x31db, 0x78c0, - 0xa685, 0x4800, 0x2030, 0x7e5a, 0x781b, 0x00e6, 0x0078, 0x1efb, - 0x784b, 0x0008, 0x6818, 0xa084, 0x8000, 0x0040, 0x31d7, 0x681b, - 0x0015, 0xa684, 0x4000, 0x0040, 0x31d7, 0x681b, 0x0007, 0x781b, - 0x00df, 0x0078, 0x1efb, 0x681b, 0x0003, 0x7858, 0xa084, 0x3f00, - 0x681e, 0x682f, 0x0000, 0x6833, 0x0000, 0x784b, 0x0008, 0x78e4, - 0xa005, 0x00d0, 0x238a, 0xa084, 0x0020, 0x0040, 0x238a, 0x0018, - 0x238a, 0x0078, 0x2f6f, 0x6b14, 0x8307, 0xa084, 0x000f, 0x8003, - 0x8003, 0x8003, 0xa080, 0x3a00, 0x2060, 0x2048, 0x704a, 0x6000, - 0x704e, 0x6004, 0x7052, 0x2a60, 0x007c, 0x0020, 0x0020, 0x0000, - 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, - 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, - 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, - 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0062, - 0x0009, 0x0014, 0x0014, 0x9848, 0x0014, 0x0014, 0x98f9, 0x98e9, - 0x0014, 0x0014, 0x0080, 0x00c0, 0x0100, 0x0402, 0x2008, 0xf880, - 0x0018, 0xa20a, 0x0014, 0x300b, 0xa20c, 0x0014, 0xa200, 0x8838, - 0x3806, 0x8839, 0x28c2, 0x9cc2, 0xa805, 0x0864, 0xa83d, 0x3008, - 0x28c1, 0x9cc2, 0xa201, 0x300c, 0x2847, 0x8161, 0x846a, 0x8000, - 0x84a4, 0x1856, 0x883a, 0xa808, 0x28e2, 0x9c9f, 0xa8f3, 0x0864, - 0xa82b, 0x300c, 0xa801, 0x3008, 0x28e1, 0x9c9f, 0x280d, 0xa204, - 0x64c0, 0x67a0, 0x6fc0, 0x1814, 0x883b, 0x7023, 0x8576, 0x8677, - 0xa80f, 0x786e, 0x883e, 0xa80c, 0x282b, 0xa205, 0x64a0, 0x67a0, - 0x6fc0, 0x1814, 0x883b, 0x7023, 0x8576, 0x8677, 0xa801, 0x883e, - 0x206b, 0x28c1, 0x9cc2, 0x2044, 0x2103, 0x20a2, 0x2081, 0xa8dc, - 0xa207, 0x2901, 0xa80a, 0x0014, 0xa203, 0x8000, 0x85a4, 0x1872, - 0x879a, 0x883c, 0x1fe2, 0xf601, 0xa208, 0x856e, 0x866f, 0x0704, - 0x3008, 0x9c9f, 0x0014, 0xa202, 0x8000, 0x85a4, 0x3009, 0x84a8, - 0x19e2, 0xf848, 0x8174, 0x86eb, 0x85eb, 0x872e, 0x87a9, 0x883f, - 0x08e6, 0xa8f1, 0xf861, 0xa8e8, 0xf801, 0x0014, 0xf881, 0x0016, - 0x85b2, 0x80f0, 0x9532, 0xfaa2, 0x1de2, 0x0014, 0x8532, 0xf221, - 0x0014, 0x1de2, 0x84a8, 0xd6e0, 0x1fe6, 0x0014, 0xa206, 0x6865, - 0x817e, 0x842a, 0x1dc1, 0x8823, 0x0016, 0x6042, 0x8008, 0xa8fa, - 0x8000, 0x84a4, 0x8160, 0x842a, 0xf021, 0x3008, 0x84a8, 0x11d6, - 0x7042, 0x20dd, 0x0011, 0x20d4, 0x8822, 0x0016, 0x8000, 0x2848, - 0x1011, 0xa8fc, 0x3008, 0x8000, 0xa000, 0x2802, 0x1011, 0xa8fd, - 0xa883, 0x3008, 0x283d, 0x1011, 0xa8fd, 0xa209, 0x0017, 0x300c, - 0x8000, 0x85a4, 0x1de2, 0xdac1, 0x0014, 0xd301, 0x0014, 0x26e0, - 0x873a, 0xfaa2, 0x19f2, 0x1fe2, 0x0014, 0xa20b, 0x0014, 0xa20d, - 0x3806, 0x0210, 0x9ccc, 0x0704, 0x0000, 0x127e, 0x2091, 0x2200, - 0x2049, 0x32f5, 0x7000, 0x7204, 0xa205, 0x720c, 0xa215, 0x7008, - 0xa084, 0xfff7, 0xa205, 0x0040, 0x3307, 0x1078, 0x3380, 0x127f, - 0x2000, 0x007c, 0x6428, 0x84ff, 0x0040, 0x3336, 0x2c70, 0x7004, - 0xa0bc, 0x000f, 0xa7b8, 0x3346, 0x273c, 0x87fb, 0x00c0, 0x3324, - 0x0048, 0x331c, 0x1078, 0x1eac, 0x609c, 0xa075, 0x0040, 0x3336, - 0x0078, 0x330f, 0x2039, 0x333b, 0x2704, 0xae68, 0x6808, 0xa630, - 0x680c, 0xa529, 0x8421, 0x0040, 0x3336, 0x8738, 0x2704, 0xa005, - 0x00c0, 0x3325, 0x709c, 0xa075, 0x00c0, 0x330f, 0x007c, 0x0000, - 0x0005, 0x0009, 0x000d, 0x0011, 0x0015, 0x0019, 0x001d, 0x0000, - 0x0003, 0x0009, 0x000f, 0x0015, 0x001b, 0x0000, 0x0000, 0x333b, - 0x3338, 0x0000, 0x0000, 0x8000, 0x0000, 0x333b, 0x0000, 0x3343, - 0x3340, 0x0000, 0x0000, 0x0000, 0x0000, 0x3343, 0x0000, 0x333e, - 0x333e, 0x0000, 0x0000, 0x8000, 0x0000, 0x333e, 0x0000, 0x3344, - 0x3344, 0x0000, 0x0000, 0x0000, 0x0000, 0x3344, 0x127e, 0x2091, - 0x2200, 0x2079, 0x3900, 0x2071, 0x0010, 0x7007, 0x000a, 0x7007, - 0x0002, 0x7003, 0x0000, 0x2071, 0x0020, 0x7007, 0x000a, 0x7007, - 0x0002, 0x7003, 0x0000, 0x2049, 0x0000, 0x127f, 0x2000, 0x007c, - 0x2049, 0x3380, 0x2019, 0x0000, 0x7004, 0x8004, 0x00c8, 0x33b2, - 0x7007, 0x0012, 0x7108, 0x7008, 0xa106, 0x00c0, 0x338a, 0xa184, - 0x01e0, 0x0040, 0x3395, 0x1078, 0x1eac, 0xa184, 0x4000, 0x00c0, - 0x338a, 0xa19c, 0x300c, 0xa386, 0x2004, 0x0040, 0x33a7, 0xa386, - 0x0008, 0x0040, 0x33b2, 0xa386, 0x200c, 0x00c0, 0x338a, 0x7200, - 0x8204, 0x0048, 0x33b2, 0x730c, 0xa384, 0x00ff, 0x0040, 0x33b2, - 0x1078, 0x1eac, 0x7007, 0x0012, 0x7000, 0xa084, 0x0001, 0x00c0, - 0x33c3, 0x7310, 0x7014, 0xa305, 0x0040, 0x33c3, 0x700c, 0xa084, - 0x00ff, 0x00c0, 0x3380, 0x7007, 0x0012, 0x7007, 0x0008, 0x7004, - 0xa084, 0x0008, 0x00c0, 0x33c7, 0x7007, 0x0012, 0x7108, 0x8103, - 0x0048, 0x33cc, 0x7003, 0x0000, 0x2049, 0x0000, 0x007c, 0x107e, - 0x007e, 0x127e, 0x157e, 0x2091, 0x2200, 0x7108, 0x1078, 0x33e7, - 0x157f, 0x127f, 0x2091, 0x8001, 0x007f, 0x107f, 0x007c, 0x7204, - 0x7500, 0x730c, 0xa384, 0x0300, 0x00c0, 0x3426, 0xa184, 0x0060, - 0x00c0, 0x3442, 0x7008, 0x7108, 0xa106, 0x00c0, 0x33f2, 0xa184, - 0x01e0, 0x00c0, 0x3442, 0xa184, 0x4000, 0x00c0, 0x33f2, 0xa986, - 0x362f, 0x00c0, 0x341a, 0xa19c, 0x300c, 0xa386, 0x2004, 0x0040, - 0x3411, 0xa386, 0x0008, 0x0040, 0x341a, 0xa386, 0x200c, 0x00c0, - 0x33f2, 0x7200, 0x8204, 0x0048, 0x341a, 0x730c, 0xa384, 0x00ff, - 0x00c0, 0x3426, 0xa184, 0x0007, 0x0079, 0x341e, 0x3428, 0x3436, - 0x3426, 0x3436, 0x3426, 0x348f, 0x3426, 0x348d, 0x1078, 0x1eac, - 0x7007, 0x0002, 0x8aff, 0x00c0, 0x3431, 0x2049, 0x0000, 0x0078, - 0x3435, 0x1078, 0x3606, 0x00c0, 0x3431, 0x007c, 0x7007, 0x0002, - 0x8aff, 0x00c0, 0x343d, 0x0078, 0x3441, 0x1078, 0x3606, 0x00c0, - 0x343d, 0x007c, 0x7108, 0x7008, 0xa106, 0x00c0, 0x3442, 0xa184, - 0x4000, 0x00c0, 0x3442, 0x7007, 0x0012, 0x7108, 0x7008, 0xa106, - 0x00c0, 0x344d, 0xa184, 0x4000, 0x00c0, 0x344d, 0x00e0, 0x3456, - 0x2091, 0x6000, 0x00e0, 0x345a, 0x2091, 0x6000, 0x7007, 0x0012, - 0x7007, 0x0008, 0x7004, 0xa084, 0x0008, 0x00c0, 0x3462, 0x7007, - 0x0012, 0x7108, 0x8103, 0x0048, 0x3467, 0x7003, 0x0000, 0x7000, - 0xa005, 0x00c0, 0x347b, 0x7004, 0xa005, 0x00c0, 0x347b, 0x700c, - 0xa005, 0x0040, 0x347d, 0x0078, 0x345e, 0x2049, 0x0000, 0x1078, - 0x30b3, 0x6818, 0xa084, 0x8000, 0x0040, 0x3488, 0x681b, 0x0002, - 0x007c, 0x1078, 0x1eac, 0x1078, 0x1eac, 0x1078, 0x34ed, 0x7210, - 0x7114, 0x700c, 0xa09c, 0x00ff, 0x2800, 0xa300, 0xa211, 0xa189, - 0x0000, 0x1078, 0x34ed, 0x2704, 0x2c58, 0xac60, 0x6308, 0x2200, - 0xa322, 0x630c, 0x2100, 0xa31b, 0x2400, 0xa305, 0x0040, 0x34b2, - 0x00c8, 0x34b2, 0x8412, 0x8210, 0x830a, 0xa189, 0x0000, 0x2b60, - 0x0078, 0x3499, 0x2b60, 0x8a07, 0x007e, 0x6004, 0xa084, 0x0008, - 0x0040, 0x34be, 0xa7ba, 0x3340, 0x0078, 0x34c0, 0xa7ba, 0x3338, - 0x007f, 0xa73d, 0x2c00, 0x6886, 0x6f8a, 0x6c92, 0x6b8e, 0x1078, - 0x3380, 0x007c, 0x8738, 0x2704, 0xa005, 0x00c0, 0x34dd, 0x609c, - 0xa005, 0x0040, 0x34ea, 0x2060, 0x6004, 0xa084, 0x000f, 0xa080, - 0x3346, 0x203c, 0x87fb, 0x1040, 0x1eac, 0x8a51, 0x0040, 0x34e9, - 0x7008, 0x7508, 0xa52e, 0x00c0, 0x34e0, 0xa084, 0x0003, 0xa086, + 0x78ec, 0xa084, 0x0021, 0x0040, 0x38ff, 0x0098, 0x38fd, 0x007f, + 0x789a, 0x78ac, 0x007e, 0x7044, 0x780a, 0x007f, 0x007c, 0x78ec, + 0xa084, 0x0002, 0x00c0, 0x461d, 0xa784, 0x007d, 0x00c0, 0x3913, + 0x2700, 0x1078, 0x23ca, 0xa784, 0x0001, 0x00c0, 0x2f43, 0xa784, + 0x0070, 0x0040, 0x3923, 0x0c7e, 0x2d60, 0x2f68, 0x1078, 0x2375, + 0x2d78, 0x2c68, 0x0c7f, 0xa784, 0x0008, 0x0040, 0x3930, 0x784b, + 0x0008, 0x78ec, 0xa084, 0x0003, 0x0040, 0x2461, 0x0078, 0x3854, + 0xa784, 0x0004, 0x0040, 0x3963, 0x78b8, 0xa084, 0x4001, 0x0040, + 0x3963, 0x784b, 0x0008, 0x78ec, 0xa084, 0x0003, 0x0040, 0x2461, + 0x78e4, 0xa084, 0x0007, 0xa086, 0x0001, 0x00c0, 0x3963, 0x78c0, + 0xa085, 0x4800, 0x2030, 0x7e5a, 0x781b, 0x00d2, 0x0078, 0x2438, + 0x784b, 0x0008, 0x6818, 0xa084, 0x8000, 0x0040, 0x395f, 0x681b, + 0x0015, 0xa684, 0x4000, 0x0040, 0x395f, 0x681b, 0x0007, 0x1078, + 0x3868, 0x0078, 0x2438, 0x681b, 0x0003, 0x7858, 0xa084, 0x3f00, + 0x681e, 0x682f, 0x0000, 0x6833, 0x0000, 0x784b, 0x0008, 0x78ec, + 0xa084, 0x0003, 0x0040, 0x2944, 0x0018, 0x2438, 0x0078, 0x3673, + 0x6b14, 0x8307, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xa080, + 0x5280, 0x2060, 0x2048, 0x7056, 0x6000, 0x705a, 0x6004, 0x705e, + 0x2a60, 0x007c, 0x0079, 0x398c, 0x3994, 0x3995, 0x3994, 0x3997, + 0x3994, 0x3994, 0x3994, 0x399c, 0x007c, 0x1078, 0x33c4, 0x1078, + 0x4633, 0x7038, 0x600a, 0x007c, 0x70a0, 0xa005, 0x0040, 0x39a9, + 0x2068, 0x1078, 0x1b45, 0x1078, 0x45b5, 0x1078, 0x45bc, 0x70a3, + 0x0000, 0x007c, 0x0e7e, 0x2091, 0x8000, 0x2071, 0x5040, 0x7000, + 0xa086, 0x0007, 0x00c0, 0x39c0, 0x6110, 0x70bc, 0xa106, 0x00c0, + 0x39c0, 0x0e7f, 0x1078, 0x1b52, 0x1078, 0x39c6, 0xa006, 0x007c, + 0x2091, 0x8001, 0x0e7f, 0xa085, 0x0001, 0x007c, 0x0f7e, 0x0e7e, + 0x2071, 0x5040, 0x0078, 0x21d9, 0x785b, 0x0000, 0x70af, 0x000e, + 0x2009, 0x0100, 0x017e, 0x70a0, 0xa06d, 0x0040, 0x39db, 0x70a3, + 0x0000, 0x0078, 0x39e1, 0x70b3, 0x0000, 0x1078, 0x1b6e, 0x0040, + 0x39e7, 0x70ac, 0x6826, 0x1078, 0x3ac2, 0x0078, 0x39db, 0x017f, + 0x157e, 0x0c7e, 0x0d7e, 0x20a9, 0x0008, 0x2061, 0x7410, 0x6000, + 0xa105, 0x6002, 0x601c, 0xa06d, 0x0040, 0x39ff, 0x6800, 0x601e, + 0x1078, 0x193d, 0x6008, 0x8000, 0x600a, 0x0078, 0x39f2, 0x6018, + 0xa06d, 0x0040, 0x3a09, 0x6800, 0x601a, 0x1078, 0x193d, 0x0078, + 0x39ff, 0xace0, 0x0008, 0x0070, 0x3a0f, 0x0078, 0x39ef, 0x709c, + 0xa084, 0x8000, 0x0040, 0x3a16, 0x1078, 0x3b3c, 0x0d7f, 0x0c7f, + 0x157f, 0x007c, 0x127e, 0x2091, 0x2300, 0x6804, 0xa084, 0x000f, + 0x0079, 0x3a22, 0x3a32, 0x3a32, 0x3a32, 0x3a32, 0x3a32, 0x3a32, + 0x3a34, 0x3a3a, 0x3a32, 0x3a32, 0x3a32, 0x3a32, 0x3a32, 0x3a3c, + 0x3a32, 0x3a34, 0x1078, 0x23ca, 0x1078, 0x4466, 0x1078, 0x193d, + 0x0078, 0x3a40, 0x6827, 0x000b, 0x1078, 0x4466, 0x1078, 0x3ac2, + 0x127f, 0x007c, 0x127e, 0x2091, 0x2300, 0x0098, 0x3a5e, 0x7830, + 0xa084, 0x00c0, 0x00c0, 0x3a5e, 0x0d7e, 0x1078, 0x45c5, 0x2d00, + 0x682e, 0x2009, 0x0004, 0x2001, 0x0000, 0x6827, 0x0084, 0x1078, + 0x457e, 0x1078, 0x3ac2, 0x0d7f, 0x0078, 0x3a90, 0x7948, 0xa185, + 0x4000, 0x784a, 0x0098, 0x3a67, 0x794a, 0x0078, 0x3a4c, 0x7828, + 0xa086, 0x1834, 0x00c0, 0x3a70, 0xa185, 0x0004, 0x0078, 0x3a77, + 0x7828, 0xa186, 0x1814, 0x00c0, 0x3a64, 0xa185, 0x000c, 0x784a, + 0x789b, 0x000e, 0x78ab, 0x0002, 0x7858, 0xa084, 0x00ff, 0xa085, + 0x0400, 0x785a, 0x70b4, 0xa080, 0x0091, 0x781a, 0x6827, 0x0002, + 0x6827, 0x0084, 0x2009, 0x0004, 0x2001, 0x0000, 0x1078, 0x457e, + 0x127f, 0x007c, 0x0d7e, 0x6b14, 0x1078, 0x1be0, 0x0040, 0x3a9f, + 0x2068, 0x6827, 0x0002, 0x1078, 0x3ac2, 0x0078, 0x3a94, 0x0d7f, + 0x007c, 0x0d7e, 0x6b14, 0x6c28, 0xa4a4, 0x00ff, 0x1078, 0x1b7e, + 0x0040, 0x3aaf, 0x2068, 0x6827, 0x0002, 0x1078, 0x3ac2, 0x0d7f, + 0x007c, 0x0d7e, 0x6b14, 0xa39c, 0x00ff, 0x1078, 0x1bb1, 0x0040, + 0x3ac0, 0x2068, 0x6827, 0x0002, 0x1078, 0x3ac2, 0x0078, 0x3ab5, + 0x0d7f, 0x007c, 0x0c7e, 0x6914, 0x1078, 0x3b33, 0x6904, 0xa18c, + 0x00ff, 0xa186, 0x0006, 0x0040, 0x3add, 0xa186, 0x000d, 0x0040, + 0x3afc, 0xa186, 0x0017, 0x00c0, 0x3ad9, 0x1078, 0x193d, 0x0078, + 0x3adb, 0x1078, 0x1c55, 0x0c7f, 0x007c, 0x6004, 0x8001, 0x0048, + 0x3afa, 0x6006, 0x2009, 0x0000, 0xa684, 0x0001, 0x00c0, 0x3aea, + 0xa18d, 0x8000, 0xa684, 0x0004, 0x0040, 0x3af0, 0xa18d, 0x0002, + 0x691e, 0x6823, 0x0000, 0x7104, 0x810f, 0x6818, 0xa105, 0x681a, + 0x0078, 0x3ad9, 0x1078, 0x23ca, 0x6018, 0xa005, 0x00c0, 0x3b0b, + 0x6008, 0x8001, 0x0048, 0x3b0b, 0x600a, 0x601c, 0x6802, 0x2d00, + 0x601e, 0x0078, 0x3b21, 0xac88, 0x0006, 0x2104, 0xa005, 0x0040, + 0x3b14, 0x2008, 0x0078, 0x3b0d, 0x6802, 0x2d0a, 0x6008, 0x8001, + 0x0048, 0x3adb, 0x600a, 0x6018, 0x2068, 0x6800, 0x601a, 0x0078, + 0x3b05, 0x157e, 0x137e, 0x147e, 0x0c7e, 0x0d7e, 0x1078, 0x191a, + 0x2da0, 0x137f, 0x20a9, 0x0031, 0x53a3, 0x0c7f, 0x147f, 0x137f, + 0x157f, 0x0078, 0x3ad9, 0xa184, 0x001f, 0x8003, 0x8003, 0x8003, + 0xa080, 0x7410, 0x2060, 0x007c, 0x2019, 0x5051, 0x2304, 0xa085, + 0x0001, 0x201a, 0x2019, 0x0102, 0x2304, 0xa085, 0x0001, 0x201a, + 0x007c, 0x2019, 0x5051, 0x2304, 0xa084, 0xfffe, 0x201a, 0x2019, + 0x0102, 0x2304, 0xa084, 0xfffe, 0x201a, 0x007c, 0x7990, 0xa18c, + 0xfff8, 0x7992, 0x70b4, 0xa080, 0x00d8, 0x781a, 0x0078, 0x2438, + 0x70a3, 0x0000, 0x7003, 0x0000, 0x7043, 0x0001, 0x7037, 0x0000, + 0x0018, 0x23ef, 0x1078, 0x1b6e, 0x0040, 0x3b91, 0x2009, 0x500f, + 0x200b, 0x0000, 0x68bc, 0x2060, 0x6100, 0xa184, 0x0300, 0x0040, + 0x3b85, 0x6827, 0x000e, 0xa084, 0x0200, 0x0040, 0x3b81, 0x6827, + 0x0017, 0x1078, 0x3ac2, 0x0078, 0x3b60, 0x7000, 0xa086, 0x0007, + 0x00c0, 0x3be3, 0x2d00, 0x70a2, 0xad80, 0x000f, 0x7036, 0x0078, + 0x3b98, 0x7040, 0xa086, 0x0001, 0x0040, 0x2471, 0x0078, 0x2438, + 0x2031, 0x0000, 0x691c, 0xa184, 0x0002, 0x0040, 0x3ba1, 0xa6b5, + 0x0004, 0xa184, 0x00c0, 0x8003, 0x8003, 0x8007, 0xa080, 0x3c72, + 0x2004, 0xa635, 0x6820, 0xa084, 0x0400, 0x0040, 0x3bb9, 0x789b, + 0x0018, 0x78ab, 0x0003, 0x789b, 0x0081, 0x78ab, 0x0001, 0xa6b5, + 0x1000, 0x6820, 0xa084, 0x8000, 0x0040, 0x3bc5, 0xa6b5, 0x0400, + 0x789b, 0x000e, 0x6824, 0x8007, 0x78aa, 0xa684, 0x0200, 0x0040, + 0x3bdf, 0x682c, 0x78d2, 0x6830, 0x78d6, 0xa684, 0x0100, 0x0040, + 0x3bdd, 0x682c, 0xa084, 0x0001, 0x0040, 0x3bdd, 0x7888, 0xa084, + 0x0040, 0x0040, 0x3bdd, 0xa6b5, 0x8000, 0x1078, 0x45ad, 0x7e5a, + 0x6eb6, 0x0078, 0x45e4, 0x1078, 0x38c6, 0x00c0, 0x3c6c, 0x702c, + 0x8004, 0x0048, 0x3bf1, 0x2019, 0x4cfd, 0x1078, 0x2255, 0x702f, + 0x0001, 0x2011, 0x0001, 0x2031, 0x1000, 0x789b, 0x0018, 0x6814, + 0xa084, 0x001f, 0xa085, 0x0080, 0x78aa, 0x691c, 0xa184, 0x0002, + 0x0040, 0x3c0a, 0xa6b5, 0x0004, 0x78ab, 0x0020, 0x6828, 0x78aa, + 0xa290, 0x0002, 0x6820, 0xa084, 0x8000, 0x0040, 0x3c18, 0xa6b5, + 0x0400, 0x789b, 0x000e, 0x6824, 0x8007, 0x78aa, 0x0078, 0x3c26, + 0x681c, 0xa084, 0x8000, 0x00c0, 0x3c26, 0xa6b5, 0x0800, 0x6820, + 0xa084, 0x0100, 0x0040, 0x3c26, 0xa6b5, 0x4000, 0x681c, 0xa084, + 0x00c0, 0x8003, 0x8003, 0x8007, 0xa080, 0x3c72, 0x2004, 0xa635, + 0xa684, 0x0100, 0x0040, 0x3c40, 0x682c, 0xa084, 0x0001, 0x0040, + 0x3c40, 0x7888, 0xa084, 0x0040, 0x0040, 0x3c40, 0xa6b5, 0x8000, + 0x789b, 0x007e, 0x7eae, 0x6eb6, 0x6814, 0x8007, 0x78aa, 0x7882, + 0x7aaa, 0x7830, 0xa084, 0x00c0, 0x00c0, 0x3c6c, 0x0018, 0x3c6c, + 0x70b4, 0xa080, 0x00dd, 0x781a, 0x1078, 0x38de, 0xa684, 0x0200, + 0x0040, 0x3c60, 0x682c, 0x78d2, 0x6830, 0x78d6, 0x1078, 0x45ad, + 0x2d00, 0x70a2, 0x704a, 0x6810, 0x70be, 0x7003, 0x0007, 0xad80, + 0x000f, 0x7036, 0x0078, 0x2438, 0x1078, 0x1b45, 0x1078, 0x38de, + 0x0078, 0x2438, 0x0000, 0x0300, 0x0200, 0x0000, 0x1078, 0x23ca, + 0x2300, 0x0079, 0x3c7b, 0x3c7e, 0x3c7e, 0x3c80, 0x1078, 0x23ca, + 0x1078, 0x45bc, 0x6924, 0xa184, 0x00ff, 0xa086, 0x000a, 0x0040, + 0x3c92, 0xa184, 0xff00, 0xa085, 0x000a, 0x6826, 0x1078, 0x1b45, + 0x0078, 0x3b60, 0x2001, 0x000a, 0x1078, 0x454c, 0x0078, 0x3b60, + 0xa282, 0x0005, 0x0050, 0x3c9e, 0x1078, 0x23ca, 0x7000, 0xa084, + 0x0007, 0x10c0, 0x398a, 0x1078, 0x191a, 0x00c0, 0x3cbd, 0xa684, + 0x0004, 0x0040, 0x3caf, 0x2001, 0x2800, 0x0078, 0x3cb1, 0x2001, + 0x0800, 0x71b4, 0xa188, 0x0091, 0x789b, 0x000e, 0x78aa, 0x2031, + 0x0400, 0x7e5a, 0x791a, 0x0078, 0x2438, 0x6807, 0x0106, 0x680b, + 0x0000, 0x689f, 0x0000, 0x6827, 0x0000, 0xa386, 0x0002, 0x00c0, + 0x3cde, 0xa286, 0x0002, 0x00c0, 0x3cde, 0x78a0, 0xa005, 0x00c0, + 0x3cde, 0xa484, 0x8000, 0x00c0, 0x3cde, 0x78e4, 0xa084, 0x0008, + 0x0040, 0x3cde, 0xa6b5, 0x0008, 0x2019, 0x0000, 0x1078, 0x40d3, + 0x2d00, 0x70a2, 0x704a, 0x7003, 0x0007, 0x7037, 0x0000, 0x6824, + 0xa084, 0x0080, 0x0040, 0x3cf0, 0x1078, 0x4180, 0x0078, 0x2438, + 0x2300, 0x0079, 0x3cf3, 0x3cf6, 0x3d77, 0x3d96, 0x2200, 0x0079, + 0x3cf9, 0x3cfe, 0x3d0e, 0x3d34, 0x3d40, 0x3d63, 0x2029, 0x0001, + 0xa026, 0x2011, 0x0000, 0x1078, 0x428d, 0x0079, 0x3d07, 0x3d0c, + 0x2438, 0x3b60, 0x3d0c, 0x3d0c, 0x1078, 0x23ca, 0x7990, 0xa18c, + 0x0007, 0x00c0, 0x3d15, 0x2009, 0x0008, 0x2011, 0x0001, 0xa684, + 0x0004, 0x0040, 0x3d1d, 0x2011, 0x0003, 0x2220, 0xa12a, 0x2011, + 0x0001, 0x1078, 0x428d, 0x0079, 0x3d25, 0x3d2a, 0x2438, 0x3b60, + 0x3d32, 0x3d2c, 0x0078, 0x45ea, 0x70ab, 0x3d30, 0x0078, 0x2438, + 0x0078, 0x3d2a, 0x1078, 0x23ca, 0xa684, 0x0010, 0x0040, 0x3d3e, + 0x1078, 0x414f, 0x0040, 0x3d3e, 0x0078, 0x2438, 0x0078, 0x41bc, + 0x6000, 0xa084, 0x0002, 0x0040, 0x3d5d, 0x70b4, 0xa080, 0x00cd, + 0x781a, 0x0d7e, 0x1078, 0x45c5, 0x2d00, 0x682e, 0x6827, 0x0000, + 0x1078, 0x3ac2, 0x0d7f, 0x1078, 0x193d, 0x7003, 0x0000, 0x7037, + 0x0000, 0x704b, 0x0000, 0x0078, 0x3b60, 0xa684, 0x0004, 0x00c0, + 0x3d63, 0x0078, 0x45ea, 0x6000, 0xa084, 0x0004, 0x00c0, 0x3d75, + 0x6000, 0xa084, 0x0001, 0x0040, 0x3d75, 0x70ab, 0x3d75, 0x2001, + 0x0007, 0x1078, 0x4544, 0x0078, 0x45f0, 0x0078, 0x45ea, 0x2200, + 0x0079, 0x3d7a, 0x3d7f, 0x3d7f, 0x3d7f, 0x3d81, 0x3d7f, 0x1078, + 0x23ca, 0x70a7, 0x3d85, 0x0078, 0x45f6, 0x2011, 0x0018, 0x1078, + 0x4287, 0x0079, 0x3d8b, 0x3d90, 0x2438, 0x3b60, 0x3d92, 0x3d94, + 0x1078, 0x23ca, 0x1078, 0x23ca, 0x1078, 0x23ca, 0x2200, 0x0079, + 0x3d99, 0x3d9e, 0x3da0, 0x3da0, 0x3d9e, 0x3d9e, 0x1078, 0x23ca, + 0x78e4, 0xa084, 0x0008, 0x0040, 0x3db5, 0x70a7, 0x3da9, 0x0078, + 0x45f6, 0x2011, 0x0004, 0x1078, 0x4287, 0x0079, 0x3daf, 0x3db5, + 0x2438, 0x3b60, 0x3db5, 0x3dbf, 0x3dc3, 0x70ab, 0x3dbd, 0x2001, + 0x0003, 0x1078, 0x4544, 0x0078, 0x45f0, 0x0078, 0x45ea, 0x70ab, + 0x3db5, 0x0078, 0x2438, 0x70ab, 0x3dc7, 0x0078, 0x2438, 0x0078, + 0x3dbd, 0xa282, 0x0003, 0x0050, 0x3dcf, 0x1078, 0x23ca, 0xa386, + 0x0002, 0x00c0, 0x3de8, 0xa286, 0x0002, 0x00c0, 0x3dee, 0x78a0, + 0xa005, 0x00c0, 0x3dee, 0xa484, 0x8000, 0x00c0, 0x3dee, 0x78e4, + 0xa084, 0x0008, 0x0040, 0x3de8, 0xa6b5, 0x0008, 0x2019, 0x0000, + 0xa684, 0x0008, 0x0040, 0x3dee, 0x1078, 0x412c, 0x6810, 0x70be, + 0x7003, 0x0007, 0x2300, 0x0079, 0x3df5, 0x3df8, 0x3e25, 0x3e2d, + 0x2200, 0x0079, 0x3dfb, 0x3e00, 0x3dfe, 0x3e19, 0x1078, 0x23ca, + 0x7990, 0xa1ac, 0x0007, 0xa026, 0x2011, 0x0001, 0x1078, 0x428d, + 0x0079, 0x3e0a, 0x3e0f, 0x2438, 0x3b60, 0x3e17, 0x3e11, 0x0078, + 0x45ea, 0x70ab, 0x3e15, 0x0078, 0x2438, 0x0078, 0x3e0f, 0x1078, + 0x23ca, 0xa684, 0x0010, 0x0040, 0x3e23, 0x1078, 0x414f, 0x0040, + 0x3e23, 0x0078, 0x2438, 0x0078, 0x41bc, 0x2200, 0x0079, 0x3e28, + 0x3e2b, 0x3e2b, 0x3e2b, 0x1078, 0x23ca, 0x2200, 0x0079, 0x3e30, + 0x3e33, 0x3e35, 0x3e35, 0x1078, 0x23ca, 0x78e4, 0xa084, 0x0008, + 0x0040, 0x3e4a, 0x70a7, 0x3e3e, 0x0078, 0x45f6, 0x2011, 0x0004, + 0x1078, 0x4287, 0x0079, 0x3e44, 0x3e4a, 0x2438, 0x3b60, 0x3e4a, + 0x3e54, 0x3e58, 0x70ab, 0x3e52, 0x2001, 0x0003, 0x1078, 0x4544, + 0x0078, 0x45f0, 0x0078, 0x45ea, 0x70ab, 0x3e4a, 0x0078, 0x2438, + 0x70ab, 0x3e5c, 0x0078, 0x2438, 0x0078, 0x3e52, 0x2300, 0x0079, + 0x3e61, 0x3e66, 0x3e68, 0x3e64, 0x1078, 0x23ca, 0x70a4, 0x007a, + 0x70a4, 0x007a, 0xa282, 0x0002, 0x0050, 0x3e70, 0x1078, 0x23ca, + 0xa684, 0x0200, 0x0040, 0x3e7a, 0x1078, 0x45b5, 0x1078, 0x426f, + 0x1078, 0x45bc, 0x2300, 0x0079, 0x3e7d, 0x3e80, 0x3ea4, 0x3f0a, + 0xa286, 0x0001, 0x0040, 0x3e86, 0x1078, 0x23ca, 0xa684, 0x0200, + 0x0040, 0x3e8e, 0x1078, 0x45b5, 0x1078, 0x45bc, 0x2001, 0x0001, + 0x1078, 0x454c, 0x78b8, 0xa084, 0xc001, 0x0040, 0x3ea0, 0x7848, + 0xa085, 0x0008, 0x784a, 0x7848, 0xa084, 0x0008, 0x00c0, 0x3e9b, + 0x7003, 0x0000, 0x0078, 0x3b60, 0x2200, 0x0079, 0x3ea7, 0x3ea9, + 0x3eda, 0x70a7, 0x3ead, 0x0078, 0x45f6, 0x2011, 0x000d, 0x1078, + 0x4287, 0x0079, 0x3eb3, 0x3eba, 0x2438, 0x3b60, 0x3ec2, 0x3eca, + 0x3ed0, 0x3ed2, 0xa6b4, 0x00ff, 0xa6b5, 0x0400, 0x6eb6, 0x7e5a, + 0x0078, 0x45e4, 0xa6b4, 0x00ff, 0xa6b5, 0x0400, 0x6eb6, 0x7e5a, + 0x0078, 0x45e4, 0x70ab, 0x3ece, 0x0078, 0x2438, 0x0078, 0x3eba, + 0x1078, 0x23ca, 0x70ab, 0x3ed6, 0x0078, 0x2438, 0x1078, 0x45fc, + 0x0078, 0x2438, 0x70a7, 0x3ede, 0x0078, 0x45f6, 0x2011, 0x0012, + 0x1078, 0x4287, 0x0079, 0x3ee4, 0x3eea, 0x2438, 0x3b60, 0x3ef6, + 0x3efe, 0x3f04, 0xa6b4, 0x00ff, 0xa6b5, 0x0400, 0x6eb6, 0x7e5a, + 0x70b4, 0xa080, 0x00a5, 0x781a, 0x0078, 0x2438, 0xa6b4, 0x00ff, + 0xa6b5, 0x0400, 0x6eb6, 0x7e5a, 0x0078, 0x45e4, 0x70ab, 0x3f02, + 0x0078, 0x2438, 0x0078, 0x3eea, 0x70ab, 0x3f08, 0x0078, 0x2438, + 0x0078, 0x3ef6, 0xa286, 0x0001, 0x0040, 0x3f10, 0x1078, 0x23ca, + 0x70a7, 0x3f14, 0x0078, 0x45f6, 0x2011, 0x0015, 0x1078, 0x4287, + 0x0079, 0x3f1a, 0x3f1f, 0x2438, 0x3b60, 0x3f2d, 0x3f39, 0xa6b4, + 0x00ff, 0xa6b5, 0x0400, 0x6eb6, 0x7e5a, 0x783b, 0x1301, 0x70b4, + 0xa080, 0x00b5, 0x781a, 0x0078, 0x2438, 0xa6b4, 0x00ff, 0xa6b5, + 0x0400, 0x6eb6, 0x7e5a, 0x70b4, 0xa080, 0x00a5, 0x781a, 0x0078, + 0x2438, 0x70ab, 0x3f3d, 0x0078, 0x2438, 0x0078, 0x3f1f, 0xa282, + 0x0003, 0x0050, 0x3f45, 0x1078, 0x23ca, 0x2300, 0x0079, 0x3f48, + 0x3f4b, 0x3f82, 0x3fdd, 0xa286, 0x0001, 0x0040, 0x3f51, 0x1078, + 0x23ca, 0x6804, 0xa084, 0x00ff, 0xa086, 0x0006, 0x00c0, 0x3f5e, + 0x1078, 0x3ac2, 0x7003, 0x0000, 0x0078, 0x3b60, 0x683b, 0x0000, + 0x6837, 0x0000, 0xa684, 0x0200, 0x0040, 0x3f6c, 0x1078, 0x45b5, + 0x1078, 0x426f, 0x1078, 0x45bc, 0x2001, 0x0001, 0x1078, 0x454c, + 0x78b8, 0xa084, 0xc001, 0x0040, 0x3f7e, 0x7848, 0xa085, 0x0008, + 0x784a, 0x7848, 0xa084, 0x0008, 0x00c0, 0x3f79, 0x7003, 0x0000, + 0x0078, 0x3b60, 0x2200, 0x0079, 0x3f85, 0x3f87, 0x3fb8, 0x70a7, + 0x3f8b, 0x0078, 0x45f6, 0x2011, 0x000d, 0x1078, 0x4287, 0x0079, + 0x3f91, 0x3f98, 0x2438, 0x3b60, 0x3fa0, 0x3fa8, 0x3fae, 0x3fb0, + 0xa6b4, 0x00ff, 0xa6b5, 0x0800, 0x6eb6, 0x7e5a, 0x0078, 0x45e4, + 0xa6b4, 0x00ff, 0xa6b5, 0x0800, 0x6eb6, 0x7e5a, 0x0078, 0x45e4, + 0x70ab, 0x3fac, 0x0078, 0x2438, 0x0078, 0x3f98, 0x1078, 0x23ca, + 0x70ab, 0x3fb4, 0x0078, 0x2438, 0x1078, 0x45fc, 0x0078, 0x2438, + 0x70a7, 0x3fbc, 0x0078, 0x45f6, 0x2011, 0x0005, 0x1078, 0x4287, + 0x0079, 0x3fc2, 0x3fc7, 0x2438, 0x3b60, 0x3fcf, 0x3fd7, 0xa6b4, + 0x00ff, 0xa6b5, 0x0800, 0x6eb6, 0x7e5a, 0x0078, 0x45e4, 0xa6b4, + 0x00ff, 0xa6b5, 0x0800, 0x6eb6, 0x7e5a, 0x0078, 0x45e4, 0x70ab, + 0x3fdb, 0x0078, 0x2438, 0x0078, 0x3fc7, 0xa286, 0x0001, 0x0040, + 0x3fe3, 0x1078, 0x23ca, 0x70a7, 0x3fe7, 0x0078, 0x45f6, 0x2011, + 0x0006, 0x1078, 0x4287, 0x0079, 0x3fed, 0x3ff2, 0x2438, 0x3b60, + 0x3ff8, 0x4002, 0xa6b5, 0x0800, 0x6eb6, 0x7e5a, 0x0078, 0x45e4, + 0xa6b4, 0x00ff, 0xa6b5, 0x0800, 0x6eb6, 0xa6b5, 0x4000, 0x7e5a, + 0x0078, 0x45e4, 0x70ab, 0x4006, 0x0078, 0x2438, 0x0078, 0x3ff2, + 0x2300, 0x0079, 0x400b, 0x4010, 0x400e, 0x400e, 0x1078, 0x23ca, + 0x1078, 0x23ca, 0x2300, 0x71a8, 0xa005, 0x017a, 0x6810, 0x70be, + 0xa282, 0x0003, 0x0050, 0x401e, 0x1078, 0x23ca, 0x2300, 0x0079, + 0x4021, 0x4024, 0x4037, 0x4059, 0x82ff, 0x00c0, 0x4029, 0x1078, + 0x23ca, 0xa684, 0x0200, 0x0040, 0x4031, 0x1078, 0x45b5, 0x1078, + 0x45bc, 0x2001, 0x0001, 0x1078, 0x454c, 0x0078, 0x2438, 0xa296, + 0x0002, 0x0040, 0x4040, 0x82ff, 0x0040, 0x4040, 0x1078, 0x23ca, + 0x70a7, 0x4044, 0x0078, 0x45f6, 0x2011, 0x0018, 0x1078, 0x4287, + 0x0079, 0x404a, 0x404f, 0x2438, 0x3b60, 0x4051, 0x4053, 0x0078, + 0x45e4, 0x0078, 0x45e4, 0x70ab, 0x4057, 0x0078, 0x2438, 0x0078, + 0x404f, 0x2200, 0x0079, 0x405c, 0x405e, 0x4077, 0x70a7, 0x4062, + 0x0078, 0x45f6, 0x2011, 0x0017, 0x1078, 0x4287, 0x0079, 0x4068, + 0x406d, 0x2438, 0x3b60, 0x406f, 0x4071, 0x0078, 0x45e4, 0x0078, + 0x45e4, 0x70ab, 0x4075, 0x0078, 0x2438, 0x0078, 0x406d, 0xa484, + 0x8000, 0x00c0, 0x40c1, 0xa684, 0x0100, 0x0040, 0x408b, 0x1078, + 0x45b5, 0x1078, 0x426f, 0x1078, 0x45bc, 0x7848, 0xa085, 0x000c, + 0x784a, 0x0078, 0x408f, 0x78d8, 0x78d2, 0x78dc, 0x78d6, 0xa6b4, + 0xefff, 0x7e5a, 0x70a7, 0x4096, 0x0078, 0x45f6, 0x2011, 0x000d, + 0x1078, 0x4287, 0x0079, 0x409c, 0x40a3, 0x2438, 0x3b60, 0x40a3, + 0x40b1, 0x40b7, 0x40b9, 0xa684, 0x0100, 0x0040, 0x40af, 0x1078, + 0x4573, 0x682c, 0x78d2, 0x6830, 0x78d6, 0x1078, 0x45ad, 0x0078, + 0x45e4, 0x70ab, 0x40b5, 0x0078, 0x2438, 0x0078, 0x40a3, 0x1078, + 0x23ca, 0x70ab, 0x40bd, 0x0078, 0x2438, 0x1078, 0x45fc, 0x0078, + 0x2438, 0x1078, 0x45bc, 0x70ab, 0x40cb, 0x2001, 0x0003, 0x1078, + 0x4544, 0x0078, 0x45f0, 0x1078, 0x45ad, 0x682c, 0x78d2, 0x6830, + 0x78d6, 0x0078, 0x45e4, 0x70b8, 0x6812, 0x70be, 0x8000, 0x70ba, + 0x681b, 0x0000, 0xa684, 0x0008, 0x0040, 0x40f6, 0x157e, 0x137e, + 0x147e, 0x7890, 0x8004, 0x8004, 0x8004, 0x8004, 0xa084, 0x000f, + 0x681a, 0x80ac, 0x789b, 0x0000, 0xaf80, 0x002b, 0x2098, 0xad80, + 0x000b, 0x20a0, 0x53a5, 0x147f, 0x137f, 0x157f, 0xa6c4, 0x0f00, + 0xa684, 0x0002, 0x00c0, 0x4102, 0x692c, 0x810d, 0x810d, 0x810d, + 0x0078, 0x410f, 0x789b, 0x0010, 0x79ac, 0x0078, 0x410f, 0x017e, + 0x2009, 0x0005, 0x2001, 0x3d00, 0x1078, 0x457e, 0x017f, 0xa184, + 0x001f, 0xa805, 0x6816, 0x1078, 0x3b33, 0x68be, 0xa684, 0x0004, + 0x0040, 0x4120, 0xa18c, 0xff00, 0x78a8, 0xa084, 0x00ff, 0xa105, + 0x682a, 0xa6b4, 0x00ff, 0x6000, 0xa084, 0x0008, 0x0040, 0x412a, + 0xa6b5, 0x4000, 0x6eb6, 0x007c, 0x157e, 0x137e, 0x147e, 0x6918, + 0x7890, 0x8004, 0x8004, 0x8004, 0x8004, 0xa084, 0x000f, 0x007e, + 0xa100, 0x681a, 0x007f, 0x8000, 0x8004, 0x0040, 0x414b, 0x20a8, + 0x8104, 0xa080, 0x000b, 0xad00, 0x20a0, 0x789b, 0x0000, 0xaf80, + 0x002b, 0x2098, 0x53a5, 0x147f, 0x137f, 0x157f, 0x007c, 0x682c, + 0xa084, 0x0020, 0x00c0, 0x4157, 0x620c, 0x0078, 0x4158, 0x6210, + 0x6b18, 0x2300, 0xa202, 0x0040, 0x4178, 0x2018, 0xa382, 0x000e, + 0x0048, 0x4168, 0x0040, 0x4168, 0x2019, 0x000e, 0x0078, 0x416c, + 0x7858, 0xa084, 0xffef, 0x785a, 0x783b, 0x1b01, 0x7893, 0x0000, + 0x7ba2, 0x70b4, 0xa080, 0x008e, 0x781a, 0xa085, 0x0001, 0x007c, + 0x7858, 0xa084, 0xffef, 0x785a, 0x7893, 0x0000, 0xa006, 0x007c, + 0x6904, 0xa18c, 0x00ff, 0xa196, 0x0007, 0x0040, 0x418d, 0xa196, + 0x000f, 0x0040, 0x418d, 0x6807, 0x0117, 0x6914, 0x1078, 0x3b33, + 0x6100, 0x8104, 0x00c8, 0x41a8, 0x601c, 0xa005, 0x0040, 0x419c, + 0x2001, 0x0800, 0x0078, 0x41aa, 0x0d7e, 0x6824, 0x007e, 0x1078, + 0x45c5, 0x007f, 0x6826, 0x2d00, 0x682e, 0x1078, 0x3ac2, 0x0d7f, + 0x2001, 0x0200, 0x6826, 0x8007, 0x789b, 0x000e, 0x78aa, 0x6820, + 0xa085, 0x8000, 0x6822, 0x2031, 0x0400, 0x6eb6, 0x7e5a, 0x71b4, + 0xa188, 0x0091, 0x791a, 0x007c, 0xa6c4, 0x0f00, 0xa684, 0x0002, + 0x00c0, 0x41cf, 0x692c, 0x810d, 0x810d, 0x810d, 0xa184, 0x001f, + 0xa805, 0x6816, 0x1078, 0x3b33, 0x68be, 0x0078, 0x41d2, 0x6914, + 0x1078, 0x3b33, 0x6100, 0x8104, 0x00c8, 0x421c, 0xa184, 0x0300, + 0x0040, 0x41de, 0x6807, 0x0117, 0x0078, 0x41fc, 0x6004, 0xa005, + 0x00c0, 0x4205, 0x6807, 0x0117, 0x601c, 0xa005, 0x00c0, 0x41f2, + 0x0d7e, 0x1078, 0x45c5, 0x6827, 0x0034, 0x2d00, 0x682e, 0x1078, + 0x3ac2, 0x0d7f, 0xa684, 0x0004, 0x0040, 0x41fc, 0x2031, 0x0400, + 0x2001, 0x2800, 0x0078, 0x4200, 0x2031, 0x0400, 0x2001, 0x0800, + 0x71b4, 0xa188, 0x0091, 0x0078, 0x424a, 0x6018, 0xa005, 0x00c0, + 0x41f2, 0x601c, 0xa005, 0x00c0, 0x41f2, 0x689f, 0x0000, 0x6827, + 0x003d, 0xa684, 0x0001, 0x0040, 0x4258, 0xa6b5, 0x0800, 0x71b4, + 0xa188, 0x00ae, 0x0078, 0x4253, 0x6807, 0x0117, 0x2031, 0x0400, + 0x692c, 0xa18c, 0x00ff, 0xa186, 0x0012, 0x00c0, 0x422d, 0x2001, + 0x4265, 0x2009, 0x0001, 0x0078, 0x423e, 0xa186, 0x0003, 0x00c0, + 0x4237, 0x2001, 0x4266, 0x2009, 0x0012, 0x0078, 0x423e, 0x2001, + 0x0200, 0x71b4, 0xa188, 0x0091, 0x0078, 0x424a, 0x1078, 0x4598, + 0x78a3, 0x0000, 0x681c, 0xa085, 0x0040, 0x681e, 0x71b4, 0xa188, + 0x00da, 0xa006, 0x6826, 0x8007, 0x789b, 0x000e, 0x78aa, 0x6820, + 0xa085, 0x8000, 0x6822, 0x6eb6, 0x7e5a, 0x791a, 0x0078, 0x2438, + 0x6eb6, 0x1078, 0x3ac2, 0x6810, 0x70be, 0x7003, 0x0007, 0x70a3, + 0x0000, 0x704b, 0x0000, 0x0078, 0x2438, 0x0023, 0x0070, 0x0005, + 0x0000, 0x0a00, 0x0000, 0x0000, 0x0025, 0x0000, 0x0000, 0x683b, + 0x0000, 0x6837, 0x0000, 0xa684, 0x0200, 0x0040, 0x4286, 0x78b8, + 0xa08c, 0x001f, 0xa084, 0x8000, 0x0040, 0x427f, 0x8108, 0x78d8, + 0xa100, 0x6836, 0x78dc, 0xa081, 0x0000, 0x683a, 0x007c, 0x7990, + 0x810f, 0xa5ac, 0x0007, 0x2021, 0x0000, 0xa480, 0x0010, 0x789a, + 0x79a8, 0xa18c, 0x00ff, 0xa184, 0x0080, 0x00c0, 0x42b5, 0xa182, + 0x0020, 0x00c8, 0x42cf, 0xa182, 0x0012, 0x00c8, 0x4536, 0x2100, + 0x1079, 0x42a3, 0x007c, 0x4536, 0x447e, 0x4536, 0x4536, 0x42dc, + 0x42df, 0x4319, 0x434f, 0x4381, 0x4384, 0x4536, 0x4536, 0x433a, + 0x43a8, 0x43e2, 0x4536, 0x4536, 0x4409, 0xa18c, 0x001f, 0x6814, + 0xa084, 0x001f, 0xa106, 0x0040, 0x42cc, 0x70b4, 0xa080, 0x00cd, + 0x781a, 0x2001, 0x0014, 0x1078, 0x454c, 0x1078, 0x45bc, 0x7003, + 0x0000, 0x2001, 0x0002, 0x007c, 0x2001, 0x0000, 0x007c, 0xa182, + 0x0024, 0x00c8, 0x4536, 0xa184, 0x0003, 0x1079, 0x42a3, 0x007c, + 0x4536, 0x4536, 0x4536, 0x4536, 0x1078, 0x4536, 0x007c, 0x2200, + 0x0079, 0x42e2, 0x440c, 0x440c, 0x4306, 0x4306, 0x4306, 0x4306, + 0x4306, 0x4306, 0x4306, 0x4306, 0x4304, 0x4306, 0x42fb, 0x4306, + 0x4306, 0x4306, 0x4306, 0x4306, 0x430e, 0x4311, 0x440c, 0x4311, + 0x4306, 0x4306, 0x4306, 0x0c7e, 0x077e, 0x6f14, 0x1078, 0x36b0, + 0x077f, 0x0c7f, 0x0078, 0x4306, 0x1078, 0x44d1, 0x6827, 0x02b3, + 0x2009, 0x000b, 0x2001, 0x4800, 0x0078, 0x4440, 0x1078, 0x452b, + 0x007c, 0x6827, 0x0093, 0x2009, 0x000b, 0x2001, 0x4800, 0x0078, + 0x4428, 0x2d58, 0x6804, 0xa084, 0x00ff, 0xa086, 0x0006, 0x00c0, + 0x4323, 0x6807, 0x0117, 0x6827, 0x0002, 0x1078, 0x45c5, 0x6827, + 0x0036, 0x6932, 0x2d00, 0x682e, 0x0d7e, 0x1078, 0x3a92, 0x1078, + 0x4466, 0x2b68, 0x1078, 0x3ac2, 0x0d7f, 0x1078, 0x3ac2, 0x2001, + 0x0002, 0x007c, 0x1078, 0x4466, 0x2001, 0x0017, 0x1078, 0x454c, + 0x70a3, 0x0000, 0x2009, 0x5038, 0x200b, 0x0006, 0x70af, 0x0017, + 0x2009, 0x0200, 0x1078, 0x39d2, 0x2001, 0x0001, 0x007c, 0x2200, + 0x0079, 0x4352, 0x440c, 0x443d, 0x443d, 0x443d, 0x4373, 0x444d, + 0x4379, 0x444d, 0x444d, 0x4450, 0x4450, 0x4455, 0x4455, 0x436b, + 0x436b, 0x443d, 0x443d, 0x444d, 0x443d, 0x4379, 0x440c, 0x4379, + 0x4379, 0x4379, 0x4379, 0x6827, 0x0084, 0x2009, 0x000b, 0x2001, + 0x4300, 0x0078, 0x445f, 0x2009, 0x000b, 0x2001, 0x4300, 0x0078, + 0x4440, 0x6827, 0x0093, 0x2009, 0x000b, 0x2001, 0x4300, 0x0078, + 0x4428, 0x2001, 0x0000, 0x007c, 0x2200, 0x0079, 0x4387, 0x440c, + 0x43a0, 0x43a0, 0x43a0, 0x43a0, 0x444d, 0x444d, 0x444d, 0x444d, + 0x444d, 0x444d, 0x444d, 0x444d, 0x43a0, 0x43a0, 0x43a0, 0x43a0, + 0x444d, 0x43a0, 0x43a0, 0x444d, 0x444d, 0x444d, 0x444d, 0x440c, + 0x6827, 0x0093, 0x2009, 0x000b, 0x2001, 0x4300, 0x0078, 0x4428, + 0xa684, 0x0004, 0x00c0, 0x43bc, 0x6804, 0xa084, 0x00ff, 0xa086, + 0x0006, 0x00c0, 0x4536, 0x1078, 0x4466, 0x6807, 0x0117, 0x1078, + 0x3ac2, 0x2001, 0x0002, 0x007c, 0x6000, 0xa084, 0x0004, 0x0040, + 0x4536, 0x2d58, 0x6804, 0xa084, 0x00ff, 0xa086, 0x0006, 0x00c0, + 0x43cb, 0x6807, 0x0117, 0x6827, 0x0002, 0x1078, 0x45c5, 0x6827, + 0x0036, 0x6932, 0x2d00, 0x682e, 0x0d7e, 0x1078, 0x3aa1, 0x1078, + 0x4466, 0x2b68, 0x1078, 0x3ac2, 0x0d7f, 0x1078, 0x3ac2, 0x2001, + 0x0002, 0x007c, 0x6000, 0xa084, 0x0004, 0x0040, 0x4536, 0x2d58, + 0x6a04, 0xa294, 0x00ff, 0xa286, 0x0006, 0x00c0, 0x43f1, 0x6807, + 0x0117, 0x6827, 0x0002, 0x2d58, 0x1078, 0x45c5, 0x6827, 0x0036, + 0x6932, 0x2d00, 0x682e, 0x0d7e, 0x1078, 0x3ab1, 0x1078, 0x4466, + 0x2b68, 0x1078, 0x3ac2, 0x0d7f, 0x1078, 0x3ac2, 0x2001, 0x0002, + 0x007c, 0x1078, 0x4536, 0x007c, 0x70b4, 0xa080, 0x00cd, 0x781a, + 0x2001, 0x0001, 0x1078, 0x454c, 0x1078, 0x45bc, 0x7003, 0x0000, + 0x2001, 0x0002, 0x007c, 0x1078, 0x457e, 0x1078, 0x45b5, 0x1078, + 0x426f, 0x1078, 0x4180, 0x1078, 0x45bc, 0x2001, 0x0001, 0x007c, + 0x1078, 0x457e, 0x1078, 0x45b5, 0x1078, 0x426f, 0x70b4, 0xa080, + 0x00cd, 0x781a, 0x2001, 0x0013, 0x1078, 0x454c, 0x1078, 0x45bc, + 0x7003, 0x0000, 0x2001, 0x0002, 0x007c, 0x1078, 0x4536, 0x007c, + 0x1078, 0x457e, 0x1078, 0x45b5, 0x1078, 0x426f, 0x1078, 0x4180, + 0x1078, 0x45bc, 0x2001, 0x0001, 0x007c, 0x2001, 0x0003, 0x007c, + 0x1078, 0x44d1, 0x2001, 0x0000, 0x007c, 0x0c7e, 0x077e, 0x6f14, + 0x1078, 0x36b0, 0x077f, 0x0c7f, 0x2001, 0x0000, 0x007c, 0x1078, + 0x457e, 0x1078, 0x4536, 0x2001, 0x0006, 0x007c, 0x6904, 0xa18c, + 0x00ff, 0xa186, 0x0007, 0x0040, 0x4471, 0xa186, 0x000f, 0x00c0, + 0x4475, 0x1078, 0x45b5, 0x1078, 0x426f, 0x70b4, 0xa080, 0x00cd, + 0x781a, 0x1078, 0x45bc, 0x7003, 0x0000, 0x007c, 0x7aa8, 0xa294, + 0x00ff, 0x78a8, 0xa084, 0x00ff, 0xa08a, 0x0004, 0x00c8, 0x4536, + 0x1079, 0x448b, 0x007c, 0x4536, 0x448f, 0x4536, 0x44df, 0xa282, + 0x0003, 0x0040, 0x4496, 0x1078, 0x4536, 0x007c, 0x7da8, 0xa5ac, + 0x00ff, 0x7ca8, 0xa4a4, 0x00ff, 0xa482, 0x000c, 0x0048, 0x44a4, + 0x0040, 0x44a4, 0x2021, 0x000c, 0x701c, 0xa502, 0x00c8, 0x44a9, + 0x751c, 0x1078, 0x451c, 0x852b, 0x852b, 0x1078, 0x372e, 0x0040, + 0x44b5, 0x1078, 0x44c3, 0x0078, 0x44b9, 0x1078, 0x4518, 0x1078, + 0x44d1, 0xa6b5, 0x1000, 0x7e5a, 0x70b4, 0xa080, 0x00b9, 0x781a, + 0x2001, 0x0004, 0x007c, 0x0c7e, 0x6914, 0x810f, 0xa18c, 0x000f, + 0x810b, 0x810b, 0x810b, 0xa1e0, 0x5280, 0x1078, 0x3538, 0x0c7f, + 0x007c, 0x0c7e, 0x6814, 0x8007, 0xa084, 0x000f, 0x8003, 0x8003, + 0x8003, 0xa0e0, 0x5280, 0x1078, 0x355f, 0x0c7f, 0x007c, 0xa282, + 0x0002, 0x00c0, 0x4536, 0x7aa8, 0xa294, 0x00ff, 0xa284, 0xfffe, + 0x0040, 0x44ec, 0x2011, 0x0001, 0x1078, 0x450a, 0x1078, 0x44fc, + 0x1078, 0x44d1, 0xa6b5, 0x1000, 0x7e5a, 0x70b4, 0xa080, 0x00b9, + 0x781a, 0x2001, 0x0004, 0x007c, 0x0c7e, 0x6814, 0x8007, 0xa084, + 0x000f, 0x8003, 0x8003, 0x8003, 0xa0e0, 0x5280, 0x1078, 0x3604, + 0x0c7f, 0x007c, 0x789b, 0x0018, 0x78ab, 0x0001, 0x78ab, 0x0002, + 0x78ab, 0x0003, 0x7aaa, 0x789b, 0x0081, 0x78ab, 0x0004, 0x007c, + 0x2021, 0x0000, 0x2029, 0x0032, 0x789b, 0x0018, 0x78ab, 0x0001, + 0x78ab, 0x0003, 0x78ab, 0x0001, 0x7daa, 0x7caa, 0x789b, 0x0081, + 0x78ab, 0x0005, 0x007c, 0x2001, 0x0003, 0x1078, 0x4544, 0x70b4, + 0xa080, 0x00b9, 0x781a, 0x2001, 0x0005, 0x007c, 0x2001, 0x0007, + 0x1078, 0x4544, 0xa6b5, 0x1000, 0x7e5a, 0x70b4, 0xa080, 0x00b9, + 0x781a, 0x2001, 0x0004, 0x007c, 0x789b, 0x0018, 0x78aa, 0x789b, + 0x0081, 0x78ab, 0x0001, 0x007c, 0x6904, 0xa18c, 0x00ff, 0xa196, + 0x0007, 0x0040, 0x455a, 0xa196, 0x000f, 0x0040, 0x455a, 0x1078, + 0x193d, 0x007c, 0x6924, 0xa194, 0x003f, 0x00c0, 0x4563, 0xa18c, + 0xffc0, 0xa105, 0x6826, 0x1078, 0x3ac2, 0x691c, 0xa184, 0x0100, + 0x0040, 0x4572, 0x1078, 0x1b7e, 0x6914, 0x1078, 0x3b33, 0x6204, + 0x8210, 0x6206, 0x007c, 0x692c, 0x6834, 0x682e, 0xa112, 0x6930, + 0x6838, 0x6832, 0xa11b, 0xa200, 0xa301, 0x007c, 0x0c7e, 0xade0, + 0x0018, 0x6003, 0x0070, 0x6106, 0x600b, 0x0000, 0x600f, 0x0a00, + 0x6013, 0x0000, 0x6017, 0x0000, 0x8007, 0x601a, 0x601f, 0x0000, + 0x6023, 0x0000, 0x0c7f, 0x6824, 0xa085, 0x0080, 0x6826, 0x007c, + 0x157e, 0x137e, 0x147e, 0x2098, 0xaf80, 0x002d, 0x20a0, 0x81ac, + 0x0040, 0x45a3, 0x53a6, 0xa184, 0x0001, 0x0040, 0x45a9, 0x3304, + 0x78be, 0x147f, 0x137f, 0x157f, 0x007c, 0x70b0, 0xa005, 0x10c0, + 0x23ca, 0x70b3, 0x8000, 0x0078, 0x48f7, 0x71b0, 0x81ff, 0x0040, + 0x45bb, 0x1078, 0x49ed, 0x007c, 0x71b0, 0x81ff, 0x0040, 0x45c4, + 0x70b3, 0x0000, 0x1078, 0x4633, 0x007c, 0x0c7e, 0x0d7e, 0x1078, + 0x191a, 0x0c7f, 0x157e, 0x137e, 0x147e, 0x2da0, 0x2c98, 0x20a9, + 0x0031, 0x53a3, 0x147f, 0x137f, 0x157f, 0x6807, 0x010d, 0x680b, + 0x0000, 0x7004, 0x8007, 0x681a, 0x6823, 0x0000, 0x681f, 0x0000, + 0x689f, 0x0000, 0x0c7f, 0x007c, 0x70b4, 0xa080, 0x0091, 0x781a, + 0x0078, 0x2438, 0x70b4, 0xa080, 0x0081, 0x781a, 0x0078, 0x2438, + 0x70b4, 0xa080, 0x00b9, 0x781a, 0x0078, 0x2438, 0x70b4, 0xa080, + 0x00c3, 0x781a, 0x0078, 0x2438, 0x6904, 0xa18c, 0x00ff, 0xa196, + 0x0007, 0x0040, 0x4609, 0xa196, 0x000f, 0x0040, 0x4609, 0x6807, + 0x0117, 0x2001, 0x0200, 0x6826, 0x8007, 0x789b, 0x000e, 0x78aa, + 0x6820, 0xa085, 0x8000, 0x6822, 0x2031, 0x0400, 0x6eb6, 0x7e5a, + 0x71b4, 0xa188, 0x0091, 0x791a, 0x007c, 0x1078, 0x45bc, 0x7848, + 0xa085, 0x000c, 0x784a, 0x70b4, 0xa080, 0x00cd, 0x781a, 0x2009, + 0x000b, 0x2001, 0x4400, 0x1078, 0x457e, 0x2001, 0x0013, 0x1078, + 0x454c, 0x0078, 0x3b60, 0x127e, 0x2091, 0x2200, 0x2049, 0x4633, + 0x7000, 0x7204, 0xa205, 0x720c, 0xa215, 0x7008, 0xa084, 0xfff7, + 0xa205, 0x0040, 0x4645, 0x0078, 0x464a, 0x7003, 0x0000, 0x127f, + 0x2000, 0x007c, 0x7000, 0xa084, 0x0001, 0x00c0, 0x4678, 0x7108, + 0x8103, 0x00c8, 0x4657, 0x1078, 0x477a, 0x0078, 0x464f, 0x700c, + 0xa08c, 0x00ff, 0x0040, 0x4678, 0x7004, 0x8004, 0x00c8, 0x466f, + 0x7014, 0xa005, 0x00c0, 0x466b, 0x7010, 0xa005, 0x0040, 0x466f, + 0xa102, 0x00c8, 0x464f, 0x7007, 0x0010, 0x0078, 0x4678, 0x8aff, + 0x0040, 0x4678, 0x1078, 0x49c4, 0x00c0, 0x4672, 0x0040, 0x464f, + 0x1078, 0x4703, 0x7003, 0x0000, 0x127f, 0x2000, 0x007c, 0x017e, + 0x6104, 0xa18c, 0x00ff, 0xa186, 0x0007, 0x0040, 0x468b, 0xa18e, + 0x000f, 0x00c0, 0x468e, 0x6040, 0x0078, 0x468f, 0x6428, 0x017f, + 0x84ff, 0x0040, 0x46b9, 0x2c70, 0x7004, 0xa0bc, 0x000f, 0xa7b8, + 0x46c9, 0x273c, 0x87fb, 0x00c0, 0x46a7, 0x0048, 0x46a1, 0x1078, + 0x23ca, 0x609c, 0xa075, 0x0040, 0x46b9, 0x0078, 0x4694, 0x2704, + 0xae68, 0x6808, 0xa630, 0x680c, 0xa529, 0x8421, 0x0040, 0x46b9, + 0x8738, 0x2704, 0xa005, 0x00c0, 0x46a8, 0x709c, 0xa075, 0x00c0, + 0x4694, 0x007c, 0x0000, 0x0005, 0x0009, 0x000d, 0x0011, 0x0015, + 0x0019, 0x001d, 0x0000, 0x0003, 0x0009, 0x000f, 0x0015, 0x001b, + 0x0000, 0x0000, 0x46be, 0x46bb, 0x0000, 0x0000, 0x8000, 0x0000, + 0x46be, 0x0000, 0x46c6, 0x46c3, 0x0000, 0x0000, 0x0000, 0x0000, + 0x46c6, 0x0000, 0x46c1, 0x46c1, 0x0000, 0x0000, 0x8000, 0x0000, + 0x46c1, 0x0000, 0x46c7, 0x46c7, 0x0000, 0x0000, 0x0000, 0x0000, + 0x46c7, 0x127e, 0x2091, 0x2200, 0x2079, 0x5000, 0x2071, 0x0010, + 0x7007, 0x000a, 0x7007, 0x0002, 0x7003, 0x0000, 0x2071, 0x0020, + 0x7007, 0x000a, 0x7007, 0x0002, 0x7003, 0x0000, 0x2049, 0x0000, + 0x127f, 0x2000, 0x007c, 0x2049, 0x4703, 0x2019, 0x0000, 0x7004, + 0x8004, 0x00c8, 0x4756, 0x7007, 0x0012, 0x7108, 0x7008, 0xa106, + 0x00c0, 0x470d, 0xa184, 0x01e0, 0x0040, 0x4718, 0x1078, 0x23ca, + 0x2001, 0x04fd, 0x2004, 0xa082, 0x0005, 0x00c8, 0x4723, 0xa184, + 0x4000, 0x00c0, 0x470d, 0xa19c, 0x300c, 0xa386, 0x2004, 0x0040, + 0x4731, 0xa386, 0x0008, 0x0040, 0x473c, 0xa386, 0x200c, 0x00c0, + 0x470d, 0x7200, 0x8204, 0x0048, 0x473c, 0x730c, 0xa384, 0x00ff, + 0x0040, 0x473c, 0x1078, 0x23ca, 0x7007, 0x0012, 0x7000, 0xa084, + 0x0001, 0x00c0, 0x4756, 0x7008, 0xa084, 0x01e0, 0x00c0, 0x4756, + 0x7310, 0x7014, 0xa305, 0x0040, 0x4756, 0x710c, 0xa184, 0x0300, + 0x00c0, 0x4756, 0xa184, 0x00ff, 0x00c0, 0x4703, 0x7007, 0x0012, + 0x7007, 0x0008, 0x7004, 0xa084, 0x0008, 0x00c0, 0x475a, 0x7007, + 0x0012, 0x7108, 0x8103, 0x0048, 0x475f, 0x7003, 0x0000, 0x2049, + 0x0000, 0x007c, 0x107e, 0x007e, 0x127e, 0x157e, 0x2091, 0x2200, + 0x7108, 0x1078, 0x477a, 0x157f, 0x127f, 0x2091, 0x8001, 0x007f, + 0x107f, 0x007c, 0x7204, 0x7500, 0x730c, 0xa384, 0x0300, 0x00c0, + 0x47a1, 0xa184, 0x01e0, 0x00c0, 0x47c5, 0x7108, 0xa184, 0x01e0, + 0x00c0, 0x47c5, 0x2001, 0x04fd, 0x2004, 0xa082, 0x0005, 0x00c8, + 0x4795, 0xa184, 0x4000, 0x00c0, 0x4785, 0xa184, 0x0007, 0x0079, + 0x4799, 0x47a3, 0x47b5, 0x47a1, 0x47b5, 0x47a1, 0x4801, 0x47a1, + 0x47ff, 0x1078, 0x23ca, 0x7004, 0xa084, 0x0010, 0xa085, 0x0002, + 0x7006, 0x8aff, 0x00c0, 0x47b0, 0x2049, 0x0000, 0x0078, 0x47b4, + 0x1078, 0x49c4, 0x00c0, 0x47b0, 0x007c, 0x7004, 0xa084, 0x0010, + 0xa085, 0x0002, 0x7006, 0x8aff, 0x00c0, 0x47c0, 0x0078, 0x47c4, + 0x1078, 0x49c4, 0x00c0, 0x47c0, 0x007c, 0x7007, 0x0012, 0x7108, + 0x00e0, 0x47c8, 0x2091, 0x6000, 0x00e0, 0x47cc, 0x2091, 0x6000, + 0x7007, 0x0012, 0x7007, 0x0008, 0x7004, 0xa084, 0x0008, 0x00c0, + 0x47d4, 0x7007, 0x0012, 0x7108, 0x8103, 0x0048, 0x47d9, 0x7003, + 0x0000, 0x7000, 0xa005, 0x00c0, 0x47ed, 0x7004, 0xa005, 0x00c0, + 0x47ed, 0x700c, 0xa005, 0x0040, 0x47ef, 0x0078, 0x47d0, 0x2049, + 0x0000, 0x1078, 0x37d7, 0x6818, 0xa084, 0x8000, 0x0040, 0x47fa, + 0x681b, 0x0002, 0x007c, 0x1078, 0x23ca, 0x1078, 0x23ca, 0x1078, + 0x485d, 0x7210, 0x7114, 0x700c, 0xa09c, 0x00ff, 0x2800, 0xa300, + 0xa211, 0xa189, 0x0000, 0x1078, 0x485d, 0x2704, 0x2c58, 0xac60, + 0x6308, 0x2200, 0xa322, 0x630c, 0x2100, 0xa31b, 0x2400, 0xa305, + 0x0040, 0x4824, 0x00c8, 0x4824, 0x8412, 0x8210, 0x830a, 0xa189, + 0x0000, 0x2b60, 0x0078, 0x480b, 0x2b60, 0x8a07, 0x007e, 0x6004, + 0xa084, 0x0008, 0x0040, 0x4830, 0xa7ba, 0x46c3, 0x0078, 0x4832, + 0xa7ba, 0x46bb, 0x007f, 0xa73d, 0x2c00, 0x6886, 0x6f8a, 0x6c92, + 0x6b8e, 0x7007, 0x0012, 0x1078, 0x4703, 0x007c, 0x8738, 0x2704, + 0xa005, 0x00c0, 0x4851, 0x609c, 0xa005, 0x0040, 0x485a, 0x2060, + 0x6004, 0xa084, 0x000f, 0xa080, 0x46c9, 0x203c, 0x87fb, 0x1040, + 0x23ca, 0x8a51, 0x0040, 0x4859, 0x7008, 0xa084, 0x0003, 0xa086, 0x0003, 0x007c, 0x2051, 0x0000, 0x007c, 0x8a50, 0x8739, 0x2704, - 0xa004, 0x00c0, 0x3501, 0x6000, 0xa064, 0x00c0, 0x34f8, 0x2d60, - 0x6004, 0xa084, 0x000f, 0xa080, 0x3356, 0x203c, 0x87fb, 0x1040, - 0x1eac, 0x007c, 0x127e, 0x0d7e, 0x2091, 0x2200, 0x0d7f, 0x6884, + 0xa004, 0x00c0, 0x4871, 0x6000, 0xa064, 0x00c0, 0x4868, 0x2d60, + 0x6004, 0xa084, 0x000f, 0xa080, 0x46d9, 0x203c, 0x87fb, 0x1040, + 0x23ca, 0x007c, 0x127e, 0x0d7e, 0x2091, 0x2200, 0x0d7f, 0x6884, 0x2060, 0x6888, 0x6b8c, 0x6c90, 0x8057, 0xaad4, 0x00ff, 0xa084, - 0x00ff, 0x007e, 0x6804, 0xa084, 0x0008, 0x007f, 0x0040, 0x351c, - 0xa0b8, 0x3340, 0x0078, 0x351e, 0xa0b8, 0x3338, 0x7e08, 0xa6b5, - 0x000c, 0x681c, 0xa084, 0x0040, 0x0040, 0x3528, 0xa6b5, 0x0001, - 0x7007, 0x0004, 0x7004, 0xa084, 0x0004, 0x00c0, 0x352a, 0x2400, - 0xa305, 0x00c0, 0x3535, 0x0078, 0x3559, 0x2c58, 0x2704, 0x6104, - 0xac60, 0x6000, 0xa400, 0x701a, 0x6004, 0xa301, 0x701e, 0xa184, - 0x0008, 0x0040, 0x3549, 0x6010, 0xa001, 0x7022, 0x6014, 0xa001, - 0x7026, 0x6208, 0x2400, 0xa202, 0x7012, 0x620c, 0x2300, 0xa203, - 0x7016, 0x7602, 0x7007, 0x0001, 0x2b60, 0x1078, 0x34ca, 0x0078, - 0x355b, 0x1078, 0x3606, 0x00c0, 0x3559, 0x127f, 0x2000, 0x007c, - 0x127e, 0x0d7e, 0x2091, 0x2200, 0x0d7f, 0x7007, 0x0004, 0x7004, - 0xa084, 0x0004, 0x00c0, 0x3567, 0x7003, 0x0008, 0x127f, 0x2000, - 0x007c, 0x127e, 0x0d7e, 0x2091, 0x2200, 0x0d7f, 0x2049, 0x3571, - 0x7007, 0x0004, 0x7004, 0xa084, 0x0004, 0x00c0, 0x357a, 0x7e08, - 0xa6b5, 0x000c, 0x681c, 0xa084, 0x0020, 0x00c0, 0x3589, 0xa6b5, - 0x0001, 0x6828, 0x2050, 0x2d60, 0x6004, 0xa0bc, 0x000f, 0xa7b8, - 0x3346, 0x273c, 0x87fb, 0x00c0, 0x359f, 0x0048, 0x3599, 0x1078, - 0x1eac, 0x689c, 0xa065, 0x0040, 0x35a3, 0x0078, 0x358c, 0x1078, - 0x3606, 0x00c0, 0x359f, 0x127f, 0x2000, 0x007c, 0x127e, 0x007e, - 0x017e, 0x0d7e, 0x2091, 0x2200, 0x0d7f, 0x037f, 0x047f, 0x7e08, - 0xa6b5, 0x000c, 0x681c, 0xa084, 0x0040, 0x0040, 0x35b9, 0xa6b5, - 0x0001, 0x2049, 0x35a6, 0x6828, 0xa055, 0x0040, 0x3603, 0x2d70, - 0x2e60, 0x7004, 0xa0bc, 0x000f, 0xa7b8, 0x3346, 0x273c, 0x87fb, - 0x00c0, 0x35d5, 0x0048, 0x35ce, 0x1078, 0x1eac, 0x709c, 0xa075, - 0x2060, 0x0040, 0x3603, 0x0078, 0x35c1, 0x2704, 0xae68, 0x6808, - 0xa422, 0x680c, 0xa31b, 0x0048, 0x35f0, 0x8a51, 0x00c0, 0x35e2, - 0x1078, 0x1eac, 0x8738, 0x2704, 0xa005, 0x00c0, 0x35d6, 0x709c, - 0xa075, 0x2060, 0x0040, 0x3603, 0x2039, 0x3338, 0x0078, 0x35c1, - 0x8422, 0x8420, 0x831a, 0xa399, 0x0000, 0x6908, 0x2400, 0xa122, - 0x690c, 0x2300, 0xa11b, 0x00c8, 0x35ff, 0x1078, 0x1eac, 0x2071, - 0x0020, 0x0078, 0x3528, 0x127f, 0x2000, 0x007c, 0x7008, 0x7508, - 0xa52e, 0x00c0, 0x3606, 0xa084, 0x0003, 0xa086, 0x0003, 0x0040, - 0x362e, 0x2704, 0xac08, 0x2104, 0x701a, 0x8108, 0x2104, 0x701e, - 0x8108, 0x2104, 0x7012, 0x8108, 0x2104, 0x7016, 0x6004, 0xa084, - 0x0008, 0x0040, 0x3629, 0x8108, 0x2104, 0x7022, 0x8108, 0x2104, - 0x7026, 0x7602, 0x7007, 0x0001, 0x1078, 0x34ca, 0x007c, 0x127e, - 0x007e, 0x0d7e, 0x2091, 0x2200, 0x2049, 0x362f, 0x0d7f, 0x087f, - 0x7108, 0x7008, 0xa106, 0x00c0, 0x3638, 0xa184, 0x4000, 0x00c0, - 0x3638, 0xa184, 0x0003, 0x00c0, 0x364f, 0x6828, 0xa005, 0x0040, - 0x365d, 0x0020, 0x364f, 0x1078, 0x348f, 0x0078, 0x365d, 0x00a0, - 0x3656, 0x7108, 0x1078, 0x33e7, 0x0078, 0x3638, 0x7007, 0x0010, - 0x00a0, 0x3658, 0x7108, 0x1078, 0x33e7, 0x7008, 0xa086, 0x0008, - 0x00c0, 0x3638, 0x7000, 0xa005, 0x00c0, 0x3638, 0x2049, 0x0000, - 0x127f, 0x2000, 0x007c, 0x127e, 0x147e, 0x137e, 0x157e, 0x0d7e, - 0x2091, 0x2200, 0x0d7f, 0x2049, 0x366b, 0xad80, 0x0011, 0x20a0, - 0x2099, 0x0031, 0x700c, 0xa084, 0x00ff, 0x682a, 0x7007, 0x0008, - 0x7007, 0x0002, 0x7003, 0x0001, 0x0040, 0x3689, 0x8000, 0x80ac, - 0x53a5, 0x7007, 0x0004, 0x7004, 0xa084, 0x0004, 0x00c0, 0x368b, - 0x2049, 0x0000, 0x7003, 0x0000, 0x157f, 0x137f, 0x147f, 0x127f, - 0x2000, 0x007c, 0x2091, 0x6000, 0x78c0, 0xa005, 0x0040, 0x36af, - 0x798c, 0x70d0, 0xa106, 0x00c0, 0x36af, 0x7804, 0xa005, 0x0040, - 0x36af, 0x7807, 0x0000, 0x0068, 0x36af, 0x2091, 0x4080, 0x7820, - 0x8001, 0x7822, 0x00c0, 0x370f, 0x7824, 0x7822, 0x2091, 0x8000, - 0x78f0, 0xa005, 0x0040, 0x36dc, 0x78d4, 0xa005, 0x00c0, 0x36dc, - 0x3a10, 0xa284, 0x0002, 0x00c0, 0x36cc, 0x78d7, 0x0007, 0x2009, - 0xff01, 0x200a, 0x0078, 0x36dc, 0xa284, 0x0001, 0x00c0, 0x36d4, - 0x78ef, 0x0000, 0x0078, 0x36dc, 0x78ec, 0xa005, 0x00c0, 0x36dc, - 0x78d7, 0x0008, 0x78ef, 0x0001, 0x2069, 0x3940, 0x6800, 0xa084, - 0x0007, 0x0040, 0x36f3, 0xa086, 0x0002, 0x0040, 0x36f3, 0x6830, - 0xa00d, 0x0040, 0x36f3, 0x2104, 0xa005, 0x0040, 0x36f3, 0x8001, - 0x200a, 0x0040, 0x37b1, 0x7848, 0xa005, 0x0040, 0x3703, 0x8001, - 0x784a, 0x00c0, 0x3703, 0x0f7e, 0x2079, 0x0100, 0x1078, 0x316a, - 0x0f7f, 0x1078, 0x1cf6, 0x68c4, 0xa005, 0x0040, 0x370f, 0x8001, - 0x68c6, 0x00c0, 0x370f, 0x68a3, 0x0000, 0x68a7, 0x0001, 0x1078, - 0x3716, 0x1078, 0x373b, 0x2091, 0x8001, 0x007c, 0x7834, 0x8001, - 0x7836, 0x00c0, 0x373a, 0x7838, 0x7836, 0x2091, 0x8000, 0x7844, - 0xa005, 0x00c0, 0x3725, 0x2001, 0x0101, 0x8001, 0x7846, 0xa080, - 0x4280, 0x2040, 0x2004, 0xa065, 0x0040, 0x373a, 0x6024, 0xa005, - 0x0040, 0x3736, 0x8001, 0x6026, 0x0040, 0x376a, 0x6000, 0x2c40, - 0x0078, 0x372b, 0x007c, 0x7828, 0x8001, 0x782a, 0x00c0, 0x3769, - 0x782c, 0x782a, 0x7830, 0xa005, 0x00c0, 0x3748, 0x2001, 0x0080, - 0x8001, 0x7832, 0x8003, 0x8003, 0x8003, 0x8003, 0xa090, 0x3a80, - 0xa298, 0x0002, 0x2304, 0xa084, 0x0008, 0x0040, 0x3769, 0xa290, - 0x0009, 0x2204, 0xa005, 0x0040, 0x3761, 0x8001, 0x2012, 0x00c0, - 0x3769, 0x2304, 0xa084, 0xfff7, 0xa085, 0x0080, 0x201a, 0x1078, - 0x1cf6, 0x007c, 0x2069, 0x3940, 0x6800, 0xa005, 0x0040, 0x3774, - 0x683c, 0xac06, 0x0040, 0x37b1, 0x601b, 0x0006, 0x60b4, 0xa084, - 0x3f00, 0x601e, 0x6020, 0xa084, 0x00ff, 0xa085, 0x0060, 0x6022, - 0x6000, 0x2042, 0x6714, 0x6fb6, 0x1078, 0x18b4, 0x6818, 0xa005, - 0x0040, 0x378c, 0x8001, 0x681a, 0x6808, 0xa084, 0xffef, 0x680a, - 0x6810, 0x8001, 0x00d0, 0x3796, 0x1078, 0x1eac, 0x6812, 0x602f, - 0x0000, 0x6033, 0x0000, 0x2c68, 0x1078, 0x1a26, 0x2069, 0x3940, - 0x2001, 0x0006, 0x68a2, 0x7944, 0xa184, 0x0100, 0x00c0, 0x37ac, - 0x69ba, 0x2001, 0x0004, 0x68a2, 0x1078, 0x1cf1, 0x2091, 0x8001, - 0x007c, 0x2009, 0x394f, 0x2164, 0x2069, 0x0100, 0x1078, 0x1e57, - 0x601b, 0x0006, 0x6858, 0xa084, 0x3f00, 0x601e, 0x6020, 0xa084, - 0x00ff, 0xa085, 0x0048, 0x6022, 0x602f, 0x0000, 0x6033, 0x0000, - 0x6830, 0xa084, 0x0040, 0x0040, 0x37ed, 0x684b, 0x0004, 0x20a9, - 0x0014, 0x6848, 0xa084, 0x0004, 0x0040, 0x37da, 0x0070, 0x37da, - 0x0078, 0x37d1, 0x684b, 0x0009, 0x20a9, 0x0014, 0x6848, 0xa084, - 0x0001, 0x0040, 0x37e7, 0x0070, 0x37e7, 0x0078, 0x37de, 0x20a9, - 0x00fa, 0x0070, 0x37ed, 0x0078, 0x37e9, 0x6808, 0xa084, 0xfffd, - 0x680a, 0x681b, 0x0047, 0x2009, 0x3968, 0x200b, 0x0007, 0x784c, - 0x784a, 0x2091, 0x8001, 0x007c, 0x2079, 0x3900, 0x1078, 0x3827, - 0x1078, 0x380b, 0x1078, 0x3819, 0x7833, 0x0000, 0x7847, 0x0000, - 0x784b, 0x0000, 0x007c, 0x2019, 0x000c, 0x2011, 0x3946, 0x2204, - 0xa086, 0x003c, 0x0040, 0x3816, 0x2019, 0x0008, 0x7b2a, 0x7b2e, - 0x007c, 0x2019, 0x0039, 0x2011, 0x3946, 0x2204, 0xa086, 0x003c, - 0x0040, 0x3824, 0x2019, 0x0027, 0x7b36, 0x7b3a, 0x007c, 0x2019, - 0x3971, 0x2011, 0x3946, 0x2204, 0xa086, 0x003c, 0x0040, 0x3832, - 0x2019, 0x2626, 0x7b22, 0x7b26, 0x783f, 0x0000, 0x7843, 0x000a, - 0x007c, 0x8e59 + 0x00ff, 0x007e, 0x6804, 0xa084, 0x0008, 0x007f, 0x0040, 0x488c, + 0xa0b8, 0x46c3, 0x0078, 0x488e, 0xa0b8, 0x46bb, 0x7e08, 0xa6b5, + 0x000c, 0x6904, 0xa18c, 0x00ff, 0xa186, 0x0007, 0x0040, 0x489c, + 0xa18e, 0x000f, 0x00c0, 0x48a5, 0x681c, 0xa084, 0x0040, 0x0040, + 0x48ac, 0xa6b5, 0x0001, 0x0078, 0x48ac, 0x681c, 0xa084, 0x0040, + 0x0040, 0x48ac, 0xa6b5, 0x0001, 0x7007, 0x0004, 0x7004, 0xa084, + 0x0004, 0x00c0, 0x48ae, 0x2400, 0xa305, 0x00c0, 0x48b9, 0x0078, + 0x48df, 0x2c58, 0x2704, 0x6104, 0xac60, 0x6000, 0xa400, 0x701a, + 0x6004, 0xa301, 0x701e, 0xa184, 0x0008, 0x0040, 0x48cf, 0x6010, + 0xa081, 0x0000, 0x7022, 0x6014, 0xa081, 0x0000, 0x7026, 0x6208, + 0x2400, 0xa202, 0x7012, 0x620c, 0x2300, 0xa203, 0x7016, 0x7602, + 0x7007, 0x0001, 0x2b60, 0x1078, 0x483e, 0x0078, 0x48e1, 0x1078, + 0x49c4, 0x00c0, 0x48df, 0x127f, 0x2000, 0x007c, 0x127e, 0x0d7e, + 0x2091, 0x2200, 0x0d7f, 0x7007, 0x0004, 0x7004, 0xa084, 0x0004, + 0x00c0, 0x48ed, 0x7003, 0x0008, 0x127f, 0x2000, 0x007c, 0x127e, + 0x0d7e, 0x2091, 0x2200, 0x0d7f, 0x2049, 0x48f7, 0x7007, 0x0004, + 0x7004, 0xa084, 0x0004, 0x00c0, 0x4900, 0x7e08, 0xa6b5, 0x000c, + 0x6904, 0xa18c, 0x00ff, 0xa186, 0x0007, 0x0040, 0x4913, 0xa18e, + 0x000f, 0x00c0, 0x491e, 0x681c, 0xa084, 0x0040, 0x0040, 0x491a, + 0xa6b5, 0x0001, 0x6840, 0x2050, 0x0078, 0x4927, 0x681c, 0xa084, + 0x0020, 0x00c0, 0x4925, 0xa6b5, 0x0001, 0x6828, 0x2050, 0x2d60, + 0x6004, 0xa0bc, 0x000f, 0xa7b8, 0x46c9, 0x273c, 0x87fb, 0x00c0, + 0x493b, 0x0048, 0x4935, 0x1078, 0x23ca, 0x689c, 0xa065, 0x0040, + 0x493f, 0x0078, 0x4928, 0x1078, 0x49c4, 0x00c0, 0x493b, 0x127f, + 0x2000, 0x007c, 0x127e, 0x007e, 0x017e, 0x0d7e, 0x2091, 0x2200, + 0x0d7f, 0x037f, 0x047f, 0x7e08, 0xa6b5, 0x000c, 0x6904, 0xa18c, + 0x00ff, 0xa186, 0x0007, 0x0040, 0x4959, 0xa18e, 0x000f, 0x00c0, + 0x4962, 0x681c, 0xa084, 0x0040, 0x0040, 0x4969, 0xa6b5, 0x0001, + 0x0078, 0x4969, 0x681c, 0xa084, 0x0040, 0x0040, 0x4969, 0xa6b5, + 0x0001, 0x2049, 0x4942, 0x017e, 0x6904, 0xa18c, 0x00ff, 0xa186, + 0x0007, 0x0040, 0x4977, 0xa18e, 0x000f, 0x00c0, 0x497a, 0x6840, + 0x0078, 0x497b, 0x6828, 0x017f, 0xa055, 0x0040, 0x49c1, 0x2d70, + 0x2e60, 0x7004, 0xa0bc, 0x000f, 0xa7b8, 0x46c9, 0x273c, 0x87fb, + 0x00c0, 0x4995, 0x0048, 0x498e, 0x1078, 0x23ca, 0x709c, 0xa075, + 0x2060, 0x0040, 0x49c1, 0x0078, 0x4981, 0x2704, 0xae68, 0x6808, + 0xa422, 0x680c, 0xa31b, 0x0048, 0x49ae, 0x8a51, 0x00c0, 0x49a2, + 0x1078, 0x23ca, 0x8738, 0x2704, 0xa005, 0x00c0, 0x4996, 0x709c, + 0xa075, 0x2060, 0x0040, 0x49c1, 0x0078, 0x4981, 0x8422, 0x8420, + 0x831a, 0xa399, 0x0000, 0x6908, 0x2400, 0xa122, 0x690c, 0x2300, + 0xa11b, 0x00c8, 0x49bd, 0x1078, 0x23ca, 0x2071, 0x0020, 0x0078, + 0x48ac, 0x127f, 0x2000, 0x007c, 0x7008, 0xa084, 0x0003, 0xa086, + 0x0003, 0x0040, 0x49ec, 0x2704, 0xac08, 0x2104, 0x701a, 0x8108, + 0x2104, 0x701e, 0x8108, 0x2104, 0x7012, 0x8108, 0x2104, 0x7016, + 0x6004, 0xa084, 0x0008, 0x0040, 0x49e3, 0x8108, 0x2104, 0x7022, + 0x8108, 0x2104, 0x7026, 0x7602, 0x7004, 0xa084, 0x0010, 0xa085, + 0x0001, 0x7006, 0x1078, 0x483e, 0x007c, 0x127e, 0x007e, 0x0d7e, + 0x2091, 0x2200, 0x2049, 0x49ed, 0x0d7f, 0x087f, 0x7108, 0xa184, + 0x0003, 0x00c0, 0x4a17, 0x017e, 0x6904, 0xa18c, 0x00ff, 0xa186, + 0x0007, 0x0040, 0x4a07, 0xa18e, 0x000f, 0x00c0, 0x4a0a, 0x6840, + 0x0078, 0x4a0b, 0x6828, 0x017f, 0xa005, 0x0040, 0x4a25, 0x0078, + 0x464a, 0x0020, 0x4a17, 0x1078, 0x4801, 0x0078, 0x4a25, 0x00a0, + 0x4a1e, 0x7108, 0x1078, 0x477a, 0x0078, 0x49f6, 0x7007, 0x0010, + 0x00a0, 0x4a20, 0x7108, 0x1078, 0x477a, 0x7008, 0xa086, 0x0008, + 0x00c0, 0x49f6, 0x7000, 0xa005, 0x00c0, 0x49f6, 0x7003, 0x0000, + 0x2049, 0x0000, 0x127f, 0x2000, 0x007c, 0x127e, 0x147e, 0x137e, + 0x157e, 0x0c7e, 0x0d7e, 0x2091, 0x2200, 0x0d7f, 0x2049, 0x4a35, + 0xad80, 0x0011, 0x20a0, 0x2099, 0x0031, 0x700c, 0xa084, 0x00ff, + 0x682a, 0x7007, 0x0008, 0x7007, 0x0002, 0x7003, 0x0001, 0x0040, + 0x4a54, 0x8000, 0x80ac, 0x53a5, 0x7007, 0x0004, 0x7004, 0xa084, + 0x0004, 0x00c0, 0x4a56, 0x0c7f, 0x2049, 0x0000, 0x7003, 0x0000, + 0x157f, 0x137f, 0x147f, 0x127f, 0x2000, 0x007c, 0x2091, 0x6000, + 0x2091, 0x8000, 0x78cc, 0xa005, 0x0040, 0x4a7d, 0x7994, 0x70d0, + 0xa106, 0x00c0, 0x4a7d, 0x7804, 0xa005, 0x0040, 0x4a7d, 0x7807, + 0x0000, 0x0068, 0x4a7d, 0x2091, 0x4080, 0x7820, 0x8001, 0x7822, + 0x00c0, 0x4ad8, 0x7824, 0x7822, 0x2069, 0x5040, 0x6800, 0xa084, + 0x0007, 0x0040, 0x4a9b, 0xa086, 0x0002, 0x0040, 0x4a9b, 0x6834, + 0xa00d, 0x0040, 0x4a9b, 0x2104, 0xa005, 0x0040, 0x4a9b, 0x8001, + 0x200a, 0x0040, 0x4b80, 0x7848, 0xa005, 0x0040, 0x4aa9, 0x8001, + 0x784a, 0x00c0, 0x4aa9, 0x2009, 0x0102, 0x6844, 0x200a, 0x1078, + 0x21b1, 0x6890, 0xa005, 0x0040, 0x4ab5, 0x8001, 0x6892, 0x00c0, + 0x4ab5, 0x686f, 0x0000, 0x6873, 0x0001, 0x2061, 0x5300, 0x20a9, + 0x0100, 0x2009, 0x0002, 0x6034, 0xa005, 0x0040, 0x4acb, 0x8001, + 0x6036, 0x00c0, 0x4acb, 0x6010, 0xa005, 0x0040, 0x4acb, 0x017e, + 0x1078, 0x21b1, 0x017f, 0xace0, 0x0010, 0x0070, 0x4ad1, 0x0078, + 0x4abb, 0x8109, 0x0040, 0x4ad8, 0x20a9, 0x0100, 0x0078, 0x4abb, + 0x1078, 0x4ae5, 0x1078, 0x4b0a, 0x2009, 0x5051, 0x2104, 0x2009, + 0x0102, 0x200a, 0x2091, 0x8001, 0x007c, 0x7834, 0x8001, 0x7836, + 0x00c0, 0x4b09, 0x7838, 0x7836, 0x2091, 0x8000, 0x7844, 0xa005, + 0x00c0, 0x4af4, 0x2001, 0x0101, 0x8001, 0x7846, 0xa080, 0x7300, + 0x2040, 0x2004, 0xa065, 0x0040, 0x4b09, 0x6024, 0xa005, 0x0040, + 0x4b05, 0x8001, 0x6026, 0x0040, 0x4b39, 0x6000, 0x2c40, 0x0078, + 0x4afa, 0x007c, 0x7828, 0x8001, 0x782a, 0x00c0, 0x4b38, 0x782c, + 0x782a, 0x7830, 0xa005, 0x00c0, 0x4b17, 0x2001, 0x0200, 0x8001, + 0x7832, 0x8003, 0x8003, 0x8003, 0x8003, 0xa090, 0x5300, 0xa298, + 0x0002, 0x2304, 0xa084, 0x0008, 0x0040, 0x4b38, 0xa290, 0x0009, + 0x2204, 0xa005, 0x0040, 0x4b30, 0x8001, 0x2012, 0x00c0, 0x4b38, + 0x2304, 0xa084, 0xfff7, 0xa085, 0x0080, 0x201a, 0x1078, 0x21b1, + 0x007c, 0x2069, 0x5040, 0x6800, 0xa005, 0x0040, 0x4b43, 0x6848, + 0xac06, 0x0040, 0x4b80, 0x601b, 0x0006, 0x60b4, 0xa084, 0x3f00, + 0x601e, 0x6020, 0xa084, 0x00ff, 0xa085, 0x0060, 0x6022, 0x6000, + 0x2042, 0x6714, 0x6f82, 0x1078, 0x1956, 0x6818, 0xa005, 0x0040, + 0x4b5b, 0x8001, 0x681a, 0x6808, 0xa084, 0xffef, 0x680a, 0x6810, + 0x8001, 0x00d0, 0x4b65, 0x1078, 0x23ca, 0x6812, 0x602f, 0x0000, + 0x6033, 0x0000, 0x2c68, 0x1078, 0x1c53, 0x2069, 0x5040, 0x7944, + 0xa184, 0x0100, 0x2001, 0x0006, 0x686e, 0x00c0, 0x4b7b, 0x6986, + 0x2001, 0x0004, 0x686e, 0x1078, 0x21ac, 0x2091, 0x8001, 0x007c, + 0x2069, 0x0100, 0x2009, 0x5040, 0x2104, 0xa084, 0x0007, 0x0040, + 0x4bdc, 0xa086, 0x0007, 0x00c0, 0x4b96, 0x0d7e, 0x2009, 0x5052, + 0x216c, 0x1078, 0x3a1a, 0x0d7f, 0x0078, 0x4bdc, 0x2009, 0x5052, + 0x2164, 0x1078, 0x2375, 0x601b, 0x0006, 0x6858, 0xa084, 0x3f00, + 0x601e, 0x6020, 0xa084, 0x00ff, 0xa085, 0x0048, 0x6022, 0x602f, + 0x0000, 0x6033, 0x0000, 0x6830, 0xa084, 0x0040, 0x0040, 0x4bd0, + 0x684b, 0x0004, 0x20a9, 0x0014, 0x6848, 0xa084, 0x0004, 0x0040, + 0x4bbd, 0x0070, 0x4bbd, 0x0078, 0x4bb4, 0x684b, 0x0009, 0x20a9, + 0x0014, 0x6848, 0xa084, 0x0001, 0x0040, 0x4bca, 0x0070, 0x4bca, + 0x0078, 0x4bc1, 0x20a9, 0x00fa, 0x0070, 0x4bd0, 0x0078, 0x4bcc, + 0x6808, 0xa084, 0xfffd, 0x680a, 0x681b, 0x0048, 0x2009, 0x505b, + 0x200b, 0x0007, 0x784c, 0x784a, 0x2091, 0x8001, 0x007c, 0x2079, + 0x5000, 0x1078, 0x4c0a, 0x1078, 0x4bee, 0x1078, 0x4bfc, 0x7833, + 0x0000, 0x7847, 0x0000, 0x784b, 0x0000, 0x007c, 0x2019, 0x0003, + 0x2011, 0x5046, 0x2204, 0xa086, 0x003c, 0x0040, 0x4bf9, 0x2019, + 0x0002, 0x7b2a, 0x7b2e, 0x007c, 0x2019, 0x0039, 0x2011, 0x5046, + 0x2204, 0xa086, 0x003c, 0x0040, 0x4c07, 0x2019, 0x0027, 0x7b36, + 0x7b3a, 0x007c, 0x2019, 0x3971, 0x2011, 0x5046, 0x2204, 0xa086, + 0x003c, 0x0040, 0x4c15, 0x2019, 0x2626, 0x7b22, 0x7b26, 0x783f, + 0x0000, 0x7843, 0x000a, 0x007c, 0x0020, 0x002b, 0x0000, 0x0020, + 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, + 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, + 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, + 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0014, + 0x0014, 0x9849, 0x0014, 0x0014, 0x0014, 0x0014, 0x0014, 0x0014, + 0x0014, 0x0080, 0x000f, 0x0000, 0x0201, 0x0604, 0x0c08, 0x2120, + 0x4022, 0xf880, 0x0018, 0x300b, 0xa201, 0x0014, 0xa200, 0x0014, + 0xa200, 0x0214, 0x0000, 0x006c, 0x0002, 0x0014, 0x98d5, 0x009e, + 0x009b, 0xa202, 0x8838, 0x3806, 0x8839, 0x20c3, 0x0864, 0x9889, + 0x28c1, 0x9cb6, 0xa203, 0x300c, 0x2846, 0x8161, 0x846a, 0x8300, + 0x1856, 0x883a, 0x9865, 0x28f2, 0x9c95, 0x9858, 0x300c, 0x28e1, + 0x9c95, 0x2809, 0xa206, 0x64c0, 0x67a0, 0x6fc0, 0x1814, 0x883b, + 0x782c, 0x786d, 0x9879, 0x282b, 0xa207, 0x64a0, 0x67a0, 0x6fc0, + 0x1814, 0x883b, 0x7822, 0x883e, 0x987d, 0x8576, 0x8677, 0x206b, + 0x28c1, 0x9cb6, 0x2044, 0x2103, 0x20a2, 0x2081, 0x9865, 0xa209, + 0x2901, 0x9891, 0x0014, 0xa205, 0xa300, 0x1872, 0x879a, 0x883c, + 0x1fe2, 0xc601, 0xa20a, 0x856e, 0x0704, 0x9c95, 0x0014, 0xa204, + 0xa300, 0x3009, 0x19e2, 0xf868, 0x8176, 0x86eb, 0x85eb, 0x872e, + 0x87a9, 0x883f, 0x08e6, 0x9895, 0xf881, 0x9890, 0xc801, 0x0014, + 0xf8c1, 0x0016, 0x85b2, 0x80f0, 0x9532, 0xfb02, 0x1de2, 0x0014, + 0x8532, 0xf241, 0x0014, 0x1de2, 0x84a8, 0xd7a0, 0x1fe6, 0x0014, + 0xa208, 0x6043, 0x8008, 0x1dc1, 0x0016, 0x8300, 0x8160, 0x842a, + 0xf041, 0x3008, 0x84a8, 0x11d6, 0x7042, 0x20dd, 0x0011, 0x20d5, + 0x8822, 0x0016, 0x8000, 0x2847, 0x1011, 0x98c8, 0x8000, 0xa000, + 0x2802, 0x1011, 0x98ce, 0x9865, 0x283e, 0x1011, 0x98d2, 0xa20b, + 0x0017, 0x300c, 0xa300, 0x1de2, 0xdb81, 0x0014, 0x0210, 0x98df, + 0x0014, 0x26e0, 0x873a, 0xfb02, 0x19f2, 0x1fe2, 0x0014, 0xa20d, + 0x3806, 0x0210, 0x9cbb, 0x0704, 0x0000, 0x006c, 0x0002, 0x984f, + 0x0014, 0x009e, 0x00a0, 0x0017, 0x60ff, 0x300c, 0x8720, 0xa211, + 0x9cd0, 0x8772, 0x8837, 0x2101, 0x987a, 0x10d2, 0x78e2, 0x9cd3, + 0x9859, 0xd984, 0xf0e2, 0xf0a1, 0x98cd, 0x0014, 0x8831, 0xd166, + 0x8830, 0x800f, 0x9401, 0xb520, 0xc802, 0x8820, 0x987a, 0x2301, + 0x987a, 0x10d2, 0x78e4, 0x9cd3, 0x8821, 0x8820, 0x9859, 0xf123, + 0xf142, 0xf101, 0x98c6, 0x10d2, 0x70f6, 0x8832, 0x8203, 0x870c, + 0xd99e, 0x6001, 0x0014, 0x6845, 0x0214, 0xa21b, 0x9cd0, 0x2001, + 0x98c5, 0x8201, 0x1852, 0xd184, 0xd163, 0x8834, 0x8001, 0x988d, + 0x3027, 0x84a8, 0x1a56, 0x8833, 0x0014, 0xa218, 0x6981, 0x9cbc, + 0x6b2a, 0x6902, 0x1834, 0x989d, 0x1814, 0x8010, 0x8592, 0x8026, + 0x84b9, 0x7021, 0x0014, 0xa300, 0x69e1, 0x9ca9, 0x694b, 0xa213, + 0x1462, 0xa213, 0x8000, 0x16e1, 0x98b5, 0x8023, 0x16e1, 0x8001, + 0x10f1, 0x0016, 0x6969, 0xa214, 0x61c2, 0x8002, 0x14e1, 0x8004, + 0x16e1, 0x0101, 0x300a, 0x8827, 0x0014, 0xa217, 0x9cbc, 0x0014, + 0xa300, 0x8181, 0x842a, 0x84a8, 0x1ce6, 0x882c, 0x0016, 0xa212, + 0x9cd0, 0x10d2, 0x70e4, 0x0004, 0x8007, 0x9424, 0xcc1a, 0x9cd3, + 0x98c5, 0x8827, 0x300a, 0x0013, 0x8000, 0x84a4, 0x0016, 0x11c2, + 0x211e, 0x870e, 0xa21d, 0x0014, 0x878e, 0x0016, 0xa21c, 0x1035, + 0x9891, 0xa210, 0xa000, 0x8010, 0x8592, 0x853b, 0xd044, 0x8022, + 0x3807, 0x84bb, 0x98ea, 0x8021, 0x3807, 0x84b9, 0x300c, 0x817e, + 0x872b, 0x8772, 0x9891, 0x0000, 0x0020, 0x002b, 0x0000, 0x0020, + 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, + 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, + 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, + 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0014, + 0x0014, 0x9849, 0x0014, 0x0014, 0x98ea, 0x98d5, 0x0014, 0x0014, + 0x0014, 0x0080, 0x013f, 0x0000, 0x0201, 0x0604, 0x0c08, 0x2120, + 0x4022, 0xf880, 0x0018, 0x300b, 0xa201, 0x0014, 0xa200, 0x0014, + 0xa200, 0x0214, 0xa202, 0x8838, 0x3806, 0x8839, 0x20c3, 0x0864, + 0xa833, 0x28c1, 0x9cb6, 0xa203, 0x300c, 0x2846, 0x8161, 0x846a, + 0x8300, 0x1856, 0x883a, 0xa804, 0x28f2, 0x9c95, 0xa8f4, 0x300c, + 0x28e1, 0x9c95, 0x2809, 0xa206, 0x64c0, 0x67a0, 0x6fc0, 0x1814, + 0x883b, 0x782c, 0x786d, 0xa808, 0x282b, 0xa207, 0x64a0, 0x67a0, + 0x6fc0, 0x1814, 0x883b, 0x7822, 0x883e, 0xa802, 0x8576, 0x8677, + 0x206b, 0x28c1, 0x9cb6, 0x2044, 0x2103, 0x20a2, 0x2081, 0xa8e0, + 0xa209, 0x2901, 0xa809, 0x0014, 0xa205, 0xa300, 0x1872, 0x879a, + 0x883c, 0x1fe2, 0xc601, 0xa20a, 0x856e, 0x0704, 0x9c95, 0x0014, + 0xa204, 0xa300, 0x3009, 0x19e2, 0xf868, 0x8176, 0x86eb, 0x85eb, + 0x872e, 0x87a9, 0x883f, 0x08e6, 0xa8f3, 0xf881, 0xa8ec, 0xc801, + 0x0014, 0xf8c1, 0x0016, 0x85b2, 0x80f0, 0x9532, 0xfb02, 0x1de2, + 0x0014, 0x8532, 0xf241, 0x0014, 0x1de2, 0x84a8, 0xd7a0, 0x1fe6, + 0x0014, 0xa208, 0x6043, 0x8008, 0x1dc1, 0x0016, 0x8300, 0x8160, + 0x842a, 0xf041, 0x3008, 0x84a8, 0x11d6, 0x7042, 0x20dd, 0x0011, + 0x20d5, 0x8822, 0x0016, 0x8000, 0x2847, 0x1011, 0xa8fc, 0x8000, + 0xa000, 0x2802, 0x1011, 0xa8fd, 0xa893, 0x283e, 0x1011, 0xa8fd, + 0xa20b, 0x0017, 0x300c, 0xa300, 0x1de2, 0xdb81, 0x0014, 0x0210, + 0xa801, 0x0014, 0x26e0, 0x873a, 0xfb02, 0x19f2, 0x1fe2, 0x0014, + 0xa20d, 0x3806, 0x0210, 0x9cbb, 0x0704, 0x0017, 0x60ff, 0x300c, + 0x8720, 0xa211, 0x9d6b, 0x8772, 0x8837, 0x2101, 0xa821, 0x10d2, + 0x78e2, 0x9d6e, 0xa8fc, 0xd984, 0xf0e2, 0xf0a1, 0xa86c, 0x0014, + 0x8831, 0xd166, 0x8830, 0x800f, 0x9401, 0xb520, 0xc802, 0x8820, + 0xa80f, 0x2301, 0xa80d, 0x10d2, 0x78e4, 0x9d6e, 0x8821, 0x8820, + 0xa8e6, 0xf123, 0xf142, 0xf101, 0xa84f, 0x10d2, 0x70f6, 0x8832, + 0x8203, 0x870c, 0xd99e, 0x6001, 0x0014, 0x6845, 0x0214, 0xa21b, + 0x9d6b, 0x2001, 0xa840, 0x8201, 0x1852, 0xd184, 0xd163, 0x8834, + 0x8001, 0xa801, 0x3027, 0x84a8, 0x1a56, 0x8833, 0x0014, 0xa218, + 0x6981, 0x9d57, 0x6b2a, 0x6902, 0x1834, 0xa805, 0x1814, 0x8010, + 0x8592, 0x8026, 0x84b9, 0x7021, 0x0014, 0xa300, 0x69e1, 0x9d44, + 0x694b, 0xa213, 0x1462, 0xa213, 0x8000, 0x16e1, 0xa80c, 0x8023, + 0x16e1, 0x8001, 0x10f1, 0x0016, 0x6969, 0xa214, 0x61c2, 0x8002, + 0x14e1, 0x8004, 0x16e1, 0x0101, 0x300a, 0x8827, 0x0014, 0xa217, + 0x9d57, 0x0014, 0xa300, 0x8181, 0x842a, 0x84a8, 0x1ce6, 0x882c, + 0x0016, 0xa212, 0x9d6b, 0x10d2, 0x70e4, 0x0004, 0x8007, 0x9424, + 0xcc1a, 0x9d6e, 0xa8f8, 0x8827, 0x300a, 0x0013, 0x8000, 0x84a4, + 0x0016, 0x11c2, 0x211e, 0x870e, 0xa21d, 0x0014, 0x878e, 0x0016, + 0xa21c, 0x1035, 0xa8b4, 0xa210, 0x3807, 0x300c, 0x817e, 0x872b, + 0x8772, 0xa8ad, 0x0000, 0x8ec6 }; #endif /* RELOAD_FIRMWARE */ -static const unsigned short risc_code_length01 = 0x283a; +static const unsigned short risc_code_length01 = 0x3f14; diff -ur --new-file old/linux/drivers/scsi/qlogicpti.c new/linux/drivers/scsi/qlogicpti.c --- old/linux/drivers/scsi/qlogicpti.c Sun Oct 4 19:22:44 1998 +++ new/linux/drivers/scsi/qlogicpti.c Tue Mar 16 01:11:31 1999 @@ -223,9 +223,15 @@ struct qlogicpti *qpti = (struct qlogicpti *) host->hostdata; struct qlogicpti_regs *qregs = qpti->qregs; u_short param[6]; + unsigned short risc_code_addr; int loop_count, i; unsigned long flags; + if(qpti->is_pti != 0) + risc_code_addr = pti_risc_code_addr01; + else + risc_code_addr = sbus_risc_code_addr01; + save_flags(flags); cli(); qregs->hcctrl = HCCTRL_PAUSE; @@ -264,7 +270,7 @@ /* Get RISC to start executing the firmware code. */ param[0] = MBOX_EXEC_FIRMWARE; - param[1] = risc_code_addr01; + param[1] = risc_code_addr; if(qlogicpti_mbox_command(qpti, param, 1)) { printk(KERN_EMERG "qlogicpti%d: Cannot execute ISP firmware.\n", qpti->qpti_id); @@ -352,21 +358,32 @@ struct qlogicpti_regs *qregs = qpti->qregs; unsigned short csum = 0; unsigned short param[6]; + unsigned short *risc_code, risc_code_addr, risc_code_length; unsigned long flags; #if !defined(MODULE) && !defined(__sparc_v9__) unsigned long dvma_addr; #endif int i, timeout; + if(qpti->is_pti != 0) { + risc_code = &pti_risc_code01[0]; + risc_code_addr = pti_risc_code_addr01; + risc_code_length = pti_risc_code_length01; + } else { + risc_code = &sbus_risc_code01[0]; + risc_code_addr = sbus_risc_code_addr01; + risc_code_length = sbus_risc_code_length01; + } + save_flags(flags); cli(); /* Verify the checksum twice, one before loading it, and once * afterwards via the mailbox commands. */ - for(i = 0; i < risc_code_length01; i++) - csum += risc_code01[i]; + for(i = 0; i < risc_code_length; i++) + csum += risc_code[i]; if(csum) { - printk(KERN_EMERG "qlogicpti%d: AIeee, firmware checksum failed!", + printk(KERN_EMERG "qlogicpti%d: Aieee, firmware checksum failed!", qpti->qpti_id); return 1; } @@ -406,11 +423,6 @@ qpti->differential = 0; qregs->hcctrl = HCCTRL_REL; - /* XXX Talk to PTI engineer about the following, ISP always - * XXX returns 0x4001 return status for stop firmware command, - * XXX documentation claims this means the cmd is unsupported - * XXX on this ISP. I think something fishy is going on. - */ param[0] = MBOX_STOP_FIRMWARE; param[1] = param[2] = param[3] = param[4] = param[5] = 0; if(qlogicpti_mbox_command(qpti, param, 1)) { @@ -423,13 +435,13 @@ /* Load the firmware. */ #if !defined(MODULE) && !defined(__sparc_v9__) if (sparc_cpu_model != sun4d) { - dvma_addr = (unsigned long) mmu_lockarea((char *)&risc_code01[0], - (sizeof(u_short) * risc_code_length01)); + dvma_addr = (unsigned long) mmu_lockarea((char *)&risc_code[0], + (sizeof(u_short) * risc_code_length)); param[0] = MBOX_LOAD_RAM; - param[1] = risc_code_addr01; + param[1] = risc_code_addr; param[2] = (dvma_addr >> 16); param[3] = (dvma_addr & 0xffff); - param[4] = (sizeof(u_short) * risc_code_length01); + param[4] = (sizeof(u_short) * risc_code_length); if(qlogicpti_mbox_command(qpti, param, 1) || (param[0] != MBOX_COMMAND_COMPLETE)) { printk(KERN_EMERG "qlogicpti%d: Firmware dload failed, I'm bolixed!\n", @@ -437,14 +449,14 @@ restore_flags(flags); return 1; } - mmu_unlockarea((char *)dvma_addr, (sizeof(u_short) * risc_code_length01)); + mmu_unlockarea((char *)dvma_addr, (sizeof(u_short) * risc_code_length)); } else #endif /* We need to do it this slow way always on Ultra, SS[12]000. */ - for(i = 0; i < risc_code_length01; i++) { + for(i = 0; i < risc_code_length; i++) { param[0] = MBOX_WRITE_RAM_WORD; - param[1] = risc_code_addr01 + i; - param[2] = risc_code01[i]; + param[1] = risc_code_addr + i; + param[2] = risc_code[i]; if(qlogicpti_mbox_command(qpti, param, 1) || param[0] != MBOX_COMMAND_COMPLETE) { printk("qlogicpti%d: Firmware dload failed, I'm bolixed!\n", @@ -464,7 +476,7 @@ /* Ask ISP to verify the checksum of the new code. */ param[0] = MBOX_VERIFY_CHECKSUM; - param[1] = risc_code_addr01; + param[1] = risc_code_addr; if(qlogicpti_mbox_command(qpti, param, 1) || (param[0] != MBOX_COMMAND_COMPLETE)) { printk(KERN_EMERG "qlogicpti%d: New firmware csum failure!\n", @@ -475,7 +487,7 @@ /* Start using newly downloaded firmware. */ param[0] = MBOX_EXEC_FIRMWARE; - param[1] = risc_code_addr01; + param[1] = risc_code_addr; qlogicpti_mbox_command(qpti, param, 1); param[0] = MBOX_ABOUT_FIRMWARE; @@ -491,16 +503,18 @@ qpti->fware_majrev = param[1]; qpti->fware_minrev = param[2]; - /* Load scsi initiator ID and interrupt level into sbus static ram. */ - param[0] = MBOX_WRITE_RAM_WORD; - param[1] = 0xff80; - param[2] = (unsigned short) qpti->scsi_id; - qlogicpti_mbox_command(qpti, param, 1); - - param[0] = MBOX_WRITE_RAM_WORD; - param[1] = 0xff00; - param[2] = (unsigned short) 3; - qlogicpti_mbox_command(qpti, param, 1); + if(qpti->is_pti != 0) { + /* Load scsi initiator ID and interrupt level into sbus static ram. */ + param[0] = MBOX_WRITE_RAM_WORD; + param[1] = 0xff80; + param[2] = (unsigned short) qpti->scsi_id; + qlogicpti_mbox_command(qpti, param, 1); + + param[0] = MBOX_WRITE_RAM_WORD; + param[1] = 0xff00; + param[2] = (unsigned short) 3; + qlogicpti_mbox_command(qpti, param, 1); + } restore_flags(flags); return 0; @@ -617,6 +631,10 @@ /* We are wide capable, 16 targets. */ qpti_host->max_id = MAX_TARGETS; +#ifdef __sparc_v9__ + qpti_host->unchecked_isa_dma = 1; +#endif + /* Setup back pointers and misc. state. */ qpti->qhost = qpti_host; qpti->qdev = qpti_dev; @@ -638,7 +656,8 @@ sizeof(qpti->prom_name)); qpti->prom_node = qpti_node; - is_pti = strcmp (qpti->prom_name, "QLGC,isp"); + qpti->is_pti = is_pti = + (strcmp (qpti->prom_name, "QLGC,isp") != 0); /* Setup the reg property for this device. */ prom_apply_sbus_ranges(qpti->qdev->my_bus, @@ -728,6 +747,9 @@ bsizes = (DMA_BURST32 - 1); qpti->bursts = bsizes; + /* Clear out Scsi_Cmnd array. */ + memset(qpti->cmd_slots, 0, sizeof(qpti->cmd_slots)); + /* The request and response queues must each be aligned * on a page boundry. */ @@ -747,11 +769,13 @@ /* Set adapter and per-device default values. */ qlogicpti_set_hostdev_defaults(qpti); - if (is_pti) { - /* Load the firmware. */ - if(qlogicpti_load_firmware(qpti)) - panic("PTI Qlogic/ISP firmware load failed"); + /* Load the firmware. */ + /* XXX Find out where is it possible to download + our sbus_risc_code on non-PTI ISP1000. */ + if(is_pti && qlogicpti_load_firmware(qpti)) + panic("SBUS Qlogic/ISP firmware load failed"); + if (is_pti) { /* Check the PTI status reg. */ if(qlogicpti_verify_tmon(qpti)) panic("PTI Qlogic/ISP tmon verification failed"); @@ -768,7 +792,10 @@ char buffer[60]; prom_getstring (qpti_node, "isp-fcode", buffer, 60); - printk("(Firmware %s)", buffer); + if (buffer[0]) + printk("(Firmware %s)", buffer); + if (prom_getbool(qpti_node, "differential")) + qpti->differential = 1; } printk (" [%s Wide, using %s interface]\n", @@ -831,11 +858,6 @@ memset(cmd, 0, sizeof(struct Command_Entry)); cmd->hdr.entry_cnt = 1; cmd->hdr.entry_type = ENTRY_COMMAND; -#ifdef __sparc_v9__ - cmd->handle = (u_int) (((unsigned long)Cmnd) - PAGE_OFFSET); /* magic mushroom */ -#else - cmd->handle = (u_int) ((unsigned long)Cmnd); /* magic mushroom */ -#endif cmd->target_id = Cmnd->target; cmd->target_lun = Cmnd->lun; cmd->cdb_length = Cmnd->cmd_len; @@ -924,9 +946,15 @@ cmd->dataseg[0].d_count = Cmnd->request_bufflen; cmd->segment_cnt = 1; } + + /* Committed, record Scsi_Cmd so we can find it later. */ + cmd->handle = in_ptr; + qpti->cmd_slots[in_ptr] = Cmnd; + qpti->cmd_count[Cmnd->target]++; qregs->mbox4 = in_ptr; qpti->req_in_ptr = in_ptr; + return in_ptr; } @@ -1099,9 +1127,18 @@ /* This looks like a network driver! */ out_ptr = qpti->res_out_ptr; while(out_ptr != in_ptr) { + u_int cmd_slot; + sts = (struct Status_Entry *) &qpti->res_cpu[out_ptr]; out_ptr = NEXT_RES_PTR(out_ptr); - Cmnd = (Scsi_Cmnd *) (((unsigned long)sts->handle)+PAGE_OFFSET); + + /* We store an index in the handle, not the pointer in + * some form. This avoids problems due to the fact + * that the handle provided is only 32-bits. -DaveM + */ + cmd_slot = sts->handle; + Cmnd = qpti->cmd_slots[cmd_slot]; + qpti->cmd_slots[cmd_slot] = NULL; if(sts->completion_status == CS_RESET_OCCURRED || sts->completion_status == CS_ABORTED || @@ -1144,8 +1181,8 @@ int again; spin_lock_irqsave(&io_request_lock, flags); - again = 0; do { + again = 0; for_each_qlogicpti(qpti) again |= qlogicpti_intr_handler(qpti); } while (again); diff -ur --new-file old/linux/drivers/scsi/qlogicpti.h new/linux/drivers/scsi/qlogicpti.h --- old/linux/drivers/scsi/qlogicpti.h Wed Aug 5 01:56:37 1998 +++ new/linux/drivers/scsi/qlogicpti.h Tue Mar 16 01:11:31 1999 @@ -455,16 +455,24 @@ /* These are the hot elements in the cache, so they come first. */ struct qlogicpti *next; /* Next active adapter */ struct qlogicpti_regs *qregs; /* Adapter registers */ - u_int req_in_ptr; /* index of next request slot */ - u_int res_out_ptr; /* index of next result slot */ struct pti_queue_entry *res_cpu; /* Ptr to RESPONSE bufs (CPU) */ - __u32 res_dvma; /* Ptr to RESPONSE bufs (DVMA)*/ struct pti_queue_entry *req_cpu; /* Ptr to REQUEST bufs (CPU) */ + + __u32 res_dvma; /* Ptr to RESPONSE bufs (DVMA)*/ __u32 req_dvma; /* Ptr to REQUEST bufs (DVMA) */ + u_int req_in_ptr; /* index of next request slot */ + u_int res_out_ptr; /* index of next result slot */ + int cmd_count[MAX_TARGETS]; unsigned long tag_ages[MAX_TARGETS]; long send_marker; /* must we send a marker? */ + /* The cmd->handler is only 32-bits, so that things work even on monster + * Ex000 sparc64 machines with >4GB of ram we just keep track of the + * scsi command pointers here. This is essentially what Matt Jacob does. -DaveM + */ + Scsi_Cmnd *cmd_slots[QLOGICISP_REQ_QUEUE_LEN + 1]; + /* The rest of the elements are unimportant for performance. */ u_char fware_majrev, fware_minrev; struct Scsi_Host *qhost; @@ -487,11 +495,7 @@ #define SREG_IMASK 0x0c /* Interrupt level */ #define SREG_SPMASK 0x03 /* Mask for switch pack */ unsigned char swsreg; - -#if 0 - char res[RES_QUEUE_LEN+1][QUEUE_ENTRY_LEN]; - char req[QLOGICISP_REQ_QUEUE_LEN+1][QUEUE_ENTRY_LEN]; -#endif + unsigned char is_pti; /* Non-zero if this is a PTI board. */ }; /* How to twiddle them bits... */ diff -ur --new-file old/linux/drivers/scsi/qlogicpti_asm.c new/linux/drivers/scsi/qlogicpti_asm.c --- old/linux/drivers/scsi/qlogicpti_asm.c Thu Apr 24 04:01:22 1997 +++ new/linux/drivers/scsi/qlogicpti_asm.c Tue Mar 16 01:11:31 1999 @@ -1,8 +1,8 @@ /* Version 1.24 Initiator Firmware (Aug 8, 1996) */ -unsigned short risc_code_addr01 = 0x1000; +unsigned short pti_risc_code_addr01 = 0x1000; -unsigned short risc_code01[] __initdata = { +unsigned short pti_risc_code01[] __initdata = { 0x0078, 0x1030, 0x0000, 0x231f, 0x0000, 0x12ff, 0x2043, 0x4f50, 0x5952, 0x4947, 0x4854, 0x2031, 0x3939, 0x312c, 0x3139, 0x3932, 0x2c31, 0x3939, 0x332c, 0x3139, 0x3934, 0x2051, 0x4c4f, 0x4749, @@ -1129,4 +1129,1170 @@ 0x331b, 0x2019, 0x2626, 0x7b22, 0x7b26, 0x007c, 0xae5b }; -unsigned short risc_code_length01 = 0x231f; +unsigned short pti_risc_code_length01 = 0x231f; + +/* Version 1.31.00 ISP1000 Initiator RISC firmware + * We use this for all non-PTI SBUS boards. + */ +unsigned short sbus_risc_code_addr01 = 0x1000; + +unsigned short sbus_risc_code01[] __initdata = { + 0x0078, 0x1030, 0xa5e3, 0x241a, 0x0001, 0x12ff, 0x2043, 0x4f50, + 0x5952, 0x4947, 0x4854, 0x2031, 0x3939, 0x312c, 0x3139, 0x3932, + 0x2c31, 0x3939, 0x332c, 0x3139, 0x3934, 0x2051, 0x4c4f, 0x4749, + 0x4320, 0x434f, 0x5250, 0x4f52, 0x4154, 0x494f, 0x4e00, 0x2049, + 0x5350, 0x3130, 0x3030, 0x2046, 0x6972, 0x6d77, 0x6172, 0x6520, + 0x2056, 0x6572, 0x7369, 0x6f6e, 0x2030, 0x312e, 0x3331, 0x2020, + 0x2071, 0x0010, 0x70c3, 0x0004, 0x20c9, 0x3fff, 0x2089, 0x10ca, + 0x70c7, 0x4953, 0x70cb, 0x5020, 0x70cf, 0x2020, 0x70d3, 0x0001, + 0x3f00, 0x70d6, 0x2031, 0x0030, 0x2079, 0x3500, 0x7863, 0x0000, + 0x2fa0, 0x2009, 0x012b, 0x2011, 0x0000, 0x20a9, 0x0040, 0x42a4, + 0x8109, 0x00c0, 0x104d, 0x789b, 0x0101, 0x780b, 0x0002, 0x780f, + 0x0002, 0x784f, 0x0bb8, 0x2069, 0x3540, 0x00a8, 0x106c, 0x681b, + 0x003c, 0x2009, 0x1313, 0xa18c, 0xff00, 0x3700, 0xa084, 0x00ff, + 0xa105, 0x20b8, 0x0078, 0x106e, 0x681b, 0x0028, 0x6807, 0x0007, + 0x680b, 0x00fa, 0x680f, 0x0008, 0x6813, 0x0005, 0x681f, 0x0000, + 0x6823, 0x0006, 0x6817, 0x0008, 0x6827, 0x0000, 0x2069, 0x3600, + 0x2011, 0x0020, 0x2009, 0x0010, 0x680b, 0x0c19, 0x680f, 0x0019, + 0x6803, 0xdd00, 0x6807, 0x001a, 0x6a1a, 0x2d00, 0xa0e8, 0x0008, + 0xa290, 0x0004, 0x8109, 0x00c0, 0x1084, 0x2069, 0x3680, 0x20a9, + 0x0080, 0x6837, 0x0000, 0x680b, 0x0040, 0x6817, 0x0064, 0x681f, + 0x0002, 0xade8, 0x0010, 0x0070, 0x10a7, 0x0078, 0x1099, 0x1078, + 0x1a42, 0x1078, 0x2f3d, 0x1078, 0x168b, 0x1078, 0x33bb, 0x3200, + 0xa085, 0x000d, 0x2090, 0x70c3, 0x0000, 0x0090, 0x10be, 0x70c0, + 0xa086, 0x0002, 0x00c0, 0x10be, 0x1078, 0x11be, 0x1078, 0x10ee, + 0x1078, 0x1821, 0x1078, 0x19b2, 0x1078, 0x3280, 0x1078, 0x1787, + 0x0078, 0x10be, 0x10d2, 0x10d4, 0x1b9f, 0x1b9f, 0x2f9b, 0x2f9b, + 0x1b9f, 0x1b9f, 0x0078, 0x10d2, 0x0078, 0x10d4, 0x0078, 0x10d6, + 0x0078, 0x10d8, 0x7008, 0x800c, 0x00c8, 0x10e9, 0x7007, 0x0002, + 0xa08c, 0x000c, 0x00c0, 0x10ea, 0x8004, 0x8004, 0x00c8, 0x10e9, + 0x087a, 0x097a, 0x70c3, 0x4002, 0x0078, 0x11c1, 0x0068, 0x1133, + 0x7814, 0xa005, 0x00c0, 0x10f8, 0x0010, 0x1134, 0x0078, 0x1133, + 0x2009, 0x3568, 0x2104, 0xa005, 0x00c0, 0x1133, 0x7814, 0xa086, + 0x0001, 0x00c0, 0x1105, 0x1078, 0x1540, 0x7817, 0x0000, 0x2009, + 0x356f, 0x2104, 0xa065, 0x0040, 0x1121, 0x2009, 0x356a, 0x211c, + 0x8108, 0x2114, 0x8108, 0x2104, 0xa210, 0xa399, 0x0000, 0x2009, + 0x001c, 0x6083, 0x0103, 0x1078, 0x161b, 0x00c0, 0x112d, 0x1078, + 0x1682, 0x2009, 0x356f, 0x200b, 0x0000, 0x2009, 0x3569, 0x2104, + 0x200b, 0x0000, 0xa005, 0x0040, 0x1131, 0x2001, 0x4005, 0x0078, + 0x11c0, 0x0078, 0x11be, 0x007c, 0x2061, 0x0000, 0x6018, 0xa084, + 0x0001, 0x0040, 0x113c, 0x007c, 0x70c3, 0x0000, 0x70c7, 0x0000, + 0x70cb, 0x0000, 0x70cf, 0x0000, 0x70c0, 0xa0bc, 0xffc0, 0x00c0, + 0x118c, 0x2038, 0x0079, 0x114c, 0x11be, 0x1209, 0x11d7, 0x1209, + 0x125a, 0x125a, 0x11ce, 0x159a, 0x1265, 0x11ca, 0x11db, 0x11dd, + 0x11df, 0x11e1, 0x159f, 0x11ca, 0x126b, 0x1287, 0x154e, 0x1594, + 0x11e3, 0x1475, 0x1497, 0x14b1, 0x14da, 0x142e, 0x143c, 0x1450, + 0x1464, 0x12f3, 0x11ca, 0x12a3, 0x12aa, 0x12af, 0x12b4, 0x12ba, + 0x12bf, 0x12c4, 0x12c9, 0x12ce, 0x12d2, 0x12e7, 0x11ca, 0x11ca, + 0x11ca, 0x11ca, 0x11ca, 0x12ff, 0x1308, 0x1317, 0x133d, 0x1347, + 0x134e, 0x137a, 0x1389, 0x1398, 0x13aa, 0x1413, 0x11ca, 0x11ca, + 0x11ca, 0x11ca, 0x11ca, 0x1423, 0xa0bc, 0xffa0, 0x00c0, 0x11ca, + 0x2038, 0xa084, 0x001f, 0x0079, 0x1195, 0x11ca, 0x11ca, 0x11ca, + 0x11ca, 0x11ca, 0x11ca, 0x11ca, 0x11ca, 0x11ca, 0x11ca, 0x11ca, + 0x11ca, 0x11ca, 0x11ca, 0x11ca, 0x11ca, 0x11ca, 0x11ca, 0x11ca, + 0x11ca, 0x11ca, 0x11ca, 0x11ca, 0x11ca, 0x11ca, 0x11ca, 0x15f7, + 0x1601, 0x1605, 0x1613, 0x11ca, 0x11ca, 0x72ca, 0x71c6, 0x2001, + 0x4006, 0x0078, 0x11c0, 0x73ce, 0x72ca, 0x71c6, 0x2001, 0x4000, + 0x70c2, 0x2061, 0x0000, 0x601b, 0x0001, 0x2091, 0x5000, 0x2091, + 0x4080, 0x007c, 0x70c3, 0x4001, 0x0078, 0x11c1, 0x2099, 0x0041, + 0x20a1, 0x0041, 0x20a9, 0x0005, 0x53a3, 0x0078, 0x11be, 0x70c4, + 0x70c3, 0x0004, 0x007a, 0x0078, 0x11be, 0x0078, 0x11be, 0x0078, + 0x11be, 0x0078, 0x11be, 0x2091, 0x8000, 0x70c3, 0x0000, 0x70c7, + 0x4953, 0x70cb, 0x5020, 0x70cf, 0x2020, 0x70d3, 0x0001, 0x3f00, + 0x70d6, 0x2079, 0x0000, 0x781b, 0x0001, 0x2031, 0x0030, 0x2059, + 0x1000, 0x2029, 0x0457, 0x2051, 0x0470, 0x2061, 0x0472, 0x20b9, + 0xffff, 0x20c1, 0x0000, 0x2091, 0x5000, 0x2091, 0x4080, 0x0078, + 0x0455, 0x71d0, 0x72c8, 0x73cc, 0x70c4, 0x20a0, 0x2098, 0x2031, + 0x0030, 0x81ff, 0x0040, 0x11be, 0x7007, 0x0004, 0x731a, 0x721e, + 0x2051, 0x0012, 0x2049, 0x1238, 0x2041, 0x11be, 0x7003, 0x0002, + 0xa786, 0x0001, 0x00c0, 0x122a, 0x2049, 0x1246, 0x2041, 0x1252, + 0x7003, 0x0003, 0x7017, 0x0000, 0x810b, 0x7112, 0x00c8, 0x1232, + 0x7017, 0x0001, 0x7007, 0x0001, 0xa786, 0x0001, 0x0040, 0x1246, + 0x700c, 0xa084, 0x007f, 0x8004, 0x2009, 0x0020, 0xa102, 0x0942, + 0x094a, 0x20a8, 0x26a0, 0x53a6, 0x0078, 0x10da, 0x700c, 0xa084, + 0x007f, 0x0040, 0x1246, 0x80ac, 0x0048, 0x1246, 0x2698, 0x53a5, + 0x0078, 0x10da, 0x700c, 0xa084, 0x007f, 0x80ac, 0x2698, 0x53a5, + 0x0078, 0x11be, 0x71c4, 0x70c8, 0x2114, 0xa79e, 0x0004, 0x00c0, + 0x1262, 0x200a, 0x72ca, 0x0078, 0x11bd, 0x70c7, 0x0001, 0x70cb, + 0x001f, 0x0078, 0x11be, 0x70c4, 0x72c8, 0x73cc, 0x74d0, 0x70c6, + 0x72ca, 0x73ce, 0x74d2, 0xa005, 0x0040, 0x1281, 0x8001, 0x7872, + 0x7a7a, 0x7b7e, 0x7c76, 0x7898, 0xa084, 0xfffc, 0x789a, 0x0078, + 0x1285, 0x7898, 0xa085, 0x0001, 0x789a, 0x0078, 0x11be, 0x70c4, + 0x72c8, 0x73cc, 0x74d4, 0x70c6, 0x72ca, 0x73ce, 0x74d6, 0xa005, + 0x0040, 0x129d, 0x8001, 0x7886, 0x7a8e, 0x7b92, 0x7c8a, 0x7898, + 0xa084, 0xfcff, 0x789a, 0x0078, 0x12a1, 0x7898, 0xa085, 0x0100, + 0x789a, 0x0078, 0x11be, 0x2009, 0x3559, 0x210c, 0x2011, 0x015c, + 0x0078, 0x11bc, 0x2009, 0x3541, 0x210c, 0x0078, 0x11bd, 0x2009, + 0x3542, 0x210c, 0x0078, 0x11bd, 0x2061, 0x3540, 0x610c, 0x6210, + 0x0078, 0x11bc, 0x2009, 0x3545, 0x210c, 0x0078, 0x11bd, 0x2009, + 0x3546, 0x210c, 0x0078, 0x11bd, 0x2009, 0x3547, 0x210c, 0x0078, + 0x11bd, 0x2009, 0x3548, 0x210c, 0x0078, 0x11bd, 0x7908, 0x7a0c, + 0x0078, 0x11bc, 0x71c4, 0x8107, 0xa084, 0x000f, 0x8003, 0x8003, + 0x8003, 0xa0e8, 0x3600, 0x6a00, 0x6804, 0xa084, 0x0008, 0x0040, + 0x12e4, 0x6b08, 0x0078, 0x12e5, 0x6b0c, 0x0078, 0x11bb, 0x77c4, + 0x1078, 0x169c, 0x2091, 0x8000, 0x6b1c, 0x6a14, 0x2091, 0x8001, + 0x2708, 0x0078, 0x11bb, 0x77c4, 0x1078, 0x169c, 0x2091, 0x8000, + 0x6908, 0x6a18, 0x6b10, 0x2091, 0x8001, 0x0078, 0x11bb, 0x71c4, + 0xa182, 0x0010, 0x00c8, 0x11b6, 0x1078, 0x1ac6, 0x0078, 0x11bb, + 0x71c4, 0xa182, 0x0010, 0x00c8, 0x11b6, 0x2011, 0x3541, 0x2204, + 0x007e, 0x2112, 0x1078, 0x1a7f, 0x017f, 0x0078, 0x11bd, 0x71c4, + 0x2011, 0x1335, 0x20a9, 0x0008, 0x2204, 0xa106, 0x0040, 0x1327, + 0x8210, 0x0070, 0x1325, 0x0078, 0x131c, 0x0078, 0x11b6, 0xa292, + 0x1335, 0x027e, 0x2011, 0x3542, 0x2204, 0x2112, 0x017f, 0x007e, + 0x1078, 0x1a8b, 0x017f, 0x0078, 0x11bd, 0x03e8, 0x00fa, 0x01f4, + 0x02ee, 0x0064, 0x0019, 0x0032, 0x004b, 0x2061, 0x3540, 0x610c, + 0x6210, 0x70c4, 0x600e, 0x70c8, 0x6012, 0x0078, 0x11bc, 0x2061, + 0x3540, 0x6114, 0x70c4, 0x6016, 0x0078, 0x11bd, 0x71c4, 0x2011, + 0x0004, 0x2019, 0x1212, 0xa186, 0x0028, 0x0040, 0x1367, 0x2011, + 0x0005, 0x2019, 0x1212, 0xa186, 0x0032, 0x0040, 0x1367, 0x2011, + 0x0006, 0x2019, 0x1313, 0xa186, 0x003c, 0x00c0, 0x11b6, 0x2061, + 0x3540, 0x6018, 0x007e, 0x611a, 0xa39c, 0xff00, 0x3700, 0xa084, + 0x00ff, 0xa305, 0x20b8, 0x1078, 0x1a9c, 0x1078, 0x33bb, 0x017f, + 0x0078, 0x11bd, 0x71c4, 0xa184, 0xffcf, 0x00c0, 0x11b6, 0x2011, + 0x3547, 0x2204, 0x2112, 0x007e, 0x1078, 0x1abe, 0x017f, 0x0078, + 0x11bd, 0x71c4, 0xa182, 0x0010, 0x00c8, 0x11b6, 0x2011, 0x3548, + 0x2204, 0x007e, 0x2112, 0x1078, 0x1aad, 0x017f, 0x0078, 0x11bd, + 0x71c4, 0x72c8, 0xa184, 0xfffd, 0x00c0, 0x11b5, 0xa284, 0xfffd, + 0x00c0, 0x11b5, 0x2100, 0x7908, 0x780a, 0x2200, 0x7a0c, 0x780e, + 0x0078, 0x11bc, 0x71c4, 0x8107, 0xa084, 0x000f, 0x8003, 0x8003, + 0x8003, 0xa0e8, 0x3600, 0x2019, 0x0000, 0x72c8, 0x6800, 0x007e, + 0xa226, 0x0040, 0x13d9, 0x6a02, 0xa484, 0x2000, 0x0040, 0x13c2, + 0xa39d, 0x0010, 0xa484, 0x1000, 0x0040, 0x13c8, 0xa39d, 0x0008, + 0xa484, 0x4000, 0x0040, 0x13d9, 0x810f, 0xa284, 0x4000, 0x0040, + 0x13d5, 0x1078, 0x1ae0, 0x0078, 0x13d9, 0x1078, 0x1ad2, 0x0078, + 0x13d9, 0x72cc, 0x82ff, 0x0040, 0x140b, 0x6808, 0xa206, 0x0040, + 0x140b, 0xa2a4, 0x00ff, 0x2061, 0x3540, 0x6118, 0xa186, 0x0028, + 0x0040, 0x13f2, 0xa186, 0x0032, 0x0040, 0x13f8, 0xa186, 0x003c, + 0x0040, 0x13fe, 0xa482, 0x0064, 0x0048, 0x1408, 0x0078, 0x1402, + 0xa482, 0x0050, 0x0048, 0x1408, 0x0078, 0x1402, 0xa482, 0x0043, + 0x0048, 0x1408, 0x71c4, 0x71c6, 0x027f, 0x72ca, 0x0078, 0x11b7, + 0x6a0a, 0xa39d, 0x000a, 0x6804, 0xa305, 0x6806, 0x027f, 0x6b0c, + 0x71c4, 0x0078, 0x11bb, 0x77c4, 0x1078, 0x169c, 0x2091, 0x8000, + 0x6a14, 0x6b1c, 0x2091, 0x8001, 0x70c8, 0x6816, 0x70cc, 0x681e, + 0x2708, 0x0078, 0x11bb, 0x71c4, 0x72c8, 0x73cc, 0xa182, 0x0010, + 0x00c8, 0x11b6, 0x1078, 0x1aee, 0x0078, 0x11bb, 0x77c4, 0x1078, + 0x169c, 0x2091, 0x8000, 0x6a08, 0xa295, 0x0002, 0x6a0a, 0x2091, + 0x8001, 0x2708, 0x0078, 0x11bc, 0x77c4, 0x1078, 0x169c, 0x2091, + 0x8000, 0x6a08, 0xa294, 0xfff9, 0x6a0a, 0x6804, 0xa005, 0x0040, + 0x144b, 0x1078, 0x1a23, 0x2091, 0x8001, 0x2708, 0x0078, 0x11bc, + 0x77c4, 0x1078, 0x169c, 0x2091, 0x8000, 0x6a08, 0xa295, 0x0004, + 0x6a0a, 0x6804, 0xa005, 0x0040, 0x145f, 0x1078, 0x1a23, 0x2091, + 0x8001, 0x2708, 0x0078, 0x11bc, 0x77c4, 0x2041, 0x0001, 0x2049, + 0x0005, 0x2051, 0x0020, 0x2091, 0x8000, 0x1078, 0x16a9, 0x2091, + 0x8001, 0x2708, 0x6a08, 0x0078, 0x11bc, 0x77c4, 0x72c8, 0x73cc, + 0x77c6, 0x72ca, 0x73ce, 0x1078, 0x1722, 0x00c0, 0x1493, 0x6818, + 0xa005, 0x0040, 0x148d, 0x2708, 0x1078, 0x1afe, 0x00c0, 0x148d, + 0x7817, 0xffff, 0x2091, 0x8001, 0x007c, 0x2091, 0x8001, 0x2001, + 0x4005, 0x0078, 0x11c0, 0x2091, 0x8001, 0x0078, 0x11be, 0x77c4, + 0x77c6, 0x2041, 0x0021, 0x2049, 0x0005, 0x2051, 0x0020, 0x2091, + 0x8000, 0x1078, 0x16a9, 0x2061, 0x3540, 0x60a3, 0x0003, 0x67b6, + 0x60a7, 0x0000, 0x7817, 0xffff, 0x2091, 0x8001, 0x1078, 0x1a23, + 0x007c, 0x77c8, 0x77ca, 0x77c4, 0x77c6, 0xa7bc, 0xff00, 0x2091, + 0x8000, 0x2061, 0x3540, 0x60a3, 0x0002, 0x60a7, 0x0000, 0x67b6, + 0x7817, 0xffff, 0x1078, 0x1a23, 0x2091, 0x8001, 0x2041, 0x0021, + 0x2049, 0x0004, 0x2051, 0x0010, 0x2091, 0x8000, 0x1078, 0x16a9, + 0x70c8, 0x6836, 0x8738, 0xa784, 0x0007, 0x00c0, 0x14ce, 0x2091, + 0x8001, 0x007c, 0x7898, 0xa084, 0x0003, 0x00c0, 0x14fe, 0x2039, + 0x0000, 0x2041, 0x0021, 0x2049, 0x0004, 0x2051, 0x0008, 0x1078, + 0x169c, 0x2091, 0x8000, 0x6808, 0xa80d, 0x690a, 0x2091, 0x8001, + 0x8738, 0xa784, 0x0007, 0x00c0, 0x14e7, 0xa7bc, 0xff00, 0x873f, + 0x8738, 0x873f, 0xa784, 0x0f00, 0x00c0, 0x14e7, 0x2091, 0x8000, + 0x2069, 0x0100, 0x6830, 0xa084, 0x0040, 0x0040, 0x1527, 0x684b, + 0x0004, 0x20a9, 0x0014, 0x6848, 0xa084, 0x0004, 0x0040, 0x1514, + 0x0070, 0x1514, 0x0078, 0x150b, 0x684b, 0x0009, 0x20a9, 0x0014, + 0x6848, 0xa084, 0x0001, 0x0040, 0x1521, 0x0070, 0x1521, 0x0078, + 0x1518, 0x20a9, 0x00fa, 0x0070, 0x1527, 0x0078, 0x1523, 0x2079, + 0x3500, 0x7817, 0x0001, 0x2061, 0x3540, 0x60a3, 0x0001, 0x60a7, + 0x0000, 0x60c3, 0x000f, 0x7898, 0xa085, 0x0002, 0x789a, 0x6808, + 0xa084, 0xfffd, 0x680a, 0x681b, 0x0046, 0x2091, 0x8001, 0x007c, + 0x7898, 0xa084, 0xfffd, 0x789a, 0xa084, 0x0001, 0x00c0, 0x154a, + 0x1078, 0x176a, 0x71c4, 0x71c6, 0x794a, 0x007c, 0x74c4, 0x73c8, + 0x72cc, 0x74c6, 0x73ca, 0x72ce, 0x2079, 0x3500, 0x2009, 0x0040, + 0x1078, 0x1679, 0x0040, 0x1590, 0x1078, 0x1649, 0x0040, 0x1564, + 0x1078, 0x1682, 0x0078, 0x1590, 0x6010, 0x2091, 0x8001, 0x7817, + 0xffff, 0x2009, 0x3568, 0x200b, 0x0005, 0x8108, 0x200b, 0x0000, + 0x8108, 0x230a, 0x8108, 0x220a, 0x8108, 0x240a, 0x8108, 0x200a, + 0x8108, 0x200b, 0x0000, 0x8108, 0x2c0a, 0xa02e, 0x2530, 0x0e7e, + 0x1078, 0x2f16, 0x0e7f, 0x6592, 0x65a2, 0x6696, 0x66a6, 0x60ab, + 0x0000, 0x60af, 0x0000, 0x2091, 0x8001, 0x1078, 0x1a23, 0x007c, + 0x70c3, 0x4005, 0x0078, 0x11c1, 0x71c4, 0x70c7, 0x0000, 0x7906, + 0x0078, 0x11be, 0x71c4, 0x71c6, 0x2168, 0x0078, 0x15a1, 0x2069, + 0x1000, 0x690c, 0xa016, 0x2d04, 0xa210, 0x8d68, 0x8109, 0x00c0, + 0x15a3, 0xa285, 0x0000, 0x00c0, 0x15b1, 0x70c3, 0x4000, 0x0078, + 0x15b3, 0x70c3, 0x4003, 0x70ca, 0x0078, 0x11c1, 0x71c4, 0x72c8, + 0x73cc, 0x2100, 0xa184, 0xfffc, 0x00c0, 0x11ca, 0x2100, 0x0079, + 0x15c1, 0x15d8, 0x15ed, 0x15ef, 0x15f1, 0x70c3, 0x4003, 0x71ce, + 0x72d2, 0x73d6, 0x0078, 0x15d4, 0x70c3, 0x4000, 0x70cf, 0x0000, + 0x70d3, 0x0000, 0x70d7, 0x0000, 0x77c6, 0x71ca, 0x0078, 0x11be, + 0x2031, 0x15f3, 0x2624, 0x8630, 0x2412, 0x2204, 0xa446, 0x00c0, + 0x15c5, 0xa484, 0xffff, 0x00c0, 0x15da, 0x2031, 0x15f3, 0x8210, + 0x8319, 0xa384, 0xffff, 0x00c0, 0x15da, 0x0078, 0x15cc, 0x0078, + 0x15cc, 0x0078, 0x15cc, 0x5555, 0xaaaa, 0xffff, 0x0000, 0x7960, + 0x71c6, 0x71c4, 0xa182, 0x0003, 0x00c8, 0x11b6, 0x7962, 0x0078, + 0x11be, 0x7960, 0x71c6, 0x0078, 0x11be, 0x7954, 0x71c6, 0x71c4, + 0x7956, 0x7958, 0x71ca, 0x71c8, 0x795a, 0x795c, 0x71ce, 0x71cc, + 0x795e, 0x0078, 0x11be, 0x7954, 0x71c6, 0x7958, 0x71ca, 0x795c, + 0x71ce, 0x0078, 0x11be, 0x700c, 0xa084, 0x007f, 0x0040, 0x1627, + 0x7007, 0x0004, 0x7004, 0xa084, 0x0004, 0x00c0, 0x1622, 0x7017, + 0x0000, 0x7112, 0x721a, 0x731e, 0x8108, 0x810c, 0x81a9, 0x8c98, + 0x20a1, 0x0030, 0x6080, 0x20a2, 0x53a6, 0x780c, 0xa085, 0x0000, + 0x7002, 0x7007, 0x0001, 0x7108, 0x8104, 0x00c8, 0x163b, 0x7007, + 0x0002, 0xa184, 0x000c, 0x710c, 0xa184, 0x0300, 0x7003, 0x0000, + 0x007c, 0x700c, 0xa084, 0x007f, 0x0040, 0x1655, 0x7007, 0x0004, + 0x7004, 0xa084, 0x0004, 0x00c0, 0x1650, 0x7017, 0x0000, 0x7112, + 0x721a, 0x731e, 0x2099, 0x0030, 0x8108, 0x81ac, 0x780c, 0xa085, + 0x0001, 0x7002, 0x7007, 0x0001, 0x7008, 0x800c, 0x00c8, 0x1664, + 0x7007, 0x0002, 0xa08c, 0x000c, 0x00c0, 0x1676, 0x710c, 0xa184, + 0x0300, 0x00c0, 0x1676, 0x2ca0, 0x53a5, 0xa006, 0x7003, 0x0000, + 0x007c, 0x7850, 0xa065, 0x0040, 0x1681, 0x2c04, 0x7852, 0x2063, + 0x0000, 0x007c, 0x0f7e, 0x2079, 0x3500, 0x7850, 0x2062, 0x2c00, + 0x7852, 0x0f7f, 0x007c, 0x2011, 0x4000, 0x7a52, 0x2019, 0x015c, + 0x8319, 0x0040, 0x1699, 0xa280, 0x002f, 0x2012, 0x2010, 0x0078, + 0x1690, 0x2013, 0x0000, 0x007c, 0xa784, 0x0f00, 0x800c, 0xa784, + 0x0007, 0x8003, 0x8003, 0x8003, 0x8003, 0xa105, 0xa0e8, 0x3680, + 0x007c, 0x1078, 0x169c, 0x2900, 0x682a, 0x2a00, 0x682e, 0x6808, + 0xa084, 0xffef, 0xa80d, 0x690a, 0x2009, 0x354f, 0x210c, 0x6804, + 0xa005, 0x0040, 0x16c6, 0xa116, 0x00c0, 0x16c6, 0x2060, 0x6000, + 0x6806, 0x017e, 0x200b, 0x0000, 0x0078, 0x16c9, 0x2009, 0x0000, + 0x017e, 0x6804, 0xa065, 0x0040, 0x16d8, 0x6000, 0x6806, 0x1078, + 0x16e9, 0x1078, 0x17d5, 0x6810, 0x8001, 0x6812, 0x00c0, 0x16c9, + 0x017f, 0x6902, 0x6906, 0x007c, 0xa065, 0x0040, 0x16e8, 0x6098, + 0x609b, 0x0000, 0x2008, 0x1078, 0x1682, 0x2100, 0x0078, 0x16dc, + 0x007c, 0x6003, 0x0103, 0x20a9, 0x001c, 0xac80, 0x0004, 0x20a0, + 0x2001, 0x0000, 0x40a4, 0x6828, 0x6016, 0x682c, 0x601e, 0x007c, + 0x0e7e, 0x2071, 0x3540, 0x7040, 0xa08c, 0x0080, 0x00c0, 0x1706, + 0xa088, 0x3580, 0x2d0a, 0x8000, 0x7042, 0xa006, 0x0e7f, 0x007c, + 0x0e7e, 0x2071, 0x3540, 0x2009, 0x3580, 0x7240, 0x8221, 0x8211, + 0x0048, 0x1720, 0x2104, 0x8108, 0xad06, 0x00c0, 0x170f, 0x8119, + 0x211e, 0x8108, 0x8318, 0x8211, 0x00c8, 0x1718, 0x7442, 0xa006, + 0x0e7f, 0x007c, 0x1078, 0x169c, 0x2091, 0x8000, 0x6804, 0x781e, + 0xa065, 0x0040, 0x1769, 0x0078, 0x1733, 0x2c00, 0x781e, 0x6000, + 0xa065, 0x0040, 0x1769, 0x600c, 0xa306, 0x00c0, 0x172d, 0x6008, + 0xa206, 0x00c0, 0x172d, 0x2c28, 0x2001, 0x354f, 0x2004, 0xac06, + 0x0040, 0x1769, 0x6804, 0xac06, 0x00c0, 0x1750, 0x6000, 0x2060, + 0x6806, 0xa005, 0x00c0, 0x1750, 0x6803, 0x0000, 0x0078, 0x175a, + 0x6400, 0x781c, 0x2060, 0x6402, 0xa486, 0x0000, 0x00c0, 0x175a, + 0x2c00, 0x6802, 0x2560, 0x1078, 0x16e9, 0x6017, 0x0005, 0x601f, + 0x0020, 0x1078, 0x17d5, 0x6810, 0x8001, 0x6812, 0x2001, 0xffff, + 0xa005, 0x007c, 0x2039, 0x0000, 0x2041, 0x0021, 0x2049, 0x0004, + 0x2051, 0x0008, 0x2091, 0x8000, 0x1078, 0x16a9, 0x8738, 0xa784, + 0x0007, 0x00c0, 0x1774, 0xa7bc, 0xff00, 0x873f, 0x8738, 0x873f, + 0xa784, 0x0f00, 0x00c0, 0x1774, 0x2091, 0x8001, 0x007c, 0x2061, + 0x0000, 0x6018, 0xa084, 0x0001, 0x00c0, 0x1794, 0x78ac, 0x78af, + 0x0000, 0xa005, 0x00c0, 0x1795, 0x007c, 0xa08c, 0xfff0, 0x0040, + 0x179b, 0x1078, 0x1b81, 0x0079, 0x179d, 0x17ad, 0x17af, 0x17b5, + 0x17b9, 0x17ad, 0x17bd, 0x17ad, 0x17ad, 0x17ad, 0x17ad, 0x17c3, + 0x17c7, 0x17ad, 0x17ad, 0x17ad, 0x17ad, 0x1078, 0x1b81, 0x1078, + 0x176a, 0x2001, 0x8001, 0x0078, 0x17cd, 0x2001, 0x8003, 0x0078, + 0x17cd, 0x2001, 0x8004, 0x0078, 0x17cd, 0x1078, 0x176a, 0x2001, + 0x8006, 0x0078, 0x17cd, 0x2001, 0x800c, 0x0078, 0x17cd, 0x1078, + 0x176a, 0x2001, 0x800d, 0x0078, 0x17cd, 0x70c2, 0x2061, 0x0000, + 0x601b, 0x0001, 0x2091, 0x4080, 0x007c, 0x2c04, 0x6082, 0x2c08, + 0x2063, 0x0000, 0x7864, 0x8000, 0x7866, 0x7868, 0xa005, 0x796a, + 0x0040, 0x17e5, 0x2c02, 0x0078, 0x17e6, 0x796e, 0x007c, 0x0c7e, + 0x2061, 0x3500, 0x6883, 0x0103, 0x2d08, 0x206b, 0x0000, 0x6064, + 0x8000, 0x6066, 0x6068, 0xa005, 0x616a, 0x0040, 0x17fa, 0x2d02, + 0x0078, 0x17fb, 0x616e, 0x0c7f, 0x007c, 0x1078, 0x180e, 0x0040, + 0x180d, 0x0c7e, 0x6098, 0xa065, 0x0040, 0x1808, 0x1078, 0x16dc, + 0x0c7f, 0x609b, 0x0000, 0x1078, 0x1682, 0x007c, 0x786c, 0xa065, + 0x0040, 0x1820, 0x2091, 0x8000, 0x7864, 0x8001, 0x7866, 0x2c04, + 0x786e, 0xa005, 0x00c0, 0x181e, 0x786a, 0x8000, 0x2091, 0x8001, + 0x007c, 0x7898, 0xa005, 0x00c0, 0x186f, 0x7974, 0x70d0, 0x0005, + 0x0005, 0x72d0, 0xa206, 0x00c0, 0x1826, 0x2200, 0xa106, 0x00c0, + 0x183d, 0x7804, 0xa005, 0x0040, 0x186f, 0x7807, 0x0000, 0x0068, + 0x186f, 0x2091, 0x4080, 0x0078, 0x186f, 0x1078, 0x1679, 0x0040, + 0x186f, 0x7a7c, 0x7b78, 0x8107, 0x8004, 0x8004, 0xa210, 0xa399, + 0x0000, 0x2009, 0x0040, 0x1078, 0x1649, 0x0040, 0x1866, 0x1078, + 0x1682, 0x7880, 0x8000, 0x7882, 0xa086, 0x0002, 0x00c0, 0x186f, + 0x2091, 0x8000, 0x78af, 0x0002, 0x7883, 0x0000, 0x7898, 0xa085, + 0x0003, 0x789a, 0x2091, 0x8001, 0x0078, 0x186f, 0x7883, 0x0000, + 0x1078, 0x199c, 0x6000, 0xa084, 0x0007, 0x0079, 0x1870, 0x007c, + 0x1878, 0x1887, 0x18a7, 0x1878, 0x18b9, 0x1878, 0x1878, 0x1878, + 0x2039, 0x0400, 0x78a8, 0xa705, 0x78aa, 0x6004, 0xa705, 0x6006, + 0x1078, 0x18f7, 0x6018, 0x78a6, 0x1078, 0x1984, 0x007c, 0x78a8, + 0xa084, 0x0100, 0x0040, 0x188e, 0x0078, 0x1878, 0x78ab, 0x0000, + 0x6000, 0x8007, 0xa084, 0x00ff, 0x789e, 0x8001, 0x609b, 0x0000, + 0x0040, 0x18a4, 0x1078, 0x18f7, 0x0040, 0x18a4, 0x78a8, 0xa085, + 0x0100, 0x78aa, 0x0078, 0x18a6, 0x1078, 0x191b, 0x007c, 0x78a8, + 0xa08c, 0x0e00, 0x00c0, 0x18b0, 0xa084, 0x0100, 0x00c0, 0x18b2, + 0x0078, 0x1878, 0x1078, 0x18f7, 0x00c0, 0x18b8, 0x1078, 0x191b, + 0x007c, 0x78a8, 0xa084, 0x0100, 0x0040, 0x18c0, 0x0078, 0x1878, + 0x78ab, 0x0000, 0x6710, 0x20a9, 0x0001, 0x6014, 0xa084, 0x00ff, + 0xa005, 0x0040, 0x18dd, 0xa7bc, 0xff00, 0x20a9, 0x0008, 0xa08e, + 0x0001, 0x0040, 0x18dd, 0x2039, 0x0000, 0x20a9, 0x0080, 0xa08e, + 0x0002, 0x0040, 0x18dd, 0x0078, 0x18f4, 0x1078, 0x169c, 0x2d00, + 0x2091, 0x8000, 0x682b, 0x0000, 0x682f, 0x0000, 0x6808, 0xa084, + 0xffde, 0x680a, 0x2d00, 0xa080, 0x0010, 0x2068, 0x2091, 0x8001, + 0x0070, 0x18f4, 0x0078, 0x18e0, 0x1078, 0x1682, 0x007c, 0x78a0, + 0xa06d, 0x00c0, 0x1902, 0x2c00, 0x78a2, 0x78a6, 0x609b, 0x0000, + 0x0078, 0x190e, 0x2c00, 0x689a, 0x609b, 0x0000, 0x78a2, 0x2d00, + 0x6002, 0x78a4, 0xad06, 0x00c0, 0x190e, 0x6002, 0x789c, 0x8001, + 0x789e, 0x00c0, 0x191a, 0x78a8, 0xa084, 0x0000, 0x78aa, 0x78a4, + 0x2060, 0xa006, 0x007c, 0xa02e, 0x2530, 0x6118, 0xa184, 0x0060, + 0x619e, 0x0040, 0x1927, 0x0e7e, 0x1078, 0x2f16, 0x0e7f, 0x6592, + 0x65a2, 0x6696, 0x66a6, 0x60ab, 0x0000, 0x60af, 0x0000, 0x6710, + 0x1078, 0x169c, 0x2091, 0x8000, 0x6808, 0xa084, 0x0001, 0x0040, + 0x1949, 0x2091, 0x8001, 0x1078, 0x16e9, 0x2091, 0x8000, 0x1078, + 0x17d5, 0x2091, 0x8001, 0x78a3, 0x0000, 0x78a7, 0x0000, 0x0078, + 0x1983, 0x6020, 0xa096, 0x0001, 0x00c0, 0x1950, 0x8000, 0x6022, + 0x6a10, 0x6814, 0x2091, 0x8001, 0xa202, 0x0048, 0x195f, 0x0040, + 0x195f, 0x2039, 0x0200, 0x1078, 0x1984, 0x0078, 0x1983, 0x2c08, + 0x2091, 0x8000, 0x6800, 0xa065, 0x0040, 0x1967, 0x6102, 0x6902, + 0x00c0, 0x196b, 0x6906, 0x2160, 0x6003, 0x0000, 0x6810, 0x8000, + 0x6812, 0x2091, 0x8001, 0x6808, 0xa08c, 0x0040, 0x0040, 0x197d, + 0xa086, 0x0040, 0x680a, 0x1078, 0x16f8, 0x1078, 0x1a23, 0x78a7, + 0x0000, 0x78a3, 0x0000, 0x007c, 0x6004, 0xa705, 0x6006, 0x2091, + 0x8000, 0x1078, 0x17d5, 0x2091, 0x8001, 0x78a4, 0xa065, 0x0040, + 0x1997, 0x6098, 0x78a6, 0x609b, 0x0000, 0x0078, 0x1987, 0x78a3, + 0x0000, 0x78a7, 0x0000, 0x007c, 0x7970, 0x7874, 0x8000, 0xa10a, + 0x00c8, 0x19a3, 0xa006, 0x7876, 0x70d2, 0x7804, 0xa005, 0x0040, + 0x19b1, 0x8001, 0x7806, 0x00c0, 0x19b1, 0x0068, 0x19b1, 0x2091, + 0x4080, 0x007c, 0x0068, 0x19cc, 0x2029, 0x0000, 0x786c, 0xa065, + 0x0040, 0x19c7, 0x1078, 0x19cd, 0x0040, 0x19c7, 0x057e, 0x1078, + 0x19e3, 0x057f, 0x00c0, 0x19c7, 0x8528, 0x0078, 0x19b6, 0x85ff, + 0x0040, 0x19cc, 0x2091, 0x4080, 0x007c, 0x7b84, 0x7988, 0x72d4, + 0x0005, 0x0005, 0x70d4, 0xa206, 0x00c0, 0x19cf, 0x2200, 0xa102, + 0x00c0, 0x19dd, 0x2300, 0xa005, 0x007c, 0x0048, 0x19e1, 0xa302, + 0x007c, 0x8002, 0x007c, 0x1078, 0x1a15, 0x2009, 0x001c, 0x6024, + 0xa005, 0x0040, 0x19ed, 0x2009, 0x0040, 0x1078, 0x161b, 0x0040, + 0x1a06, 0x7894, 0x8000, 0x7896, 0xa086, 0x0002, 0x00c0, 0x1a14, + 0x2091, 0x8000, 0x78af, 0x0003, 0x7897, 0x0000, 0x7898, 0xa085, + 0x0300, 0x789a, 0x2091, 0x8001, 0x0078, 0x1a14, 0x7897, 0x0000, + 0x1078, 0x17fd, 0x7984, 0x7888, 0x8000, 0xa10a, 0x00c8, 0x1a11, + 0xa006, 0x788a, 0x70d6, 0xa006, 0x007c, 0x8107, 0x8004, 0x8004, + 0x7a90, 0x7b8c, 0xa210, 0xa399, 0x0000, 0x007c, 0x2009, 0x3568, + 0x2091, 0x8000, 0x200a, 0x0f7e, 0x2079, 0x0100, 0x2009, 0x3540, + 0x2091, 0x8000, 0x2104, 0xa086, 0x0000, 0x00c0, 0x1a3e, 0x2009, + 0x3512, 0x2104, 0xa005, 0x00c0, 0x1a3e, 0x7830, 0xa084, 0x00c0, + 0x00c0, 0x1a3e, 0x0018, 0x1a3e, 0x781b, 0x0044, 0x2091, 0x8001, + 0x0f7f, 0x007c, 0x127e, 0x2091, 0x2300, 0x2071, 0x3540, 0x2079, + 0x0100, 0x2019, 0x2ddb, 0x20a1, 0x012b, 0x2304, 0xa005, 0x0040, + 0x1a5a, 0x789a, 0x8318, 0x23ac, 0x8318, 0x2398, 0x53a6, 0x3318, + 0x0078, 0x1a4d, 0x789b, 0x0020, 0x20a9, 0x0010, 0x78af, 0x0000, + 0x78af, 0x0220, 0x0070, 0x1a66, 0x0078, 0x1a5e, 0x7003, 0x0000, + 0x1078, 0x1b65, 0x7004, 0xa084, 0x000f, 0xa085, 0x6280, 0x7806, + 0x780f, 0x9200, 0x7843, 0x00d8, 0x7853, 0x0080, 0x780b, 0x0008, + 0x7047, 0x357f, 0x7043, 0x0000, 0x127f, 0x2000, 0x007c, 0xa18c, + 0x000f, 0x2011, 0x0101, 0x2204, 0xa084, 0xfff0, 0xa105, 0x2012, + 0x1078, 0x1b65, 0x007c, 0x2011, 0x0101, 0x20a9, 0x0009, 0x810b, + 0x0070, 0x1a94, 0x0078, 0x1a8f, 0xa18c, 0x0e00, 0x2204, 0xa084, + 0xf1ff, 0xa105, 0x2012, 0x007c, 0x2009, 0x0101, 0x20a9, 0x0005, + 0x8213, 0x0070, 0x1aa5, 0x0078, 0x1aa0, 0xa294, 0x00e0, 0x2104, + 0xa084, 0xff1f, 0xa205, 0x200a, 0x007c, 0x2011, 0x0101, 0x20a9, + 0x000c, 0x810b, 0x0070, 0x1ab6, 0x0078, 0x1ab1, 0xa18c, 0xf000, + 0x2204, 0xa084, 0x0fff, 0xa105, 0x2012, 0x007c, 0x2011, 0x0102, + 0x2204, 0xa084, 0xffcf, 0xa105, 0x2012, 0x007c, 0x8103, 0x8003, + 0xa080, 0x0020, 0x0c7e, 0x2061, 0x0100, 0x609a, 0x62ac, 0x63ac, + 0x0c7f, 0x007c, 0x8103, 0x8003, 0xa080, 0x0022, 0x0c7e, 0x2061, + 0x0100, 0x609a, 0x60a4, 0xa084, 0xffdf, 0x60ae, 0x0c7f, 0x007c, + 0x8103, 0x8003, 0xa080, 0x0022, 0x0c7e, 0x2061, 0x0100, 0x609a, + 0x60a4, 0xa085, 0x0020, 0x60ae, 0x0c7f, 0x007c, 0x8103, 0x8003, + 0xa080, 0x0020, 0x0c7e, 0x2061, 0x0100, 0x609a, 0x60a4, 0x62ae, + 0x2010, 0x60a4, 0x63ae, 0x2018, 0x0c7f, 0x007c, 0x2091, 0x8000, + 0x0c7e, 0x0e7e, 0x6818, 0xa005, 0x0040, 0x1b43, 0x2061, 0x3f80, + 0x1078, 0x1b4b, 0x0040, 0x1b31, 0x20a9, 0x0000, 0x2061, 0x3e80, + 0x0c7e, 0x1078, 0x1b4b, 0x0040, 0x1b1d, 0x0c7f, 0x8c60, 0x0070, + 0x1b1b, 0x0078, 0x1b10, 0x0078, 0x1b43, 0x007f, 0xa082, 0x3e80, + 0x2071, 0x3540, 0x70ba, 0x601c, 0xa085, 0x0800, 0x601e, 0x71b6, + 0x60a7, 0x0000, 0x2001, 0x0004, 0x70a2, 0x1078, 0x1a1e, 0x0078, + 0x1b3f, 0x2071, 0x3540, 0x601c, 0xa085, 0x0800, 0x601e, 0x71b6, + 0x60a7, 0x0000, 0x2001, 0x0006, 0x70a2, 0x1078, 0x1a1e, 0x2001, + 0x0000, 0x0078, 0x1b45, 0x2001, 0x0001, 0x2091, 0x8001, 0xa005, + 0x0e7f, 0x0c7f, 0x007c, 0x2c04, 0xa005, 0x0040, 0x1b62, 0x2060, + 0x600c, 0xa306, 0x00c0, 0x1b5f, 0x6008, 0xa206, 0x00c0, 0x1b5f, + 0x6010, 0xa106, 0x00c0, 0x1b5f, 0xa006, 0x0078, 0x1b64, 0x6000, + 0x0078, 0x1b4c, 0xa085, 0x0001, 0x007c, 0x2011, 0x3541, 0x220c, + 0xa18c, 0x000f, 0x2011, 0x013b, 0x2204, 0xa084, 0x0100, 0x0040, + 0x1b80, 0x2019, 0x0112, 0x201b, 0x1000, 0x2021, 0x013a, 0x2122, + 0x2013, 0x0080, 0x2013, 0x008c, 0x2013, 0x0000, 0x201b, 0x0000, + 0x007c, 0x0068, 0x1b81, 0x007e, 0x2071, 0x0000, 0x7018, 0xa084, + 0x0001, 0x00c0, 0x1b86, 0x007f, 0x2e08, 0x2071, 0x0010, 0x70ca, + 0x007f, 0x70c6, 0x70c3, 0x8002, 0x2071, 0x0000, 0x701b, 0x0001, + 0x2091, 0x4080, 0x007f, 0x2070, 0x007f, 0x0078, 0x1b9d, 0x107e, + 0x007e, 0x127e, 0x2091, 0x2300, 0x7f3c, 0x7e58, 0x7c30, 0x7d38, + 0xa594, 0x003f, 0xa484, 0x4000, 0x0040, 0x1bb4, 0xa784, 0x007c, + 0x00c0, 0x2da7, 0x1078, 0x1b81, 0xa49c, 0x000f, 0xa382, 0x0004, + 0x0050, 0x1bbc, 0x1078, 0x1b81, 0x8507, 0xa084, 0x000f, 0x0079, + 0x1bc1, 0x1fed, 0x209d, 0x20c3, 0x22e9, 0x2576, 0x25be, 0x25f5, + 0x2670, 0x26ca, 0x274f, 0x1be7, 0x1bd1, 0x1e56, 0x1f20, 0x2555, + 0x1bd1, 0x1078, 0x1b81, 0x0018, 0x1ba4, 0x127f, 0x2091, 0x8001, + 0x007f, 0x107f, 0x007c, 0x7003, 0x0000, 0x703f, 0x0000, 0x7030, + 0xa005, 0x0040, 0x1be5, 0x7033, 0x0000, 0x0018, 0x1ba4, 0x705c, + 0xa005, 0x00c0, 0x1ca5, 0x70a0, 0xa084, 0x0007, 0x0079, 0x1bf0, + 0x1cd1, 0x1bf8, 0x1c06, 0x1c27, 0x1c4d, 0x1c79, 0x1c77, 0x1bf8, + 0x7808, 0xa084, 0xfffd, 0x780a, 0x2009, 0x0046, 0x1078, 0x241b, + 0x00c0, 0x1c04, 0x7003, 0x0004, 0x0078, 0x1bd3, 0x1078, 0x2d69, + 0x00c0, 0x1c25, 0x70b4, 0x8007, 0x789b, 0x007e, 0x78aa, 0x789b, + 0x0010, 0x78ab, 0x000c, 0x789b, 0x0060, 0x78ab, 0x0001, 0x785b, + 0x0004, 0x2009, 0x00f7, 0x1078, 0x2419, 0x00c0, 0x1c25, 0x7003, + 0x0004, 0x70c3, 0x000f, 0x7033, 0x3570, 0x0078, 0x1bd3, 0x1078, + 0x2d69, 0x00c0, 0x1c4b, 0x71b4, 0x8107, 0x789b, 0x007e, 0x78aa, + 0x789b, 0x0010, 0xa18c, 0x0007, 0xa18d, 0x00c0, 0x79aa, 0x78ab, + 0x0006, 0x789b, 0x0060, 0x78ab, 0x0002, 0x785b, 0x0004, 0x2009, + 0x00f7, 0x1078, 0x2419, 0x00c0, 0x1c4b, 0x7003, 0x0004, 0x70c3, + 0x000f, 0x7033, 0x3570, 0x0078, 0x1bd3, 0x1078, 0x2d69, 0x00c0, + 0x1c75, 0x71b4, 0x8107, 0x789b, 0x007e, 0x78aa, 0x789b, 0x0010, + 0xa18c, 0x0007, 0xa18d, 0x00c0, 0x79aa, 0x78ab, 0x0020, 0x71b8, + 0x79aa, 0x78ab, 0x000d, 0x789b, 0x0060, 0x78ab, 0x0004, 0x785b, + 0x0004, 0x2009, 0x00f7, 0x1078, 0x2419, 0x00c0, 0x1c75, 0x7003, + 0x0004, 0x70c3, 0x000f, 0x7033, 0x3570, 0x0078, 0x1bd3, 0x0078, + 0x1c27, 0x1078, 0x2d69, 0x00c0, 0x1bd3, 0x70bc, 0x2068, 0x789b, + 0x0010, 0x6f10, 0x1078, 0x2cac, 0x2c50, 0x6810, 0x007e, 0x8007, + 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xa080, 0x3600, 0x2048, + 0x0c7e, 0x2060, 0x704a, 0x6000, 0x704e, 0x6004, 0x7052, 0x0c7f, + 0x007f, 0xa084, 0x0007, 0xa085, 0x0080, 0x78aa, 0x6e18, 0x2041, + 0x0001, 0x2001, 0x0004, 0x0078, 0x1dcc, 0x1078, 0x2d69, 0x00c0, + 0x1bd3, 0x789b, 0x0010, 0x705c, 0x2068, 0x6f10, 0x1078, 0x2cac, + 0x2c50, 0x6008, 0xa085, 0x0010, 0x600a, 0x6820, 0xa005, 0x0040, + 0x1cc1, 0xa082, 0x0006, 0x0048, 0x1cbf, 0x0078, 0x1cc1, 0x6823, + 0x0005, 0x6810, 0xa084, 0x0007, 0xa085, 0x0080, 0x78aa, 0x2031, + 0x0020, 0x2041, 0x0001, 0x1078, 0x2dc8, 0x2001, 0x0003, 0x0078, + 0x1dcc, 0x0018, 0x1ba4, 0x7440, 0xa485, 0x0000, 0x0040, 0x1ceb, + 0xa080, 0x3580, 0x2030, 0x7144, 0x8108, 0xa12a, 0x0048, 0x1ce2, + 0x2009, 0x3580, 0x2164, 0x6504, 0x85ff, 0x00c0, 0x1cf8, 0x8421, + 0x00c0, 0x1cdc, 0x7146, 0x7003, 0x0000, 0x703f, 0x0000, 0x0078, + 0x1bd3, 0x7640, 0xa6b0, 0x3580, 0x7144, 0x2600, 0x0078, 0x1ce7, + 0x7146, 0x2568, 0x2558, 0x753e, 0x2c50, 0x6034, 0xa085, 0x0000, + 0x00c0, 0x1cf5, 0x6708, 0x7736, 0xa784, 0x013f, 0x0040, 0x1d2a, + 0xa784, 0x0021, 0x00c0, 0x1cf5, 0xa784, 0x0002, 0x0040, 0x1d17, + 0xa784, 0x0004, 0x0040, 0x1cf5, 0xa7bc, 0xfffb, 0x670a, 0xa784, + 0x0008, 0x00c0, 0x1cf5, 0xa784, 0x0010, 0x00c0, 0x1cf5, 0xa784, + 0x0100, 0x0040, 0x1d2a, 0x6018, 0xa005, 0x00c0, 0x1cf5, 0xa7bc, + 0xfeff, 0x670a, 0x681f, 0x0000, 0x6e18, 0xa684, 0x000e, 0x6118, + 0x0040, 0x1d3a, 0x601c, 0xa102, 0x0048, 0x1d3d, 0x0040, 0x1d3d, + 0x0078, 0x1cf1, 0x81ff, 0x00c0, 0x1cf1, 0xa784, 0x0080, 0x00c0, + 0x1d43, 0x700c, 0x6022, 0xa7bc, 0xff7f, 0x670a, 0x6b10, 0x8307, + 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xa080, 0x3600, 0x2060, + 0x2048, 0x704a, 0x6000, 0x704e, 0x6004, 0x7052, 0x2a60, 0x0018, + 0x1ba4, 0x789b, 0x0010, 0xa046, 0x1078, 0x2d69, 0x00c0, 0x1bd3, + 0x6b10, 0xa39c, 0x0007, 0xa39d, 0x00c0, 0x704c, 0xa084, 0x8000, + 0x0040, 0x1d6e, 0xa684, 0x0001, 0x0040, 0x1d74, 0xa39c, 0xffbf, + 0xa684, 0x000e, 0x00c0, 0x2901, 0xa684, 0x0010, 0x0040, 0x1d7e, + 0xa39d, 0x0020, 0xa684, 0x000e, 0x00c0, 0x2907, 0x7baa, 0x8840, + 0xa684, 0x000e, 0x00c0, 0x1d89, 0xa7bd, 0x0010, 0x670a, 0x0078, + 0x1dca, 0x714c, 0xa18c, 0x0800, 0x0040, 0x290d, 0x2011, 0x0021, + 0x8004, 0x8004, 0x0048, 0x1da0, 0x2011, 0x0022, 0x8004, 0x0048, + 0x1da0, 0x2011, 0x0020, 0x8004, 0x0048, 0x1da0, 0x0040, 0x1dca, + 0x7aaa, 0x8840, 0x1078, 0x2d82, 0x6a10, 0x610c, 0x8108, 0xa18c, + 0x00ff, 0xa1e0, 0x3e80, 0x2c64, 0x8cff, 0x0040, 0x1dc1, 0x6010, + 0xa206, 0x00c0, 0x1dab, 0x60b4, 0x8001, 0x60b6, 0x00c0, 0x1da6, + 0x0c7e, 0x2a60, 0x6008, 0xa085, 0x0100, 0x600a, 0x0c7f, 0x0078, + 0x1cd1, 0x1078, 0x2d69, 0x00c0, 0x1bd3, 0x2a60, 0x610e, 0x79aa, + 0x8840, 0x712e, 0x2001, 0x0001, 0x007e, 0x7150, 0xa184, 0x0018, + 0x0040, 0x1de0, 0xa184, 0x0010, 0x0040, 0x1dda, 0x1078, 0x2ad7, + 0x00c0, 0x1de0, 0xa184, 0x0008, 0x0040, 0x1de0, 0x1078, 0x29f1, + 0x007f, 0x7002, 0xa68c, 0x0060, 0x88ff, 0x0040, 0x1de9, 0xa18d, + 0x0004, 0x795a, 0x69b2, 0x789b, 0x0060, 0x2800, 0x78aa, 0x789b, + 0x0061, 0x6814, 0xa085, 0x8000, 0x6816, 0x78aa, 0x157e, 0x137e, + 0x147e, 0x20a1, 0x012c, 0x789b, 0x0000, 0x8000, 0x80ac, 0xad80, + 0x000a, 0x2098, 0x53a6, 0x147f, 0x137f, 0x157f, 0x6810, 0x8007, + 0x789b, 0x007e, 0x78aa, 0x6d90, 0x7dd6, 0x7dde, 0x6e94, 0x7ed2, + 0x7eda, 0x7830, 0xa084, 0x00c0, 0x00c0, 0x1e18, 0x0098, 0x1e20, + 0x6008, 0xa084, 0xffef, 0x600a, 0x1078, 0x2d82, 0x0078, 0x1bdb, + 0x7200, 0xa284, 0x0007, 0xa086, 0x0001, 0x00c0, 0x1e2d, 0x781b, + 0x0049, 0x1078, 0x2d82, 0x0078, 0x1e3e, 0x6ab0, 0xa295, 0x2000, + 0x7a5a, 0x781b, 0x0049, 0x1078, 0x2d82, 0x7200, 0x2500, 0xa605, + 0x0040, 0x1e3e, 0xa284, 0x0007, 0x1079, 0x1e4c, 0xad80, 0x0008, + 0x7032, 0xa284, 0x0007, 0xa086, 0x0001, 0x00c0, 0x1e4a, 0x6018, + 0x8000, 0x601a, 0x0078, 0x1bd3, 0x1e54, 0x30f3, 0x30f3, 0x30e2, + 0x30f3, 0x1e54, 0x1e54, 0x1e54, 0x1078, 0x1b81, 0x7808, 0xa084, + 0xfffd, 0x780a, 0x0f7e, 0x2079, 0x3500, 0x7898, 0x0f7f, 0xa084, + 0x0001, 0x0040, 0x1e7c, 0x70a0, 0xa086, 0x0001, 0x00c0, 0x1e6b, + 0x70a2, 0x0078, 0x1f04, 0x70a0, 0xa086, 0x0005, 0x00c0, 0x1e7a, + 0x70bc, 0x2068, 0x6817, 0x0004, 0x6813, 0x0000, 0x681c, 0xa085, + 0x0008, 0x681e, 0x70a3, 0x0000, 0x157e, 0x2011, 0x0004, 0x71a0, + 0xa186, 0x0001, 0x0040, 0x1e9e, 0xa186, 0x0007, 0x00c0, 0x1e8e, + 0x2009, 0x352b, 0x200b, 0x0005, 0x0078, 0x1e9e, 0x2009, 0x3513, + 0x2104, 0x2009, 0x3512, 0x200a, 0x2009, 0x352b, 0x200b, 0x0001, + 0x70a3, 0x0000, 0x70a7, 0x0001, 0x0078, 0x1ea0, 0x70a3, 0x0000, + 0x1078, 0x2eca, 0x20a9, 0x0010, 0x2039, 0x0000, 0x1078, 0x2bb1, + 0xa7b8, 0x0100, 0x0070, 0x1eae, 0x0078, 0x1ea6, 0x7000, 0x2020, + 0x0079, 0x1eb2, 0x1ee0, 0x1ec9, 0x1ec9, 0x1ebc, 0x1ee0, 0x1ee0, + 0x1eba, 0x1eba, 0x1078, 0x1b81, 0x2021, 0x3557, 0x2404, 0xa005, + 0x0040, 0x1ec9, 0xad06, 0x00c0, 0x1ec9, 0x6800, 0x2022, 0x0078, + 0x1ed9, 0x681c, 0xa084, 0x0001, 0x00c0, 0x1ed5, 0x6f10, 0x1078, + 0x2cac, 0x1078, 0x28e4, 0x0078, 0x1ed9, 0x7054, 0x2060, 0x6800, + 0x6002, 0x6a16, 0x681c, 0xa085, 0x0008, 0x681e, 0x1078, 0x17e7, + 0x2021, 0x3f80, 0x1078, 0x1f0a, 0x2021, 0x3557, 0x1078, 0x1f0a, + 0x20a9, 0x0000, 0x2021, 0x3e80, 0x1078, 0x1f0a, 0x8420, 0x0070, + 0x1ef3, 0x0078, 0x1eec, 0x20a9, 0x0080, 0x2061, 0x3680, 0x6018, + 0x6110, 0xa102, 0x6012, 0x601b, 0x0000, 0xace0, 0x0010, 0x0070, + 0x1f03, 0x0078, 0x1ef7, 0x157f, 0x7003, 0x0000, 0x703f, 0x0000, + 0x0078, 0x1bd3, 0x047e, 0x2404, 0xa005, 0x0040, 0x1f1c, 0x2068, + 0x6800, 0x007e, 0x6a16, 0x681c, 0xa085, 0x0008, 0x681e, 0x1078, + 0x17e7, 0x007f, 0x0078, 0x1f0c, 0x047f, 0x2023, 0x0000, 0x007c, + 0xa282, 0x0003, 0x0050, 0x1f26, 0x1078, 0x1b81, 0x2300, 0x0079, + 0x1f29, 0x1f2c, 0x1f9f, 0x1fad, 0xa282, 0x0002, 0x0040, 0x1f32, + 0x1078, 0x1b81, 0x70a0, 0x70a3, 0x0000, 0x70c3, 0x0000, 0x0079, + 0x1f39, 0x1f41, 0x1f41, 0x1f43, 0x1f77, 0x2913, 0x1f41, 0x1f77, + 0x1f41, 0x1078, 0x1b81, 0x77b4, 0x1078, 0x2bb1, 0x77b4, 0xa7bc, + 0x0f00, 0x1078, 0x2cac, 0x6018, 0xa005, 0x0040, 0x1f6e, 0x2021, + 0x3f80, 0x2009, 0x0004, 0x2011, 0x0010, 0x1078, 0x1fc8, 0x0040, + 0x1f6e, 0x157e, 0x20a9, 0x0000, 0x2021, 0x3e80, 0x047e, 0x2009, + 0x0004, 0x2011, 0x0010, 0x1078, 0x1fc8, 0x047f, 0x0040, 0x1f6d, + 0x8420, 0x0070, 0x1f6d, 0x0078, 0x1f5e, 0x157f, 0x8738, 0xa784, + 0x0007, 0x00c0, 0x1f49, 0x0078, 0x1bdb, 0x0078, 0x1bdb, 0x77b4, + 0x1078, 0x2cac, 0x6018, 0xa005, 0x0040, 0x1f9d, 0x2021, 0x3f80, + 0x2009, 0x0005, 0x2011, 0x0020, 0x1078, 0x1fc8, 0x0040, 0x1f9d, + 0x157e, 0x20a9, 0x0000, 0x2021, 0x3e80, 0x047e, 0x2009, 0x0005, + 0x2011, 0x0020, 0x1078, 0x1fc8, 0x047f, 0x0040, 0x1f9c, 0x8420, + 0x0070, 0x1f9c, 0x0078, 0x1f8d, 0x157f, 0x0078, 0x1bdb, 0x2200, + 0x0079, 0x1fa2, 0x1fa5, 0x1fa7, 0x1fa7, 0x1078, 0x1b81, 0x70a3, + 0x0000, 0x70a7, 0x0001, 0x0078, 0x1bd3, 0x2200, 0x0079, 0x1fb0, + 0x1fb5, 0x1fa7, 0x1fb3, 0x1078, 0x1b81, 0x1078, 0x2428, 0x7000, + 0xa086, 0x0001, 0x00c0, 0x28ba, 0x1078, 0x28fa, 0x6008, 0xa084, + 0xffef, 0x600a, 0x1078, 0x28ad, 0x0040, 0x28ba, 0x0078, 0x1cd1, + 0x2404, 0xa005, 0x0040, 0x1fe9, 0x2068, 0x2d04, 0x007e, 0x6810, + 0xa706, 0x0040, 0x1fd7, 0x2d20, 0x007f, 0x0078, 0x1fc9, 0x007f, + 0x2022, 0x6916, 0x681c, 0xa205, 0x681e, 0x1078, 0x17e7, 0x6010, + 0x8001, 0x6012, 0x6008, 0xa084, 0xffef, 0x600a, 0x1078, 0x28fa, + 0x007c, 0xa085, 0x0001, 0x0078, 0x1fe8, 0x2300, 0x0079, 0x1ff0, + 0x1ff5, 0x1ff3, 0x2038, 0x1078, 0x1b81, 0x78e4, 0xa005, 0x00d0, + 0x2018, 0x0018, 0x2018, 0x2008, 0xa084, 0x0030, 0x00c0, 0x2004, + 0x781b, 0x0049, 0x0078, 0x1bd3, 0x78ec, 0xa084, 0x0003, 0x0040, + 0x2000, 0x2100, 0xa084, 0x0007, 0x0079, 0x200e, 0x2026, 0x202c, + 0x2020, 0x2016, 0x2d63, 0x2d63, 0x2016, 0x2032, 0x1078, 0x1b81, + 0x7000, 0xa005, 0x0040, 0x1bdb, 0x2001, 0x0003, 0x0078, 0x22fd, + 0x1078, 0x2b94, 0x781b, 0x0055, 0x0078, 0x1bd3, 0x1078, 0x2b94, + 0x781b, 0x00dc, 0x0078, 0x1bd3, 0x1078, 0x2b94, 0x781b, 0x00e3, + 0x0078, 0x1bd3, 0x1078, 0x2b94, 0x781b, 0x009d, 0x0078, 0x1bd3, + 0xa584, 0x000f, 0x00c0, 0x2062, 0x1078, 0x2428, 0x7000, 0x0079, + 0x2041, 0x2049, 0x2056, 0x2049, 0x28ba, 0x204b, 0x28ba, 0x2049, + 0x2049, 0x1078, 0x1b81, 0x71a0, 0x70a3, 0x0000, 0xa186, 0x0004, + 0x00c0, 0x2054, 0x0078, 0x2913, 0x0078, 0x28ba, 0x1078, 0x28fa, + 0x6008, 0xa084, 0xffef, 0x600a, 0x1078, 0x28ad, 0x0040, 0x28ba, + 0x0078, 0x1cd1, 0x78e4, 0xa005, 0x00d0, 0x2018, 0x0018, 0x2018, + 0x2008, 0xa084, 0x0030, 0x00c0, 0x2071, 0x781b, 0x0049, 0x0078, + 0x1bd3, 0x78ec, 0xa084, 0x0003, 0x0040, 0x206d, 0x2100, 0xa184, + 0x0007, 0x0079, 0x207b, 0x208b, 0x2091, 0x2085, 0x2083, 0x2d63, + 0x2d63, 0x2083, 0x2d5b, 0x1078, 0x1b81, 0x1078, 0x2b9c, 0x781b, + 0x0055, 0x0078, 0x1bd3, 0x1078, 0x2b9c, 0x781b, 0x00dc, 0x0078, + 0x1bd3, 0x1078, 0x2b9c, 0x781b, 0x00e3, 0x0078, 0x1bd3, 0x1078, + 0x2b9c, 0x781b, 0x009d, 0x0078, 0x1bd3, 0x2300, 0x0079, 0x20a0, + 0x20a5, 0x20a3, 0x20a7, 0x1078, 0x1b81, 0x0078, 0x2670, 0x6817, + 0x0008, 0x78a3, 0x0000, 0x79e4, 0xa184, 0x0030, 0x0040, 0x2670, + 0x78ec, 0xa084, 0x0003, 0x0040, 0x2670, 0xa184, 0x0007, 0x0079, + 0x20b9, 0x2026, 0x202c, 0x2020, 0x2d3b, 0x2d63, 0x2d63, 0x20c1, + 0x2d5b, 0x1078, 0x1b81, 0xa282, 0x0005, 0x0050, 0x20c9, 0x1078, + 0x1b81, 0x2300, 0x0079, 0x20cc, 0x20cf, 0x22d1, 0x22dd, 0x2200, + 0x0079, 0x20d2, 0x20d7, 0x20d9, 0x20ec, 0x20d7, 0x22b6, 0x1078, + 0x1b81, 0x789b, 0x0018, 0x78a8, 0xa084, 0x00ff, 0xa082, 0x0020, + 0x0048, 0x2b75, 0xa08a, 0x0004, 0x00c8, 0x2b75, 0x0079, 0x20e8, + 0x2b75, 0x2b75, 0x2b75, 0x2b17, 0x789b, 0x0018, 0x79a8, 0xa184, + 0x0080, 0x0040, 0x2101, 0xa184, 0x0018, 0x0040, 0x20fd, 0x0078, + 0x2b75, 0x7000, 0xa005, 0x00c0, 0x20f7, 0x2011, 0x0003, 0x0078, + 0x275d, 0xa184, 0x00ff, 0xa08a, 0x0010, 0x00c8, 0x2b75, 0x0079, + 0x2109, 0x211b, 0x2119, 0x2131, 0x2133, 0x21c5, 0x2b75, 0x2b75, + 0x21c7, 0x2b75, 0x2b75, 0x22b2, 0x22b2, 0x2b75, 0x2b75, 0x2b75, + 0x22b4, 0x1078, 0x1b81, 0xa684, 0x1000, 0x0040, 0x2128, 0x2001, + 0x0300, 0x8000, 0x8000, 0x783a, 0x781b, 0x009a, 0x0078, 0x1bd3, + 0x6814, 0xa084, 0x8000, 0x0040, 0x212f, 0x6817, 0x0003, 0x0078, + 0x2d3b, 0x1078, 0x1b81, 0x691c, 0x691e, 0xa684, 0x1800, 0x00c0, + 0x214d, 0x681c, 0xa084, 0x0001, 0x00c0, 0x2155, 0x6814, 0xa086, + 0x0008, 0x00c0, 0x2145, 0x6817, 0x0000, 0xa684, 0x0400, 0x0040, + 0x21c1, 0x781b, 0x0058, 0x0078, 0x1bd3, 0xa684, 0x1000, 0x0040, + 0x2155, 0x781b, 0x0058, 0x0078, 0x1bd3, 0xa684, 0x0060, 0x0040, + 0x21bd, 0xa684, 0x0800, 0x0040, 0x21bd, 0xa684, 0x8000, 0x00c0, + 0x2163, 0x0078, 0x217d, 0xa6b4, 0x7fff, 0x7e5a, 0x6eb2, 0x789b, + 0x0074, 0x7aac, 0x79ac, 0x78ac, 0x801b, 0x00c8, 0x2170, 0x8000, + 0xa084, 0x003f, 0xa108, 0xa291, 0x0000, 0x6b94, 0x2100, 0xa302, + 0x68ae, 0x6b90, 0x2200, 0xa303, 0x68aa, 0xa684, 0x4000, 0x0040, + 0x2185, 0xa6b4, 0xbfff, 0x7e5a, 0x6eb2, 0x7000, 0xa086, 0x0003, + 0x00c0, 0x2192, 0x1078, 0x2f3d, 0x1078, 0x30e2, 0x781b, 0x0067, + 0x0078, 0x1bd3, 0xa006, 0x1078, 0x3197, 0x6aac, 0x69a8, 0x6c94, + 0x6b90, 0x2200, 0xa105, 0x0040, 0x21a1, 0x2200, 0xa422, 0x2100, + 0xa31b, 0x7cd2, 0x7bd6, 0x2300, 0xa405, 0x00c0, 0x21af, 0xa6b5, + 0x4000, 0x7e5a, 0x6eb2, 0x781b, 0x0067, 0x0078, 0x1bd3, 0x781b, + 0x0067, 0x2200, 0xa115, 0x00c0, 0x21b9, 0x1078, 0x30f3, 0x0078, + 0x1bd3, 0x1078, 0x3120, 0x0078, 0x1bd3, 0x781b, 0x006a, 0x0078, + 0x1bd3, 0x781b, 0x0058, 0x0078, 0x1bd3, 0x1078, 0x1b81, 0x0078, + 0x2224, 0x691c, 0xa184, 0x0100, 0x0040, 0x21df, 0xa18c, 0xfeff, + 0x691e, 0x0c7e, 0x7048, 0x2060, 0x6000, 0xa084, 0xefff, 0x6002, + 0x6004, 0xa084, 0xfff5, 0x6006, 0x0c7f, 0x0078, 0x2213, 0xa184, + 0x0200, 0x0040, 0x2213, 0xa18c, 0xfdff, 0x691e, 0x0c7e, 0x7048, + 0x2060, 0x6000, 0xa084, 0xdfff, 0x6002, 0x6004, 0xa084, 0xffef, + 0x6006, 0x2008, 0x2c48, 0x0c7f, 0xa184, 0x0008, 0x0040, 0x2213, + 0x1078, 0x2ca8, 0x1078, 0x29f1, 0x88ff, 0x0040, 0x2213, 0x789b, + 0x0060, 0x2800, 0x78aa, 0x7e58, 0xa6b5, 0x0004, 0x7e5a, 0xa684, + 0x0400, 0x00c0, 0x220f, 0x781b, 0x0055, 0x0078, 0x1bd3, 0x781b, + 0x0069, 0x0078, 0x1bd3, 0x7e58, 0xa684, 0x0400, 0x00c0, 0x221c, + 0x781b, 0x0058, 0x0078, 0x1bd3, 0x781b, 0x006a, 0x0078, 0x1bd3, + 0x0078, 0x2b7b, 0x0078, 0x2b7b, 0x2019, 0x0000, 0x7990, 0xa18c, + 0x0007, 0x0040, 0x2222, 0x789b, 0x0010, 0x78a8, 0xa094, 0x00ff, + 0xa286, 0x0001, 0x00c0, 0x2247, 0x2300, 0x7ca8, 0xa400, 0x2018, + 0xa102, 0x0040, 0x223f, 0x0048, 0x223f, 0x0078, 0x2241, 0x0078, + 0x21c9, 0x24a8, 0x7aa8, 0x00f0, 0x2241, 0x0078, 0x222d, 0xa284, + 0x00f0, 0xa086, 0x0020, 0x00c0, 0x22a3, 0x8318, 0x8318, 0x2300, + 0xa102, 0x0040, 0x2257, 0x0048, 0x2257, 0x0078, 0x22a0, 0xa286, + 0x0023, 0x0040, 0x2222, 0x6818, 0xa084, 0xfff1, 0x681a, 0x7e58, + 0xa684, 0xfff1, 0xa085, 0x0010, 0x2030, 0x7e5a, 0x6008, 0xa085, + 0x0010, 0x600a, 0x0c7e, 0x7048, 0x2060, 0x6004, 0x2008, 0x2c48, + 0x0c7f, 0xa184, 0x0010, 0x0040, 0x227b, 0x1078, 0x2ca8, 0x1078, + 0x2ad7, 0x0078, 0x228a, 0x0c7e, 0x7048, 0x2060, 0x6004, 0x2008, + 0x2c48, 0x0c7f, 0xa184, 0x0008, 0x0040, 0x2213, 0x1078, 0x2ca8, + 0x1078, 0x29f1, 0x88ff, 0x0040, 0x2213, 0x789b, 0x0060, 0x2800, + 0x78aa, 0xa6b5, 0x0004, 0x7e5a, 0xa684, 0x0400, 0x00c0, 0x229c, + 0x781b, 0x0055, 0x0078, 0x1bd3, 0x781b, 0x0069, 0x0078, 0x1bd3, + 0x7aa8, 0x0078, 0x222d, 0x8318, 0x2300, 0xa102, 0x0040, 0x22ac, + 0x0048, 0x22ac, 0x0078, 0x222d, 0xa284, 0x0080, 0x00c0, 0x2b81, + 0x0078, 0x2b7b, 0x0078, 0x2b81, 0x0078, 0x2b75, 0x789b, 0x0018, + 0x78a8, 0xa084, 0x00ff, 0xa08e, 0x0001, 0x0040, 0x22c1, 0x1078, + 0x1b81, 0x7aa8, 0xa294, 0x00ff, 0x78a8, 0xa084, 0x00ff, 0xa08a, + 0x0004, 0x00c8, 0x2b75, 0x0079, 0x22cd, 0x2b75, 0x2944, 0x2b75, + 0x2a72, 0xa282, 0x0000, 0x00c0, 0x22d7, 0x1078, 0x1b81, 0x1078, + 0x2b94, 0x781b, 0x0069, 0x0078, 0x1bd3, 0xa282, 0x0003, 0x00c0, + 0x22e3, 0x1078, 0x1b81, 0x1078, 0x2ba4, 0x781b, 0x0069, 0x0078, + 0x1bd3, 0xa282, 0x0004, 0x0050, 0x22ef, 0x1078, 0x1b81, 0x2300, + 0x0079, 0x22f2, 0x22f5, 0x23d2, 0x2403, 0xa286, 0x0003, 0x0040, + 0x22fb, 0x1078, 0x1b81, 0x2001, 0x0000, 0x703a, 0x7000, 0xa084, + 0x0007, 0x0079, 0x2303, 0x230b, 0x230d, 0x230d, 0x2513, 0x253b, + 0x24dd, 0x230b, 0x230b, 0x1078, 0x1b81, 0xa684, 0x1000, 0x00c0, + 0x2315, 0x1078, 0x2eca, 0x0040, 0x23ac, 0x7868, 0xa08c, 0x00ff, + 0x0040, 0x235d, 0xa186, 0x0008, 0x00c0, 0x232c, 0x1078, 0x28fa, + 0x6008, 0xa084, 0xffef, 0x600a, 0x1078, 0x28ad, 0x0040, 0x235d, + 0x1078, 0x2eca, 0x0078, 0x2344, 0xa186, 0x0028, 0x00c0, 0x235d, + 0x1078, 0x2eca, 0x6008, 0xa084, 0xffef, 0x600a, 0x6018, 0xa005, + 0x0040, 0x2344, 0x8001, 0x601a, 0xa005, 0x0040, 0x2344, 0x8001, + 0xa005, 0x0040, 0x2344, 0x601e, 0x681c, 0xa084, 0x0001, 0x0040, + 0x1bdb, 0x681c, 0xa084, 0xfffe, 0x681e, 0x7054, 0x0c7e, 0x2060, + 0x6800, 0x6002, 0x0c7f, 0x6004, 0x6802, 0xa005, 0x2d00, 0x00c0, + 0x235a, 0x6002, 0x6006, 0x0078, 0x1bdb, 0x017e, 0x1078, 0x2428, + 0x017f, 0xa684, 0xdf00, 0x681a, 0x6827, 0x0000, 0x6f10, 0x81ff, + 0x0040, 0x23ac, 0xa186, 0x0002, 0x00c0, 0x23a4, 0xa684, 0x0800, + 0x00c0, 0x237a, 0xa684, 0x0060, 0x0040, 0x237a, 0x78d8, 0x7adc, + 0x682e, 0x6a2a, 0x8717, 0xa294, 0x000f, 0x8213, 0x8213, 0x8213, + 0xa290, 0x3600, 0xa290, 0x0000, 0x221c, 0xa384, 0x0100, 0x00c0, + 0x238b, 0x0078, 0x2391, 0x8210, 0x2204, 0xa085, 0x0018, 0x2012, + 0x8211, 0xa384, 0x0400, 0x0040, 0x239e, 0x689c, 0xa084, 0x0100, + 0x00c0, 0x239e, 0x1078, 0x249c, 0x0078, 0x1bdb, 0x6008, 0xa085, + 0x0002, 0x600a, 0x0078, 0x23ac, 0xa186, 0x0018, 0x0040, 0x23ac, + 0xa186, 0x0014, 0x0040, 0x1bdb, 0x6912, 0x6814, 0xa084, 0x8000, + 0x0040, 0x23b4, 0x7038, 0x6816, 0xa68c, 0xdf00, 0x691a, 0x1078, + 0x28eb, 0x1078, 0x28fa, 0x00c0, 0x23c1, 0x6008, 0xa084, 0xffef, + 0x600a, 0x681c, 0xa084, 0x0001, 0x00c0, 0x23ca, 0x1078, 0x28e4, + 0x0078, 0x23ce, 0x7054, 0x2060, 0x6800, 0x6002, 0x1078, 0x17e7, + 0x0078, 0x1bdb, 0xa282, 0x0004, 0x0048, 0x23d8, 0x1078, 0x1b81, + 0x2200, 0x0079, 0x23db, 0x23df, 0x23e1, 0x23ee, 0x23e1, 0x1078, + 0x1b81, 0x7000, 0xa086, 0x0005, 0x0040, 0x23ea, 0x1078, 0x2b94, + 0x781b, 0x0069, 0x781b, 0x006a, 0x0078, 0x1bd3, 0x7890, 0x8007, + 0x8001, 0xa084, 0x0007, 0xa080, 0x0018, 0x789a, 0x79a8, 0xa18c, + 0x00ff, 0xa186, 0x0003, 0x0040, 0x23ff, 0x0078, 0x2b75, 0x781b, + 0x006a, 0x0078, 0x1bd3, 0x681c, 0xa085, 0x0004, 0x681e, 0x82ff, + 0x00c0, 0x240e, 0x1078, 0x2b94, 0x0078, 0x2415, 0x8211, 0x0040, + 0x2413, 0x1078, 0x1b81, 0x1078, 0x2ba4, 0x781b, 0x0069, 0x0078, + 0x1bd3, 0x1078, 0x2d82, 0x7830, 0xa084, 0x00c0, 0x00c0, 0x2425, + 0x0018, 0x2425, 0x791a, 0xa006, 0x007c, 0xa085, 0x0001, 0x007c, + 0xa684, 0x0060, 0x00c0, 0x2432, 0x682f, 0x0000, 0x682b, 0x0000, + 0x0078, 0x249b, 0xa684, 0x0800, 0x00c0, 0x2441, 0x68b0, 0xa084, + 0x4800, 0xa635, 0xa684, 0x0800, 0x00c0, 0x2441, 0x1078, 0x2eca, + 0x007c, 0xa684, 0x0020, 0x0040, 0x246d, 0x78d0, 0x8003, 0x00c8, + 0x244f, 0xa006, 0x1078, 0x3197, 0x78d4, 0x1078, 0x31fc, 0xa684, + 0x4000, 0x0040, 0x2459, 0x682f, 0x0000, 0x682b, 0x0000, 0x0078, + 0x243e, 0x68b0, 0xa084, 0x4800, 0xa635, 0xa684, 0x4000, 0x00c0, + 0x2453, 0x7038, 0xa005, 0x00c0, 0x2467, 0x703b, 0x0007, 0x79d8, + 0x7adc, 0x692e, 0x6a2a, 0x0078, 0x243e, 0xa684, 0x4000, 0x0040, + 0x2477, 0x682f, 0x0000, 0x682b, 0x0000, 0x0078, 0x243e, 0x68b0, + 0xa084, 0x4800, 0xa635, 0xa684, 0x4000, 0x00c0, 0x2471, 0x7038, + 0xa005, 0x00c0, 0x2485, 0x703b, 0x0007, 0x79d8, 0x7adc, 0x78d0, + 0x80f3, 0x00c8, 0x248c, 0x8000, 0xa084, 0x003f, 0xa108, 0xa291, + 0x0000, 0x692e, 0x6a2a, 0x2100, 0xa205, 0x00c0, 0x2499, 0x0078, + 0x243e, 0x1078, 0x3197, 0x007c, 0xa384, 0x0200, 0x0040, 0x24a4, + 0x6008, 0xa085, 0x0002, 0x600a, 0x6817, 0x0006, 0x6a28, 0x692c, + 0x6a3a, 0x693e, 0x682b, 0x0300, 0x682f, 0x0000, 0x6833, 0x2000, + 0x6893, 0x0000, 0x6897, 0x0020, 0x7000, 0x0079, 0x24b7, 0x24bf, + 0x24c1, 0x24ca, 0x24bf, 0x24bf, 0x24bf, 0x24bf, 0x24bf, 0x1078, + 0x1b81, 0x681c, 0xa084, 0x0001, 0x00c0, 0x24ca, 0x1078, 0x28e4, + 0x0078, 0x24d0, 0x7054, 0x2c50, 0x2060, 0x6800, 0x6002, 0x2a60, + 0x2021, 0x3557, 0x2404, 0xa005, 0x0040, 0x24d9, 0x2020, 0x0078, + 0x24d2, 0x2d22, 0x206b, 0x0000, 0x007c, 0x77b4, 0x1078, 0x2bb1, + 0xa7bc, 0x0f00, 0x1078, 0x2cac, 0x6018, 0xa005, 0x0040, 0x250c, + 0x0d7e, 0x2001, 0x3f90, 0x2068, 0x0d7f, 0x2021, 0x3f80, 0x2009, + 0x0004, 0x2011, 0x0010, 0x1078, 0x1fc8, 0x0040, 0x250c, 0x157e, + 0x20a9, 0x0000, 0x2021, 0x3e80, 0x047e, 0x2009, 0x0004, 0x2011, + 0x0010, 0x1078, 0x1fc8, 0x047f, 0x0040, 0x250b, 0x8420, 0x0070, + 0x250b, 0x0078, 0x24fc, 0x157f, 0x8738, 0xa784, 0x0007, 0x00c0, + 0x24e2, 0x0078, 0x1bdb, 0x1078, 0x28eb, 0x1078, 0x28fa, 0x6827, + 0x0000, 0x789b, 0x000e, 0x6f10, 0x6813, 0x0002, 0x1078, 0x31cd, + 0xa684, 0x0800, 0x0040, 0x2528, 0x6918, 0xa18d, 0x2000, 0x691a, + 0x6814, 0xa084, 0x8000, 0x0040, 0x252f, 0x6817, 0x0000, 0x2021, + 0x3557, 0x6800, 0x2022, 0x6a38, 0x693c, 0x6a2a, 0x692e, 0x1078, + 0x17e7, 0x0078, 0x1bdb, 0x1078, 0x2428, 0x6827, 0x0000, 0x789b, + 0x000e, 0x6f10, 0x1078, 0x2d87, 0xa08c, 0x00ff, 0x6912, 0x6814, + 0xa084, 0x8000, 0x0040, 0x254e, 0x7038, 0x6816, 0xa68c, 0xdf00, + 0x691a, 0x70a3, 0x0000, 0x0078, 0x1bdb, 0xa006, 0x1078, 0x2eca, + 0x6813, 0x0000, 0x6817, 0x0001, 0xa68c, 0xdf00, 0x691a, 0x6827, + 0x0000, 0x7000, 0x0079, 0x2564, 0x256c, 0x256e, 0x256e, 0x2570, + 0x2570, 0x2570, 0x256c, 0x256c, 0x1078, 0x1b81, 0x1078, 0x28fa, + 0x6008, 0xa084, 0xffef, 0x600a, 0x0078, 0x28c5, 0x2300, 0x0079, + 0x2579, 0x257c, 0x257e, 0x25bc, 0x1078, 0x1b81, 0x7000, 0x0079, + 0x2581, 0x2589, 0x258b, 0x258b, 0x2596, 0x258b, 0x259d, 0x2589, + 0x2589, 0x1078, 0x1b81, 0xa684, 0x2000, 0x00c0, 0x2596, 0xa6b5, + 0x2000, 0x7e5a, 0x1078, 0x30f3, 0x0078, 0x2d3b, 0x6814, 0xa084, + 0x8000, 0x0040, 0x259d, 0x6817, 0x0007, 0x2009, 0x3518, 0x210c, + 0xa186, 0x0000, 0x0040, 0x25b2, 0xa186, 0x0001, 0x0040, 0x25b6, + 0x2009, 0x352b, 0x200b, 0x000b, 0x70a3, 0x0001, 0x781b, 0x0046, + 0x0078, 0x1bd3, 0x781b, 0x00dd, 0x0078, 0x1bd3, 0x2009, 0x352b, + 0x200b, 0x000a, 0x0078, 0x1bd3, 0x1078, 0x1b81, 0x2300, 0x0079, + 0x25c1, 0x25c4, 0x25c6, 0x25e9, 0x1078, 0x1b81, 0x7000, 0x0079, + 0x25c9, 0x25d1, 0x25d3, 0x25d3, 0x25de, 0x25d3, 0x25e5, 0x25d1, + 0x25d1, 0x1078, 0x1b81, 0xa684, 0x2000, 0x00c0, 0x25de, 0xa6b5, + 0x2000, 0x7e5a, 0x1078, 0x30f3, 0x0078, 0x2d3b, 0x6814, 0xa084, + 0x8000, 0x0040, 0x25e5, 0x6817, 0x0007, 0x781b, 0x00e4, 0x0078, + 0x1bd3, 0x681c, 0xa085, 0x0004, 0x681e, 0xa6b5, 0x0800, 0x1078, + 0x2b94, 0x781b, 0x0069, 0x0078, 0x1bd3, 0x2300, 0x0079, 0x25f8, + 0x25fb, 0x25fd, 0x25ff, 0x1078, 0x1b81, 0x1078, 0x1b81, 0xa684, + 0x0400, 0x00c0, 0x261e, 0x782b, 0x3009, 0x789b, 0x0060, 0x78ab, + 0x0000, 0xa684, 0xfffb, 0x785a, 0x79e4, 0xa184, 0x0020, 0x0040, + 0x2616, 0x78ec, 0xa084, 0x0003, 0x00c0, 0x261a, 0x2001, 0x0014, + 0x0078, 0x22fd, 0xa184, 0x0007, 0x0079, 0x2656, 0x7a90, 0xa294, + 0x0007, 0x789b, 0x0060, 0x79a8, 0x81ff, 0x0040, 0x2654, 0x789b, + 0x0010, 0x7ba8, 0xa384, 0x0001, 0x00c0, 0x2645, 0x7ba8, 0x7ba8, + 0xa386, 0x0001, 0x00c0, 0x2638, 0x2009, 0xfff7, 0x0078, 0x263e, + 0xa386, 0x0003, 0x00c0, 0x2645, 0x2009, 0xffef, 0x0c7e, 0x7048, + 0x2060, 0x6004, 0xa104, 0x6006, 0x0c7f, 0x789b, 0x0060, 0x78ab, + 0x0000, 0xa684, 0xfffb, 0x785a, 0x782b, 0x3009, 0x691c, 0xa18c, + 0xfdff, 0xa18c, 0xfeff, 0x691e, 0x0078, 0x2d3b, 0x2026, 0x202c, + 0x2660, 0x2668, 0x265e, 0x265e, 0x265e, 0x2d3b, 0x1078, 0x1b81, + 0x691c, 0xa18c, 0xfdff, 0xa18c, 0xfeff, 0x691e, 0x0078, 0x2d43, + 0x691c, 0xa18c, 0xfdff, 0xa18c, 0xfeff, 0x691e, 0x0078, 0x2d3b, + 0x79e4, 0xa184, 0x0030, 0x0040, 0x267a, 0x78ec, 0xa084, 0x0003, + 0x00c0, 0x2682, 0x6814, 0xa085, 0x8000, 0x6816, 0x2001, 0x0014, + 0x0078, 0x22fd, 0xa184, 0x0007, 0x0079, 0x2686, 0x2d3b, 0x2d3b, + 0x268e, 0x2d3b, 0x2d63, 0x2d63, 0x2d3b, 0x2d3b, 0xa684, 0x0400, + 0x00c0, 0x26bf, 0x681c, 0xa084, 0x0001, 0x0040, 0x2d43, 0xa68c, + 0x2060, 0xa18c, 0xfffb, 0x795a, 0x69b2, 0x789b, 0x0060, 0x78ab, + 0x0000, 0x789b, 0x0061, 0x6814, 0xa085, 0x8000, 0x6816, 0x78aa, + 0x157e, 0x137e, 0x147e, 0x20a1, 0x012c, 0x789b, 0x0000, 0x8000, + 0x80ac, 0xad80, 0x000a, 0x2098, 0x53a6, 0x147f, 0x137f, 0x157f, + 0x6810, 0x8007, 0x789b, 0x007e, 0x78aa, 0x0078, 0x2d43, 0x6814, + 0xa084, 0x8000, 0x0040, 0x26c6, 0x6817, 0x0008, 0x781b, 0x00d8, + 0x0078, 0x1bd3, 0x2300, 0x0079, 0x26cd, 0x26d2, 0x274d, 0x26d0, + 0x1078, 0x1b81, 0x7000, 0xa084, 0x0007, 0x0079, 0x26d7, 0x26df, + 0x26e1, 0x26fd, 0x26df, 0x26df, 0x24dd, 0x26df, 0x26df, 0x1078, + 0x1b81, 0x691c, 0xa18d, 0x0001, 0x691e, 0x6800, 0x6006, 0xa005, + 0x00c0, 0x26eb, 0x6002, 0x6818, 0xa084, 0x000e, 0x0040, 0x26f7, + 0x7014, 0x68b6, 0x712c, 0xa188, 0x3e80, 0x0078, 0x26f9, 0x2009, + 0x3f80, 0x2104, 0x6802, 0x2d0a, 0x7156, 0x6eb2, 0xa684, 0x0060, + 0x0040, 0x274b, 0xa684, 0x0800, 0x00c0, 0x270f, 0xa684, 0x7fff, + 0x68b2, 0x6890, 0x6894, 0x1078, 0x2eca, 0x0078, 0x274b, 0xa684, + 0x0020, 0x0040, 0x2721, 0xa006, 0x1078, 0x3197, 0x78d0, 0x8003, + 0x00c8, 0x271d, 0x78d4, 0x1078, 0x31fc, 0x79d8, 0x7adc, 0x0078, + 0x2725, 0x1078, 0x2cb9, 0x1078, 0x3197, 0xa684, 0x8000, 0x0040, + 0x274b, 0xa684, 0x7fff, 0x68b2, 0x789b, 0x0074, 0x1078, 0x2d87, + 0x2010, 0x1078, 0x2d87, 0x2008, 0xa684, 0x0020, 0x00c0, 0x2743, + 0x1078, 0x2d87, 0x801b, 0x00c8, 0x273e, 0x8000, 0xa084, 0x003f, + 0xa108, 0xa291, 0x0000, 0x6b94, 0x2100, 0xa302, 0x68ae, 0x6b90, + 0x2200, 0xa303, 0x68aa, 0x0078, 0x1bdb, 0x0078, 0x2b81, 0x7033, + 0x0000, 0xa282, 0x0005, 0x0050, 0x2757, 0x1078, 0x1b81, 0x2300, + 0x0079, 0x275a, 0x275d, 0x2767, 0x278a, 0x2200, 0x0079, 0x2760, + 0x2765, 0x2b81, 0x2765, 0x27b3, 0x2804, 0x1078, 0x1b81, 0x7000, + 0xa086, 0x0001, 0x00c0, 0x2774, 0x1078, 0x28fa, 0x1078, 0x2eca, + 0x7034, 0x600a, 0x0078, 0x2779, 0x7000, 0xa086, 0x0003, 0x0040, + 0x276e, 0x7003, 0x0005, 0x2001, 0x3f90, 0x2068, 0x703e, 0x7032, + 0x2200, 0x0079, 0x2783, 0x2b81, 0x2788, 0x27b3, 0x2788, 0x2b81, + 0x1078, 0x1b81, 0x7000, 0xa086, 0x0001, 0x00c0, 0x2797, 0x1078, + 0x28fa, 0x1078, 0x2eca, 0x7034, 0x600a, 0x0078, 0x279c, 0x7000, + 0xa086, 0x0003, 0x0040, 0x2791, 0x7003, 0x0005, 0x2001, 0x3f90, + 0x2068, 0x703e, 0x7032, 0x2200, 0x0079, 0x27a6, 0x27ad, 0x27ab, + 0x27ad, 0x27ab, 0x27ad, 0x1078, 0x1b81, 0x1078, 0x2ba4, 0x781b, + 0x0069, 0x0078, 0x1bd3, 0x7000, 0xa086, 0x0001, 0x00c0, 0x27c0, + 0x1078, 0x28fa, 0x1078, 0x2eca, 0x7034, 0x600a, 0x0078, 0x27c5, + 0x7000, 0xa086, 0x0003, 0x0040, 0x27ba, 0x7003, 0x0002, 0x7a80, + 0xa294, 0x0f00, 0x789b, 0x0018, 0x7ca8, 0xa484, 0x0007, 0xa215, + 0x2069, 0x3f80, 0x2d04, 0x2d08, 0x7156, 0x2068, 0xa005, 0x0040, + 0x27e0, 0x6810, 0xa206, 0x0040, 0x27f9, 0x6800, 0x0078, 0x27d3, + 0x7003, 0x0005, 0x2001, 0x3f90, 0x2068, 0x703e, 0x7032, 0x157e, + 0x20a9, 0x002f, 0x2003, 0x0000, 0x8000, 0x0070, 0x27f1, 0x0078, + 0x27ea, 0x157f, 0x6a12, 0x68b3, 0x0700, 0x681f, 0x0800, 0x6823, + 0x0003, 0x6eb0, 0x7e5a, 0x681c, 0xa084, 0x0c00, 0x0040, 0x285a, + 0x1078, 0x2b9c, 0x0078, 0x285a, 0x7000, 0xa086, 0x0001, 0x00c0, + 0x2811, 0x1078, 0x28fa, 0x1078, 0x2eca, 0x7034, 0x600a, 0x0078, + 0x2816, 0x7000, 0xa086, 0x0003, 0x0040, 0x280b, 0x7003, 0x0002, + 0x7a80, 0xa294, 0x0f00, 0x789b, 0x0018, 0x7ca8, 0xa484, 0x0007, + 0xa215, 0x79a8, 0x79a8, 0xa18c, 0x00ff, 0xa1e8, 0x3e80, 0x2d04, + 0x2d08, 0x7156, 0x2068, 0xa005, 0x0040, 0x2835, 0x6810, 0xa206, + 0x0040, 0x284e, 0x6800, 0x0078, 0x2828, 0x7003, 0x0005, 0x2001, + 0x3f90, 0x2068, 0x703e, 0x7032, 0x157e, 0x20a9, 0x002f, 0x2003, + 0x0000, 0x8000, 0x0070, 0x2846, 0x0078, 0x283f, 0x157f, 0x6a12, + 0x68b3, 0x0700, 0x681f, 0x0800, 0x6823, 0x0003, 0x6eb0, 0x7e5a, + 0x681c, 0xa084, 0x0c00, 0x0040, 0x285a, 0x1078, 0x2b98, 0x7e58, + 0x0078, 0x285a, 0x027e, 0x8207, 0xa084, 0x000f, 0x8003, 0x8003, + 0x8003, 0xa080, 0x3600, 0x2060, 0x704a, 0x6000, 0x704e, 0x6004, + 0x7052, 0xa684, 0x0060, 0x0040, 0x2891, 0x6b94, 0x6c90, 0x69a8, + 0x68ac, 0xa105, 0x00c0, 0x287f, 0x7bd2, 0x7bda, 0x7cd6, 0x7cde, + 0xa6b4, 0xb7ff, 0x7e5a, 0x1078, 0x30f3, 0x0078, 0x2891, 0x68ac, + 0xa31a, 0x2100, 0xa423, 0x2400, 0xa305, 0x0040, 0x2891, 0x7bd2, + 0x7bda, 0x7cd6, 0x7cde, 0x68ac, 0xa6b4, 0xbfff, 0x7e5a, 0x1078, + 0x3120, 0x077f, 0x1078, 0x2cac, 0x2009, 0x006a, 0xa684, 0x0008, + 0x0040, 0x289c, 0x2009, 0x0069, 0xa6b5, 0x2000, 0x7e5a, 0x791a, + 0x2d00, 0x703e, 0x8207, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, + 0xa080, 0x3600, 0x2048, 0x0078, 0x1bd3, 0x6020, 0xa005, 0x0040, + 0x28b9, 0x8001, 0x6022, 0x6008, 0xa085, 0x0008, 0x600a, 0x7010, + 0x6026, 0x007c, 0xa006, 0x1078, 0x2eca, 0x6813, 0x0000, 0x6817, + 0x0001, 0x681f, 0x0040, 0x681b, 0x0100, 0x7000, 0xa084, 0x0007, + 0x0079, 0x28ca, 0x28d2, 0x28d4, 0x28d4, 0x28e0, 0x28dc, 0x28d2, + 0x28d2, 0x28d2, 0x1078, 0x1b81, 0x1078, 0x28eb, 0x1078, 0x28e4, + 0x1078, 0x17e7, 0x0078, 0x1bdb, 0x70a3, 0x0000, 0x0078, 0x1bdb, + 0x6817, 0x0000, 0x0078, 0x2513, 0x6800, 0xa005, 0x00c0, 0x28e9, + 0x6002, 0x6006, 0x007c, 0x6010, 0xa005, 0x0040, 0x28f4, 0x8001, + 0x00d0, 0x28f4, 0x1078, 0x1b81, 0x6012, 0x6008, 0xa084, 0xffef, + 0x600a, 0x007c, 0x6018, 0xa005, 0x0040, 0x2900, 0x8001, 0x601a, + 0x007c, 0x1078, 0x2d82, 0x6817, 0x0018, 0x0078, 0x2931, 0x1078, + 0x2d82, 0x6817, 0x0019, 0x0078, 0x2931, 0x1078, 0x2d82, 0x6817, + 0x001a, 0x0078, 0x2931, 0x77b4, 0x1078, 0x2cac, 0x71b8, 0xa18c, + 0x00ff, 0xa1e8, 0x3e80, 0x2d04, 0x2d08, 0x2068, 0xa005, 0x00c0, + 0x2923, 0x0078, 0x1bdb, 0x6810, 0x72b4, 0xa206, 0x0040, 0x292b, + 0x6800, 0x0078, 0x291c, 0x6800, 0x200a, 0x6817, 0x0005, 0x70bf, + 0x0000, 0x1078, 0x28eb, 0x681c, 0xa084, 0x0001, 0x00c0, 0x293a, + 0x1078, 0x28e4, 0x1078, 0x28fa, 0x681b, 0x0000, 0x681f, 0x0020, + 0x1078, 0x17e7, 0x0078, 0x1bdb, 0xa282, 0x0003, 0x00c0, 0x2b75, + 0x7da8, 0xa5ac, 0x00ff, 0x7ea8, 0xa6b4, 0x00ff, 0x691c, 0xa18d, + 0x0080, 0x691e, 0xa184, 0x0100, 0x0040, 0x29a4, 0xa18c, 0xfeff, + 0x691e, 0xa6b4, 0x00ff, 0x0040, 0x298e, 0xa682, 0x000f, 0x0048, + 0x2965, 0x0040, 0x2965, 0x2031, 0x000f, 0x852b, 0x852b, 0x1078, + 0x2c2f, 0x0040, 0x296f, 0x1078, 0x2a3e, 0x0078, 0x2997, 0x1078, + 0x2bea, 0x0c7e, 0x2960, 0x6004, 0xa084, 0xfff5, 0x6006, 0x1078, + 0x2a62, 0x0c7f, 0x691c, 0xa18d, 0x0100, 0x691e, 0x7e58, 0xa6b5, + 0x0004, 0x7e5a, 0xa684, 0x0400, 0x00c0, 0x298a, 0x781b, 0x0055, + 0x0078, 0x1bd3, 0x781b, 0x0069, 0x0078, 0x1bd3, 0x0c7e, 0x2960, + 0x6004, 0xa084, 0xfff5, 0x6006, 0x1078, 0x2a62, 0x0c7f, 0x7e58, + 0xa684, 0x0400, 0x00c0, 0x29a0, 0x781b, 0x0058, 0x0078, 0x1bd3, + 0x781b, 0x006a, 0x0078, 0x1bd3, 0x0c7e, 0x7048, 0x2060, 0x6100, + 0xa18c, 0x1000, 0x0040, 0x29e4, 0x6208, 0x8217, 0xa294, 0x00ff, + 0xa282, 0x000f, 0x0048, 0x29b8, 0x0040, 0x29b8, 0x2011, 0x000f, + 0x2600, 0xa202, 0x00c8, 0x29bd, 0x2230, 0x6208, 0xa294, 0x00ff, + 0x7018, 0xa086, 0x0028, 0x00c0, 0x29cd, 0xa282, 0x0019, 0x00c8, + 0x29d3, 0x2011, 0x0019, 0x0078, 0x29d3, 0xa282, 0x000c, 0x00c8, + 0x29d3, 0x2011, 0x000c, 0x2200, 0xa502, 0x00c8, 0x29d8, 0x2228, + 0x1078, 0x2bee, 0x852b, 0x852b, 0x1078, 0x2c2f, 0x0040, 0x29e4, + 0x1078, 0x2a3e, 0x0078, 0x29e8, 0x1078, 0x2bea, 0x1078, 0x2a62, + 0x7858, 0xa085, 0x0004, 0x785a, 0x0c7f, 0x781b, 0x0069, 0x0078, + 0x1bd3, 0x0c7e, 0x2960, 0x6000, 0xa084, 0x1000, 0x00c0, 0x2a0c, + 0x6010, 0xa084, 0x000f, 0x00c0, 0x2a06, 0xa18c, 0x0002, 0x00c0, + 0x2a06, 0xa18c, 0xfff5, 0x6106, 0x0c7f, 0x007c, 0x2011, 0x0032, + 0x2019, 0x0000, 0x0078, 0x2a2e, 0x6208, 0xa294, 0x00ff, 0x7018, + 0xa086, 0x0028, 0x00c0, 0x2a1c, 0xa282, 0x0019, 0x00c8, 0x2a22, + 0x2011, 0x0019, 0x0078, 0x2a22, 0xa282, 0x000c, 0x00c8, 0x2a22, + 0x2011, 0x000c, 0x6308, 0x831f, 0xa39c, 0x00ff, 0xa382, 0x000f, + 0x0048, 0x2a2e, 0x0040, 0x2a2e, 0x2019, 0x000f, 0x78ab, 0x0001, + 0x78ab, 0x0003, 0x78ab, 0x0001, 0x7aaa, 0x7baa, 0xa8c0, 0x0005, + 0x681c, 0xa085, 0x0100, 0x681e, 0x0c7f, 0x007c, 0x0c7e, 0x7148, + 0x2160, 0x2008, 0xa084, 0xfff0, 0xa635, 0x7e86, 0x6018, 0x789a, + 0x7eae, 0x6612, 0x78a4, 0xa084, 0xfff8, 0xa18c, 0x0007, 0xa105, + 0x78a6, 0x6016, 0x788a, 0xa6b4, 0x000f, 0x8637, 0x8204, 0x8004, + 0xa084, 0x00ff, 0xa605, 0x600e, 0x6004, 0xa084, 0xfff5, 0x6006, + 0x0c7f, 0x007c, 0x0c7e, 0x7048, 0x2060, 0x6018, 0x789a, 0x78a4, + 0xa084, 0xfff0, 0x78a6, 0x6012, 0x7884, 0xa084, 0xfff0, 0x7886, + 0x0c7f, 0x007c, 0xa282, 0x0002, 0x00c0, 0x2b75, 0x7aa8, 0x691c, + 0xa18d, 0x0080, 0x691e, 0xa184, 0x0200, 0x0040, 0x2ab7, 0xa18c, + 0xfdff, 0x691e, 0xa294, 0x00ff, 0xa282, 0x0002, 0x00c8, 0x2b75, + 0x1078, 0x2afe, 0x1078, 0x2a62, 0xa980, 0x0001, 0x200c, 0x1078, + 0x2ca8, 0x1078, 0x29f1, 0x88ff, 0x0040, 0x2aaa, 0x789b, 0x0060, + 0x2800, 0x78aa, 0x7e58, 0xa6b5, 0x0004, 0x7e5a, 0xa684, 0x0400, + 0x00c0, 0x2aa6, 0x781b, 0x0055, 0x0078, 0x1bd3, 0x781b, 0x0069, + 0x0078, 0x1bd3, 0x7e58, 0xa684, 0x0400, 0x00c0, 0x2ab3, 0x781b, + 0x0058, 0x0078, 0x1bd3, 0x781b, 0x006a, 0x0078, 0x1bd3, 0xa282, + 0x0002, 0x00c8, 0x2abf, 0xa284, 0x0001, 0x0040, 0x2ac9, 0x7148, + 0xa188, 0x0000, 0x210c, 0xa18c, 0x2000, 0x00c0, 0x2ac9, 0x2011, + 0x0000, 0x1078, 0x2bdc, 0x1078, 0x2afe, 0x1078, 0x2a62, 0x7858, + 0xa085, 0x0004, 0x785a, 0x781b, 0x0069, 0x0078, 0x1bd3, 0x0c7e, + 0x027e, 0x2960, 0x6000, 0x2011, 0x0001, 0xa084, 0x2000, 0x00c0, + 0x2aee, 0x6014, 0xa084, 0x0040, 0x00c0, 0x2aec, 0xa18c, 0xffef, + 0x6106, 0xa006, 0x0078, 0x2afb, 0x2011, 0x0000, 0x78ab, 0x0001, + 0x78ab, 0x0002, 0x78ab, 0x0003, 0x7aaa, 0xa8c0, 0x0004, 0x681c, + 0xa085, 0x0200, 0x681e, 0x027f, 0x0c7f, 0x007c, 0x0c7e, 0x7048, + 0x2060, 0x82ff, 0x0040, 0x2b06, 0x2011, 0x0040, 0x6018, 0xa080, + 0x0002, 0x789a, 0x78a4, 0xa084, 0xffbf, 0xa205, 0x78a6, 0x6016, + 0x788a, 0x6004, 0xa084, 0xffef, 0x6006, 0x0c7f, 0x007c, 0x007e, + 0x7000, 0xa086, 0x0003, 0x0040, 0x2b20, 0x007f, 0x0078, 0x2b23, + 0x007f, 0x0078, 0x2b71, 0xa684, 0x0020, 0x0040, 0x2b71, 0x7888, + 0xa084, 0x0040, 0x0040, 0x2b71, 0x78a8, 0x8001, 0x0040, 0x2b30, + 0x7bb8, 0xa384, 0x003f, 0x831b, 0x00c8, 0x2b37, 0x8000, 0xa005, + 0x0040, 0x2b58, 0x831b, 0x00c8, 0x2b40, 0x8001, 0x0040, 0x2b6d, + 0xa006, 0x1078, 0x3197, 0x78b4, 0x1078, 0x31fc, 0x0078, 0x2b71, + 0xa684, 0x4000, 0x0040, 0x2b58, 0x78b8, 0x801b, 0x00c8, 0x2b51, + 0x8000, 0xa084, 0x003f, 0x00c0, 0x2b6d, 0xa6b4, 0xbfff, 0x7e5a, + 0x79d8, 0x7adc, 0x2001, 0x0001, 0xa108, 0x00c8, 0x2b61, 0xa291, + 0x0000, 0x79d2, 0x79da, 0x7ad6, 0x7ade, 0x1078, 0x3197, 0x781b, + 0x0067, 0x1078, 0x3061, 0x0078, 0x1bd3, 0x781b, 0x0067, 0x0078, + 0x1bd3, 0x781b, 0x006a, 0x0078, 0x1bd3, 0x1078, 0x2ba8, 0x781b, + 0x0069, 0x0078, 0x1bd3, 0x1078, 0x2b94, 0x781b, 0x0069, 0x0078, + 0x1bd3, 0x6823, 0x0002, 0x1078, 0x2b9c, 0x691c, 0xa18d, 0x0020, + 0x691e, 0x6814, 0xa084, 0x8000, 0x0040, 0x2b90, 0x6817, 0x0005, + 0x781b, 0x0069, 0x0078, 0x1bd3, 0x2001, 0x0005, 0x0078, 0x2baa, + 0x2001, 0x000c, 0x0078, 0x2baa, 0x2001, 0x0006, 0x0078, 0x2baa, + 0x2001, 0x000d, 0x0078, 0x2baa, 0x2001, 0x0009, 0x0078, 0x2baa, + 0x2001, 0x0007, 0x789b, 0x007f, 0x78aa, 0xa6b5, 0x0008, 0x7e5a, + 0x007c, 0x077e, 0x873f, 0xa7bc, 0x000f, 0x873b, 0x873b, 0x8703, + 0xa0e0, 0x3600, 0xa7b8, 0x0020, 0x7f9a, 0x79a4, 0xa184, 0x000f, + 0x0040, 0x2bca, 0xa184, 0xfff0, 0x78a6, 0x6012, 0x6004, 0xa085, + 0x0008, 0x6006, 0x8738, 0x8738, 0x7f9a, 0x79a4, 0xa184, 0x0040, + 0x0040, 0x2bda, 0xa184, 0xffbf, 0x78a6, 0x6016, 0x6004, 0xa085, + 0x0010, 0x6006, 0x077f, 0x007c, 0x789b, 0x0010, 0x78ab, 0x0001, + 0x78ab, 0x0002, 0x78ab, 0x0003, 0x7aaa, 0x789b, 0x0060, 0x78ab, + 0x0004, 0x007c, 0x2031, 0x0000, 0x2029, 0x0032, 0x789b, 0x0010, + 0x78ab, 0x0001, 0x78ab, 0x0003, 0x78ab, 0x0001, 0x7daa, 0x7eaa, + 0x789b, 0x0060, 0x78ab, 0x0005, 0x007c, 0x157e, 0x8007, 0xa084, + 0x00ff, 0x8003, 0x8003, 0xa080, 0x0020, 0x789a, 0x79a4, 0xa18c, + 0xfff0, 0x2001, 0x3546, 0x2004, 0xa082, 0x0028, 0x0040, 0x2c18, + 0x2021, 0x2c8f, 0x2019, 0x0014, 0x20a9, 0x000c, 0x0078, 0x2c1e, + 0x2021, 0x2c9b, 0x2019, 0x0019, 0x20a9, 0x000d, 0x2011, 0x0064, + 0x2404, 0xa084, 0xfff0, 0xa106, 0x0040, 0x2c2d, 0x8420, 0x2300, + 0xa210, 0x0070, 0x2c2d, 0x0078, 0x2c20, 0x157f, 0x007c, 0x157e, + 0x2011, 0x3546, 0x2214, 0xa282, 0x0032, 0x0048, 0x2c43, 0x0040, + 0x2c47, 0x2021, 0x2c81, 0x2019, 0x0011, 0x20a9, 0x000e, 0x2011, + 0x0032, 0x0078, 0x2c57, 0xa282, 0x0028, 0x0040, 0x2c4f, 0x2021, + 0x2c8f, 0x2019, 0x0014, 0x20a9, 0x000c, 0x0078, 0x2c55, 0x2021, + 0x2c9b, 0x2019, 0x0019, 0x20a9, 0x000d, 0x2011, 0x0064, 0x2200, + 0xa502, 0x0040, 0x2c67, 0x0048, 0x2c67, 0x8420, 0x2300, 0xa210, + 0x0070, 0x2c64, 0x0078, 0x2c57, 0x157f, 0xa006, 0x007c, 0x157f, + 0xa582, 0x0064, 0x00c8, 0x2c70, 0x7808, 0xa085, 0x0070, 0x780a, + 0x78ec, 0xa084, 0x0300, 0x0040, 0x2c7e, 0x2404, 0xa09e, 0x1201, + 0x00c0, 0x2c7e, 0x2001, 0x2101, 0x0078, 0x2c7f, 0x2404, 0xa005, + 0x007c, 0x1201, 0x3002, 0x3202, 0x4203, 0x4403, 0x5404, 0x5604, + 0x6605, 0x6805, 0x7806, 0x7a06, 0x0a07, 0x0c07, 0x0e07, 0x3202, + 0x4202, 0x5202, 0x6202, 0x7202, 0x6605, 0x7605, 0x7805, 0x7a05, + 0x7c05, 0x7e05, 0x7f05, 0x2202, 0x3202, 0x4202, 0x5202, 0x5404, + 0x6404, 0x7404, 0x7604, 0x7804, 0x7a04, 0x7c04, 0x7e04, 0x7f04, + 0x789b, 0x0010, 0xa046, 0x007c, 0xa784, 0x0f00, 0x800c, 0xa784, + 0x0007, 0x8003, 0x8003, 0x8003, 0x8003, 0xa105, 0xa0e0, 0x3680, + 0x007c, 0x79d8, 0x7adc, 0x78d0, 0x801b, 0x00c8, 0x2cc0, 0x8000, + 0xa084, 0x003f, 0xa108, 0xa291, 0x0000, 0x007c, 0x0f7e, 0x2079, + 0x0100, 0x2009, 0x3540, 0x2091, 0x8000, 0x2104, 0x0079, 0x2cd0, + 0x2d02, 0x2cda, 0x2cda, 0x2cda, 0x2cda, 0x2cda, 0x2cd8, 0x2cd8, + 0x1078, 0x1b81, 0x784b, 0x0004, 0x7848, 0xa084, 0x0004, 0x00c0, + 0x2cdc, 0x784b, 0x0008, 0x7848, 0xa084, 0x0008, 0x00c0, 0x2ce3, + 0x68b0, 0xa085, 0x4000, 0x68b2, 0x7858, 0xa085, 0x4000, 0x785a, + 0x7830, 0xa084, 0x0080, 0x00c0, 0x2d02, 0x0018, 0x2d02, 0x6818, + 0xa084, 0x0020, 0x00c0, 0x2d00, 0x781b, 0x00dd, 0x0078, 0x2d02, + 0x781b, 0x00e4, 0x2091, 0x8001, 0x0f7f, 0x007c, 0x0c7e, 0x6810, + 0x8007, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xa0e0, 0x3600, + 0x6004, 0xa084, 0x000a, 0x00c0, 0x2d39, 0x6108, 0xa194, 0xff00, + 0x0040, 0x2d39, 0xa18c, 0x00ff, 0x2001, 0x0019, 0xa106, 0x0040, + 0x2d28, 0x2001, 0x0032, 0xa106, 0x0040, 0x2d2c, 0x0078, 0x2d30, + 0x2009, 0x0020, 0x0078, 0x2d32, 0x2009, 0x003f, 0x0078, 0x2d32, + 0x2011, 0x0000, 0x2100, 0xa205, 0x600a, 0x6004, 0xa085, 0x0002, + 0x6006, 0x0c7f, 0x007c, 0x781b, 0x006a, 0x0078, 0x1bd3, 0x781b, + 0x0069, 0x0078, 0x1bd3, 0x781b, 0x0058, 0x0078, 0x1bd3, 0x781b, + 0x0055, 0x0078, 0x1bd3, 0x781b, 0x00dd, 0x0078, 0x1bd3, 0x781b, + 0x00dc, 0x0078, 0x1bd3, 0x781b, 0x00e4, 0x0078, 0x1bd3, 0x781b, + 0x00e3, 0x0078, 0x1bd3, 0x781b, 0x009e, 0x0078, 0x1bd3, 0x781b, + 0x009d, 0x0078, 0x1bd3, 0x70a3, 0x0001, 0x781b, 0x0046, 0x0078, + 0x1bd3, 0x007e, 0x7830, 0xa084, 0x00c0, 0x00c0, 0x2d80, 0x7808, + 0xa084, 0xfffd, 0x780a, 0x0005, 0x0005, 0x0005, 0x0005, 0x78ec, + 0xa084, 0x0021, 0x0040, 0x2d80, 0x7808, 0xa085, 0x0002, 0x780a, + 0x007f, 0x007c, 0x7808, 0xa085, 0x0002, 0x780a, 0x007c, 0x7830, + 0xa084, 0x0040, 0x00c0, 0x2d87, 0x0098, 0x2d90, 0x78ac, 0x007c, + 0x7808, 0xa084, 0xfffd, 0x780a, 0x0005, 0x0005, 0x0005, 0x0005, + 0x78ec, 0xa084, 0x0021, 0x0040, 0x2d9f, 0x0098, 0x2d9d, 0x78ac, + 0x007e, 0x7808, 0xa085, 0x0002, 0x780a, 0x007f, 0x007c, 0xa784, + 0x0070, 0x0040, 0x2dab, 0x6817, 0x0003, 0x7858, 0xa084, 0x3f00, + 0x681a, 0x682f, 0x0000, 0x682b, 0x0000, 0x784b, 0x0008, 0x78e4, + 0xa005, 0x00d0, 0x2018, 0xa084, 0x0020, 0x0040, 0x2018, 0x78ec, + 0xa084, 0x0003, 0x0040, 0x2018, 0x0018, 0x2018, 0x0078, 0x2b7b, + 0x0c7e, 0x6810, 0x8007, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, + 0xa080, 0x3600, 0x2060, 0x2048, 0x704a, 0x6000, 0x704e, 0x6004, + 0x7052, 0x0c7f, 0x007c, 0x0020, 0x0020, 0x0000, 0x0020, 0x0000, + 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, + 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, + 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, + 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0062, 0x0009, 0x0014, + 0x0014, 0x9847, 0x0014, 0x0014, 0x98f5, 0x98e7, 0x0014, 0x0014, + 0x0080, 0x00bf, 0x0100, 0x0402, 0x2008, 0xf880, 0xa20a, 0x0014, + 0x300b, 0xa20c, 0x0014, 0xa200, 0x8838, 0x817e, 0x842a, 0x84a0, + 0x3806, 0x8839, 0x28c2, 0x9cc3, 0xa805, 0x0864, 0xa83b, 0x3008, + 0x28c1, 0x9cc3, 0xa201, 0x300c, 0x2847, 0x8161, 0x846a, 0x8000, + 0x84a4, 0x1856, 0x883a, 0xa808, 0x28e2, 0x9ca0, 0xa8f3, 0x0864, + 0xa829, 0x300c, 0xa801, 0x3008, 0x28e1, 0x9ca0, 0x280d, 0xa204, + 0x64c0, 0x67a0, 0x6fc0, 0x1814, 0x883b, 0x7023, 0x8576, 0x8677, + 0xa80f, 0x786e, 0x883e, 0xa80c, 0x282b, 0xa205, 0x64a0, 0x67a0, + 0x6fc0, 0x1814, 0x883b, 0x7023, 0x8576, 0x8677, 0xa801, 0x883e, + 0x2069, 0x28c1, 0x9cc3, 0x2044, 0x2103, 0x20a2, 0x2081, 0xa8dc, + 0xa207, 0x0014, 0xa203, 0x8000, 0x84a8, 0x85a4, 0x1872, 0x849a, + 0x883c, 0x1fe2, 0xf601, 0xa208, 0x856e, 0x866f, 0x0704, 0x3008, + 0x9ca0, 0x0014, 0xa202, 0x8000, 0x85a4, 0x3009, 0x84a8, 0x19e2, + 0xf848, 0x8174, 0x86eb, 0x85eb, 0x872e, 0x87a9, 0x883f, 0x08e6, + 0xa8f1, 0xf861, 0xa8e8, 0xf801, 0x0014, 0xf881, 0x0016, 0x85b2, + 0x80f0, 0x9532, 0xfaa2, 0x1de2, 0x0014, 0x8532, 0xf221, 0x0014, + 0x1de2, 0x84a8, 0xd6e0, 0x1fe6, 0x0014, 0xa206, 0x6865, 0x817f, + 0x842a, 0x1dc1, 0x8823, 0x0016, 0x6042, 0x8008, 0xa8fa, 0x8000, + 0x84a4, 0x8160, 0x842a, 0xf021, 0x3008, 0x84a8, 0x1dc6, 0x20d7, + 0x8822, 0x0016, 0x8000, 0x2848, 0x1011, 0xa8fc, 0x3008, 0x8000, + 0xa000, 0x2802, 0x1011, 0xa8fd, 0xa887, 0x3008, 0x283d, 0x1011, + 0xa8fd, 0xa209, 0x0017, 0x300c, 0x8000, 0x85a4, 0x1de2, 0xdac1, + 0x0014, 0x26e0, 0x873a, 0xfaa2, 0x19f2, 0x1fe2, 0x0014, 0xa20b, + 0x0014, 0xa20d, 0x817e, 0x842a, 0x84a0, 0x3806, 0x0210, 0x9ccd, + 0x0704, 0x0000, 0x127e, 0x2091, 0x2200, 0x2049, 0x2eca, 0x7000, + 0x7204, 0xa205, 0x720c, 0xa215, 0x7008, 0xa084, 0xfffd, 0xa205, + 0x0040, 0x2edc, 0x0078, 0x2ee1, 0x7003, 0x0000, 0x127f, 0x2000, + 0x007c, 0x7000, 0xa084, 0x0001, 0x00c0, 0x2f0f, 0x7108, 0x8104, + 0x00c8, 0x2eee, 0x1078, 0x2fab, 0x0078, 0x2ee6, 0x700c, 0xa08c, + 0x007f, 0x0040, 0x2f0f, 0x7004, 0x8004, 0x00c8, 0x2f06, 0x7014, + 0xa005, 0x00c0, 0x2f02, 0x7010, 0xa005, 0x0040, 0x2f06, 0xa102, + 0x00c8, 0x2ee6, 0x7007, 0x0010, 0x0078, 0x2f0f, 0x8aff, 0x0040, + 0x2f0f, 0x1078, 0x316e, 0x00c0, 0x2f09, 0x0040, 0x2ee6, 0x1078, + 0x2f59, 0x7003, 0x0000, 0x127f, 0x2000, 0x007c, 0x6424, 0x84ff, + 0x0040, 0x2f33, 0x2c70, 0x2039, 0x2f38, 0x2704, 0xae68, 0x680c, + 0xa630, 0x6808, 0xa529, 0x8421, 0x0040, 0x2f33, 0x8738, 0x2704, + 0xa005, 0x00c0, 0x2f1e, 0x7098, 0xa075, 0x0040, 0x2f33, 0x2039, + 0x2f35, 0x0078, 0x2f1d, 0x007c, 0x0000, 0x0004, 0x0008, 0x000c, + 0x0010, 0x0014, 0x0018, 0x001c, 0x0000, 0x127e, 0x2091, 0x2200, + 0x2079, 0x3500, 0x2071, 0x0010, 0x7007, 0x000a, 0x7007, 0x0002, + 0x7003, 0x0000, 0x2071, 0x0020, 0x7007, 0x000a, 0x7007, 0x0002, + 0x7003, 0x0000, 0x2049, 0x0000, 0x78b3, 0x0000, 0x127f, 0x2000, + 0x007c, 0x2049, 0x2f59, 0x7004, 0x8004, 0x00c8, 0x2f85, 0x7007, + 0x0012, 0x7108, 0x7008, 0xa106, 0x00c0, 0x2f61, 0xa184, 0x0030, + 0x0040, 0x2f6e, 0xa086, 0x0030, 0x00c0, 0x2f61, 0x7000, 0xa084, + 0x0001, 0x00c0, 0x2f85, 0x7008, 0xa084, 0x000c, 0x00c0, 0x2f83, + 0x710c, 0xa184, 0x0300, 0x00c0, 0x2f83, 0xa184, 0x007f, 0x00c0, + 0x2f59, 0x0078, 0x2f85, 0x6817, 0x0003, 0x7007, 0x0012, 0x7007, + 0x0008, 0x7004, 0xa084, 0x0008, 0x00c0, 0x2f89, 0x7007, 0x0012, + 0x7108, 0x8104, 0x0048, 0x2f8e, 0x78b3, 0x0000, 0x7003, 0x0000, + 0x2049, 0x0000, 0x007c, 0x107e, 0x007e, 0x127e, 0x157e, 0x2091, + 0x2200, 0x7108, 0x1078, 0x2fab, 0x157f, 0x127f, 0x2091, 0x8001, + 0x007f, 0x107f, 0x007c, 0x7204, 0x2118, 0x7108, 0x700c, 0xa084, + 0x0300, 0x00c0, 0x2fed, 0xa184, 0x000c, 0x00c0, 0x2fed, 0x8213, + 0x8213, 0x8213, 0x8213, 0xa284, 0x0100, 0xa10d, 0x810b, 0x810b, + 0x810f, 0xa184, 0x0007, 0x0079, 0x2fc5, 0x2fcf, 0x2fdf, 0x2fed, + 0x2fdf, 0x3001, 0x3001, 0x2fed, 0x2fff, 0x1078, 0x1b81, 0x7007, + 0x0002, 0x8aff, 0x00c0, 0x2fd8, 0x2049, 0x0000, 0x0078, 0x2fdc, + 0x1078, 0x316e, 0x00c0, 0x2fd8, 0x78b3, 0x0000, 0x007c, 0x7007, + 0x0002, 0x8aff, 0x00c0, 0x2fe6, 0x0078, 0x2fea, 0x1078, 0x316e, + 0x00c0, 0x2fe6, 0x78b3, 0x0000, 0x007c, 0x7007, 0x0002, 0x1078, + 0x2f59, 0x1078, 0x2cc6, 0x6814, 0xa084, 0x8000, 0x0040, 0x2ffa, + 0x6817, 0x0002, 0x007c, 0x1078, 0x1b81, 0x1078, 0x1b81, 0x1078, + 0x3053, 0x7210, 0x7114, 0x700c, 0xa09c, 0x007f, 0x2800, 0xa300, + 0xa211, 0xa189, 0x0000, 0x78b0, 0xa005, 0x0040, 0x3013, 0x78b3, + 0x0000, 0x0078, 0x3036, 0x1078, 0x3053, 0x2704, 0x2c58, 0xac60, + 0x630c, 0x2200, 0xa322, 0x6308, 0x2100, 0xa31b, 0x2400, 0xa305, + 0x0040, 0x302c, 0x00c8, 0x302c, 0x8412, 0x8210, 0x830a, 0xa189, + 0x0000, 0x2b60, 0x0078, 0x3013, 0x2b60, 0x8a07, 0xa7ba, 0x2f35, + 0xa73d, 0x2c00, 0x6882, 0x6f86, 0x6c8e, 0x6b8a, 0x7007, 0x0012, + 0x1078, 0x2f59, 0x007c, 0x8738, 0x2704, 0xa005, 0x00c0, 0x3047, + 0x6098, 0xa005, 0x0040, 0x3050, 0x2060, 0x2039, 0x2f35, 0x8a51, + 0x0040, 0x304f, 0x7008, 0xa084, 0x00c0, 0xa086, 0x00c0, 0x007c, + 0x2051, 0x0000, 0x007c, 0x8a50, 0x8739, 0x2704, 0xa004, 0x00c0, + 0x3060, 0x2039, 0x2f3b, 0x6000, 0xa064, 0x00c0, 0x3060, 0x2d60, + 0x007c, 0x127e, 0x0d7e, 0x2091, 0x2200, 0x0d7f, 0x6880, 0x2060, + 0x6884, 0x6b88, 0x6c8c, 0x8057, 0xaad4, 0x00ff, 0xa084, 0x00ff, + 0xa0b8, 0x2f35, 0x7e08, 0xa6b5, 0x000c, 0x6818, 0xa084, 0x0040, + 0x0040, 0x307c, 0xa6b5, 0x0001, 0x0f7e, 0x2079, 0x0100, 0x7858, + 0x0f7f, 0xa084, 0x0040, 0x0040, 0x308b, 0xa684, 0x0001, 0x00c0, + 0x308b, 0xa6b5, 0x0001, 0x7007, 0x0004, 0x7004, 0xa084, 0x0004, + 0x00c0, 0x308d, 0x7000, 0xa005, 0x0040, 0x3098, 0x1078, 0x1b81, + 0x2400, 0xa305, 0x00c0, 0x309e, 0x0078, 0x30db, 0x2c58, 0x2704, + 0xac60, 0x6004, 0xa400, 0x007e, 0x701a, 0x6000, 0xa301, 0x701e, + 0x2009, 0x04fd, 0x2104, 0xa086, 0x04fd, 0x007f, 0x00c0, 0x30cb, + 0xa084, 0x0001, 0x0040, 0x30cb, 0xa684, 0x0001, 0x00c0, 0x30cb, + 0x7013, 0x0001, 0x7017, 0x0000, 0x7602, 0x7007, 0x0001, 0x78b3, + 0x0001, 0xa4a0, 0x0001, 0xa399, 0x0000, 0x6004, 0xa400, 0x701a, + 0x6000, 0xa301, 0x701e, 0x620c, 0x2400, 0xa202, 0x7012, 0x6208, + 0x2300, 0xa203, 0x7016, 0x7602, 0x7007, 0x0001, 0x2b60, 0x1078, + 0x303b, 0x0078, 0x30dd, 0x1078, 0x316e, 0x00c0, 0x30db, 0x127f, + 0x2000, 0x007c, 0x127e, 0x0d7e, 0x2091, 0x2200, 0x0d7f, 0x7007, + 0x0004, 0x7004, 0xa084, 0x0004, 0x00c0, 0x30e9, 0x7003, 0x0008, + 0x127f, 0x2000, 0x007c, 0x127e, 0x0d7e, 0x2091, 0x2200, 0x0d7f, + 0x2049, 0x30f3, 0x7007, 0x0004, 0x7004, 0xa084, 0x0004, 0x00c0, + 0x30fc, 0x7000, 0xa005, 0x0040, 0x3107, 0x1078, 0x1b81, 0x7e08, + 0xa6b5, 0x000c, 0x6818, 0xa084, 0x0040, 0x0040, 0x3111, 0xa6b5, + 0x0001, 0x6824, 0xa005, 0x0040, 0x311d, 0x2050, 0x2039, 0x2f38, + 0x2d60, 0x1078, 0x316e, 0x00c0, 0x3119, 0x127f, 0x2000, 0x007c, + 0x127e, 0x007e, 0x017e, 0x0d7e, 0x2091, 0x2200, 0x0d7f, 0x037f, + 0x047f, 0x7e08, 0xa6b5, 0x000c, 0x6818, 0xa084, 0x0040, 0x0040, + 0x3133, 0xa6b5, 0x0001, 0x2049, 0x3120, 0x6824, 0xa055, 0x0040, + 0x316b, 0x2d70, 0x2e60, 0x2039, 0x2f38, 0x2704, 0xae68, 0x680c, + 0xa422, 0x6808, 0xa31b, 0x0048, 0x3158, 0x8a51, 0x00c0, 0x314a, + 0x1078, 0x1b81, 0x8738, 0x2704, 0xa005, 0x00c0, 0x313e, 0x7098, + 0xa075, 0x2060, 0x0040, 0x316b, 0x2039, 0x2f35, 0x0078, 0x313d, + 0x8422, 0x8420, 0x831a, 0xa399, 0x0000, 0x690c, 0x2400, 0xa122, + 0x6908, 0x2300, 0xa11b, 0x00c8, 0x3167, 0x1078, 0x1b81, 0x2071, + 0x0020, 0x0078, 0x308b, 0x127f, 0x2000, 0x007c, 0x7008, 0xa084, + 0x00c0, 0xa086, 0x00c0, 0x0040, 0x3196, 0x2704, 0xac08, 0x2104, + 0x701e, 0x8108, 0x2104, 0x701a, 0x8108, 0x2104, 0x7016, 0x8108, + 0x2104, 0x7012, 0x0f7e, 0x2079, 0x0100, 0x7858, 0x0f7f, 0xa084, + 0x0040, 0x0040, 0x3191, 0xa684, 0x0001, 0x00c0, 0x3191, 0xa6b5, + 0x0001, 0x7602, 0x7007, 0x0001, 0x1078, 0x303b, 0x007c, 0x127e, + 0x007e, 0x0d7e, 0x2091, 0x2200, 0x2049, 0x3197, 0x0d7f, 0x087f, + 0x7108, 0xa184, 0x00c0, 0x00c0, 0x31ad, 0x6824, 0xa005, 0x0040, + 0x31bd, 0x0078, 0x2ee1, 0x0078, 0x31bd, 0x7108, 0x8104, 0x00c8, + 0x31b5, 0x1078, 0x2fab, 0x0078, 0x31a0, 0x7007, 0x0010, 0x7108, + 0x8104, 0x00c8, 0x31b7, 0x1078, 0x2fab, 0x7008, 0xa086, 0x0002, + 0x00c0, 0x31a0, 0x7000, 0xa005, 0x00c0, 0x31a0, 0x7003, 0x0000, + 0x2049, 0x0000, 0x127f, 0x2000, 0x007c, 0x127e, 0x147e, 0x137e, + 0x157e, 0x0d7e, 0x2091, 0x2200, 0x0d7f, 0x2049, 0x31cd, 0xad80, + 0x0010, 0x20a0, 0x2099, 0x0031, 0x700c, 0xa084, 0x007f, 0x6826, + 0x7007, 0x0008, 0x7007, 0x0002, 0x7003, 0x0001, 0x0040, 0x31eb, + 0x8000, 0x80ac, 0x53a5, 0x7007, 0x0004, 0x7004, 0xa084, 0x0004, + 0x00c0, 0x31ed, 0x2049, 0x0000, 0x7003, 0x0000, 0x157f, 0x137f, + 0x147f, 0x127f, 0x2000, 0x007c, 0x127e, 0x007e, 0x0d7e, 0x2091, + 0x2200, 0x0d7f, 0x2049, 0x31fc, 0x6880, 0x2060, 0x6884, 0x6b88, + 0x6c8c, 0x8057, 0xaad4, 0x00ff, 0xa084, 0x00ff, 0xa0b8, 0x2f35, + 0x7e08, 0xa6b5, 0x0004, 0x7007, 0x0004, 0x7004, 0xa084, 0x0004, + 0x00c0, 0x3215, 0x2c58, 0x2704, 0xac60, 0x6004, 0xa400, 0x701a, + 0x6000, 0xa301, 0x701e, 0x7013, 0x0001, 0x7017, 0x0000, 0x7602, + 0x7007, 0x0001, 0x007f, 0x8007, 0x2009, 0x0031, 0x200a, 0x00a0, + 0x322f, 0x7108, 0x7007, 0x0002, 0x810c, 0x00c8, 0x322f, 0x810c, + 0x0048, 0x323c, 0x0078, 0x2fed, 0xa4a0, 0x0001, 0xa399, 0x0000, + 0x6b8a, 0x6c8e, 0x7007, 0x0004, 0x2049, 0x0000, 0x7003, 0x0000, + 0x127f, 0x2000, 0x007c, 0x20a9, 0x0010, 0xa006, 0x8004, 0x8086, + 0x818e, 0x00c8, 0x3254, 0xa200, 0x00f0, 0x324f, 0x8086, 0x818e, + 0x007c, 0x157e, 0x20a9, 0x0010, 0xa005, 0x0040, 0x327a, 0xa11a, + 0x00c8, 0x327a, 0x8213, 0x818d, 0x0048, 0x326d, 0xa11a, 0x00c8, + 0x326e, 0x00f0, 0x3262, 0x0078, 0x3272, 0xa11a, 0x2308, 0x8210, + 0x00f0, 0x3262, 0x007e, 0x3200, 0xa084, 0xf7ff, 0x2080, 0x007f, + 0x157f, 0x007c, 0x007e, 0x3200, 0xa085, 0x0800, 0x0078, 0x3276, + 0x00e0, 0x32c2, 0x2091, 0x6000, 0x7820, 0x8001, 0x7822, 0x00c0, + 0x32bc, 0x7824, 0x7822, 0x2091, 0x8000, 0x2069, 0x3540, 0x6800, + 0xa084, 0x0007, 0x0040, 0x32a4, 0xa086, 0x0002, 0x0040, 0x32a4, + 0x6830, 0xa00d, 0x0040, 0x32a4, 0x2104, 0xa005, 0x0040, 0x32a4, + 0x8001, 0x200a, 0x0040, 0x3372, 0x2061, 0x3680, 0x20a9, 0x0080, + 0x6034, 0xa005, 0x0040, 0x32b6, 0x8001, 0x6036, 0x00c0, 0x32b6, + 0x6010, 0xa005, 0x0040, 0x32b6, 0x1078, 0x1a23, 0xace0, 0x0010, + 0x0070, 0x32bc, 0x0078, 0x32a8, 0x1078, 0x32d7, 0x1078, 0x32c5, + 0x1078, 0x32fc, 0x2091, 0x8001, 0x007c, 0x783c, 0x8001, 0x783e, + 0x00c0, 0x32d6, 0x7840, 0x783e, 0x7848, 0xa005, 0x0040, 0x32d6, + 0x8001, 0x784a, 0x00c0, 0x32d6, 0x1078, 0x1a23, 0x007c, 0x7834, + 0x8001, 0x7836, 0x00c0, 0x32fb, 0x7838, 0x7836, 0x2091, 0x8000, + 0x7844, 0xa005, 0x00c0, 0x32e6, 0x2001, 0x0101, 0x8001, 0x7846, + 0xa080, 0x3e80, 0x2040, 0x2004, 0xa065, 0x0040, 0x32fb, 0x6020, + 0xa005, 0x0040, 0x32f7, 0x8001, 0x6022, 0x0040, 0x332b, 0x6000, + 0x2c40, 0x0078, 0x32ec, 0x007c, 0x7828, 0x8001, 0x782a, 0x00c0, + 0x332a, 0x782c, 0x782a, 0x7830, 0xa005, 0x00c0, 0x3309, 0x2001, + 0x0080, 0x8001, 0x7832, 0x8003, 0x8003, 0x8003, 0x8003, 0xa090, + 0x3680, 0xa298, 0x0002, 0x2304, 0xa084, 0x0008, 0x0040, 0x332a, + 0xa290, 0x0009, 0x2204, 0xa005, 0x0040, 0x3322, 0x8001, 0x2012, + 0x00c0, 0x332a, 0x2304, 0xa084, 0xfff7, 0xa085, 0x0080, 0x201a, + 0x1078, 0x1a23, 0x007c, 0x2069, 0x3540, 0x6800, 0xa005, 0x0040, + 0x3335, 0x683c, 0xac06, 0x0040, 0x3372, 0x6017, 0x0006, 0x60b0, + 0xa084, 0x3f00, 0x601a, 0x601c, 0xa084, 0x00ff, 0xa085, 0x0060, + 0x601e, 0x6000, 0x2042, 0x6710, 0x6fb6, 0x1078, 0x169c, 0x6818, + 0xa005, 0x0040, 0x334d, 0x8001, 0x681a, 0x6808, 0xa084, 0xffef, + 0x680a, 0x6810, 0x8001, 0x00d0, 0x3357, 0x1078, 0x1b81, 0x6812, + 0x602f, 0x0000, 0x602b, 0x0000, 0x2c68, 0x1078, 0x17e7, 0x2069, + 0x3540, 0x2001, 0x0006, 0x68a2, 0x7944, 0xa184, 0x0100, 0x00c0, + 0x336d, 0x69ba, 0x2001, 0x0004, 0x68a2, 0x1078, 0x1a1e, 0x2091, + 0x8001, 0x007c, 0x2009, 0x354f, 0x2164, 0x2069, 0x0100, 0x6017, + 0x0006, 0x6858, 0xa084, 0x3f00, 0x601a, 0x601c, 0xa084, 0x00ff, + 0xa085, 0x0048, 0x601e, 0x602f, 0x0000, 0x602b, 0x0000, 0x6830, + 0xa084, 0x0040, 0x0040, 0x33ac, 0x684b, 0x0004, 0x20a9, 0x0014, + 0x6848, 0xa084, 0x0004, 0x0040, 0x3399, 0x0070, 0x3399, 0x0078, + 0x3390, 0x684b, 0x0009, 0x20a9, 0x0014, 0x6848, 0xa084, 0x0001, + 0x0040, 0x33a6, 0x0070, 0x33a6, 0x0078, 0x339d, 0x20a9, 0x00fa, + 0x0070, 0x33ac, 0x0078, 0x33a8, 0x6808, 0xa084, 0xfffd, 0x680a, + 0x681b, 0x0046, 0x2009, 0x3568, 0x200b, 0x0007, 0x784c, 0x784a, + 0x2091, 0x8001, 0x007c, 0x2079, 0x3500, 0x1078, 0x3404, 0x1078, + 0x33cc, 0x1078, 0x33e1, 0x1078, 0x33f6, 0x7833, 0x0000, 0x7847, + 0x0000, 0x784b, 0x0000, 0x007c, 0x2019, 0x000a, 0x2011, 0x3546, + 0x2204, 0xa086, 0x0032, 0x0040, 0x33de, 0x2019, 0x000c, 0x2204, + 0xa086, 0x003c, 0x0040, 0x33de, 0x2019, 0x0008, 0x7b2a, 0x7b2e, + 0x007c, 0x2019, 0x0030, 0x2011, 0x3546, 0x2204, 0xa086, 0x0032, + 0x0040, 0x33f3, 0x2019, 0x0039, 0x2204, 0xa086, 0x003c, 0x0040, + 0x33f3, 0x2019, 0x0027, 0x7b36, 0x7b3a, 0x007c, 0x2019, 0x000d, + 0x2011, 0x3546, 0x2204, 0xa086, 0x003c, 0x0040, 0x3401, 0x2019, + 0x000a, 0x7b3e, 0x7b42, 0x007c, 0x2019, 0x2faf, 0x2011, 0x3546, + 0x2204, 0xa086, 0x0032, 0x0040, 0x3416, 0x2019, 0x3971, 0x2204, + 0xa086, 0x003c, 0x0040, 0x3416, 0x2019, 0x2626, 0x7b22, 0x7b26, + 0x007c, 0xda3e +}; + +unsigned short sbus_risc_code_length01 = 0x241a; diff -ur --new-file old/linux/drivers/scsi/scsi.c new/linux/drivers/scsi/scsi.c --- old/linux/drivers/scsi/scsi.c Mon Jan 18 03:29:54 1999 +++ new/linux/drivers/scsi/scsi.c Thu Apr 29 20:53:41 1999 @@ -162,7 +162,11 @@ "Scanner ", "Optical Device ", "Medium Changer ", - "Communications " + "Communications ", + "Unknown ", + "Unknown ", + "Unknown ", + "Enclosure ", }; /* @@ -241,6 +245,7 @@ {"SONY","CD-ROM CDU-541","4.3d", BLIST_NOLUN}, {"SONY","CD-ROM CDU-55S","1.0i", BLIST_NOLUN}, {"SONY","CD-ROM CDU-561","1.7x", BLIST_NOLUN}, +{"SONY","CD-ROM CDU-8012","*", BLIST_NOLUN}, {"TANDBERG","TDC 3600","U07", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */ {"TEAC","CD-R55S","1.0H", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */ {"TEAC","CD-ROM","1.06", BLIST_NOLUN}, /* causes failed REQUEST SENSE on lun 1 @@ -276,12 +281,11 @@ {"EMULEX","MD21/S2 ESDI","*", BLIST_SINGLELUN}, {"CANON","IPUBJD","*", BLIST_SPARSELUN}, {"nCipher","Fastness Crypto","*", BLIST_FORCELUN}, +{"NEC","PD-1 ODX654P","*", BLIST_FORCELUN | BLIST_SINGLELUN}, {"MATSHITA","PD","*", BLIST_FORCELUN | BLIST_SINGLELUN}, {"YAMAHA","CDR100","1.00", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */ {"YAMAHA","CDR102","1.00", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */ {"iomega","jaz 1GB","J.86", BLIST_NOTQ | BLIST_NOLUN}, -{"IBM","DPES-","*", BLIST_NOTQ | BLIST_NOLUN}, -{"WDIGTL","WDE","*", BLIST_NOTQ | BLIST_NOLUN}, /* * Must be at end of list... */ @@ -759,6 +763,7 @@ case TYPE_PROCESSOR: case TYPE_SCANNER: case TYPE_MEDIUM_CHANGER: + case TYPE_ENCLOSURE: SDpnt->writeable = 1; break; case TYPE_WORM: @@ -1921,10 +1926,12 @@ SDpnt->device_queue = NULL; for(j=0;jqueue_depth;j++){ - SCpnt = (Scsi_Cmnd *) + SCpnt = (Scsi_Cmnd *) scsi_init_malloc(sizeof(Scsi_Cmnd), GFP_ATOMIC | (host->unchecked_isa_dma ? GFP_DMA : 0)); + if (NULL == SCpnt) + break; /* If not, the next line will oops ... */ memset(&SCpnt->eh_timeout, 0, sizeof(SCpnt->eh_timeout)); SCpnt->host = host; SCpnt->device = SDpnt; @@ -1947,6 +1954,12 @@ SCpnt->state = SCSI_STATE_UNUSED; SCpnt->owner = SCSI_OWNER_NOBODY; } + if (j < SDpnt->queue_depth) { /* low on space (D.Gilbert 990424) */ + 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 = 1; } @@ -2471,7 +2484,8 @@ } else if (SDpnt->type == TYPE_SCANNER || SDpnt->type == TYPE_PROCESSOR || - SDpnt->type == TYPE_MEDIUM_CHANGER) { + SDpnt->type == TYPE_MEDIUM_CHANGER || + SDpnt->type == TYPE_ENCLOSURE) { new_dma_sectors += (4096 >> 9) * SDpnt->queue_depth; } else { @@ -3293,7 +3307,7 @@ /* One bit per sector to indicate free/busy */ size = (dma_sectors / SECTORS_PER_PAGE)*sizeof(FreeSectorBitmap); - dma_malloc_freelist = (unsigned char *) scsi_init_malloc(size, GFP_ATOMIC); + dma_malloc_freelist = (FreeSectorBitmap *) scsi_init_malloc(size, GFP_ATOMIC); memset(dma_malloc_freelist, 0, size); /* One pointer per page for the page list */ diff -ur --new-file old/linux/drivers/scsi/scsi.h new/linux/drivers/scsi/scsi.h --- old/linux/drivers/scsi/scsi.h Thu Jan 28 21:42:05 1999 +++ new/linux/drivers/scsi/scsi.h Tue May 11 19:36:28 1999 @@ -39,7 +39,7 @@ # define FALSE 0 #endif -#define MAX_SCSI_DEVICE_CODE 10 +#define MAX_SCSI_DEVICE_CODE 14 extern const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE]; #ifdef DEBUG diff -ur --new-file old/linux/drivers/scsi/scsi_error.c new/linux/drivers/scsi/scsi_error.c --- old/linux/drivers/scsi/scsi_error.c Thu Jan 7 18:24:00 1999 +++ new/linux/drivers/scsi/scsi_error.c Thu Feb 25 01:27:54 1999 @@ -563,6 +563,7 @@ struct semaphore sem = MUTEX_LOCKED; struct timer_list timer; + init_timer(&timer); timer.data = (unsigned long) &sem; timer.expires = jiffies + timeout; timer.function = (void (*)(unsigned long))scsi_sleep_done; diff -ur --new-file old/linux/drivers/scsi/scsi_ioctl.c new/linux/drivers/scsi/scsi_ioctl.c --- old/linux/drivers/scsi/scsi_ioctl.c Tue Sep 8 19:32:46 1998 +++ new/linux/drivers/scsi/scsi_ioctl.c Thu Apr 29 20:53:41 1999 @@ -131,15 +131,16 @@ else printk("SCSI device (ioctl) reports ILLEGAL REQUEST.\n"); break; case NOT_READY: /* This happens if there is no disc in drive */ - if(dev->removable){ + if(dev->removable && (cmd[0] != TEST_UNIT_READY)){ printk(KERN_INFO "Device not ready. Make sure there is a disc in the drive.\n"); break; - }; + } case UNIT_ATTENTION: if (dev->removable){ dev->changed = 1; SCpnt->result = 0; /* This is no longer considered an error */ - printk(KERN_INFO "Disc change detected.\n"); + /* gag this error, VFS will log it anyway /axboe */ + /* printk(KERN_INFO "Disc change detected.\n"); */ break; }; default: /* Fall through for non-removable media */ diff -ur --new-file old/linux/drivers/scsi/sd.c new/linux/drivers/scsi/sd.c --- old/linux/drivers/scsi/sd.c Mon Jan 18 03:29:54 1999 +++ new/linux/drivers/scsi/sd.c Thu Apr 29 20:53:41 1999 @@ -708,17 +708,23 @@ */ if (rscsi_disks[dev].sector_size == 1024) if((block & 1) || (SCpnt->request.nr_sectors & 1)) { - printk("sd.c:Bad block number requested"); + printk("sd.c:Bad block number/count requested"); SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors); goto repeat; } if (rscsi_disks[dev].sector_size == 2048) if((block & 3) || (SCpnt->request.nr_sectors & 3)) { - printk("sd.c:Bad block number requested"); + printk("sd.c:Bad block number/count requested"); SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors); goto repeat; } + if (rscsi_disks[dev].sector_size == 4096) + if((block & 7) || (SCpnt->request.nr_sectors & 7)) { + printk("sd.cBad block number/count requested"); + SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors); + goto repeat; + } switch (SCpnt->request.cmd) { @@ -984,6 +990,13 @@ cmd[1] = (SCpnt->lun << 5) & 0xe0; + if (rscsi_disks[dev].sector_size == 4096){ + if(block & 7) panic("sd.c:Bad block number requested"); + if(this_count & 7) panic("sd.c:Bad block number requested"); + block = block >> 3; + this_count = block >> 3; + } + if (rscsi_disks[dev].sector_size == 2048){ if(block & 3) panic("sd.c:Bad block number requested"); if(this_count & 3) panic("sd.c:Bad block number requested"); @@ -1335,6 +1348,7 @@ if (rscsi_disks[i].sector_size != 512 && rscsi_disks[i].sector_size != 1024 && rscsi_disks[i].sector_size != 2048 && + rscsi_disks[i].sector_size != 4096 && rscsi_disks[i].sector_size != 256) { printk ("%s : unsupported sector size %d.\n", @@ -1394,6 +1408,8 @@ nbuff, hard_sector, rscsi_disks[i].capacity, mb, sz_quot, sz_rem); } + if(rscsi_disks[i].sector_size == 4096) + rscsi_disks[i].capacity <<= 3; if(rscsi_disks[i].sector_size == 2048) rscsi_disks[i].capacity <<= 2; /* Change into 512 byte sectors */ if(rscsi_disks[i].sector_size == 1024) diff -ur --new-file old/linux/drivers/scsi/sd_ioctl.c new/linux/drivers/scsi/sd_ioctl.c --- old/linux/drivers/scsi/sd_ioctl.c Wed Oct 14 20:43:14 1998 +++ new/linux/drivers/scsi/sd_ioctl.c Thu Feb 25 01:27:54 1999 @@ -108,6 +108,11 @@ return -EACCES; return revalidate_scsidisk(dev, 1); + case BLKSSZGET: + /* Block size of media */ + return put_user(blksize_size[MAJOR(dev)][MINOR(dev)&0x0F], + (int *)arg); + RO_IOCTLS(dev, arg); default: diff -ur --new-file old/linux/drivers/scsi/sg.c new/linux/drivers/scsi/sg.c --- old/linux/drivers/scsi/sg.c Mon Aug 24 22:14:10 1998 +++ new/linux/drivers/scsi/sg.c Fri May 7 20:05:30 1999 @@ -4,7 +4,45 @@ * to allow user process control of SCSI devices. * Development Sponsored by Killy Corp. NY NY * - * Borrows code from st driver. + * Original driver (sg.c): + * Copyright (C) 1992 Lawrence Foard + * 2.x extensions to driver: + * Copyright (C) 1998, 1999 Douglas Gilbert + * + * 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. + * + * Borrows code from st driver. Thanks to Alessandro Rubini's "dd" book. + */ + static char * sg_version_str = "Version: 2.1.32 (990501)"; +/* + * D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au) + * - scatter list logic replaces previous large atomic SG_BIG_BUFF + * sized allocation. See notes in include file. + * + * - scsi logging is available via SCSI_LOG_TIMEOUT macros. First + * the kernel/module needs to be built with CONFIG_SCSI_LOGGING + * (otherwise the macros compile to empty statements), then do + * something like: 'echo "scsi log all" > /proc/scsi/scsi' to log + * everything or 'echo "scsi log {token} #N" > /proc/scsi/scsi' + * where {token} is one of [error,timeout,scan,mlqueue,mlcomplete, + * llqueue,llcomplete,hlqueue,hlcomplete,ioctl] and #N is 0...7 + * (with 0 meaning off). For example: 'scsi log timeout 7 > + * /proc/scsi/scsi' to get all logging messages from this driver. + * Should use hlcomplete but it is too "noisy" (sd uses it). + * + * - This driver obtains memory (heap) for the low-level driver to + * transfer/dma to and from. It is obtained from up to 4 sources: + * - 1 SG_SCATTER_SZ sized buffer on open() (per fd) + * [could be less if SG_SCATTER_SZ bytes not available] + * - obtain heap as required on write()s (get_free_pages) + * - obtain heap from the shared scsi dma pool + * - obtain heap from kernel directly (kmalloc) [last choice] + * the 'alt_address' field in the scatter_list structure and the + * related 'mem_src' indicate the source of the heap allocation. + * */ #include @@ -28,541 +66,838 @@ #include #include -int sg_big_buff = SG_BIG_BUFF; /* for now, sg_big_buff is read-only through sysctl */ + +int sg_big_buff = SG_SCATTER_SZ; /* sg_big_buff is ro through sysctl */ +/* N.B. This global is here to keep existing software happy. It now holds + the size of the "first buffer" of the most recent sucessful sg_open(). + Only available when 'sg' compiled into kernel (rather than a module). + This should probably be deprecated (use SG_GET_RESERVED_SIZE instead). */ + +#define SG_SECTOR_SZ 512 +#define SG_SECTOR_MSK (SG_SECTOR_SZ - 1) + +#define SG_LOW_POOL_THRESHHOLD 30 +#define SG_MAX_POOL_SECTORS 320 /* Max. number of pool sectors to take */ + +static int sg_pool_secs_avail = SG_MAX_POOL_SECTORS; + +/* #define SG_DEBUG */ /* for counting varieties of allocations */ + +#ifdef SG_DEBUG +static int sg_num_kmal = 0; +static int sg_num_pool = 0; +static int sg_num_page = 0; +#endif + +#define SG_HEAP_FB 0 /* heap obtained at open() (one buffer per fd) */ +#define SG_HEAP_PAGE 1 /* heap from kernel via get_free_pages() */ +#define SG_HEAP_KMAL 2 /* heap from kernel via kmalloc() */ +#define SG_HEAP_POOL 3 /* heap from scsi dma pool (mid-level) */ + static int sg_init(void); static int sg_attach(Scsi_Device *); +static void sg_finish(void); static int sg_detect(Scsi_Device *); static void sg_detach(Scsi_Device *); struct Scsi_Device_Template sg_template = {NULL, NULL, "sg", NULL, 0xff, - SCSI_GENERIC_MAJOR, 0, 0, 0, 0, - sg_detect, sg_init, - NULL, sg_attach, sg_detach}; - -#ifdef SG_BIG_BUFF -static char *big_buff = NULL; -static struct wait_queue *big_wait; /* wait for buffer available */ -static int big_inuse=0; -#endif + SCSI_GENERIC_MAJOR, 0, 0, 0, 0, + sg_detect, sg_init, + sg_finish, sg_attach, sg_detach}; -struct scsi_generic + +typedef struct sg_scatter_hold /* holding area for scsi scatter gather info */ { - Scsi_Device *device; - int users; /* how many people have it open? */ - struct wait_queue *generic_wait; /* wait for device to be available */ - struct wait_queue *read_wait; /* wait for response */ - struct wait_queue *write_wait; /* wait for free buffer */ - int timeout; /* current default value for device */ - int buff_len; /* length of current buffer */ - char *buff; /* the buffer */ - struct sg_header header; /* header of pending command */ - char exclude; /* opened for exclusive access */ - char pending; /* don't accept writes now */ - char complete; /* command complete allow a read */ -}; + unsigned short use_sg; /* Number of pieces of scatter-gather */ + unsigned short sglist_len; /* size of malloc'd scatter-gather list */ + unsigned bufflen; /* Size of data buffer */ + unsigned b_malloc_len; /* actual len malloc'ed in buffer */ + void * buffer; /* Data buffer or scatter list (12 bytes) */ + char mem_src; /* heap whereabouts of 'buffer' */ +} Sg_scatter_hold; /* 20 bytes long on i386 */ -static struct scsi_generic *scsi_generics=NULL; -static void sg_free(char *buff,int size); +struct sg_device; /* forward declarations */ +struct sg_fd; -static int sg_ioctl(struct inode * inode,struct file * file, - unsigned int cmd_in, unsigned long arg) +typedef struct sg_request /* SG_MAX_QUEUE requests outstanding per file */ { - int dev = MINOR(inode->i_rdev); - int result; + Scsi_Cmnd * my_cmdp; /* NULL -> ready to read, else id */ + struct sg_request * nextrp; /* NULL -> tail request (slist) */ + struct sg_fd * parentfp; /* NULL -> not in use */ + Sg_scatter_hold data; /* hold buffers, perhaps scatter list */ + struct sg_header header; /* scsi command+info */ + char fb_used; /* 1 -> using fst_buf, normally 0 (used) */ +} Sg_request; /* around 72 bytes long on i386 */ - if ((dev<0) || (dev>=sg_template.dev_max)) - return -ENXIO; - - /* - * If we are in the middle of error recovery, then don't allow any - * access to this device. Also, error recovery *may* have taken the - * device offline, in which case all further access is prohibited. - */ - if( !scsi_block_when_processing_errors(scsi_generics[dev].device) ) - { - return -ENXIO; - } +typedef struct sg_fd /* holds the state of a file descriptor */ +{ + struct sg_fd * nextfp; /* NULL when last opened fd on this device */ + struct sg_device * parentdp; /* owning device */ + struct wait_queue * read_wait; /* queue read until command done */ + int timeout; /* defaults to SG_DEFAULT_TIMEOUT */ + char * fst_buf; /* try to grab SG_SCATTER_SZ sized buffer on open */ + int fb_size; /* actual size of allocated fst_buf */ + Sg_request * headrp; /* head of request slist, NULL->empty */ + struct fasync_struct * async_qp; /* used by asynchronous notification */ + Sg_request req_arr[SG_MAX_QUEUE]; /* used as singly-linked list */ + char low_dma; /* as in parent but possible overridden to 1 */ + char force_packid; /* 1 -> pack_id input to read(), 0 -> ignored */ + char closed; /* 1 -> fd closed but request(s) outstanding */ + char my_mem_src; /* heap whereabouts of this sg_fb object */ + char cmd_q; /* 1 -> allow command queuing, 0 -> don't */ + char underrun_flag; /* 1 -> flag underruns, 0 -> don't, 2 -> test */ +} Sg_fd; /* around 1192 bytes long on i386 */ + +typedef struct sg_device /* holds the state of each scsi generic device */ +{ + Scsi_Device * device; + struct wait_queue * generic_wait;/* queue open if O_EXCL on prev. open */ + int sg_tablesize; /* adapter's max scatter-gather table size */ + Sg_fd * headfp; /* first open fd belonging to this device */ + kdev_t i_rdev; /* holds device major+minor number */ + char exclude; /* opened for exclusive access */ + char sgdebug; /* 0->off, 1->sense, 9->dump dev, 10-> all devs */ + unsigned char merge_fd; /* 0->sequencing per fd (def) else fd count */ +} Sg_device; /* around 24 bytes long on i386 */ + + +static int sg_fasync(int fd, struct file * filp, int mode); +static void sg_command_done(Scsi_Cmnd * SCpnt); +static int sg_sc_build(Sg_request * srp, int max_buff_size, + const char * inp, int num_write_xfer); +static int sg_sc_undo_rem(Sg_request * srp, char * outp, + int num_read_xfer); +static char * sg_malloc(Sg_request * srp, int size, int * retSzp, + int * mem_srcp); +static void sg_free(Sg_request * srp, char * buff, int size, int mem_src); +static char * sg_low_malloc(int rqSz, int lowDma, int mem_src, + int * retSzp); +static void sg_low_free(char * buff, int size, int mem_src); +static Sg_fd * sg_add_sfp(Sg_device * sdp, int dev, int get_reserved); +static int sg_remove_sfp(Sg_device * sdp, Sg_fd * sfp); +static Sg_request * sg_get_request(const Sg_fd * sfp, int pack_id); +static Sg_request * sg_add_request(Sg_fd * sfp); +static int sg_remove_request(Sg_fd * sfp, const Sg_request * srp); +static int sg_fb_in_use(const Sg_fd * sfp); +static void sg_clr_scpnt(Scsi_Cmnd * SCpnt); +static void sg_shorten_timeout(Scsi_Cmnd * scpnt); +static void sg_debug(const Sg_device * sdp, const Sg_fd * sfp, int part_of); +static void sg_debug_all(const Sg_fd * sfp); + +static Sg_device * sg_dev_arr = NULL; +static const int size_sg_header = sizeof(struct sg_header); - switch(cmd_in) - { - case SG_SET_TIMEOUT: - result = verify_area(VERIFY_READ, (const void *)arg, sizeof(int)); - if (result) return result; - get_user(scsi_generics[dev].timeout, (int *) arg); - return 0; - case SG_GET_TIMEOUT: - return scsi_generics[dev].timeout; - case SG_EMULATED_HOST: - return put_user(scsi_generics[dev].device->host->hostt->emulated, (int *) arg); - case SCSI_IOCTL_SEND_COMMAND: - /* - Allow SCSI_IOCTL_SEND_COMMAND without checking suser() since the - user already has read/write access to the generic device and so - can execute arbitrary SCSI commands. - */ - return scsi_ioctl_send_command(scsi_generics[dev].device, (void *) arg); - default: - return scsi_ioctl(scsi_generics[dev].device, cmd_in, (void *) arg); - } -} static int sg_open(struct inode * inode, struct file * filp) { - int dev=MINOR(inode->i_rdev); - int flags=filp->f_flags; - if (dev>=sg_template.dev_max || !scsi_generics[dev].device) - return -ENXIO; - - if( !scsi_block_when_processing_errors(scsi_generics[dev].device) ) - { - return -ENXIO; - } - - if (O_RDWR!=(flags & O_ACCMODE)) - return -EACCES; - - /* - * If we want exclusive access, then wait until the device is not - * busy, and then set the flag to prevent anyone else from using it. - */ - if (flags & O_EXCL) - { - while(scsi_generics[dev].users) - { - if (flags & O_NONBLOCK) - return -EBUSY; - interruptible_sleep_on(&scsi_generics[dev].generic_wait); - if (signal_pending(current)) - return -ERESTARTSYS; - } - scsi_generics[dev].exclude=1; - } - else - /* - * Wait until nobody has an exclusive open on - * this device. - */ - while(scsi_generics[dev].exclude) - { - if (flags & O_NONBLOCK) - return -EBUSY; - interruptible_sleep_on(&scsi_generics[dev].generic_wait); - if (signal_pending(current)) - return -ERESTARTSYS; - } + int dev = MINOR(inode->i_rdev); + int flags = filp->f_flags; + Sg_device * sdp; + Sg_fd * sfp; + + if ((NULL == sg_dev_arr) || (dev < 0) || (dev >= sg_template.dev_max)) + return -ENXIO; + sdp = &sg_dev_arr[dev]; + if ((! sdp->device) || (! sdp->device->host)) + return -ENXIO; + if (sdp->i_rdev != inode->i_rdev) + printk("sg_open: inode maj=%d, min=%d sdp maj=%d, min=%d\n", + MAJOR(inode->i_rdev), MINOR(inode->i_rdev), + MAJOR(sdp->i_rdev), MINOR(sdp->i_rdev)); + if(! scsi_block_when_processing_errors(sdp->device)) + return -ENXIO; +/* if (O_RDWR != (flags & O_ACCMODE)) */ +/* return -EACCES; May just want to get to a ioctl, so remove */ - /* - * OK, we should have grabbed the device. Mark the thing so + SCSI_LOG_TIMEOUT(3, printk("sg_open: dev=%d, flags=0x%x\n", dev, flags)); + /* If we want exclusive access, then wait until the device is not + * busy, and then set the flag to prevent anyone else from using it. */ + if (flags & O_EXCL) { + if (O_RDONLY == (flags & O_ACCMODE)) + return -EACCES; /* Can't lock it with read only access */ + while (sdp->headfp) { + if (flags & O_NONBLOCK) + return -EBUSY; + interruptible_sleep_on(&sdp->generic_wait); + if (signal_pending(current)) + return -ERESTARTSYS; + } + sdp->exclude = 1; + } + else { /* Wait until nobody has an exclusive open on this device. */ + while (sdp->exclude) { + if (flags & O_NONBLOCK) + return -EBUSY; + interruptible_sleep_on(&sdp->generic_wait); + if (signal_pending(current)) + return -ERESTARTSYS; + } + } + /* OK, we should have grabbed the device. Mark the thing so * that other processes know that we have it, and initialize the - * state variables to known values. - */ - if (!scsi_generics[dev].users - && scsi_generics[dev].pending - && scsi_generics[dev].complete) - { - if (scsi_generics[dev].buff != NULL) - sg_free(scsi_generics[dev].buff,scsi_generics[dev].buff_len); - scsi_generics[dev].buff=NULL; - scsi_generics[dev].pending=0; - } - if (!scsi_generics[dev].users) - scsi_generics[dev].timeout=SG_DEFAULT_TIMEOUT; - if (scsi_generics[dev].device->host->hostt->module) - __MOD_INC_USE_COUNT(scsi_generics[dev].device->host->hostt->module); + * state variables to known values. */ + if (! sdp->headfp) { /* no existing opens on this device */ + sdp->sgdebug = 0; + sdp->sg_tablesize = sdp->device->host->sg_tablesize; + sdp->merge_fd = 0; /* A little tricky if SG_DEF_MERGE_FD set */ + } + if ((sfp = sg_add_sfp(sdp, dev, O_RDWR == (flags & O_ACCMODE)))) { + filp->private_data = sfp; +#if SG_DEF_MERGE_FD + if (0 == sdp->merge_fd) + sdp->merge_fd = 1; +#endif + } + else { + if (flags & O_EXCL) sdp->exclude = 0; /* undo if error */ + return -ENOMEM; + } + + if (sdp->device->host->hostt->module) + __MOD_INC_USE_COUNT(sdp->device->host->hostt->module); if (sg_template.module) __MOD_INC_USE_COUNT(sg_template.module); - scsi_generics[dev].users++; return 0; } -static int sg_close(struct inode * inode, struct file * filp) +/* Following function was formerly called 'sg_close' */ +static int sg_release(struct inode * inode, struct file * filp) { - int dev=MINOR(inode->i_rdev); - scsi_generics[dev].users--; - if (scsi_generics[dev].device->host->hostt->module) - __MOD_DEC_USE_COUNT(scsi_generics[dev].device->host->hostt->module); + Sg_device * sdp; + Sg_fd * sfp; + + if ((! (sfp = (Sg_fd *)filp->private_data)) || (! (sdp = sfp->parentdp))) + return -ENXIO; + SCSI_LOG_TIMEOUT(3, printk("sg_release: dev=%d\n", MINOR(sdp->i_rdev))); + sg_fasync(-1, filp, 0); /* remove filp from async notification list */ + sg_remove_sfp(sdp, sfp); + if (! sdp->headfp) { + filp->private_data = NULL; + sdp->merge_fd = 0; + } + + if (sdp->device->host->hostt->module) + __MOD_DEC_USE_COUNT(sdp->device->host->hostt->module); if(sg_template.module) __MOD_DEC_USE_COUNT(sg_template.module); - scsi_generics[dev].exclude=0; - wake_up(&scsi_generics[dev].generic_wait); + sdp->exclude = 0; + wake_up_interruptible(&sdp->generic_wait); return 0; } -static char *sg_malloc(int size) +/* Read back the results of a SCSI command which was sent in a prior + write(). */ +static ssize_t sg_read(struct file * filp, char * buf, + size_t count, loff_t *ppos) { - if (size<=4096) - return (char *) scsi_malloc(size); -#ifdef SG_BIG_BUFF - if (size<=SG_BIG_BUFF) - { - while(big_inuse) - { - interruptible_sleep_on(&big_wait); - if (signal_pending(current)) - return NULL; - } - big_inuse=1; - return big_buff; + int k; + Sg_device * sdp; + Sg_fd * sfp; + Sg_request * srp; + int req_pack_id = -1; + struct sg_header * shp = (struct sg_header *)buf; + + if ((! (sfp = (Sg_fd *)filp->private_data)) || (! (sdp = sfp->parentdp))) + return -ENXIO; + SCSI_LOG_TIMEOUT(3, printk("sg_read: dev=%d, count=%d\n", + MINOR(sdp->i_rdev), (int)count)); + + /* If we are in the middle of error recovery, don't let anyone + * else try and use this device. Also, if error recovery fails, it + * may try and take the device offline, in which case all further + * access to the device is prohibited. */ + if(! scsi_block_when_processing_errors(sdp->device)) + return -ENXIO; + + if (ppos != &filp->f_pos) + ; /* FIXME: Hmm. Seek to the right place, or fail? */ + if ((k = verify_area(VERIFY_WRITE, buf, count))) + return k; + if (sfp->force_packid && (count >= size_sg_header)) + req_pack_id = shp->pack_id; + srp = sg_get_request(sfp, req_pack_id); + while(! srp) { + if (filp->f_flags & O_NONBLOCK) + return -EAGAIN; + interruptible_sleep_on(&sfp->read_wait); + if (signal_pending(current)) + return -ERESTARTSYS; + srp = sg_get_request(sfp, req_pack_id); } -#endif - return NULL; -} + if (2 != sfp->underrun_flag) + srp->header.pack_len = srp->header.reply_len; /* Why ????? */ -static void sg_free(char *buff,int size) -{ -#ifdef SG_BIG_BUFF - if (buff==big_buff) - { - big_inuse=0; - wake_up(&big_wait); - return; + /* Now copy the result back to the user buffer. */ + if (count >= size_sg_header) { + __copy_to_user(buf, &srp->header, size_sg_header); + buf += size_sg_header; + if (count > srp->header.reply_len) + count = srp->header.reply_len; + if (count > size_sg_header) /* release does copy_to_user */ + sg_sc_undo_rem(srp, buf, count - size_sg_header); + else + sg_sc_undo_rem(srp, NULL, 0); } -#endif - scsi_free(buff,size); + else { + count = (srp->header.result == 0) ? 0 : -EIO; + sg_sc_undo_rem(srp, NULL, 0); + } + return count; } -/* - * Read back the results of a previous command. We use the pending and - * complete semaphores to tell us whether the buffer is available for us - * and whether the command is actually done. - */ -static ssize_t sg_read(struct file *filp, char *buf, - size_t count, loff_t *ppos) +static ssize_t sg_write(struct file * filp, const char * buf, + size_t count, loff_t *ppos) { - struct inode *inode = filp->f_dentry->d_inode; - int dev=MINOR(inode->i_rdev); - int i; - struct scsi_generic *device=&scsi_generics[dev]; + unsigned long flags; + int mxsize, cmd_size, k; + unsigned char cmnd[MAX_COMMAND_SIZE]; + int input_size; + unsigned char opcode; + Scsi_Cmnd * SCpnt; + Sg_device * sdp; + Sg_fd * sfp; + Sg_request * srp; - /* - * If we are in the middle of error recovery, don't let anyone - * else try and use this device. Also, if error recovery fails, it - * may try and take the device offline, in which case all further - * access to the device is prohibited. - */ - if( !scsi_block_when_processing_errors(scsi_generics[dev].device) ) - { + if ((! (sfp = (Sg_fd *)filp->private_data)) || (! (sdp = sfp->parentdp))) + return -ENXIO; + SCSI_LOG_TIMEOUT(3, printk("sg_write: dev=%d, count=%d\n", + MINOR(sdp->i_rdev), (int)count)); + +/* If we are in the middle of error recovery, don't let anyone + * else try and use this device. Also, if error recovery fails, it + * may try and take the device offline, in which case all further + * access to the device is prohibited. */ + if(! scsi_block_when_processing_errors(sdp->device) ) return -ENXIO; - } - if (ppos != &filp->f_pos) { - /* FIXME: Hmm. Seek to the right place, or fail? */ + if (ppos != &filp->f_pos) + ; /* FIXME: Hmm. Seek to the right place, or fail? */ + + if ((k = verify_area(VERIFY_READ, buf, count))) + return k; /* protects following copy_from_user()s + get_user()s */ +/* The minimum scsi command length is 6 bytes. If we get anything + * less than this, it is clearly bogus. */ + if (count < (size_sg_header + 6)) + return -EIO; + + srp = sg_add_request(sfp); + if (! srp) { + SCSI_LOG_TIMEOUT(1, printk("sg_write: queue full, domain error\n")); + return -EDOM; + } + __copy_from_user(&srp->header, buf, size_sg_header); + buf += size_sg_header; + srp->header.pack_len = count; + __get_user(opcode, buf); + cmd_size = COMMAND_SIZE(opcode); + if ((opcode >= 0xc0) && srp->header.twelve_byte) + cmd_size = 12; + SCSI_LOG_TIMEOUT(4, printk("sg_write: scsi opcode=0x%02x, cmd_size=%d\n", + (int)opcode, cmd_size)); +/* Determine buffer size. */ + input_size = count - cmd_size; + mxsize = (input_size > srp->header.reply_len) ? input_size : + srp->header.reply_len; +/* Don't include the command header itself in the size. */ + mxsize -= size_sg_header; + input_size -= size_sg_header; +/* Verify user has actually passed enough bytes for this command. */ + if (input_size < 0) { + sg_sc_undo_rem(srp, NULL, 0); + return -EIO; } - if ((i=verify_area(VERIFY_WRITE,buf,count))) - return i; +/* If we cannot allocate the buffer, report an error. */ + if ((k = sg_sc_build(srp, mxsize, buf + cmd_size, input_size))) { + SCSI_LOG_TIMEOUT(1, printk("sg_write: build err=%d\n", k)); + sg_sc_undo_rem(srp, NULL, 0); + return k; + } - /* - * Wait until the command is actually done. - */ - while(!device->pending || !device->complete) - { - if (filp->f_flags & O_NONBLOCK) - { - return -EAGAIN; - } - interruptible_sleep_on(&device->read_wait); - if (signal_pending(current)) - { - return -ERESTARTSYS; - } - } - - /* - * Now copy the result back to the user buffer. - */ - device->header.pack_len=device->header.reply_len; +/* SCSI_LOG_TIMEOUT(7, printk("sg_write: allocating device\n")); */ +/* Grab a command pointer for the device we want to talk to. If we + * don't want to block, just return with the appropriate message. */ + if (! (SCpnt = scsi_allocate_device(NULL, sdp->device, + !(filp->f_flags & O_NONBLOCK)))) { + sg_sc_undo_rem(srp, NULL, 0); + return -EAGAIN; + } +/* SCSI_LOG_TIMEOUT(7, printk("sg_write: device allocated\n")); */ - if (count>=sizeof(struct sg_header)) + srp->my_cmdp = SCpnt; + SCpnt->request.rq_dev = sdp->i_rdev; + SCpnt->request.rq_status = RQ_ACTIVE; + SCpnt->sense_buffer[0] = 0; + SCpnt->cmd_len = cmd_size; + /* Now copy the SCSI command from the user's address space. */ + __copy_from_user(cmnd, buf, cmd_size); + +/* Set the LUN field in the command structure. */ + cmnd[1]= (cmnd[1] & 0x1f) | (sdp->device->lun << 5); +/* SCSI_LOG_TIMEOUT(7, printk("sg_write: do cmd\n")); */ +/* Now pass the actual command down to the low-level driver. We + * do not do any more here - when the interrupt arrives, we will + * then do the post-processing. */ + spin_lock_irqsave(&io_request_lock, flags); + SCpnt->use_sg = srp->data.use_sg; + SCpnt->sglist_len = srp->data.sglist_len; + SCpnt->bufflen = srp->data.bufflen; + if (1 == sfp->underrun_flag) + SCpnt->underflow = srp->data.bufflen; + else + SCpnt->underflow = 0; + SCpnt->buffer = srp->data.buffer; + srp->data.use_sg = 0; + srp->data.sglist_len = 0; + srp->data.bufflen = 0; + srp->data.buffer = NULL; + scsi_do_cmd(SCpnt, (void *)cmnd, + (void *)SCpnt->buffer, mxsize, + sg_command_done, sfp->timeout, SG_DEFAULT_RETRIES); + /* 'mxsize' overwrites SCpnt->bufflen, hence need for b_malloc_len */ + spin_unlock_irqrestore(&io_request_lock, flags); +/* SCSI_LOG_TIMEOUT(6, printk("sg_write: sent scsi cmd to mid-level\n")); */ + return count; +} + +static int sg_ioctl(struct inode * inode, struct file * filp, + unsigned int cmd_in, unsigned long arg) +{ + int result, val; + Sg_device * sdp; + Sg_fd * sfp; + Sg_request * srp; + + if ((! (sfp = (Sg_fd *)filp->private_data)) || (! (sdp = sfp->parentdp))) + return -ENXIO; + SCSI_LOG_TIMEOUT(3, printk("sg_ioctl: dev=%d, cmd=0x%x\n", + MINOR(sdp->i_rdev), (int)cmd_in)); + /* If we are in the middle of error recovery, then don't allow any + * access to this device. Also, error recovery *may* have taken the + * device offline, in which case all further access is prohibited. */ + if(! scsi_block_when_processing_errors(sdp->device) ) + return -ENXIO; + + switch(cmd_in) { - copy_to_user(buf,&device->header,sizeof(struct sg_header)); - buf+=sizeof(struct sg_header); - if (count>device->header.pack_len) - count=device->header.pack_len; - if (count > sizeof(struct sg_header)) { - copy_to_user(buf,device->buff,count-sizeof(struct sg_header)); - } + case SG_SET_TIMEOUT: + return get_user(sfp->timeout, (int *)arg); + case SG_GET_TIMEOUT: + return sfp->timeout; /* strange ..., for backward compatibility */ + case SG_SET_FORCE_LOW_DMA: + result = get_user(val, (int *)arg); + if (result) return result; + if (val) { + if ((0 == sfp->low_dma) && (0 == sg_fb_in_use(sfp))) { + sg_low_free(sfp->fst_buf, sfp->fb_size, SG_HEAP_PAGE); + sfp->fst_buf = sg_low_malloc(SG_SCATTER_SZ, 1, + SG_HEAP_PAGE, &sfp->fb_size); + } + sfp->low_dma = 1; + if (! sfp->fst_buf) + return -ENOMEM; + } + else + sfp->low_dma = sdp->device->host->unchecked_isa_dma; + return 0; + case SG_GET_LOW_DMA: + return put_user((int)sfp->low_dma, (int *)arg); + case SG_GET_SCSI_ID: + result = verify_area(VERIFY_WRITE, (void *)arg, sizeof(Sg_scsi_id)); + if (result) return result; + else { + Sg_scsi_id * sg_idp = (Sg_scsi_id *)arg; + __put_user((int)sdp->device->host->host_no, &sg_idp->host_no); + __put_user((int)sdp->device->channel, &sg_idp->channel); + __put_user((int)sdp->device->id, &sg_idp->scsi_id); + __put_user((int)sdp->device->lun, &sg_idp->lun); + __put_user((int)sdp->device->type, &sg_idp->scsi_type); + __put_user(0, &sg_idp->unused1); + __put_user(0, &sg_idp->unused2); + __put_user(0, &sg_idp->unused3); + return 0; + } + case SG_SET_FORCE_PACK_ID: + result = get_user(val, (int *)arg); + if (result) return result; + sfp->force_packid = val ? 1 : 0; + return 0; + case SG_GET_PACK_ID: + result = verify_area(VERIFY_WRITE, (void *) arg, sizeof(int)); + if (result) return result; + srp = sfp->headrp; + while (srp) { + if (! srp->my_cmdp) { + __put_user(srp->header.pack_id, (int *)arg); + return 0; + } + srp = srp->nextrp; + } + __put_user(-1, (int *)arg); + return 0; + case SG_GET_NUM_WAITING: + srp = sfp->headrp; + val = 0; + while (srp) { + if (! srp->my_cmdp) + ++val; + srp = srp->nextrp; + } + return put_user(val, (int *)arg); + case SG_GET_SG_TABLESIZE: + return put_user(sdp->sg_tablesize, (int *)arg); + case SG_SET_RESERVED_SIZE: + /* currently ignored, future extension */ + if (O_RDWR != (filp->f_flags & O_ACCMODE)) + return -EACCES; + result = get_user(val, (int *)arg); + if (result) return result; + /* logic should go here */ + return 0; + case SG_GET_RESERVED_SIZE: + return put_user(sfp->fb_size, (int *)arg); + case SG_GET_MERGE_FD: + return put_user((int)sdp->merge_fd, (int *)arg); + case SG_SET_MERGE_FD: + if (O_RDWR != (filp->f_flags & O_ACCMODE)) + return -EACCES; /* require write access since effect wider + then just this fd */ + result = get_user(val, (int *)arg); + if (result) return result; + val = val ? 1 : 0; + if ((val ^ (0 != sdp->merge_fd)) && + sdp->headfp && sdp->headfp->nextfp) + return -EBUSY; /* too much work if multiple fds already */ + sdp->merge_fd = val; + return 0; + case SG_SET_COMMAND_Q: + result = get_user(val, (int *)arg); + if (result) return result; + sfp->cmd_q = val ? 1 : 0; + return 0; + case SG_GET_COMMAND_Q: + return put_user((int)sfp->cmd_q, (int *)arg); + case SG_SET_UNDERRUN_FLAG: + result = get_user(val, (int *)arg); + if (result) return result; + sfp->underrun_flag = val; + return 0; + case SG_GET_UNDERRUN_FLAG: + return put_user((int)sfp->underrun_flag, (int *)arg); + case SG_EMULATED_HOST: + return put_user(sdp->device->host->hostt->emulated, (int *)arg); + case SCSI_IOCTL_SEND_COMMAND: + /* Allow SCSI_IOCTL_SEND_COMMAND without checking suser() since the + user already has read/write access to the generic device and so + can execute arbitrary SCSI commands. */ + if (O_RDWR != (filp->f_flags & O_ACCMODE)) + return -EACCES; /* require write access since these could be + dangerous */ + return scsi_ioctl_send_command(sdp->device, (void *)arg); + case SG_SET_DEBUG: + result = get_user(val, (int *)arg); + if (result) return result; + sdp->sgdebug = (char)val; + if (9 == sdp->sgdebug) + sg_debug(sdp, sfp, 0); + else if (sdp->sgdebug > 9) + sg_debug_all(sfp); + return 0; + case SCSI_IOCTL_GET_IDLUN: + case SCSI_IOCTL_GET_BUS_NUMBER: + case SCSI_IOCTL_PROBE_HOST: + case SG_GET_TRANSFORM: + return scsi_ioctl(sdp->device, cmd_in, (void *)arg); + default: + if (O_RDWR != (filp->f_flags & O_ACCMODE)) + return -EACCES; /* require write access since these could be + dangerous */ + return scsi_ioctl(sdp->device, cmd_in, (void *)arg); } - else - count= device->header.result==0 ? 0 : -EIO; +} - /* - * Clean up, and release the device so that we can send another - * command. - */ - sg_free(device->buff,device->buff_len); - device->buff = NULL; - device->pending=0; - wake_up(&device->write_wait); - return count; +static unsigned int sg_poll(struct file * filp, poll_table * wait) +{ + unsigned int res = 0; + Sg_device * sdp; + Sg_fd * sfp; + Sg_request * srp; + int count = 0; + + if ((! (sfp = (Sg_fd *)filp->private_data)) || (! (sdp = sfp->parentdp))) + return POLLERR; + poll_wait(filp, &sfp->read_wait, wait); + srp = sfp->headrp; + while (srp) { /* if any read waiting, flag it */ + if (! (res || srp->my_cmdp)) + res = POLLIN | POLLRDNORM; + ++count; + srp = srp->nextrp; + } + if (0 == sfp->cmd_q) { + if (0 == count) + res |= POLLOUT | POLLWRNORM; + } + else if (count < SG_MAX_QUEUE) + res |= POLLOUT | POLLWRNORM; + SCSI_LOG_TIMEOUT(3, printk("sg_poll: dev=%d, res=0x%x\n", + MINOR(sdp->i_rdev), (int)res)); + return res; } -/* - * This function is called by the interrupt handler when we +static int sg_fasync(int fd, struct file * filp, int mode) +{ + int retval; + Sg_device * sdp; + Sg_fd * sfp; + + if ((! (sfp = (Sg_fd *)filp->private_data)) || (! (sdp = sfp->parentdp))) + return -ENXIO; + SCSI_LOG_TIMEOUT(3, printk("sg_fasync: dev=%d, mode=%d\n", + MINOR(sdp->i_rdev), mode)); + + retval = fasync_helper(fd, filp, mode, &sfp->async_qp); + return (retval < 0) ? retval : 0; +} + +/* This function is called by the interrupt handler when we * actually have a command that is complete. Change the - * flags to indicate that we have a result. - */ + * flags to indicate that we have a result. */ static void sg_command_done(Scsi_Cmnd * SCpnt) { int dev = MINOR(SCpnt->request.rq_dev); - struct scsi_generic *device = &scsi_generics[dev]; - if (!device->pending) - { - printk("unexpected done for sg %d\n",dev); + Sg_device * sdp; + Sg_fd * sfp; + Sg_request * srp = NULL; + int closed = 0; + + if ((NULL == sg_dev_arr) || (dev < 0) || (dev >= sg_template.dev_max)) { + SCSI_LOG_TIMEOUT(1, printk("sg__done: bad args dev=%d\n", dev)); scsi_release_command(SCpnt); SCpnt = NULL; - return; + return; } - - /* - * See if the command completed normally, or whether something went - * wrong. - */ - memcpy(device->header.sense_buffer, SCpnt->sense_buffer, - sizeof(SCpnt->sense_buffer)); - switch (host_byte(SCpnt->result)) { + sdp = &sg_dev_arr[dev]; + if (NULL == sdp->device) + return; /* Get out of here quick ... */ + + sfp = sdp->headfp; + while (sfp) { + srp = sfp->headrp; + while (srp) { + if (SCpnt == srp->my_cmdp) + break; + srp = srp->nextrp; + } + if (srp) + break; + sfp = sfp->nextfp; + } + if (! srp) { + SCSI_LOG_TIMEOUT(1, printk("sg__done: req missing, dev=%d\n", dev)); + scsi_release_command(SCpnt); + SCpnt = NULL; + return; + } +/* First transfer ownership of data buffers to sg_device object. */ + srp->data.use_sg = SCpnt->use_sg; + srp->data.sglist_len = SCpnt->sglist_len; + srp->data.bufflen = SCpnt->bufflen; + srp->data.buffer = SCpnt->buffer; + if (2 == sfp->underrun_flag) + srp->header.pack_len = SCpnt->underflow; + sg_clr_scpnt(SCpnt); + srp->my_cmdp = NULL; + + SCSI_LOG_TIMEOUT(4, + printk("sg__done: dev=%d, scsi_stat=%d, res=0x%x\n", + dev, (int)status_byte(SCpnt->result), (int)SCpnt->result)); +/* See if the command completed normally, or whether something went wrong. */ + memcpy(srp->header.sense_buffer, SCpnt->sense_buffer, + sizeof(SCpnt->sense_buffer)); + switch (host_byte(SCpnt->result)) + { case DID_OK: - device->header.result = 0; + case DID_PASSTHROUGH: /* just guessing */ + case DID_SOFT_ERROR: /* just guessing */ + srp->header.result = 0; break; case DID_NO_CONNECT: case DID_BUS_BUSY: case DID_TIME_OUT: - device->header.result = EBUSY; + srp->header.result = EBUSY; break; case DID_BAD_TARGET: case DID_ABORT: case DID_PARITY: case DID_RESET: case DID_BAD_INTR: - device->header.result = EIO; + srp->header.result = EIO; break; case DID_ERROR: - /* - * There really should be DID_UNDERRUN and DID_OVERRUN error values, + /* There really should be DID_UNDERRUN and DID_OVERRUN error values, * and a means for callers of scsi_do_cmd to indicate whether an * underrun or overrun should signal an error. Until that can be * implemented, this kludge allows for returning useful error values * except in cases that return DID_ERROR that might be due to an - * underrun. - */ + * underrun. */ if (SCpnt->sense_buffer[0] == 0 && - status_byte(SCpnt->result) == GOOD) - device->header.result = 0; - else device->header.result = EIO; + status_byte(SCpnt->result) == GOOD) + srp->header.result = 0; + else + srp->header.result = EIO; + break; + default: + SCSI_LOG_TIMEOUT(1, printk( + "sg: unexpected host_byte=%d, dev=%d in 'done'\n", + host_byte(SCpnt->result), dev)); + srp->header.result = EIO; break; } - /* - * Now wake up the process that is waiting for the - * result. - */ - device->complete=1; +/* Following if statement is a patch supplied by Eric Youngdale */ + if (driver_byte(SCpnt->result) != 0 + && (SCpnt->sense_buffer[0] & 0x7f) == 0x70 + && (SCpnt->sense_buffer[2] & 0xf) == UNIT_ATTENTION + && sdp->device->removable) { +/* Detected disc change. Set the bit - this may be used if there are */ +/* filesystems using this device. */ + sdp->device->changed = 1; + } + +/* Pick up error and status information */ + srp->header.target_status = status_byte(SCpnt->result); + if ((sdp->sgdebug > 0) && + ((CHECK_CONDITION == srp->header.target_status) || + (COMMAND_TERMINATED == srp->header.target_status))) + print_sense("sg_command_done", SCpnt); + srp->header.host_status = host_byte(SCpnt->result); + srp->header.driver_status = driver_byte(SCpnt->result); + scsi_release_command(SCpnt); SCpnt = NULL; - wake_up(&scsi_generics[dev].read_wait); + if (sfp->closed) { /* whoops this fd already released, cleanup */ + closed = 1; + SCSI_LOG_TIMEOUT(1, + printk("sg__done: already closed, freeing ...\n")); +/* should check if module is unloaded <<<<<<< */ + sg_sc_undo_rem(srp, NULL, 0); + if (NULL == sfp->headrp) { + SCSI_LOG_TIMEOUT(1, + printk("sg__done: already closed, final cleanup\n")); + sg_remove_sfp(sdp, sfp); + } + } +/* Now wake up the process that is waiting for the result. */ + /* A. Rubini says this is preferable+faster than wake_up() */ + wake_up_interruptible(&sfp->read_wait); + if ((sfp->async_qp) && (! closed)) + kill_fasync(sfp->async_qp, SIGPOLL); } -static ssize_t sg_write(struct file *filp, const char *buf, - size_t count, loff_t *ppos) +static void sg_debug_all(const Sg_fd * sfp) { - unsigned long flags; - struct inode *inode = filp->f_dentry->d_inode; - int bsize,size,amt,i; - unsigned char cmnd[MAX_COMMAND_SIZE]; - kdev_t devt = inode->i_rdev; - int dev = MINOR(devt); - struct scsi_generic * device=&scsi_generics[dev]; - int input_size; - unsigned char opcode; - Scsi_Cmnd * SCpnt; - - /* - * If we are in the middle of error recovery, don't let anyone - * else try and use this device. Also, if error recovery fails, it - * may try and take the device offline, in which case all further - * access to the device is prohibited. - */ - if( !scsi_block_when_processing_errors(scsi_generics[dev].device) ) - { - return -ENXIO; - } - - if (ppos != &filp->f_pos) { - /* FIXME: Hmm. Seek to the right place, or fail? */ - } - - if ((i=verify_area(VERIFY_READ,buf,count))) - return i; - /* - * The minimum scsi command length is 6 bytes. If we get anything - * less than this, it is clearly bogus. - */ - if (count<(sizeof(struct sg_header) + 6)) - return -EIO; - - /* - * If we still have a result pending from a previous command, - * wait until the result has been read by the user before sending - * another command. - */ - while(device->pending) - { - if (filp->f_flags & O_NONBLOCK) - return -EAGAIN; -#ifdef DEBUG - printk("sg_write: sleeping on pending request\n"); + const Sg_device * sdp = sg_dev_arr; + int k; + + if (NULL == sg_dev_arr) { + printk("sg_debug_all: sg_dev_arr NULL, death is imminent\n"); + return; + } + if (! sfp) + printk("sg_debug_all: sfp (file descriptor pointer) NULL\n"); + + printk("sg_debug_all: dev_max=%d, %s\n", + sg_template.dev_max, sg_version_str); + printk(" scsi_dma_free_sectors=%u, sg_pool_secs_aval=%d\n", + scsi_dma_free_sectors, sg_pool_secs_avail); + printk(" sg_big_buff=%d\n", sg_big_buff); +#ifdef SG_DEBUG + printk(" malloc counts, kmallocs=%d, dma_pool=%d, pages=%d\n", + sg_num_kmal, sg_num_pool, sg_num_page); #endif - interruptible_sleep_on(&device->write_wait); - if (signal_pending(current)) - return -ERESTARTSYS; - } - - /* - * Mark the device flags for the new state. - */ - device->pending=1; - device->complete=0; - copy_from_user(&device->header,buf,sizeof(struct sg_header)); - - device->header.pack_len=count; - buf+=sizeof(struct sg_header); - - /* - * Now we need to grab the command itself from the user's buffer. - */ - get_user(opcode, buf); - size=COMMAND_SIZE(opcode); - if (opcode >= 0xc0 && device->header.twelve_byte) size = 12; - - /* - * Determine buffer size. - */ - input_size = device->header.pack_len - size; - if( input_size > device->header.reply_len) - { - bsize = input_size; - } else { - bsize = device->header.reply_len; + for (k = 0; k < sg_template.dev_max; ++k, ++sdp) { + if (sdp->headfp) { + if (! sfp) + sfp = sdp->headfp; /* just to keep things going */ + else if (sdp == sfp->parentdp) + printk(" ***** Invoking device follows *****\n"); + sg_debug(sdp, sfp, 1); + } } +} - /* - * Don't include the command header itself in the size. - */ - bsize-=sizeof(struct sg_header); - input_size-=sizeof(struct sg_header); - - /* - * Verify that the user has actually passed enough bytes for this command. - */ - if( input_size < 0 ) - { - device->pending=0; - wake_up( &device->write_wait ); - return -EIO; - } - - /* - * Allocate a buffer that is large enough to hold the data - * that has been requested. Round up to an even number of sectors, - * since scsi_malloc allocates in chunks of 512 bytes. - */ - amt=bsize; - if (!bsize) - bsize++; - bsize=(bsize+511) & ~511; - - /* - * If we cannot allocate the buffer, report an error. - */ - if ((bsize<0) || !(device->buff=sg_malloc(device->buff_len=bsize))) - { - device->pending=0; - wake_up(&device->write_wait); - return -ENOMEM; +static void sg_debug(const Sg_device * sdp, const Sg_fd * sfp, int part_of) +{ + Sg_fd * fp; + Sg_request * srp; + int dev; + int k; + + if (! sfp) + printk("sg_debug: sfp (file descriptor pointer) NULL\n"); + if (! sdp) { + printk("sg_debug: sdp pointer (to device) NULL\n"); + return; } - -#ifdef DEBUG - printk("allocating device\n"); -#endif - - /* - * Grab a device pointer for the device we want to talk to. If we - * don't want to block, just return with the appropriate message. - */ - if (!(SCpnt=scsi_allocate_device(NULL,device->device, !(filp->f_flags & O_NONBLOCK)))) - { - device->pending=0; - wake_up(&device->write_wait); - sg_free(device->buff,device->buff_len); - device->buff = NULL; - return -EAGAIN; + else if (! sdp->device) { + printk("sg_debug: device detached ??\n"); + return; } -#ifdef DEBUG - printk("device allocated\n"); -#endif - - SCpnt->request.rq_dev = devt; - SCpnt->request.rq_status = RQ_ACTIVE; - SCpnt->sense_buffer[0]=0; - SCpnt->cmd_len = size; + dev = MINOR(sdp->i_rdev); - /* - * Now copy the SCSI command from the user's address space. - */ - copy_from_user(cmnd,buf,size); - buf+=size; - - /* - * If we are writing data, copy the data we are writing. The pack_len - * field also includes the length of the header and the command, - * so we need to subtract these off. - */ - if (input_size > 0) copy_from_user(device->buff, buf, input_size); - - /* - * Set the LUN field in the command structure. - */ - cmnd[1]= (cmnd[1] & 0x1f) | (device->device->lun<<5); - -#ifdef DEBUG - printk("do cmd\n"); -#endif - - /* - * Now pass the actual command down to the low-level driver. We - * do not do any more here - when the interrupt arrives, we will - * then do the post-processing. - */ - spin_lock_irqsave(&io_request_lock, flags); - scsi_do_cmd (SCpnt,(void *) cmnd, - (void *) device->buff,amt, - sg_command_done,device->timeout,SG_DEFAULT_RETRIES); - spin_unlock_irqrestore(&io_request_lock, flags); - -#ifdef DEBUG - printk("done cmd\n"); + if (part_of) + printk(" >>> device=%d(sg%c), ", dev, 'a' + dev); + else + printk("sg_debug: device=%d(sg%c), ", dev, 'a' + dev); + printk("scsi%d chan=%d id=%d lun=%d em=%d\n", sdp->device->host->host_no, + sdp->device->channel, sdp->device->id, sdp->device->lun, + sdp->device->host->hostt->emulated); + printk(" sg_tablesize=%d, excl=%d, sgdebug=%d, merge_fd=%d\n", + sdp->sg_tablesize, sdp->exclude, sdp->sgdebug, sdp->merge_fd); + if (! part_of) { + printk(" scsi_dma_free_sectors=%u, sg_pool_secs_aval=%d\n", + scsi_dma_free_sectors, sg_pool_secs_avail); +#ifdef SG_DEBUG + printk(" mallocs: kmallocs=%d, dma_pool=%d, pages=%d\n", + sg_num_kmal, sg_num_pool, sg_num_page); #endif + } - return count; -} - -static unsigned int sg_poll(struct file *file, poll_table * wait) -{ - int dev = MINOR(file->f_dentry->d_inode->i_rdev); - struct scsi_generic *device = &scsi_generics[dev]; - unsigned int mask = 0; - - poll_wait(file, &scsi_generics[dev].read_wait, wait); - poll_wait(file, &scsi_generics[dev].write_wait, wait); - if(device->pending && device->complete) - mask |= POLLIN | POLLRDNORM; - if(!device->pending) - mask |= POLLOUT | POLLWRNORM; - - return mask; + fp = sdp->headfp; + for (k = 1; fp; fp = fp->nextfp, ++k) { + if (sfp == fp) + printk(" *** Following data belongs to invoking FD ***\n"); + else if (! fp->parentdp) + printk(">> Following FD has NULL parent pointer ???\n"); + printk(" FD(%d): timeout=%d, fb_size=%d, cmd_q=%d\n", + k, fp->timeout, fp->fb_size, (int)fp->cmd_q); + printk(" low_dma=%d, force_packid=%d, urun_flag=%d, closed=%d\n", + (int)fp->low_dma, (int)fp->force_packid, + (int)fp->underrun_flag, (int)fp->closed); + srp = fp->headrp; + if (NULL == srp) + printk(" No requests active\n"); + while (srp) { + if (srp->fb_used) + printk("using 1st buff >> "); + else + printk(" "); + if (srp->my_cmdp) + printk("written: pack_id=%d, bufflen=%d, use_sg=%d\n", + srp->header.pack_id, srp->my_cmdp->bufflen, + srp->my_cmdp->use_sg); + else + printk("to_read: pack_id=%d, bufflen=%d, use_sg=%d\n", + srp->header.pack_id, srp->data.bufflen, srp->data.use_sg); + if (! srp->parentfp) + printk(">> request has NULL parent pointer ???\n"); + srp = srp->nextrp; + } + } } static struct file_operations sg_fops = { @@ -574,24 +909,30 @@ sg_ioctl, /* ioctl */ NULL, /* mmap */ sg_open, /* open */ - NULL, /* flush */ - sg_close, /* release */ - NULL /* fsync */ + NULL, /* flush */ + sg_release, /* release, was formerly sg_close */ + NULL, /* fsync */ + sg_fasync, /* fasync */ + NULL, /* check_media_change */ + NULL, /* revalidate */ + NULL, /* lock */ }; -static int sg_detect(Scsi_Device * SDp){ - - switch (SDp->type) { - case TYPE_DISK: - case TYPE_MOD: - case TYPE_ROM: - case TYPE_WORM: - case TYPE_TAPE: break; - default: - printk("Detected scsi generic sg%c at scsi%d, channel %d, id %d, lun %d\n", - 'a'+sg_template.dev_noticed, - SDp->host->host_no, SDp->channel, SDp->id, SDp->lun); +static int sg_detect(Scsi_Device * scsidp) +{ + switch (scsidp->type) { + case TYPE_DISK: + case TYPE_MOD: + case TYPE_ROM: + case TYPE_WORM: + case TYPE_TAPE: break; + default: + printk("Detected scsi generic sg%c at scsi%d," + " channel %d, id %d, lun %d\n", + 'a'+sg_template.dev_noticed, + scsidp->host->host_no, scsidp->channel, + scsidp->id, scsidp->lun); } sg_template.dev_noticed++; return 1; @@ -605,84 +946,108 @@ if (sg_template.dev_noticed == 0) return 0; if(!sg_registered) { - if (register_chrdev(SCSI_GENERIC_MAJOR,"sg",&sg_fops)) - { - printk("Unable to get major %d for generic SCSI device\n", - SCSI_GENERIC_MAJOR); - return 1; - } - sg_registered++; + if (register_chrdev(SCSI_GENERIC_MAJOR,"sg",&sg_fops)) + { + printk("Unable to get major %d for generic SCSI device\n", + SCSI_GENERIC_MAJOR); + return 1; + } + sg_registered++; } /* If we have already been through here, return */ - if(scsi_generics) return 0; - -#ifdef DEBUG - printk("sg: Init generic device.\n"); -#endif - -#ifdef SG_BIG_BUFF - big_buff= (char *) scsi_init_malloc(SG_BIG_BUFF, GFP_ATOMIC | GFP_DMA); -#endif - - scsi_generics = (struct scsi_generic *) - scsi_init_malloc((sg_template.dev_noticed + SG_EXTRA_DEVS) - * sizeof(struct scsi_generic), GFP_ATOMIC); - memset(scsi_generics, 0, (sg_template.dev_noticed + SG_EXTRA_DEVS) - * sizeof(struct scsi_generic)); + if(sg_dev_arr) return 0; + SCSI_LOG_TIMEOUT(3, printk("sg_init\n")); + sg_dev_arr = (Sg_device *) + scsi_init_malloc((sg_template.dev_noticed + SG_EXTRA_DEVS) + * sizeof(Sg_device), GFP_ATOMIC); + if (NULL == sg_dev_arr) { + printk("sg_init: no space for sg_dev_arr\n"); + return 1; + } sg_template.dev_max = sg_template.dev_noticed + SG_EXTRA_DEVS; return 0; } -static int sg_attach(Scsi_Device * SDp) +static int sg_attach(Scsi_Device * scsidp) { - struct scsi_generic * gpnt; - int i; + Sg_device * sdp = sg_dev_arr; + int k; - if(sg_template.nr_dev >= sg_template.dev_max) + if ((sg_template.nr_dev >= sg_template.dev_max) || (! sdp)) { - SDp->attached--; - return 1; + scsidp->attached--; + return 1; } - for(gpnt = scsi_generics, i=0; idevice) break; + for(k = 0; k < sg_template.dev_max; k++, sdp++) + if(! sdp->device) break; - if(i >= sg_template.dev_max) panic ("scsi_devices corrupt (sg)"); + if(k >= sg_template.dev_max) panic ("scsi_devices corrupt (sg)"); - scsi_generics[i].device=SDp; - scsi_generics[i].users=0; - scsi_generics[i].generic_wait=NULL; - scsi_generics[i].read_wait=NULL; - scsi_generics[i].write_wait=NULL; - scsi_generics[i].buff=NULL; - scsi_generics[i].exclude=0; - scsi_generics[i].pending=0; - scsi_generics[i].timeout=SG_DEFAULT_TIMEOUT; + SCSI_LOG_TIMEOUT(3, printk("sg_attach: dev=%d \n", k)); + sdp->device = scsidp; + sdp->generic_wait = NULL; + sdp->headfp= NULL; + sdp->exclude = 0; + sdp->merge_fd = 0; /* Cope with SG_DEF_MERGE_FD on open */ + sdp->sgdebug = 0; + sdp->sg_tablesize = scsidp->host ? scsidp->host->sg_tablesize : 0; + sdp->i_rdev = MKDEV(SCSI_GENERIC_MAJOR, k); sg_template.nr_dev++; return 0; -}; - - +} -static void sg_detach(Scsi_Device * SDp) +/* Called at 'finish' of init process, after all attaches */ +static void sg_finish(void) { - struct scsi_generic * gpnt; - int i; + SCSI_LOG_TIMEOUT(3, printk("sg_finish: dma_free_sectors=%u\n", + scsi_dma_free_sectors)); +} - for(gpnt = scsi_generics, i=0; idevice == SDp) { - gpnt->device = NULL; - SDp->attached--; - sg_template.nr_dev--; - /* - * avoid associated device /dev/sg? bying incremented - * each time module is inserted/removed , - */ - sg_template.dev_noticed--; - return; - } +static void sg_detach(Scsi_Device * scsidp) +{ + Sg_device * sdp = sg_dev_arr; + unsigned long flags = 0; + Sg_fd * sfp; + Sg_request * srp; + int k; + + if (NULL == sdp) return; /* all is not well ... */ + for (k = 0; k < sg_template.dev_max; k++, sdp++) { + if(sdp->device != scsidp) + continue; /* dirty but lowers nesting */ + if (sdp->headfp) { +/* Need to stop sg_command_done() playing with this list during this loop */ + spin_lock_irqsave(&io_request_lock, flags); + sfp = sdp->headfp; + while (sfp) { + srp = sfp->headrp; + while (srp) { + if (srp->my_cmdp) + sg_shorten_timeout(srp->my_cmdp); + srp = srp->nextrp; + } + sfp = sfp->nextfp; + } + spin_unlock_irqrestore(&io_request_lock, flags); + SCSI_LOG_TIMEOUT(3, printk("sg_detach: dev=%d, dirty, sleep(3)\n", k)); + scsi_sleep(3); /* sleep 3 jiffies, hoping for timeout to go off */ + } + else { + SCSI_LOG_TIMEOUT(3, printk("sg_detach: dev=%d\n", k)); + sdp->device = NULL; + } + scsidp->attached--; + sg_template.nr_dev--; + /* + * avoid associated device /dev/sg? bying incremented + * each time module is inserted/removed , + */ + sg_template.dev_noticed--; + return; + } return; } @@ -698,34 +1063,561 @@ scsi_unregister_module(MODULE_SCSI_DEV, &sg_template); unregister_chrdev(SCSI_GENERIC_MAJOR, "sg"); - if(scsi_generics != NULL) { - scsi_init_free((char *) scsi_generics, - (sg_template.dev_noticed + SG_EXTRA_DEVS) - * sizeof(struct scsi_generic)); + if(sg_dev_arr != NULL) { +/* Really worrying situation of writes still pending and get here */ +/* Strategy: shorten timeout on release + wait on detach ... */ + scsi_init_free((char *) sg_dev_arr, + (sg_template.dev_noticed + SG_EXTRA_DEVS) + * sizeof(Sg_device)); + sg_dev_arr = NULL; } sg_template.dev_max = 0; -#ifdef SG_BIG_BUFF - if(big_buff != NULL) - scsi_init_free(big_buff, SG_BIG_BUFF); -#endif } #endif /* MODULE */ -/* - * Overrides for Emacs so that we almost follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-indent-level: 4 - * c-brace-imaginary-offset: 0 - * c-brace-offset: -4 - * c-argdecl-indent: 4 - * c-label-offset: -4 - * c-continued-statement-offset: 4 - * c-continued-brace-offset: 0 - * indent-tabs-mode: nil - * tab-width: 8 - * End: - */ + +#if 0 +extern void scsi_times_out (Scsi_Cmnd * SCpnt); +extern void scsi_old_times_out (Scsi_Cmnd * SCpnt); +#endif + +/* Can't see clean way to abort a command so shorten timeout to 1 jiffy */ +static void sg_shorten_timeout(Scsi_Cmnd * scpnt) +{ +#if 0 /* scsi_syms.c is very miserly about exported functions */ + scsi_delete_timer(scpnt); + if (! scpnt) + return; + scpnt->timeout_per_command = 1; /* try 1 jiffy (perhaps 0 jiffies) */ + if (scpnt->host->hostt->use_new_eh_code) + scsi_add_timer(scpnt, scpnt->timeout_per_command, scsi_times_out); + else + scsi_add_timer(scpnt, scpnt->timeout_per_command, + scsi_old_times_out); +#else + scsi_sleep(HZ); /* just sleep 1 second and hope ... */ +#endif +} + +static int sg_sc_build(Sg_request * srp, int max_buff_size, + const char * inp, int num_write_xfer) +{ + int ret_sz, mem_src; + int blk_size = max_buff_size; + char * p = NULL; + + if ((blk_size < 0) || (! srp)) + return -EFAULT; + + SCSI_LOG_TIMEOUT(4, printk("sg_sc_build: m_b_s=%d, num_write_xfer=%d\n", + max_buff_size, num_write_xfer)); + if (0 == blk_size) + ++blk_size; /* don't know why */ +/* round request up to next highest SG_SECTOR_SZ byte boundary */ + blk_size = (blk_size + SG_SECTOR_MSK) & (~SG_SECTOR_MSK); + SCSI_LOG_TIMEOUT(5, printk("sg_sc_build: blk_size=%d\n", blk_size)); + + if (blk_size <= SG_SCATTER_SZ) { + mem_src = SG_HEAP_FB; + p = sg_malloc(srp, blk_size, &ret_sz, &mem_src); + if (! p) + return -ENOMEM; + if (blk_size == ret_sz) { /* got it on the first attempt */ + srp->data.buffer = p; + srp->data.bufflen = blk_size; + srp->data.mem_src = mem_src; + srp->data.b_malloc_len = blk_size; + if (inp && (num_write_xfer > 0)) + __copy_from_user(srp->data.buffer, inp, num_write_xfer); + return 0; + } + } + else { + mem_src = SG_HEAP_PAGE; + p = sg_malloc(srp, SG_SCATTER_SZ, &ret_sz, &mem_src); + if (! p) + return -ENOMEM; + } +/* Want some local declarations, so start new block ... */ + { /* lets try and build a scatter gather list */ + struct scatterlist * sclp; + int k, rem_sz, num, nxt; + int sc_bufflen = PAGE_SIZE; + int mx_sc_elems = (sc_bufflen / sizeof(struct scatterlist)) - 1; + int sg_tablesize = srp->parentfp->parentdp->sg_tablesize; + int first = 1; + + k = SG_HEAP_KMAL; /* want to protect mem_src, use k as scratch */ + srp->data.buffer = (struct scatterlist *)sg_malloc(srp, + sc_bufflen, &num, &k); + srp->data.mem_src = (char)k; + /* N.B. ret_sz and mem_src carried into this block ... */ + if (! srp->data.buffer) + return -ENOMEM; + else if (num != sc_bufflen) { + sc_bufflen = num; + mx_sc_elems = (sc_bufflen / sizeof(struct scatterlist)) - 1; + } + srp->data.sglist_len = sc_bufflen; + memset(srp->data.buffer, 0, sc_bufflen); + for (k = 0, sclp = srp->data.buffer, rem_sz = blk_size, nxt =0; + (k < sg_tablesize) && (rem_sz > 0) && (k < mx_sc_elems); + ++k, rem_sz -= ret_sz, ++sclp) { + if (first) + first = 0; + else { + num = (rem_sz > SG_SCATTER_SZ) ? SG_SCATTER_SZ : rem_sz; + mem_src = SG_HEAP_PAGE; + p = sg_malloc(srp, num, &ret_sz, &mem_src); + if (! p) + break; + } + sclp->address = p; + sclp->length = ret_sz; + sclp->alt_address = (char *)(long)mem_src; + + if(inp && (num_write_xfer > 0)) { + num = (ret_sz > num_write_xfer) ? num_write_xfer : ret_sz; + __copy_from_user(sclp->address, inp, num); + num_write_xfer -= num; + inp += num; + } + SCSI_LOG_TIMEOUT(5, + printk("sg_sc_build: k=%d, a=0x%p, len=%d, ms=%d\n", + k, sclp->address, ret_sz, mem_src)); + } /* end of for loop */ + srp->data.use_sg = k; + SCSI_LOG_TIMEOUT(5, + printk("sg_sc_build: use_sg=%d, rem_sz=%d\n", k, rem_sz)); + srp->data.bufflen = blk_size; + if (rem_sz > 0) /* must have failed */ + return -ENOMEM; + } + return 0; +} + +static int sg_sc_undo_rem(Sg_request * srp, char * outp, + int num_read_xfer) +{ + if (! srp) + return -EFAULT; + SCSI_LOG_TIMEOUT(4, printk("sg_sc_undo_rem: num_read_xfer=%d\n", + num_read_xfer)); + if (! outp) + num_read_xfer = 0; + if(srp->data.use_sg) { + int k, num, mem_src; + struct scatterlist * sclp = (struct scatterlist *)srp->data.buffer; + + for (k = 0; (k < srp->data.use_sg) && sclp->address; ++k, ++sclp) { + if (num_read_xfer > 0) { + num = (int)sclp->length; + if (num > num_read_xfer) { + __copy_to_user(outp, sclp->address, num_read_xfer); + outp += num_read_xfer; + num_read_xfer = 0; + } + else { + __copy_to_user(outp, sclp->address, num); + outp += num; + num_read_xfer -= num; + } + } + mem_src = (int)(long)sclp->alt_address; + SCSI_LOG_TIMEOUT(5, + printk("sg_sc_undo_rem: k=%d, a=0x%p, len=%d, ms=%d\n", + k, sclp->address, sclp->length, mem_src)); + sg_free(srp, sclp->address, sclp->length, mem_src); + } + sg_free(srp, srp->data.buffer, srp->data.sglist_len, + srp->data.mem_src); + } + else { + if (num_read_xfer > 0) + __copy_to_user(outp, srp->data.buffer, num_read_xfer); + sg_free(srp, srp->data.buffer, srp->data.b_malloc_len, + srp->data.mem_src); + } + if (0 == sg_remove_request(srp->parentfp, srp)) { + SCSI_LOG_TIMEOUT(1, printk("sg_sc_undo_rem: srp=0x%p not found\n", + srp)); + } + return 0; +} + +static Sg_request * sg_get_request(const Sg_fd * sfp, int pack_id) +{ + Sg_request * resp = NULL; + + resp = sfp->headrp; + while (resp) { + if ((! resp->my_cmdp) && + ((-1 == pack_id) || (resp->header.pack_id == pack_id))) + return resp; + resp = resp->nextrp; + } + return resp; +} + +/* always adds to end of list */ +static Sg_request * sg_add_request(Sg_fd * sfp) +{ + int k; + Sg_request * resp = NULL; + Sg_request * rp; + + resp = sfp->headrp; + rp = sfp->req_arr; + if (! resp) { + resp = rp; + sfp->headrp = resp; + } + else { + if (0 == sfp->cmd_q) + resp = NULL; /* command queuing disallowed */ + else { + for (k = 0, rp; k < SG_MAX_QUEUE; ++k, ++rp) { + if (! rp->parentfp) + break; + } + if (k < SG_MAX_QUEUE) { + while (resp->nextrp) resp = resp->nextrp; + resp->nextrp = rp; + resp = rp; + } + else + resp = NULL; + } + } + if (resp) { + resp->parentfp = sfp; + resp->nextrp = NULL; + resp->fb_used = 0; + memset(&resp->data, 0, sizeof(Sg_scatter_hold)); + memset(&resp->header, 0, sizeof(struct sg_header)); + resp->my_cmdp = NULL; + } + return resp; +} + +/* Return of 1 for found; 0 for not found */ +static int sg_remove_request(Sg_fd * sfp, const Sg_request * srp) +{ + Sg_request * prev_rp; + Sg_request * rp; + + if ((! sfp) || (! srp) || (! sfp->headrp)) + return 0; + prev_rp = sfp->headrp; + if (srp == prev_rp) { + prev_rp->parentfp = NULL; + sfp->headrp = prev_rp->nextrp; + return 1; + } + while ((rp = prev_rp->nextrp)) { + if (srp == rp) { + rp->parentfp = NULL; + prev_rp->nextrp = rp->nextrp; + return 1; + } + prev_rp = rp; + } + return 0; +} + +static Sg_fd * sg_add_sfp(Sg_device * sdp, int dev, int get_reserved) +{ + Sg_fd * sfp; + + if (sdp->merge_fd) { + ++sdp->merge_fd; + return sdp->headfp; + } + sfp = (Sg_fd *)sg_low_malloc(sizeof(Sg_fd), 0, SG_HEAP_KMAL, 0); + if (sfp) { + memset(sfp, 0, sizeof(Sg_fd)); + sfp->my_mem_src = SG_HEAP_KMAL; + } + else + return NULL; + + sfp->timeout = SG_DEFAULT_TIMEOUT; + sfp->force_packid = SG_DEF_FORCE_PACK_ID; + sfp->low_dma = (SG_DEF_FORCE_LOW_DMA == 0) ? + sdp->device->host->unchecked_isa_dma : 1; + sfp->cmd_q = SG_DEF_COMMAND_Q; + sfp->underrun_flag = SG_DEF_UNDERRUN_FLAG; + if (get_reserved) + sfp->fst_buf = sg_low_malloc(SG_SCATTER_SZ, sfp->low_dma, + SG_HEAP_PAGE, &sfp->fb_size); + else + sfp->fst_buf = NULL; + if (! sfp->fst_buf) + sfp->fb_size = 0; + sfp->parentdp = sdp; + if (! sdp->headfp) + sdp->headfp = sfp; + else { /* add to tail of existing list */ + Sg_fd * pfp = sdp->headfp; + while (pfp->nextfp) + pfp = pfp->nextfp; + pfp->nextfp = sfp; + } + sg_big_buff = sfp->fb_size; /* show sysctl most recent "fb" size */ + SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: sfp=0x%p, m_s=%d\n", + sfp, (int)sfp->my_mem_src)); + SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: fb_sz=%d, fst_buf=0x%p\n", + sfp->fb_size, sfp->fst_buf)); + return sfp; +} + +static int sg_remove_sfp(Sg_device * sdp, Sg_fd * sfp) +{ + Sg_request * srp; + Sg_request * tsrp; + int dirty = 0; + int res = 0; + + if (sdp->merge_fd) { + if (--sdp->merge_fd) + return 0; /* if merge_fd then dec merge_fd counter */ + } + srp = sfp->headrp; + if (srp) { +/* Need to stop sg_command_done() playing with this list during this loop */ + while (srp) { + tsrp = srp->nextrp; + if (! srp->my_cmdp) + sg_sc_undo_rem(srp, NULL, 0); + else + ++dirty; + srp = tsrp; + } + } + if (0 == dirty) { + Sg_fd * fp; + Sg_fd * prev_fp = sdp->headfp; + + if (sfp == prev_fp) + sdp->headfp = prev_fp->nextfp; + else { + while ((fp = prev_fp->nextfp)) { + if (sfp == fp) { + prev_fp->nextfp = fp->nextfp; + break; + } + prev_fp = fp; + } + } +SCSI_LOG_TIMEOUT(6, printk("sg_remove_sfp: fb_sz=%d, fst_buf=0x%p\n", + sfp->fb_size, sfp->fst_buf)); + sg_low_free(sfp->fst_buf, sfp->fb_size, SG_HEAP_PAGE); + sfp->parentdp = NULL; + sfp->fst_buf = NULL; + sfp->fb_size = 0; + SCSI_LOG_TIMEOUT(6, printk("sg_remove_sfp: sfp=0x%p\n", sfp)); + sg_low_free((char *)sfp, sizeof(Sg_fd), sfp->my_mem_src); + res = 1; + } + else { + sfp->closed = 1; /* flag dirty state on this fd */ + SCSI_LOG_TIMEOUT(1, printk( + "sg_remove_sfp: worrisome, %d writes pending\n", dirty)); + } + return res; +} + +static int sg_fb_in_use(const Sg_fd * sfp) +{ + const Sg_request * srp = sfp->headrp; + + while (srp) { + if (srp->fb_used) + return 1; + srp = srp->nextrp; + } + return 0; +} + +/* If retSzp==NULL want exact size or fail */ +/* sg_low_malloc() should always be called from a process context allowing + GFP_KERNEL to be used instead of GFP_ATOMIC */ +static char * sg_low_malloc(int rqSz, int lowDma, int mem_src, int * retSzp) +{ + char * resp = NULL; + int page_mask = lowDma ? (GFP_KERNEL | GFP_DMA) : GFP_KERNEL; + + if (rqSz <= 0) + return resp; + if (SG_HEAP_KMAL == mem_src) { + page_mask = lowDma ? (GFP_ATOMIC | GFP_DMA) : GFP_ATOMIC; + /* Seen kmalloc(..,GFP_KERNEL) hang for 40 secs! */ + resp = kmalloc(rqSz, page_mask); + if (resp && retSzp) *retSzp = rqSz; +#ifdef SG_DEBUG + if (resp) ++sg_num_kmal; +#endif + return resp; + } + if (SG_HEAP_POOL == mem_src) { + int num_sect = rqSz / SG_SECTOR_SZ; + + if (0 != (rqSz & SG_SECTOR_MSK)) { + if (! retSzp) + return resp; + ++num_sect; + rqSz = num_sect * SG_SECTOR_SZ; + } + while (num_sect > 0) { + if ((num_sect <= sg_pool_secs_avail) && + (scsi_dma_free_sectors > (SG_LOW_POOL_THRESHHOLD + num_sect))) { + resp = scsi_malloc(rqSz); + if (resp) { + if (retSzp) *retSzp = rqSz; + sg_pool_secs_avail -= num_sect; +#ifdef SG_DEBUG + ++sg_num_pool; +#endif + return resp; + } + } + if (! retSzp) + return resp; + num_sect /= 2; /* try half as many */ + rqSz = num_sect * SG_SECTOR_SZ; + } + } + else if (SG_HEAP_PAGE == mem_src) { + int order, a_size; + int resSz = rqSz; + + for (order = 0, a_size = PAGE_SIZE; + a_size < rqSz; order++, a_size <<= 1) + ; + resp = (char *)__get_free_pages(page_mask, order); + while ((! resp) && order && retSzp) { + --order; + a_size >>= 1; /* divide by 2, until PAGE_SIZE */ + resp = (char *)__get_free_pages(page_mask, order); /* try half */ + resSz = a_size; + } + if (retSzp) *retSzp = resSz; +#ifdef SG_DEBUG + if (resp) ++sg_num_page; +#endif + } + else + printk("sg_low_malloc: bad mem_src=%d, rqSz=%df\n", mem_src, rqSz); + return resp; +} + +static char * sg_malloc(Sg_request * srp, int size, int * retSzp, + int * mem_srcp) +{ + char * resp = NULL; + + if (retSzp) *retSzp = size; + if (size <= 0) + ; + else { + Sg_fd * sfp = srp->parentfp; + int low_dma = sfp->low_dma; + int l_ms = -1; /* invalid value */ + + switch (*mem_srcp) + { + case SG_HEAP_PAGE: + case SG_HEAP_FB: + l_ms = (size < PAGE_SIZE) ? SG_HEAP_POOL : SG_HEAP_PAGE; + resp = sg_low_malloc(size, low_dma, l_ms, 0); + if (resp) + break; + if ((size <= sfp->fb_size) && (0 == sg_fb_in_use(sfp))) { + SCSI_LOG_TIMEOUT(6, + printk("sg_malloc: scsi_malloc failed, get fst_buf\n")); + resp = sfp->fst_buf; + srp->fb_used = 1; + l_ms = SG_HEAP_FB; + break; + } + resp = sg_low_malloc(size, low_dma, l_ms, &size); + if (! resp) { + l_ms = (SG_HEAP_POOL == l_ms) ? SG_HEAP_PAGE : SG_HEAP_POOL; + resp = sg_low_malloc(size, low_dma, l_ms, &size); + if (! resp) { + l_ms = SG_HEAP_KMAL; + resp = sg_low_malloc(size, low_dma, l_ms, &size); + } + } + if (resp && retSzp) *retSzp = size; + break; + case SG_HEAP_KMAL: + l_ms = SG_HEAP_PAGE; + resp = sg_low_malloc(size, low_dma, l_ms, 0); + if (resp) + break; + l_ms = SG_HEAP_POOL; + resp = sg_low_malloc(size, low_dma, l_ms, &size); + if (resp && retSzp) *retSzp = size; + break; + default: + SCSI_LOG_TIMEOUT(1, printk("sg_malloc: bad ms=%d\n", *mem_srcp)); + break; + } + if (resp) *mem_srcp = l_ms; + } + SCSI_LOG_TIMEOUT(6, printk("sg_malloc: size=%d, ms=%d, ret=0x%p\n", + size, *mem_srcp, resp)); + return resp; +} + +static void sg_low_free(char * buff, int size, int mem_src) +{ + if (! buff) + return; + if (SG_HEAP_POOL == mem_src) { + int num_sect = size / SG_SECTOR_SZ; + scsi_free(buff, size); + sg_pool_secs_avail += num_sect; + } + else if (SG_HEAP_KMAL == mem_src) + kfree(buff); /* size not used */ + else if (SG_HEAP_PAGE == mem_src) { + int order, a_size; + + for (order = 0, a_size = PAGE_SIZE; + a_size < size; order++, a_size <<= 1) + ; + free_pages((unsigned long)buff, order); + } + else + printk("sg_low_free: bad mem_src=%d, buff=0x%p, rqSz=%df\n", + mem_src, buff, size); +} + +static void sg_free(Sg_request * srp, char * buff, int size, int mem_src) +{ + Sg_fd * sfp = srp->parentfp; + + SCSI_LOG_TIMEOUT(6, + printk("sg_free: buff=0x%p, size=%d\n", buff, size)); + if ((! sfp) || (! buff) || (size <= 0)) + ; + else if (sfp->fst_buf == buff) { + srp->fb_used = 0; + SCSI_LOG_TIMEOUT(6, printk("sg_free: left cause fst_buf\n")); + } + else + sg_low_free(buff, size, mem_src); +} + +static void sg_clr_scpnt(Scsi_Cmnd * SCpnt) +{ + SCpnt->use_sg = 0; + SCpnt->sglist_len = 0; + SCpnt->bufflen = 0; + SCpnt->buffer = NULL; + SCpnt->underflow = 0; + SCpnt->request.rq_dev = MKDEV(0, 0); /* "sg" _disowns_ command blk */ +} + diff -ur --new-file old/linux/drivers/scsi/sr_ioctl.c new/linux/drivers/scsi/sr_ioctl.c --- old/linux/drivers/scsi/sr_ioctl.c Tue Sep 8 19:32:46 1998 +++ new/linux/drivers/scsi/sr_ioctl.c Mon May 10 22:01:21 1999 @@ -82,7 +82,8 @@ switch(SCpnt->sense_buffer[2] & 0xf) { case UNIT_ATTENTION: scsi_CDs[target].device->changed = 1; - printk(KERN_INFO "sr%d: disc change detected.\n", target); + if (!quiet) + printk(KERN_INFO "sr%d: disc change detected.\n", target); if (retries++ < 10) goto retry; err = -ENOMEDIUM; @@ -105,12 +106,13 @@ spin_unlock_irqrestore(&io_request_lock, flags); goto retry; } else { - /* 20 secs are enouth? */ + /* 20 secs are enough? */ err = -ENOMEDIUM; break; } } - printk(KERN_INFO "sr%d: CDROM not ready. Make sure there is a disc in the drive.\n",target); + if (!quiet) + printk(KERN_INFO "sr%d: CDROM not ready. Make sure there is a disc in the drive.\n",target); #ifdef DEBUG print_sense("sr", SCpnt); #endif @@ -120,9 +122,11 @@ if (!quiet) printk(KERN_ERR "sr%d: CDROM (ioctl) reports ILLEGAL " "REQUEST.\n", target); - if (SCpnt->sense_buffer[12] == 0x20 && + if ((SCpnt->sense_buffer[12] == 0x20 || + SCpnt->sense_buffer[12] == 0x24) && SCpnt->sense_buffer[13] == 0x00) { /* sense: Invalid command operation code */ + /* or Invalid field in cdb */ err = -EDRIVE_CANT_DO_THIS; } else { err = -EINVAL; @@ -408,7 +412,7 @@ spin_unlock_irqrestore(&io_request_lock, flags); if(!buffer) return -ENOMEM; - result = sr_do_ioctl(target, sr_cmd, buffer, 12, 0); + result = sr_do_ioctl(target, sr_cmd, buffer, 12, 1); tochdr->cdth_trk0 = buffer[2]; tochdr->cdth_trk1 = buffer[3]; @@ -871,6 +875,11 @@ return -EINVAL; read_ahead[MAJOR(cdi->dev)] = arg; return 0; + + case BLKSSZGET: + /* Block size of media */ + return put_user(blksize_size[MAJOR(cdi->dev)][MINOR(cdi->dev)], + (int *)arg); RO_IOCTLS(cdi->dev,arg); diff -ur --new-file old/linux/drivers/scsi/sr_vendor.c new/linux/drivers/scsi/sr_vendor.c --- old/linux/drivers/scsi/sr_vendor.c Mon May 18 20:06:42 1998 +++ new/linux/drivers/scsi/sr_vendor.c Mon May 10 22:01:21 1999 @@ -175,7 +175,7 @@ cmd[1] = (scsi_CDs[minor].device->lun << 5); cmd[8] = 12; cmd[9] = 0x40; - rc = sr_do_ioctl(minor, cmd, buffer, 12, 0); + rc = sr_do_ioctl(minor, cmd, buffer, 12, 1); if (rc != 0) break; if ((buffer[0] << 8) + buffer[1] < 0x0a) { @@ -199,7 +199,7 @@ cmd[0] = 0xde; cmd[1] = (scsi_CDs[minor].device->lun << 5) | 0x03; cmd[2] = 0xb0; - rc = sr_do_ioctl(minor, cmd, buffer, 0x16, 0); + rc = sr_do_ioctl(minor, cmd, buffer, 0x16, 1); if (rc != 0) break; if (buffer[14] != 0 && buffer[14] != 0xb0) { @@ -223,7 +223,7 @@ memset(cmd,0,12); cmd[0] = 0xc7; cmd[1] = (scsi_CDs[minor].device->lun << 5) | 3; - rc = sr_do_ioctl(minor, cmd, buffer, 4, 0); + rc = sr_do_ioctl(minor, cmd, buffer, 4, 1); if (rc == -EINVAL) { printk(KERN_INFO "sr%d: Hmm, seems the drive " "doesn't support multisession CD's\n",minor); @@ -248,7 +248,7 @@ cmd[1] = (scsi_CDs[minor].device->lun << 5); cmd[8] = 0x04; cmd[9] = 0x40; - rc = sr_do_ioctl(minor, cmd, buffer, 0x04, 0); + rc = sr_do_ioctl(minor, cmd, buffer, 0x04, 1); if (rc != 0) { break; } @@ -263,7 +263,7 @@ cmd[6] = rc & 0x7f; /* number of last session */ cmd[8] = 0x0c; cmd[9] = 0x40; - rc = sr_do_ioctl(minor, cmd, buffer, 12, 0); + rc = sr_do_ioctl(minor, cmd, buffer, 12, 1); if (rc != 0) { break; } diff -ur --new-file old/linux/drivers/scsi/st.c new/linux/drivers/scsi/st.c --- old/linux/drivers/scsi/st.c Sun Dec 27 19:18:55 1998 +++ new/linux/drivers/scsi/st.c Mon Mar 8 00:20:26 1999 @@ -8,10 +8,10 @@ order) Klaus Ehrenfried, Wolfgang Denk, Steve Hirsch, Andreas Koppenh"ofer, Michael Leodolter, Eyal Lebedinsky, J"org Weule, and Eric Youngdale. - Copyright 1992 - 1998 Kai Makisara + Copyright 1992 - 1999 Kai Makisara email Kai.Makisara@metla.fi - Last modified: Thu Dec 3 20:27:46 1998 by makisara@home + Last modified: Sun Mar 7 09:03:17 1999 by makisara@home Some small formal changes - aeb, 950809 */ @@ -1094,8 +1094,11 @@ #endif /* Write must be integral number of blocks */ - if (STp->block_size != 0 && (count % STp->block_size) != 0) + if (STp->block_size != 0 && (count % STp->block_size) != 0) { + printk(KERN_WARNING "st%d: Write not multiple of tape block size.\n", + dev); return (-EIO); + } if (STp->can_partitions && (retval = update_partition(inode)) < 0) diff -ur --new-file old/linux/drivers/scsi/sym53c416.c new/linux/drivers/scsi/sym53c416.c --- old/linux/drivers/scsi/sym53c416.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/scsi/sym53c416.c Thu Feb 25 01:28:43 1999 @@ -0,0 +1,806 @@ +/* + * sym53c416.c + * Low-level SCSI driver for sym53c416 chip. + * Copyright (C) 1998 Lieven Willems (lw_linux@hotmail.com) + * + * LILO command line usage: sym53c416=[,] + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "scsi.h" +#include "hosts.h" +#include "sd.h" +#include "sym53c416.h" + +#define VERSION_STRING "Version 1.0.0" + +#define TC_LOW 0x00 /* Transfer counter low */ +#define TC_MID 0x01 /* Transfer counter mid */ +#define SCSI_FIFO 0x02 /* SCSI FIFO register */ +#define COMMAND_REG 0x03 /* Command Register */ +#define STATUS_REG 0x04 /* Status Register (READ) */ +#define DEST_BUS_ID 0x04 /* Destination Bus ID (WRITE) */ +#define INT_REG 0x05 /* Interrupt Register (READ) */ +#define TOM 0x05 /* Time out multiplier (WRITE) */ +#define STP 0x06 /* Synchronous Transfer period */ +#define SYNC_OFFSET 0x07 /* Synchronous Offset */ +#define CONF_REG_1 0x08 /* Configuration register 1 */ +#define CONF_REG_2 0x0B /* Configuration register 2 */ +#define CONF_REG_3 0x0C /* Configuration register 3 */ +#define CONF_REG_4 0x0D /* Configuration register 4 */ +#define TC_HIGH 0x0E /* Transfer counter high */ +#define PIO_FIFO_1 0x10 /* PIO FIFO register 1 */ +#define PIO_FIFO_2 0x11 /* PIO FIFO register 2 */ +#define PIO_FIFO_3 0x12 /* PIO FIFO register 3 */ +#define PIO_FIFO_4 0x13 /* PIO FIFO register 4 */ +#define PIO_FIFO_CNT 0x14 /* PIO FIFO count */ +#define PIO_INT_REG 0x15 /* PIO interrupt register */ +#define CONF_REG_5 0x16 /* Configuration register 5 */ +#define FEATURE_EN 0x1D /* Feature Enable register */ + +/* Configuration register 1 entries: */ +/* Bits 2-0: SCSI ID of host adapter */ +#define SCM 0x80 /* Slow Cable Mode */ +#define SRID 0x40 /* SCSI Reset Interrupt Disable */ +#define PTM 0x20 /* Parity Test Mode */ +#define EPC 0x10 /* Enable Parity Checking */ +#define CTME 0x08 /* Special Test Mode */ + +/* Configuration register 2 entries: */ +#define FE 0x40 /* Features Enable */ +#define SCSI2 0x08 /* SCSI 2 Enable */ +#define TBPA 0x04 /* Target Bad Parity Abort */ + +/* Configuration register 3 entries: */ +#define IDMRC 0x80 /* ID Message Reserved Check */ +#define QTE 0x40 /* Queue Tag Enable */ +#define CDB10 0x20 /* Command Descriptor Block 10 */ +#define FSCSI 0x10 /* FastSCSI */ +#define FCLK 0x08 /* FastClock */ + +/* Configuration register 4 entries: */ +#define RBS 0x08 /* Register bank select */ +#define EAN 0x04 /* Enable Active Negotiation */ + +/* Configuration register 5 entries: */ +#define LPSR 0x80 /* Lower Power SCSI Reset */ +#define IE 0x20 /* Interrupt Enable */ +#define LPM 0x02 /* Low Power Mode */ +#define WSE0 0x01 /* 0WS Enable */ + +/* Interrupt register entries: */ +#define SRST 0x80 /* SCSI Reset */ +#define ILCMD 0x40 /* Illegal Command */ +#define DIS 0x20 /* Disconnect */ +#define BS 0x10 /* Bus Service */ +#define FC 0x08 /* Function Complete */ +#define RESEL 0x04 /* Reselected */ +#define SI 0x03 /* Selection Interrupt */ + +/* Status Register Entries: */ +#define SCI 0x80 /* SCSI Core Int */ +#define GE 0x40 /* Gross Error */ +#define PE 0x20 /* Parity Error */ +#define TC 0x10 /* Terminal Count */ +#define VGC 0x08 /* Valid Group Code */ +#define PHBITS 0x07 /* Phase bits */ + +/* PIO Interrupt Register Entries: */ +#define SCI 0x80 /* SCSI Core Int */ +#define PFI 0x40 /* PIO FIFO Interrupt */ +#define FULL 0x20 /* PIO FIFO Full */ +#define EMPTY 0x10 /* PIO FIFO Empty */ +#define CE 0x08 /* Collision Error */ +#define OUE 0x04 /* Overflow / Underflow error */ +#define FIE 0x02 /* Full Interrupt Enable */ +#define EIE 0x01 /* Empty Interrupt Enable */ + +/* SYM53C416 SCSI phases (lower 3 bits of SYM53C416_STATUS_REG) */ +#define PHASE_DATA_OUT 0x00 +#define PHASE_DATA_IN 0x01 +#define PHASE_COMMAND 0x02 +#define PHASE_STATUS 0x03 +#define PHASE_RESERVED_1 0x04 +#define PHASE_RESERVED_2 0x05 +#define PHASE_MESSAGE_OUT 0x06 +#define PHASE_MESSAGE_IN 0x07 + +/* SYM53C416 core commands */ +#define NOOP 0x00 +#define FLUSH_FIFO 0x01 +#define RESET_CHIP 0x02 +#define RESET_SCSI_BUS 0x03 +#define DISABLE_SEL_RESEL 0x45 +#define RESEL_SEQ 0x40 +#define SEL_WITHOUT_ATN_SEQ 0x41 +#define SEL_WITH_ATN_SEQ 0x42 +#define SEL_WITH_ATN_AND_STOP_SEQ 0x43 +#define ENABLE_SEL_RESEL 0x44 +#define SEL_WITH_ATN3_SEQ 0x46 +#define RESEL3_SEQ 0x47 +#define SND_MSG 0x20 +#define SND_STAT 0x21 +#define SND_DATA 0x22 +#define DISCONNECT_SEQ 0x23 +#define TERMINATE_SEQ 0x24 +#define TARGET_COMM_COMPLETE_SEQ 0x25 +#define DISCONN 0x27 +#define RECV_MSG_SEQ 0x28 +#define RECV_CMD 0x29 +#define RECV_DATA 0x2A +#define RECV_CMD_SEQ 0x2B +#define TARGET_ABORT_PIO 0x04 +#define TRANSFER_INFORMATION 0x10 +#define INIT_COMM_COMPLETE_SEQ 0x11 +#define MSG_ACCEPTED 0x12 +#define TRANSFER_PAD 0x18 +#define SET_ATN 0x1A +#define RESET_ATN 0x1B +#define ILLEGAL 0xFF + +#define PIO_MODE 0x80 + +#define IO_RANGE 0x20 /* 0x00 - 0x1F */ +#define ID "sym53c416" +#define PIO_SIZE 128 /* Size of PIO fifo is 128 bytes */ + +#define READ_TIMEOUT 150 +#define WRITE_TIMEOUT 150 + +#ifdef MODULE + +#define sym53c416_base sym53c416 +#define sym53c416_base_1 sym53c416_1 +#define sym53c416_base_2 sym53c416_2 +#define sym53c416_base_3 sym53c416_3 + +static unsigned short sym53c416_base = 0; +static unsigned int sym53c416_irq = 0; +static unsigned short sym53c416_base_1 = 0; +static unsigned int sym53c416_irq_1 = 0; +static unsigned short sym53c416_base_2 = 0; +static unsigned int sym53c416_irq_2 = 0; +static unsigned short sym53c416_base_3 = 0; +static unsigned int sym53c416_irq_3 = 0; + +#endif + +/* #define DEBUG */ + +/* Macro for debugging purposes */ + +#ifdef DEBUG +#define DEB(x) x +#else +#define DEB(x) +#endif + +#define MAXHOSTS 4 + +enum phases + { + idle, + data_out, + data_in, + command_ph, + status_ph, + message_out, + message_in + }; + +typedef struct + { + int base; + int irq; + int scsi_id; + } host; + +host hosts[MAXHOSTS] = { + {0, 0, SYM53C416_SCSI_ID}, + {0, 0, SYM53C416_SCSI_ID}, + {0, 0, SYM53C416_SCSI_ID}, + {0, 0, SYM53C416_SCSI_ID} + }; + +static int host_index = 0; + +static char info[120]; + +static Scsi_Cmnd *current_command = NULL; + +struct proc_dir_entry proc_scsi_sym53c416 = {PROC_SCSI_SYM53C416, 7, ID, S_IFDIR | S_IRUGO | S_IXUGO, 2}; + +int fastpio = 1; + +int probeaddrs[] = {0x200, 0x220, 0x240, 0}; + +static void sym53c416_set_transfer_counter(int base, unsigned int len) + { + /* Program Transfer Counter */ + outb(len & 0x0000FF, base + TC_LOW); + outb((len & 0x00FF00) >> 8, base + TC_MID); + outb((len & 0xFF0000) >> 16, base + TC_HIGH); + } + +/* Returns the number of bytes read */ +static __inline__ unsigned int sym53c416_read(int base, unsigned char *buffer, unsigned int len) + { + unsigned int orig_len = len; + unsigned long flags = 0; + unsigned int bytes_left; + int i; + int timeout = READ_TIMEOUT; + + /* Do transfer */ + save_flags(flags); + cli(); + while(len && timeout) + { + bytes_left = inb(base + PIO_FIFO_CNT); /* Number of bytes in the PIO FIFO */ + if(fastpio && bytes_left > 3) + { + insl(base + PIO_FIFO_1, buffer, bytes_left >> 2); + buffer += bytes_left & 0xFC; + len -= bytes_left & 0xFC; + } + else if(bytes_left > 0) + { + len -= bytes_left; + for(; bytes_left > 0; bytes_left--) + *(buffer++) = inb(base + PIO_FIFO_1); + } + else + { + i = jiffies + timeout; + restore_flags(flags); + while(jiffies < i && (inb(base + PIO_INT_REG) & EMPTY) && timeout) + if(inb(base + PIO_INT_REG) & SCI) + timeout = 0; + save_flags(flags); + cli(); + if(inb(base + PIO_INT_REG) & EMPTY) + timeout = 0; + } + } + restore_flags(flags); + return orig_len - len; + } + +/* Returns the number of bytes written */ +static __inline__ unsigned int sym53c416_write(int base, unsigned char *buffer, unsigned int len) + { + unsigned int orig_len = len; + unsigned long flags = 0; + unsigned int bufferfree; + unsigned int i; + unsigned int timeout = WRITE_TIMEOUT; + + /* Do transfer */ + save_flags(flags); + cli(); + while(len && timeout) + { + bufferfree = PIO_SIZE - inb(base + PIO_FIFO_CNT); + if(bufferfree > len) + bufferfree = len; + if(fastpio && bufferfree > 3) + { + outsl(base + PIO_FIFO_1, buffer, bufferfree >> 2); + buffer += bufferfree & 0xFC; + len -= bufferfree & 0xFC; + } + else if(bufferfree > 0) + { + len -= bufferfree; + for(; bufferfree > 0; bufferfree--) + outb(*(buffer++), base + PIO_FIFO_1); + } + else + { + i = jiffies + timeout; + restore_flags(flags); + while(jiffies < i && (inb(base + PIO_INT_REG) & FULL) && timeout) + ; + save_flags(flags); + cli(); + if(inb(base + PIO_INT_REG) & FULL) + timeout = 0; + } + } + restore_flags(flags); + return orig_len - len; + } + +static void sym53c416_intr_handle(int irq, void *dev_id, struct pt_regs *regs) + { + int base = 0; + int i; + unsigned long flags = 0; + unsigned char status_reg, pio_int_reg, int_reg; + struct scatterlist *sglist; + unsigned int sgcount; + unsigned int tot_trans = 0; + + /* We search the base address of the host adapter which caused the interrupt */ + for(i = 0; i < host_index && !base; i++) + if(irq == hosts[i].irq) + base = hosts[i].base; + /* If no adapter found, we cannot handle the interrupt. Leave a message */ + /* and continue. This should never happen... */ + if(!base) + { + printk("sym53c416: No host adapter defined for interrupt %d\n", irq); + return; + } + /* Now we have the base address and we can start handling the interrupt */ + save_flags(flags); + cli(); + status_reg = inb(base + STATUS_REG); + pio_int_reg = inb(base + PIO_INT_REG); + int_reg = inb(base + INT_REG); + restore_flags(flags); + + /* First, we handle error conditions */ + if(int_reg & SCI) /* SCSI Reset */ + { + printk("sym53c416: Warning: Reset received\n"); + current_command->SCp.phase = idle; + current_command->result = DID_RESET << 16; + current_command->scsi_done(current_command); + return; + } + if(int_reg & ILCMD) /* Illegal Command */ + { + printk("sym53c416: Warning: Illegal Command: 0x%02x\n", inb(base + COMMAND_REG)); + current_command->SCp.phase = idle; + current_command->result = DID_ERROR << 16; + current_command->scsi_done(current_command); + return; + } + if(status_reg & GE) /* Gross Error */ + { + printk("sym53c416: Warning: Gross Error\n"); + current_command->SCp.phase = idle; + current_command->result = DID_ERROR << 16; + current_command->scsi_done(current_command); + return; + } + if(status_reg & PE) /* Parity Error */ + { + printk("sym53c416: Warning: Parity Error\n"); + current_command->SCp.phase = idle; + current_command->result = DID_PARITY << 16; + current_command->scsi_done(current_command); + return; + } + if(pio_int_reg & (CE | OUE)) + { + printk("sym53c416: Warning: PIO Interrupt Error\n"); + current_command->SCp.phase = idle; + current_command->result = DID_ERROR << 16; + current_command->scsi_done(current_command); + return; + } + if(int_reg & DIS) /* Disconnect */ + { + if(current_command->SCp.phase != message_in) + current_command->result = DID_NO_CONNECT << 16; + else + current_command->result = (current_command->SCp.Status & 0xFF) | ((current_command->SCp.Message & 0xFF) << 8) | (DID_OK << 16); + current_command->SCp.phase = idle; + current_command->scsi_done(current_command); + return; + } + /* Now we handle SCSI phases */ + switch(status_reg & PHBITS) /* Filter SCSI phase out of status reg */ + { + case PHASE_DATA_OUT: + { + if(int_reg & BS) + { + current_command->SCp.phase = data_out; + outb(FLUSH_FIFO, base + COMMAND_REG); + sym53c416_set_transfer_counter(base, current_command->request_bufflen); + outb(TRANSFER_INFORMATION | PIO_MODE, base + COMMAND_REG); + if(!current_command->use_sg) + tot_trans = sym53c416_write(base, current_command->request_buffer, current_command->request_bufflen); + else + { + sgcount = current_command->use_sg; + sglist = current_command->request_buffer; + while(sgcount--) + { + tot_trans += sym53c416_write(base, sglist->address, sglist->length); + sglist++; + } + } + if(tot_trans < current_command->underflow) + printk("sym53c416: Warning: underflow, wrote %d bytes, request for %d bytes\n", tot_trans, current_command->underflow); + } + break; + } + case PHASE_DATA_IN: + { + if(int_reg & BS) + { + current_command->SCp.phase = data_in; + outb(FLUSH_FIFO, base + COMMAND_REG); + sym53c416_set_transfer_counter(base, current_command->request_bufflen); + outb(TRANSFER_INFORMATION | PIO_MODE, base + COMMAND_REG); + if(!current_command->use_sg) + tot_trans = sym53c416_read(base, current_command->request_buffer, current_command->request_bufflen); + else + { + sgcount = current_command->use_sg; + sglist = current_command->request_buffer; + while(sgcount--) + { + tot_trans += sym53c416_read(base, sglist->address, sglist->length); + sglist++; + } + } + if(tot_trans < current_command->underflow) + printk("sym53c416: Warning: underflow, read %d bytes, request for %d bytes\n", tot_trans, current_command->underflow); + } + break; + } + case PHASE_COMMAND: + { + current_command->SCp.phase = command_ph; + printk("sym53c416: Warning: Unknown interrupt in command phase\n"); + break; + } + case PHASE_STATUS: + { + current_command->SCp.phase = status_ph; + outb(FLUSH_FIFO, base + COMMAND_REG); + outb(INIT_COMM_COMPLETE_SEQ, base + COMMAND_REG); + break; + } + case PHASE_RESERVED_1: + case PHASE_RESERVED_2: + { + printk("sym53c416: Warning: Reserved phase\n"); + break; + } + case PHASE_MESSAGE_OUT: + { + current_command->SCp.phase = message_out; + outb(SET_ATN, base + COMMAND_REG); + outb(MSG_ACCEPTED, base + COMMAND_REG); + break; + } + case PHASE_MESSAGE_IN: + { + current_command->SCp.phase = message_in; + current_command->SCp.Status = inb(base + SCSI_FIFO); + current_command->SCp.Message = inb(base + SCSI_FIFO); + if(current_command->SCp.Message == SAVE_POINTERS || current_command->SCp.Message == DISCONNECT) + outb(SET_ATN, base + COMMAND_REG); + outb(MSG_ACCEPTED, base + COMMAND_REG); + break; + } + } + } + +static void sym53c416_init(int base, int scsi_id) + { + outb(RESET_CHIP, base + COMMAND_REG); + outb(NOOP, base + COMMAND_REG); + outb(0x99, base + TOM); /* Time out of 250 ms */ + outb(0x05, base + STP); + outb(0x00, base + SYNC_OFFSET); + outb(EPC | scsi_id, base + CONF_REG_1); + outb(FE | SCSI2 | TBPA, base + CONF_REG_2); + outb(IDMRC | QTE | CDB10 | FSCSI | FCLK, base + CONF_REG_3); + outb(0x83 | EAN, base + CONF_REG_4); + outb(IE | WSE0, base + CONF_REG_5); + outb(0, base + FEATURE_EN); + } + +static int sym53c416_probeirq(int base, int scsi_id) + { + int irq, irqs, i; + + /* Clear interrupt register */ + inb(base + INT_REG); + /* Start probing for irq's */ + irqs = probe_irq_on(); + /* Reinit chip */ + sym53c416_init(base, scsi_id); + /* Cause interrupt */ + outb(NOOP, base + COMMAND_REG); + outb(ILLEGAL, base + COMMAND_REG); + outb(0x07, base + DEST_BUS_ID); + outb(0x00, base + DEST_BUS_ID); + /* Wait for interrupt to occur */ + i = jiffies + 20; + while(i > jiffies && !(inb(base + STATUS_REG) & SCI)) + barrier(); + if(i <= jiffies) /* timed out */ + return 0; + /* Get occurred irq */ + irq = probe_irq_off(irqs); + sym53c416_init(base, scsi_id); + return irq; + } + +/* Setup: sym53c416=base,irq */ +void sym53c416_setup(char *str, int *ints) + { + int i; + + if(host_index >= MAXHOSTS) + { + printk("sym53c416.c: Too many hosts defined\n"); + } + else + { + if(ints[0] < 1 || ints[0] > 2) + { + printk("sym53c416.c: Wrong number of parameters:\n"); + printk("sym53c416.c: usage: sym53c416=[,]\n"); + } + else + { + for(i = 0; i < host_index && i >= 0; i++) + if(hosts[i].base == ints[1]) + i = -2; + if(i >= 0) + { + hosts[host_index].base = ints[1]; + hosts[host_index].irq = (ints[0] == 2)? ints[2] : 0; + host_index++; + } + } + } + } + +static int sym53c416_test(int base) + { + outb(RESET_CHIP, base + COMMAND_REG); + outb(NOOP, base + COMMAND_REG); + if(inb(base + COMMAND_REG) != NOOP) + return 0; + if(!inb(base + TC_HIGH) || inb(base + TC_HIGH) == 0xFF) + return 0; + if((inb(base + PIO_INT_REG) & (FULL | EMPTY | CE | OUE | FIE | EIE)) != EMPTY) + return 0; + return 1; + } + +void sym53c416_probe(void) + { + int *base = probeaddrs; + int ints[2]; + + ints[0] = 1; + for(; *base; base++) + if(!check_region(*base, IO_RANGE) && sym53c416_test(*base)) + { + ints[1] = *base; + sym53c416_setup(NULL, ints); + } + } + +int sym53c416_detect(Scsi_Host_Template *tpnt) + { + unsigned long flags; + struct Scsi_Host * shpnt = NULL; + int i; + int count; + +#ifdef MODULE + int ints[3]; + + ints[0] = 2; + if(sym53c416_base) + { + ints[1] = sym53c416_base; + ints[2] = sym53c416_irq; + sym53c416_setup(NULL, ints); + } + if(sym53c416_base_1) + { + ints[1] = sym53c416_base_1; + ints[2] = sym53c416_irq_1; + sym53c416_setup(NULL, ints); + } + if(sym53c416_base_2) + { + ints[1] = sym53c416_base_2; + ints[2] = sym53c416_irq_2; + sym53c416_setup(NULL, ints); + } + if(sym53c416_base_3) + { + ints[1] = sym53c416_base_3; + ints[2] = sym53c416_irq_3; + sym53c416_setup(NULL, ints); + } +#endif + + printk("sym53c416.c: %s\n", VERSION_STRING); + + sym53c416_probe(); + + /* Now we register and set up each host adapter found... */ + for(count = 0, i = 0; i < host_index; i++) + if(!sym53c416_test(hosts[i].base)) + printk("No sym53c416 found at address 0x%03x\n", hosts[i].base); + else + { + if(hosts[i].irq == 0) + /* We don't have an irq yet, so we should probe for one */ + if((hosts[i].irq = sym53c416_probeirq(hosts[i].base, hosts[i].scsi_id)) == 0) + printk("irq autoprobing failed for sym53c416 at address 0x%03x\n", hosts[i].base); + if(hosts[i].irq && !check_region(hosts[i].base, IO_RANGE)) + { + shpnt = scsi_register(tpnt, 0); + save_flags(flags); + cli(); + /* Request for specified IRQ */ + if(request_irq(hosts[i].irq, sym53c416_intr_handle, 0, ID, NULL)) + { + restore_flags(flags); + printk("Unable to assign IRQ %d\n", hosts[i].irq); + scsi_unregister(shpnt); + } + else + { + /* Inform the kernel of our IO range */ + request_region(hosts[i].base, IO_RANGE, ID); + shpnt->unique_id = hosts[i].base; + shpnt->io_port = hosts[i].base; + shpnt->n_io_port = IO_RANGE; + shpnt->irq = hosts[i].irq; + shpnt->this_id = hosts[i].scsi_id; + sym53c416_init(hosts[i].base, hosts[i].scsi_id); + count++; + restore_flags(flags); + } + } + } + return count; + } + +const char *sym53c416_info(struct Scsi_Host *SChost) + { + int i; + int base = SChost->io_port; + int irq = SChost->irq; + int scsi_id = 0; + int rev = inb(base + TC_HIGH); + + for(i = 0; i < host_index; i++) + if(hosts[i].base == base) + scsi_id = hosts[i].scsi_id; + sprintf(info, "Symbios Logic 53c416 (rev. %d) at 0x%03x, irq %d, SCSI-ID %d, %s pio", rev, base, irq, scsi_id, (fastpio)? "fast" : "slow"); + return info; + } + +int sym53c416_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) + { + int base; + unsigned long flags = 0; + int i; + + /* Store base register as we can have more than one controller in the system */ + base = SCpnt->host->io_port; + current_command = SCpnt; /* set current command */ + current_command->scsi_done = done; /* set ptr to done function */ + current_command->SCp.phase = command_ph; /* currect phase is the command phase */ + current_command->SCp.Status = 0; + current_command->SCp.Message = 0; + + save_flags(flags); + cli(); + outb(SCpnt->target, base + DEST_BUS_ID); /* Set scsi id target */ + outb(FLUSH_FIFO, base + COMMAND_REG); /* Flush SCSI and PIO FIFO's */ + /* Write SCSI command into the SCSI fifo */ + for(i = 0; i < SCpnt->cmd_len; i++) + outb(SCpnt->cmnd[i], base + SCSI_FIFO); + /* Start selection sequence */ + outb(SEL_WITHOUT_ATN_SEQ, base + COMMAND_REG); + /* Now an interrupt will be generated which we will catch in out interrupt routine */ + restore_flags(flags); + return 0; + } + +static void internal_done(Scsi_Cmnd *SCpnt) + { + SCpnt->SCp.Status++; + } + +int sym53c416_command(Scsi_Cmnd *SCpnt) + { + sym53c416_queuecommand(SCpnt, internal_done); + SCpnt->SCp.Status = 0; + while(!SCpnt->SCp.Status) + barrier(); + return SCpnt->result; + } + +int sym53c416_abort(Scsi_Cmnd *SCpnt) + { + printk("sym53c416_abort\n"); + + /* We don't know how to abort for the moment */ + return SCSI_ABORT_SNOOZE; + } + +int sym53c416_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags) + { + int base; + int scsi_id = -1; + int i; + + printk("sym53c416_reset\n"); + base = SCpnt->host->io_port; + /* search scsi_id */ + for(i = 0; i < host_index && scsi_id != -1; i++) + if(hosts[i].base == base) + scsi_id = hosts[i].scsi_id; + outb(RESET_CHIP, base + COMMAND_REG); + outb(NOOP | PIO_MODE, base + COMMAND_REG); + outb(RESET_SCSI_BUS, base + COMMAND_REG); + sym53c416_init(base, scsi_id); + return SCSI_RESET_PENDING; + } + +int sym53c416_bios_param(Disk *disk, kdev_t dev, int *ip) + { + int size; + + size = disk->capacity; + ip[0] = 64; /* heads */ + ip[1] = 32; /* sectors */ + if((ip[2] = size >> 11) > 1024) /* cylinders, test for big disk */ + { + ip[0] = 255; /* heads */ + ip[1] = 63; /* sectors */ + ip[2] = size / (255 * 63); /* cylinders */ + } + return 0; + } + +/* Loadable module support */ +#ifdef MODULE + +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,26) +MODULE_AUTHOR("Lieven Willems"); +MODULE_PARM(sym53c416, "1-2i"); +MODULE_PARM(sym53c416_1, "1-2i"); +MODULE_PARM(sym53c416_2, "1-2i"); +MODULE_PARM(sym53c416_3, "1-2i"); +#endif + +Scsi_Host_Template driver_template = SYM53C416; + +#include "scsi_module.c" +#endif diff -ur --new-file old/linux/drivers/scsi/sym53c416.h new/linux/drivers/scsi/sym53c416.h --- old/linux/drivers/scsi/sym53c416.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/scsi/sym53c416.h Tue May 11 19:36:35 1999 @@ -0,0 +1,91 @@ +/* + * sym53c416.h + * + * Copyright (C) 1998 Lieven Willems (lw_linux@hotmail.com) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, 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. + * + */ + +#ifndef _SYM53C416_H +#define _SYM53C416_H + +#if !defined(LINUX_VERSION_CODE) +#include +#endif + +#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s)) + +#include +#include + +#define SYM53C416_SCSI_ID 7 + +extern struct proc_dir_entry proc_scsi_sym53c416; + +extern int sym53c416_detect(Scsi_Host_Template *); +extern const char *sym53c416_info(struct Scsi_Host *); +extern int sym53c416_command(Scsi_Cmnd *); +extern int sym53c416_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); +extern int sym53c416_abort(Scsi_Cmnd *); +extern int sym53c416_reset(Scsi_Cmnd *, unsigned int); +extern int sym53c416_bios_param(Disk *, kdev_t, int *); +extern void sym53c416_setup(char *str, int *ints); + +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,75) + +#define SYM53C416 { \ + proc_dir: &proc_scsi_sym53c416, \ + name: "Symbios Logic 53c416", \ + detect: sym53c416_detect, \ + info: sym53c416_info, \ + command: sym53c416_command, \ + queuecommand: sym53c416_queuecommand, \ + abort: sym53c416_abort, \ + reset: sym53c416_reset, \ + bios_param: sym53c416_bios_param, \ + can_queue: 1, \ + this_id: SYM53C416_SCSI_ID, \ + sg_tablesize: 32, \ + cmd_per_lun: 1, \ + unchecked_isa_dma: 1, \ + use_clustering: ENABLE_CLUSTERING \ + } + +#else + +#define SYM53C416 { \ + NULL, \ + NULL, \ + &proc_scsi_sym53c416, \ + NULL, \ + "Symbios Logic 53c416", \ + sym53c416_detect, \ + NULL, \ + sym53c416_info, \ + sym53c416_command, \ + sym53c416_queuecommand, \ + sym53c416_abort, \ + sym53c416_reset, \ + NULL, \ + sym53c416_bios_param, \ + 1, \ + SYM53C416_SCSI_ID, \ + 32, /* ???? */ \ + 1, \ + 0, \ + 1, \ + ENABLE_CLUSTERING \ + } + +#endif + +#endif diff -ur --new-file old/linux/drivers/scsi/sym53c8xx.c new/linux/drivers/scsi/sym53c8xx.c --- old/linux/drivers/scsi/sym53c8xx.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/scsi/sym53c8xx.c Mon Apr 12 18:51:04 1999 @@ -0,0 +1,11768 @@ +/****************************************************************************** +** High Performance device driver for the Symbios 53C896 controller. +** +** Copyright (C) 1998 Gerard Roudier +** +** This driver also supports all the Symbios 53C8XX controller family, +** except 53C810 revisions < 16, 53C825 revisions < 16 and all +** revisions of 53C815 controllers. +** +** This driver is based on the Linux port of the FreeBSD ncr driver. +** +** Copyright (C) 1994 Wolfgang Stanglmeier +** +**----------------------------------------------------------------------------- +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +**----------------------------------------------------------------------------- +** +** The Linux port of the FreeBSD ncr driver has been achieved in +** november 1995 by: +** +** Gerard Roudier +** +** Being given that this driver originates from the FreeBSD version, and +** in order to keep synergy on both, any suggested enhancements and corrections +** received on Linux are automatically a potential candidate for the FreeBSD +** version. +** +** The original driver has been written for 386bsd and FreeBSD by +** Wolfgang Stanglmeier +** Stefan Esser +** +**----------------------------------------------------------------------------- +** +** Major contributions: +** -------------------- +** +** NVRAM detection and reading. +** Copyright (C) 1997 Richard Waltham +** +******************************************************************************* +*/ + +/* +** April 2 1999, sym53c8xx version 1.3c +** +** Supported SCSI features: +** Synchronous data transfers +** Wide16 SCSI BUS +** Disconnection/Reselection +** Tagged command queuing +** SCSI Parity checking +** +** Supported NCR chips: +** 53C810A (8 bits, Fast 10, no rom BIOS) +** 53C825A (Wide, Fast 10, on-board rom BIOS) +** 53C860 (8 bits, Fast 20, no rom BIOS) +** 53C875 (Wide, Fast 20, on-board rom BIOS) +** 53C876 (Wide, Fast 20 Dual, on-board rom BIOS) +** 53C895 (Wide, Fast 40, on-board rom BIOS) +** 53C896 (Wide, Fast 40 Dual, on-board rom BIOS) +** +** Other features: +** Memory mapped IO +** Module +** Shared IRQ +*/ + +/* +** Name and version of the driver +*/ +#define SCSI_NCR_DRIVER_NAME "sym53c8xx - version 1.3c" + +/* #define DEBUG_896R1 */ +#define SCSI_NCR_OPTIMIZE_896 +/* #define SCSI_NCR_OPTIMIZE_896_1 */ + +#define SCSI_NCR_DEBUG_FLAGS (0) + +#define NAME53C "sym53c" +#define NAME53C8XX "sym53c8xx" + +/*========================================================== +** +** Include files +** +**========================================================== +*/ + +#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s)) + +#ifdef MODULE +#include +#endif + +#include +#include +#include +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,93) +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,35) +#include +#else +#ifndef __initdata +#define __initdata +#endif +#ifndef __initfunc +#define __initfunc(__arginit) __arginit +#endif +#endif + +#if LINUX_VERSION_CODE <= LinuxVersionCode(2,1,92) +#include +#endif + +#include "scsi.h" +#include "hosts.h" +#include "constants.h" +#include "sd.h" + +#include + +/* +** Define BITS_PER_LONG for earlier linux versions. +*/ +#ifndef BITS_PER_LONG +#if (~0UL) == 0xffffffffUL +#define BITS_PER_LONG 32 +#else +#define BITS_PER_LONG 64 +#endif +#endif + +/* +** Define the BSD style u_int32 and u_int64 type. +** Are in fact u_int32_t and u_int64_t :-) +*/ +typedef u32 u_int32; +typedef u64 u_int64; + +#include "sym53c8xx.h" + +/*========================================================== +** +** A la VMS/CAM-3 queue management. +** Implemented from linux list management. +** +**========================================================== +*/ + +typedef struct xpt_quehead { + struct xpt_quehead *flink; /* Forward pointer */ + struct xpt_quehead *blink; /* Backward pointer */ +} XPT_QUEHEAD; + +#define xpt_que_init(ptr) do { \ + (ptr)->flink = (ptr); (ptr)->blink = (ptr); \ +} while (0) + +static inline void __xpt_que_add(struct xpt_quehead * new, + struct xpt_quehead * blink, + struct xpt_quehead * flink) +{ + flink->blink = new; + new->flink = flink; + new->blink = blink; + blink->flink = new; +} + +static inline void __xpt_que_del(struct xpt_quehead * blink, + struct xpt_quehead * flink) +{ + flink->blink = blink; + blink->flink = flink; +} + +static inline int xpt_que_empty(struct xpt_quehead *head) +{ + return head->flink == head; +} + +static inline void xpt_que_splice(struct xpt_quehead *list, + struct xpt_quehead *head) +{ + struct xpt_quehead *first = list->flink; + + if (first != list) { + struct xpt_quehead *last = list->blink; + struct xpt_quehead *at = head->flink; + + first->blink = head; + head->flink = first; + + last->flink = at; + at->blink = last; + } +} + +#define xpt_que_entry(ptr, type, member) \ + ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member))) + + +#define xpt_insque(new, pos) __xpt_que_add(new, pos, (pos)->flink) + +#define xpt_remque(el) __xpt_que_del((el)->blink, (el)->flink) + +#define xpt_insque_head(new, head) __xpt_que_add(new, head, (head)->flink) + +static inline struct xpt_quehead *xpt_remque_head(struct xpt_quehead *head) +{ + struct xpt_quehead *elem = head->flink; + + if (elem != head) + __xpt_que_del(head, elem->flink); + else + elem = 0; + return elem; +} + +#define xpt_insque_tail(new, head) __xpt_que_add(new, (head)->blink, head) + +static inline struct xpt_quehead *xpt_remque_tail(struct xpt_quehead *head) +{ + struct xpt_quehead *elem = head->blink; + + if (elem != head) + __xpt_que_del(elem->blink, head); + else + elem = 0; + return elem; +} + +/*========================================================== +** +** On x86 architecture, write buffers management does +** not reorder writes to memory. So, using compiler +** optimization barriers is enough to guarantee some +** ordering when the CPU is writing data accessed by +** the NCR. +** On Alpha architecture, explicit memory barriers have +** to be used. +** Other architectures are defaulted to mb() macro if +** defined, otherwise use compiler barrier. +** +**========================================================== +*/ + +#if defined(__i386__) +#define MEMORY_BARRIER() barrier() +#elif defined(__alpha__) +#define MEMORY_BARRIER() mb() +#else +# ifdef mb +# define MEMORY_BARRIER() mb() +# else +# define MEMORY_BARRIER() barrier() +# endif +#endif + +/*========================================================== +** +** Configuration and Debugging +** +**========================================================== +*/ + +/* +** SCSI address of this device. +** The boot routines should have set it. +** If not, use this. +*/ + +#ifndef SCSI_NCR_MYADDR +#define SCSI_NCR_MYADDR (7) +#endif + +/* +** The maximum number of tags per logic unit. +** Used only for devices that support tags. +*/ + +#ifndef SCSI_NCR_MAX_TAGS +#define SCSI_NCR_MAX_TAGS (8) +#endif + +/* +** TAGS are actually limited to 64 tags/lun. +** We need to deal with power of 2, for alignment constraints. +*/ +#if SCSI_NCR_MAX_TAGS > 64 +#undef SCSI_NCR_MAX_TAGS +#define SCSI_NCR_MAX_TAGS (64) +#endif + +#define NO_TAG (255) + +/* +** Choose appropriate type for tag bitmap. +*/ +#if SCSI_NCR_MAX_TAGS > 32 +typedef u_int64 tagmap_t; +#else +typedef u_int32 tagmap_t; +#endif + +/* +** Number of targets supported by the driver. +** n permits target numbers 0..n-1. +** Default is 16, meaning targets #0..#15. +** #7 .. is myself. +*/ + +#ifdef SCSI_NCR_MAX_TARGET +#define MAX_TARGET (SCSI_NCR_MAX_TARGET) +#else +#define MAX_TARGET (16) +#endif + +/* +** Number of logic units supported by the driver. +** n enables logic unit numbers 0..n-1. +** The common SCSI devices require only +** one lun, so take 1 as the default. +*/ + +#ifdef SCSI_NCR_MAX_LUN +#define MAX_LUN SCSI_NCR_MAX_LUN +#else +#define MAX_LUN (1) +#endif + +/* +** Asynchronous pre-scaler (ns). Shall be 40 for +** the SCSI timings to be compliant. +*/ + +#ifndef SCSI_NCR_MIN_ASYNC +#define SCSI_NCR_MIN_ASYNC (40) +#endif + +/* +** The maximum number of jobs scheduled for starting. +** We allocate 4 entries more than the value we announce +** to the SCSI upper layer. Guess why ! :-) +*/ + +#ifdef SCSI_NCR_CAN_QUEUE +#define MAX_START (SCSI_NCR_CAN_QUEUE + 4) +#else +#define MAX_START (MAX_TARGET + 7 * SCSI_NCR_MAX_TAGS) +#endif + +/* +** The maximum number of segments a transfer is split into. +** We support up to 127 segments for both read and write. +** Since we try to avoid phase mismatches by testing the PHASE +** before each MOV, the both DATA_IN and DATA_OUT scripts do +** not fit in the 4K on-chip RAM. For this reason, the data +** scripts are broken into 2 sub-scripts. +** 80 (MAX_SCATTERL) segments are moved from a sub-script +** in on-chip RAM. This makes data transfers shorter than +** 80k (assuming 1k fs) as fast as possible. +** The 896 allows to handle phase mismatches from SCRIPTS. +** So, for this chip, we use a simple array of MOV's. +** Perhaps, using a simple array of MOV's and going with +** the phase mismatch interrupt is also the best solution +** for the 895 in Ultra2-mode, since the PHASE test + MOV +** latency may be enough to fill the SCSI offset for very +** fast disks like the Cheatah Wide LVD and so, may waste +** SCSI BUS bandwitch. +*/ + +#define MAX_SCATTER (SCSI_NCR_MAX_SCATTER) + +#ifdef SCSI_NCR_OPTIMIZE_896 +#define SCR_SG_SIZE (2) +#define MAX_SCATTERL MAX_SCATTER +#define MAX_SCATTERH 0 +#else +#if (MAX_SCATTER > 80) +#define SCR_SG_SIZE (4) +#define MAX_SCATTERL 80 +#define MAX_SCATTERH (MAX_SCATTER - MAX_SCATTERL) +#else +#define MAX_SCATTERL MAX_SCATTER +#define MAX_SCATTERH 0 +#endif +#endif /* SCSI_NCR_OPTIMIZE_896 */ + +/* +** Io mapped or memory mapped. +*/ + +#if defined(SCSI_NCR_IOMAPPED) +#define NCR_IOMAPPED +#endif + +/* +** other +*/ + +#define NCR_SNOOP_TIMEOUT (1000000) + +/*========================================================== +** +** Miscallaneous BSDish defines. +** +**========================================================== +*/ + +#define u_char unsigned char +#define u_short unsigned short +#define u_int unsigned int +#define u_long unsigned long + +#ifndef bcopy +#define bcopy(s, d, n) memcpy((d), (s), (n)) +#endif + +#ifndef bzero +#define bzero(d, n) memset((d), 0, (n)) +#endif + +#ifndef offsetof +#define offsetof(t, m) ((size_t) (&((t *)0)->m)) +#endif + +/*========================================================== +** +** Debugging tags +** +**========================================================== +*/ + +#define DEBUG_ALLOC (0x0001) +#define DEBUG_PHASE (0x0002) +#define DEBUG_POLL (0x0004) +#define DEBUG_QUEUE (0x0008) +#define DEBUG_RESULT (0x0010) +#define DEBUG_SCATTER (0x0020) +#define DEBUG_SCRIPT (0x0040) +#define DEBUG_TINY (0x0080) +#define DEBUG_TIMING (0x0100) +#define DEBUG_NEGO (0x0200) +#define DEBUG_TAGS (0x0400) +#define DEBUG_FREEZE (0x0800) +#define DEBUG_RESTART (0x1000) + +/* +** Enable/Disable debug messages. +** Can be changed at runtime too. +*/ + +#ifdef SCSI_NCR_DEBUG_INFO_SUPPORT +static int ncr_debug = SCSI_NCR_DEBUG_FLAGS; + #define DEBUG_FLAGS ncr_debug +#else + #define DEBUG_FLAGS SCSI_NCR_DEBUG_FLAGS +#endif + +/* +** SMP threading. +** +** Assuming that SMP systems are generally high end systems and may +** use several SCSI adapters, we are using one lock per controller +** instead of some global one. For the moment (linux-2.1.95), driver's +** entry points are called with the 'io_request_lock' lock held, so: +** - We are uselessly loosing a couple of micro-seconds to lock the +** controller data structure. +** - But the driver is not broken by design for SMP and so can be +** more resistant to bugs or bad changes in the IO sub-system code. +** - A small advantage could be that the interrupt code is grained as +** wished (e.g.: threaded by controller). +*/ + +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,93) + +spinlock_t sym53c8xx_lock; +#define NCR_LOCK_DRIVER(flags) spin_lock_irqsave(&sym53c8xx_lock, flags) +#define NCR_UNLOCK_DRIVER(flags) spin_unlock_irqrestore(&sym53c8xx_lock,flags) + +#define NCR_INIT_LOCK_NCB(np) spin_lock_init(&np->smp_lock); +#define NCR_LOCK_NCB(np, flags) spin_lock_irqsave(&np->smp_lock, flags) +#define NCR_UNLOCK_NCB(np, flags) spin_unlock_irqrestore(&np->smp_lock, flags) + +# if LINUX_VERSION_CODE < LinuxVersionCode(2,3,99) + +# define NCR_LOCK_SCSI_DONE(np, flags) \ + spin_lock_irqsave(&io_request_lock, flags) +# define NCR_UNLOCK_SCSI_DONE(np, flags) \ + spin_unlock_irqrestore(&io_request_lock, flags) + +# else + +# define NCR_LOCK_SCSI_DONE(np, flags) do {;} while (0) +# define NCR_UNLOCK_SCSI_DONE(np, flags) do {;} while (0) + +# endif + +#else + +#define NCR_LOCK_DRIVER(flags) do { save_flags(flags); cli(); } while (0) +#define NCR_UNLOCK_DRIVER(flags) do { restore_flags(flags); } while (0) + +#define NCR_INIT_LOCK_NCB(np) do { } while (0) +#define NCR_LOCK_NCB(np, flags) do { save_flags(flags); cli(); } while (0) +#define NCR_UNLOCK_NCB(np, flags) do { restore_flags(flags); } while (0) + +#define NCR_LOCK_SCSI_DONE(np, flags) do {;} while (0) +#define NCR_UNLOCK_SCSI_DONE(np, flags) do {;} while (0) + +#endif + +/* +** Address translation +** +** The driver has to provide bus memory addresses to +** the script processor. Because some architectures use +** different physical addressing scheme from the PCI BUS, +** we use virt_to_bus() instead of virt_to_phys(). +*/ + +#define vtobus(p) virt_to_bus(p) + +/* +** Memory mapped IO +** +** Since linux-2.1, we must use ioremap() to map the io memory space. +** iounmap() to unmap it. That allows portability. +** Linux 1.3.X and 2.0.X allow to remap physical pages addresses greater +** than the highest physical memory address to kernel virtual pages with +** vremap() / vfree(). That was not portable but worked with i386 +** architecture. +*/ + +#if LINUX_VERSION_CODE < LinuxVersionCode(2,1,0) +#define ioremap vremap +#define iounmap vfree +#endif + +#ifdef __sparc__ +#define remap_pci_mem(base, size) ((u_long) __va(base)) +#define unmap_pci_mem(vaddr, size) +#define pcivtobus(p) ((p) & pci_dvma_mask) +#else /* __sparc__ */ +#define pcivtobus(p) (p) + +#if !defined(NCR_IOMAPPED) || defined(__i386__) +__initfunc( +static u_long remap_pci_mem(u_long base, u_long size) +) +{ + u_long page_base = ((u_long) base) & PAGE_MASK; + u_long page_offs = ((u_long) base) - page_base; + u_long page_remapped = (u_long) ioremap(page_base, page_offs+size); + + return page_remapped? (page_remapped + page_offs) : 0UL; +} + +__initfunc( +static void unmap_pci_mem(u_long vaddr, u_long size) +) +{ + if (vaddr) + iounmap((void *) (vaddr & PAGE_MASK)); +} +#endif /* !NCR_IOMAPPED || __i386__ */ +#endif /* __sparc__ */ + +/* +** Insert a delay in micro-seconds and milli-seconds. +** ------------------------------------------------- +** Under Linux, udelay() is restricted to delay < 1 milli-second. +** In fact, it generally works for up to 1 second delay. +** Since 2.1.105, the mdelay() function is provided for delays +** in milli-seconds. +** Under 2.0 kernels, udelay() is an inline function that is very +** inaccurate on Pentium processors. +*/ + +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,105) +#define UDELAY udelay +#define MDELAY mdelay +#else +static void UDELAY(long us) { udelay(us); } +static void MDELAY(long ms) { while (ms--) UDELAY(1000); } +#endif + +/* +** Simple power of two buddy-like allocator +** ---------------------------------------- +** This simple code is not intended to be fast, but to provide +** power of 2 aligned memory allocations. +** Since the SCRIPTS processor only supplies 8 bit arithmetic, +** this allocator allows simple and fast address calculations +** from the SCRIPTS code. In addition, cache line alignment +** is guaranteed for power of 2 cache line size. +*/ + +#define MEMO_SHIFT 4 /* 16 bytes minimum memory chunk */ +#define MEMO_PAGE_ORDER 0 /* 1 PAGE maximum (for now (ever?) */ +typedef unsigned long addr; /* Enough bits to bit-hack addresses */ + +#define MEMO_FREE_UNUSED /* Free unused pages immediately */ + +struct m_link { + struct m_link *next; /* Simple links are enough */ +}; + +#ifndef GFP_DMA_32BIT +#define GFP_DMA_32BIT 0 /* Will this flag ever exist */ +#endif + +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,0) +#define get_pages(order) __get_free_pages(GFP_ATOMIC | GFP_DMA_32BIT, order) +#else +#define get_pages(order) __get_free_pages(GFP_ATOMIC | GFP_DMA_32BIT, order, 0) +#endif + +/* +** Lists of available memory chunks. +** Starts with 16 bytes chunks until 1 PAGE chunks. +*/ +static struct m_link h[PAGE_SHIFT-MEMO_SHIFT+MEMO_PAGE_ORDER+1]; + +/* +** Allocate a memory area aligned on the lowest power of 2 +** greater than the requested size. +*/ +static void *__m_alloc(int size) +{ + int i = 0; + int s = (1 << MEMO_SHIFT); + int j; + addr a ; + + if (size > (PAGE_SIZE << MEMO_PAGE_ORDER)) + return 0; + + while (size > s) { + s <<= 1; + ++i; + } + + j = i; + while (!h[j].next) { + if (s == (PAGE_SIZE << MEMO_PAGE_ORDER)) { + h[j].next = (struct m_link *)get_pages(MEMO_PAGE_ORDER); + if (h[j].next) + h[j].next->next = 0; + break; + } + ++j; + s <<= 1; + } + a = (addr) h[j].next; + if (a) { + h[j].next = h[j].next->next; + while (j > i) { + j -= 1; + s >>= 1; + h[j].next = (struct m_link *) (a+s); + h[j].next->next = 0; + } + } +#ifdef DEBUG + printk("m_alloc(%d) = %p\n", size, (void *) a); +#endif + return (void *) a; +} + +/* +** Free a memory area allocated using m_alloc(). +** Coalesce buddies. +** Free pages that become unused if MEMO_FREE_UNUSED is defined. +*/ +static void __m_free(void *ptr, int size) +{ + int i = 0; + int s = (1 << MEMO_SHIFT); + struct m_link *q; + addr a, b; + +#ifdef DEBUG + printk("m_free(%p, %d)\n", ptr, size); +#endif + + if (size > (PAGE_SIZE << MEMO_PAGE_ORDER)) + return; + + while (size > s) { + s <<= 1; + ++i; + } + + a = (addr) ptr; + + while (1) { +#ifdef MEMO_FREE_UNUSED + if (s == (PAGE_SIZE << MEMO_PAGE_ORDER)) { + free_pages(a, MEMO_PAGE_ORDER); + break; + } +#endif + b = a ^ s; + q = &h[i]; + while (q->next && q->next != (struct m_link *) b) { + q = q->next; + } + if (!q->next) { + ((struct m_link *) a)->next = h[i].next; + h[i].next = (struct m_link *) a; + break; + } + q->next = q->next->next; + a = a & b; + s <<= 1; + ++i; + } +} + +#define MEMO_WARN 1 + +/* +** The memory pool is shared by all instances. +** We use a global SMP LOCK to be SMP safe. +*/ + +static void *m_calloc(int size, char *name, int uflags) +{ + u_long flags; + void *p; + + NCR_LOCK_DRIVER(flags); + p = __m_alloc(size); + NCR_UNLOCK_DRIVER(flags); + + if (DEBUG_FLAGS & DEBUG_ALLOC) + printk ("new %s[%d] @%p.\n", name, size, p); + + if (p) + memset(p, 0, size); + else if (uflags & MEMO_WARN) + printk (NAME53C8XX ": failed to allocate %s[%d]\n", name, size); + + return p; +} + +static void m_free(void *ptr, int size, char *name) +{ + u_long flags; + + if (DEBUG_FLAGS & DEBUG_ALLOC) + printk ("freeing %s[%d] @%p.\n", name, size, ptr); + + NCR_LOCK_DRIVER(flags); + __m_free(ptr, size); + NCR_UNLOCK_DRIVER(flags); +} + +/* +** Transfer direction +** +** Low-level scsi drivers under Linux do not receive the expected +** data transfer direction from upper scsi drivers. +** The driver will only check actual data direction for common +** scsi opcodes. Other ones may cause problem, since they may +** depend on device type or be vendor specific. +** I would prefer to never trust the device for data direction, +** but that is not possible. +** +** The original driver requires the expected direction to be known. +** The Linux version of the driver has been enhanced in order to +** be able to transfer data in the direction choosen by the target. +*/ + +#define XFER_IN (1) +#define XFER_OUT (2) + +/* +** Head of list of NCR boards +** +** For kernel version < 1.3.70, host is retrieved by its irq level. +** For later kernels, the internal host control block address +** (struct ncb) is used as device id parameter of the irq stuff. +*/ + +static struct Scsi_Host *first_host = NULL; + + +/* +** /proc directory entry and proc_info function +*/ + +static struct proc_dir_entry proc_scsi_sym53c8xx = { + PROC_SCSI_SYM53C8XX, 9, NAME53C8XX, + S_IFDIR | S_IRUGO | S_IXUGO, 2 +}; +#ifdef SCSI_NCR_PROC_INFO_SUPPORT +static int sym53c8xx_proc_info(char *buffer, char **start, off_t offset, + int length, int hostno, int func); +#endif + +/* +** Driver setup. +** +** This structure is initialized from linux config options. +** It can be overridden at boot-up by the boot command line. +*/ +#define SCSI_NCR_MAX_EXCLUDES 8 +struct ncr_driver_setup { + u_char master_parity; + u_char scsi_parity; + u_char disconnection; + u_char special_features; + u_char ultra_scsi; + u_char force_sync_nego; + u_char reverse_probe; + u_char pci_fix_up; + u_char use_nvram; + u_char verbose; + u_char default_tags; + u_short default_sync; + u_short debug; + u_char burst_max; + u_char led_pin; + u_char max_wide; + u_char settle_delay; + u_char diff_support; + u_char irqm; + u_char bus_check; + u_char optimize; + u_char recovery; + u_int excludes[SCSI_NCR_MAX_EXCLUDES]; + char tag_ctrl[100]; +}; + +static struct ncr_driver_setup + driver_setup = SCSI_NCR_DRIVER_SETUP; + +#ifdef SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT +static struct ncr_driver_setup + driver_safe_setup __initdata = SCSI_NCR_DRIVER_SAFE_SETUP; +# ifdef MODULE +char *sym53c8xx = 0; /* command line passed by insmod */ +# if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,30) +MODULE_PARM(sym53c8xx, "s"); +# endif +# endif +#endif + +/* +** Other Linux definitions +*/ +#define SetScsiResult(cmd, h_sts, s_sts) \ + cmd->result = (((h_sts) << 16) + ((s_sts) & 0x7f)) + +static void sym53c8xx_select_queue_depths( + struct Scsi_Host *host, struct scsi_device *devlist); +static void sym53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs); +static void sym53c8xx_timeout(unsigned long np); + +#define initverbose (driver_setup.verbose) +#define bootverbose (np->verbose) + +#ifdef SCSI_NCR_NVRAM_SUPPORT +/* +** Symbios NvRAM data format +*/ +#define SYMBIOS_NVRAM_SIZE 368 +#define SYMBIOS_NVRAM_ADDRESS 0x100 + +struct Symbios_nvram { +/* Header 6 bytes */ + u_short type; /* 0x0000 */ + u_short byte_count; /* excluding header/trailer */ + u_short checksum; + +/* Controller set up 20 bytes */ + u_char v_major; /* 0x00 */ + u_char v_minor; /* 0x30 */ + u_int32 boot_crc; + u_short flags; +#define SYMBIOS_SCAM_ENABLE (1) +#define SYMBIOS_PARITY_ENABLE (1<<1) +#define SYMBIOS_VERBOSE_MSGS (1<<2) +#define SYMBIOS_CHS_MAPPING (1<<3) +#define SYMBIOS_NO_NVRAM (1<<3) /* ??? */ + u_short flags1; +#define SYMBIOS_SCAN_HI_LO (1) + u_short term_state; +#define SYMBIOS_TERM_CANT_PROGRAM (0) +#define SYMBIOS_TERM_ENABLED (1) +#define SYMBIOS_TERM_DISABLED (2) + u_short rmvbl_flags; +#define SYMBIOS_RMVBL_NO_SUPPORT (0) +#define SYMBIOS_RMVBL_BOOT_DEVICE (1) +#define SYMBIOS_RMVBL_MEDIA_INSTALLED (2) + u_char host_id; + u_char num_hba; /* 0x04 */ + u_char num_devices; /* 0x10 */ + u_char max_scam_devices; /* 0x04 */ + u_char num_valid_scam_devives; /* 0x00 */ + u_char rsvd; + +/* Boot order 14 bytes * 4 */ + struct Symbios_host{ + u_short type; /* 4:8xx / 0:nok */ + u_short device_id; /* PCI device id */ + u_short vendor_id; /* PCI vendor id */ + u_char bus_nr; /* PCI bus number */ + u_char device_fn; /* PCI device/function number << 3*/ + u_short word8; + u_short flags; +#define SYMBIOS_INIT_SCAN_AT_BOOT (1) + u_short io_port; /* PCI io_port address */ + } host[4]; + +/* Targets 8 bytes * 16 */ + struct Symbios_target { + u_char flags; +#define SYMBIOS_DISCONNECT_ENABLE (1) +#define SYMBIOS_SCAN_AT_BOOT_TIME (1<<1) +#define SYMBIOS_SCAN_LUNS (1<<2) +#define SYMBIOS_QUEUE_TAGS_ENABLED (1<<3) + u_char rsvd; + u_char bus_width; /* 0x08/0x10 */ + u_char sync_offset; + u_short sync_period; /* 4*period factor */ + u_short timeout; + } target[16]; +/* Scam table 8 bytes * 4 */ + struct Symbios_scam { + u_short id; + u_short method; +#define SYMBIOS_SCAM_DEFAULT_METHOD (0) +#define SYMBIOS_SCAM_DONT_ASSIGN (1) +#define SYMBIOS_SCAM_SET_SPECIFIC_ID (2) +#define SYMBIOS_SCAM_USE_ORDER_GIVEN (3) + u_short status; +#define SYMBIOS_SCAM_UNKNOWN (0) +#define SYMBIOS_SCAM_DEVICE_NOT_FOUND (1) +#define SYMBIOS_SCAM_ID_NOT_SET (2) +#define SYMBIOS_SCAM_ID_VALID (3) + u_char target_id; + u_char rsvd; + } scam[4]; + + u_char spare_devices[15*8]; + u_char trailer[6]; /* 0xfe 0xfe 0x00 0x00 0x00 0x00 */ +}; +typedef struct Symbios_nvram Symbios_nvram; +typedef struct Symbios_host Symbios_host; +typedef struct Symbios_target Symbios_target; +typedef struct Symbios_scam Symbios_scam; + +/* +** Tekram NvRAM data format. +*/ +#define TEKRAM_NVRAM_SIZE 64 +#define TEKRAM_NVRAM_ADDRESS 0 + +struct Tekram_nvram { + struct Tekram_target { + u_char flags; +#define TEKRAM_PARITY_CHECK (1) +#define TEKRAM_SYNC_NEGO (1<<1) +#define TEKRAM_DISCONNECT_ENABLE (1<<2) +#define TEKRAM_START_CMD (1<<3) +#define TEKRAM_TAGGED_COMMANDS (1<<4) +#define TEKRAM_WIDE_NEGO (1<<5) + u_char sync_index; + u_short word2; + } target[16]; + u_char host_id; + u_char flags; +#define TEKRAM_MORE_THAN_2_DRIVES (1) +#define TEKRAM_DRIVES_SUP_1GB (1<<1) +#define TEKRAM_RESET_ON_POWER_ON (1<<2) +#define TEKRAM_ACTIVE_NEGATION (1<<3) +#define TEKRAM_IMMEDIATE_SEEK (1<<4) +#define TEKRAM_SCAN_LUNS (1<<5) +#define TEKRAM_REMOVABLE_FLAGS (3<<6) /* 0: disable; 1: boot device; 2:all */ + u_char boot_delay_index; + u_char max_tags_index; + u_short flags1; +#define TEKRAM_F2_F6_ENABLED (1) + u_short spare[29]; +}; +typedef struct Tekram_nvram Tekram_nvram; +typedef struct Tekram_target Tekram_target; + +static u_char Tekram_sync[12] __initdata = {25,31,37,43,50,62,75,125,12,15,18,21}; + +#endif /* SCSI_NCR_NVRAM_SUPPORT */ + +/* +** Structures used by sym53c8xx_detect/sym53c8xx_pci_init to +** transmit device configuration to the ncr_attach() function. +*/ +typedef struct { + int bus; + u_char device_fn; + u_long base; + u_long base_2; + u_long io_port; + int irq; +/* port and reg fields to use INB, OUTB macros */ + u_long base_io; + volatile struct ncr_reg *reg; +} ncr_slot; + +typedef struct { + int type; +#define SCSI_NCR_SYMBIOS_NVRAM (1) +#define SCSI_NCR_TEKRAM_NVRAM (2) +#ifdef SCSI_NCR_NVRAM_SUPPORT + union { + Symbios_nvram Symbios; + Tekram_nvram Tekram; + } data; +#endif +} ncr_nvram; + +/* +** Structure used by sym53c8xx_detect/sym53c8xx_pci_init +** to save data on each detected board for ncr_attach(). +*/ +typedef struct { + ncr_slot slot; + ncr_chip chip; + ncr_nvram *nvram; + u_char host_id; +#ifdef SCSI_NCR_PQS_PDS_SUPPORT + u_char pqs_pds; +#endif + int attach_done; +} ncr_device; + +/*========================================================== +** +** assert () +** +**========================================================== +** +** modified copy from 386bsd:/usr/include/sys/assert.h +** +**---------------------------------------------------------- +*/ + +#define assert(expression) { \ + if (!(expression)) { \ + (void)panic( \ + "assertion \"%s\" failed: file \"%s\", line %d\n", \ + #expression, \ + __FILE__, __LINE__); \ + } \ +} + +/*========================================================== +** +** Big/Little endian support. +** +**========================================================== +*/ + +/* +** If the NCR uses big endian addressing mode over the +** PCI, actual io register addresses for byte and word +** accesses must be changed according to lane routing. +** Btw, ncr_offb() and ncr_offw() macros only apply to +** constants and so donnot generate bloated code. +*/ + +#if defined(SCSI_NCR_BIG_ENDIAN) + +#define ncr_offb(o) (((o)&~3)+((~((o)&3))&3)) +#define ncr_offw(o) (((o)&~3)+((~((o)&3))&2)) + +#else + +#define ncr_offb(o) (o) +#define ncr_offw(o) (o) + +#endif + +/* +** If the CPU and the NCR use same endian-ness adressing, +** no byte reordering is needed for script patching. +** Macro cpu_to_scr() is to be used for script patching. +** Macro scr_to_cpu() is to be used for getting a DWORD +** from the script. +*/ + +#if defined(__BIG_ENDIAN) && !defined(SCSI_NCR_BIG_ENDIAN) + +#define cpu_to_scr(dw) cpu_to_le32(dw) +#define scr_to_cpu(dw) le32_to_cpu(dw) + +#elif defined(__LITTLE_ENDIAN) && defined(SCSI_NCR_BIG_ENDIAN) + +#define cpu_to_scr(dw) cpu_to_be32(dw) +#define scr_to_cpu(dw) be32_to_cpu(dw) + +#else + +#define cpu_to_scr(dw) (dw) +#define scr_to_cpu(dw) (dw) + +#endif + +/*========================================================== +** +** Access to the controller chip. +** +** If NCR_IOMAPPED is defined, the driver will use +** normal IOs instead of the MEMORY MAPPED IO method +** recommended by PCI specifications. +** If all PCI bridges, host brigdes and architectures +** would have been correctly designed for PCI, this +** option would be useless. +** +**========================================================== +*/ + +/* +** If the CPU and the NCR use same endian-ness adressing, +** no byte reordering is needed for accessing chip io +** registers. Functions suffixed by '_raw' are assumed +** to access the chip over the PCI without doing byte +** reordering. Functions suffixed by '_l2b' are +** assumed to perform little-endian to big-endian byte +** reordering, those suffixed by '_b2l' blah, blah, +** blah, ... +*/ + +#if defined(NCR_IOMAPPED) + +/* +** IO mapped only input / ouput +*/ + +#define INB_OFF(o) inb (np->base_io + ncr_offb(o)) +#define OUTB_OFF(o, val) outb ((val), np->base_io + ncr_offb(o)) + +#if defined(__BIG_ENDIAN) && !defined(SCSI_NCR_BIG_ENDIAN) + +#define INW_OFF(o) inw_l2b (np->base_io + ncr_offw(o)) +#define INL_OFF(o) inl_l2b (np->base_io + (o)) + +#define OUTW_OFF(o, val) outw_b2l ((val), np->base_io + ncr_offw(o)) +#define OUTL_OFF(o, val) outl_b2l ((val), np->base_io + (o)) + +#elif defined(__LITTLE_ENDIAN) && defined(SCSI_NCR_BIG_ENDIAN) + +#define INW_OFF(o) inw_b2l (np->base_io + ncr_offw(o)) +#define INL_OFF(o) inl_b2l (np->base_io + (o)) + +#define OUTW_OFF(o, val) outw_l2b ((val), np->base_io + ncr_offw(o)) +#define OUTL_OFF(o, val) outl_l2b ((val), np->base_io + (o)) + +#else + +#define INW_OFF(o) inw_raw (np->base_io + ncr_offw(o)) +#define INL_OFF(o) inl_raw (np->base_io + (o)) + +#define OUTW_OFF(o, val) outw_raw ((val), np->base_io + ncr_offw(o)) +#define OUTL_OFF(o, val) outl_raw ((val), np->base_io + (o)) + +#endif /* ENDIANs */ + +#else /* defined NCR_IOMAPPED */ + +/* +** MEMORY mapped IO input / output +*/ + +#define INB_OFF(o) readb((char *)np->reg + ncr_offb(o)) +#define OUTB_OFF(o, val) writeb((val), (char *)np->reg + ncr_offb(o)) + +#if defined(__BIG_ENDIAN) && !defined(SCSI_NCR_BIG_ENDIAN) + +#define INW_OFF(o) readw_l2b((char *)np->reg + ncr_offw(o)) +#define INL_OFF(o) readl_l2b((char *)np->reg + (o)) + +#define OUTW_OFF(o, val) writew_b2l((val), (char *)np->reg + ncr_offw(o)) +#define OUTL_OFF(o, val) writel_b2l((val), (char *)np->reg + (o)) + +#elif defined(__LITTLE_ENDIAN) && defined(SCSI_NCR_BIG_ENDIAN) + +#define INW_OFF(o) readw_b2l((char *)np->reg + ncr_offw(o)) +#define INL_OFF(o) readl_b2l((char *)np->reg + (o)) + +#define OUTW_OFF(o, val) writew_l2b((val), (char *)np->reg + ncr_offw(o)) +#define OUTL_OFF(o, val) writel_l2b((val), (char *)np->reg + (o)) + +#else + +#define INW_OFF(o) readw_raw((char *)np->reg + ncr_offw(o)) +#define INL_OFF(o) readl_raw((char *)np->reg + (o)) + +#define OUTW_OFF(o, val) writew_raw((val), (char *)np->reg + ncr_offw(o)) +#define OUTL_OFF(o, val) writel_raw((val), (char *)np->reg + (o)) + +#endif + +#endif /* defined NCR_IOMAPPED */ + +#define INB(r) INB_OFF (offsetof(struct ncr_reg,r)) +#define INW(r) INW_OFF (offsetof(struct ncr_reg,r)) +#define INL(r) INL_OFF (offsetof(struct ncr_reg,r)) + +#define OUTB(r, val) OUTB_OFF (offsetof(struct ncr_reg,r), (val)) +#define OUTW(r, val) OUTW_OFF (offsetof(struct ncr_reg,r), (val)) +#define OUTL(r, val) OUTL_OFF (offsetof(struct ncr_reg,r), (val)) + +/* +** Set bit field ON, OFF +*/ + +#define OUTONB(r, m) OUTB(r, INB(r) | (m)) +#define OUTOFFB(r, m) OUTB(r, INB(r) & ~(m)) +#define OUTONW(r, m) OUTW(r, INW(r) | (m)) +#define OUTOFFW(r, m) OUTW(r, INW(r) & ~(m)) +#define OUTONL(r, m) OUTL(r, INL(r) | (m)) +#define OUTOFFL(r, m) OUTL(r, INL(r) & ~(m)) + + +/*========================================================== +** +** Command control block states. +** +**========================================================== +*/ + +#define HS_IDLE (0) +#define HS_BUSY (1) +#define HS_NEGOTIATE (2) /* sync/wide data transfer*/ +#define HS_DISCONNECT (3) /* Disconnected by target */ + +#define HS_DONEMASK (0x80) +#define HS_COMPLETE (4|HS_DONEMASK) +#define HS_SEL_TIMEOUT (5|HS_DONEMASK) /* Selection timeout */ +#define HS_RESET (6|HS_DONEMASK) /* SCSI reset */ +#define HS_ABORTED (7|HS_DONEMASK) /* Transfer aborted */ +#define HS_TIMEOUT (8|HS_DONEMASK) /* Software timeout */ +#define HS_FAIL (9|HS_DONEMASK) /* SCSI or PCI bus errors */ +#define HS_UNEXPECTED (10|HS_DONEMASK)/* Unexpected disconnect */ + +#define DSA_INVALID 0xffffffff + +/*========================================================== +** +** Software Interrupt Codes +** +**========================================================== +*/ + +#define SIR_BAD_STATUS (1) +#define SIR_SEL_ATN_NO_MSG_OUT (2) +#define SIR_NEGO_SYNC (3) +#define SIR_NEGO_WIDE (4) +#define SIR_NEGO_FAILED (5) +#define SIR_NEGO_PROTO (6) +#define SIR_REJECT_RECEIVED (7) +#define SIR_REJECT_TO_SEND (8) +#define SIR_IGN_RESIDUE (9) +#define SIR_MISSING_SAVE (10) +#define SIR_RESEL_NO_MSG_IN (11) +#define SIR_RESEL_NO_IDENTIFY (12) +#define SIR_RESEL_BAD_LUN (13) +#define SIR_UNUSED_14 (14) +#define SIR_RESEL_BAD_I_T_L (15) +#define SIR_RESEL_BAD_I_T_L_Q (16) +#define SIR_UNUSED_17 (17) +#define SIR_RESEL_ABORTED (18) +#define SIR_MSG_OUT_DONE (19) +#define SIR_MAX (19) + +/*========================================================== +** +** Extended error codes. +** xerr_status field of struct ccb. +** +**========================================================== +*/ + +#define XE_OK (0) +#define XE_EXTRA_DATA (1) /* unexpected data phase */ +#define XE_BAD_PHASE (2) /* illegal phase (4/5) */ + +/*========================================================== +** +** Negotiation status. +** nego_status field of struct ccb. +** +**========================================================== +*/ + +#define NS_SYNC (1) +#define NS_WIDE (2) + +/*========================================================== +** +** "Special features" of targets. +** quirks field of struct tcb. +** actualquirks field of struct ccb. +** +**========================================================== +*/ + +#define QUIRK_AUTOSAVE (0x01) +#define QUIRK_NOMSG (0x02) +#define QUIRK_NOSYNC (0x10) +#define QUIRK_NOWIDE16 (0x20) + +/*========================================================== +** +** Capability bits in Inquire response byte 7. +** +**========================================================== +*/ + +#define INQ7_QUEUE (0x02) +#define INQ7_SYNC (0x10) +#define INQ7_WIDE16 (0x20) + +/*========================================================== +** +** A CCB hashed table is used to retrieve CCB address +** from DSA value. +** +**========================================================== +*/ + +#define CCB_HASH_SHIFT 8 +#define CCB_HASH_SIZE (1UL << CCB_HASH_SHIFT) +#define CCB_HASH_MASK (CCB_HASH_SIZE-1) +#define CCB_HASH_CODE(dsa) (((dsa) >> 11) & CCB_HASH_MASK) + +/*========================================================== +** +** Declaration of structs. +** +**========================================================== +*/ + +struct tcb; +struct lcb; +struct ccb; +struct ncb; +struct script; + +typedef struct ncb * ncb_p; +typedef struct tcb * tcb_p; +typedef struct lcb * lcb_p; +typedef struct ccb * ccb_p; + +struct link { + ncrcmd l_cmd; + ncrcmd l_paddr; +}; + +struct usrcmd { + u_long target; + u_long lun; + u_long data; + u_long cmd; +}; + +#define UC_SETSYNC 10 +#define UC_SETTAGS 11 +#define UC_SETDEBUG 12 +#define UC_SETORDER 13 +#define UC_SETWIDE 14 +#define UC_SETFLAG 15 +#define UC_CLEARPROF 16 +#define UC_SETVERBOSE 17 + +#define UF_TRACE (0x01) +#define UF_NODISC (0x02) +#define UF_NOSCAN (0x04) + +#ifdef SCSI_NCR_PROFILE_SUPPORT +/* +** profiling data (per host) +*/ + +struct profile { + u_long num_trans; + u_long num_disc; + u_long num_disc0; + u_long num_break; + u_long num_int; + u_long num_fly; + u_long num_kbytes; +#if 000 + u_long num_br1k; + u_long num_br2k; + u_long num_br4k; + u_long num_br8k; + u_long num_brnk; +#endif +}; +#endif + +/*======================================================================== +** +** Declaration of structs: target control block +** +**======================================================================== +*/ +struct tcb { + /*---------------------------------------------------------------- + ** LUN tables. + ** An array of bus addresses is used on reselection by + ** the SCRIPT. + **---------------------------------------------------------------- + */ + u_int32 *luntbl; /* lcbs bus address table */ + u_int32 b_luntbl; /* bus address of this table */ + lcb_p lp[MAX_LUN]; /* The lcb's of this tcb */ + + /*---------------------------------------------------------------- + ** Target capabilities. + **---------------------------------------------------------------- + */ + u_char inq_done; /* Target capabilities received */ + u_char inq_byte7; /* Contains these capabilities */ + + /*---------------------------------------------------------------- + ** Pointer to the ccb used for negotiation. + ** Prevent from starting a negotiation for all queued commands + ** when tagged command queuing is enabled. + **---------------------------------------------------------------- + */ + ccb_p nego_cp; + + /*---------------------------------------------------------------- + ** statistical data + **---------------------------------------------------------------- + */ + u_long transfers; + u_long bytes; + + /*---------------------------------------------------------------- + ** negotiation of wide and synch transfer and device quirks. + ** sval and wval are read from SCRIPTS and so have alignment + ** constraints. + **---------------------------------------------------------------- + */ +/*0*/ u_char minsync; +/*1*/ u_char sval; +/*2*/ u_short period; +/*0*/ u_char maxoffs; +/*1*/ u_char quirks; +/*2*/ u_char widedone; +/*3*/ u_char wval; + + /*---------------------------------------------------------------- + ** User settable limits and options. + ** These limits are read from the NVRAM if present. + **---------------------------------------------------------------- + */ + u_char usrsync; + u_char usrwide; + u_char usrtags; + u_char usrflag; +}; + +/*======================================================================== +** +** Declaration of structs: lun control block +** +**======================================================================== +*/ +struct lcb { + /*---------------------------------------------------------------- + ** On reselection, SCRIPTS use this value as a JUMP address + ** after the IDENTIFY has been successfully received. + ** This field is set to 'resel_tag' if TCQ is enabled and + ** to 'resel_notag' if TCQ is disabled. + ** (Must be at zero due to bad lun handling on reselection) + **---------------------------------------------------------------- + */ +/*0*/ u_int32 resel_task; + + /*---------------------------------------------------------------- + ** Task table used by the script processor to retrieve the + ** task corresponding to a reselected nexus. The TAG is used + ** as offset to determine the corresponding entry. + ** Each entry contains the associated CCB bus address. + **---------------------------------------------------------------- + */ + u_int32 tasktbl_0; /* Used if TCQ not enabled */ + u_int32 *tasktbl; + u_int32 b_tasktbl; + + /*---------------------------------------------------------------- + ** CCB queue management. + **---------------------------------------------------------------- + */ + XPT_QUEHEAD busy_ccbq; /* Queue of busy CCBs */ + XPT_QUEHEAD wait_ccbq; /* Queue of waiting for IO CCBs */ + u_char busyccbs; /* CCBs busy for this lun */ + u_char queuedccbs; /* CCBs queued to the controller*/ + u_char queuedepth; /* Queue depth for this lun */ + u_char scdev_depth; /* SCSI device queue depth */ + u_char maxnxs; /* Max possible nexuses */ + + /*---------------------------------------------------------------- + ** Control of tagged command queuing. + ** Tags allocation is performed using a circular buffer. + ** This avoids using a loop for tag allocation. + **---------------------------------------------------------------- + */ + u_char ia_tag; /* Tag allocation index */ + u_char if_tag; /* Tag release index */ + u_char cb_tags[SCSI_NCR_MAX_TAGS]; /* Circular tags buffer */ + u_char usetags; /* Command queuing is active */ + u_char maxtags; /* Max NR of tags asked by user */ + u_char numtags; /* Current number of tags */ + u_char inq_byte7; /* Store unit CmdQ capabitility */ + + /*---------------------------------------------------------------- + ** QUEUE FULL and ORDERED tag control. + **---------------------------------------------------------------- + */ + u_short num_good; /* Nr of GOOD since QUEUE FULL */ + tagmap_t tags_umap; /* Used tags bitmap */ + tagmap_t tags_smap; /* Tags in use at 'tag_stime' */ + u_long tags_stime; /* Last time we set smap=umap */ +}; + +/*======================================================================== +** +** Declaration of structs: actions for a task. +** +**======================================================================== +** +** It is part of the CCB and is called by the scripts processor to +** start or restart the data structure (nexus). +** +**------------------------------------------------------------------------ +*/ +struct action { + u_int32 start; + u_int32 restart; +}; + +/*======================================================================== +** +** Declaration of structs: Phase mismatch context. +** +**======================================================================== +** +** It is part of the CCB and is used as parameters for the DATA +** pointer. We need two contexts to handle correctly the SAVED +** DATA POINTER. +** +**------------------------------------------------------------------------ +*/ +struct pm_ctx { + struct scr_tblmove sg; /* Updated interrupted SG block */ + u_int32 ret; /* SCRIPT return address */ +}; + +/*======================================================================== +** +** Declaration of structs: global HEADER. +** +**======================================================================== +** +** In earlier driver versions, this substructure was copied from the +** ccb to a global address after selection (or reselection) and copied +** back before disconnect. Since we are now using LOAD/STORE DSA +** RELATIVE instructions, the script is able to access directly these +** fields, and so, this header is no more copied. +** +**------------------------------------------------------------------------ +*/ + +struct head { + /*---------------------------------------------------------------- + ** Start and restart SCRIPTS addresses (must be at 0). + **---------------------------------------------------------------- + */ + struct action go; + + /*---------------------------------------------------------------- + ** Saved data pointer. + ** Points to the position in the script responsible for the + ** actual transfer of data. + ** It's written after reception of a SAVE_DATA_POINTER message. + ** The goalpointer points after the last transfer command. + **---------------------------------------------------------------- + */ + u_int32 savep; + u_int32 lastp; + u_int32 goalp; + + /*---------------------------------------------------------------- + ** Alternate data pointer. + ** They are copied back to savep/lastp/goalp by the SCRIPTS + ** when the direction is unknown and the device claims data out. + **---------------------------------------------------------------- + */ + u_int32 wlastp; + u_int32 wgoalp; + + /*---------------------------------------------------------------- + ** Status fields. + **---------------------------------------------------------------- + */ + u_char scr_st[4]; /* script status */ + u_char status[4]; /* host status */ +}; + +/* +** The status bytes are used by the host and the script processor. +** +** The last four bytes (status[4]) are copied to the scratchb register +** (declared as scr0..scr3 in ncr_reg.h) just after the select/reselect, +** and copied back just after disconnecting. +** Inside the script the XX_REG are used. +** +** The first four bytes (scr_st[4]) are used inside the script by +** "LOAD/STORE" commands. +** Because source and destination must have the same alignment +** in a DWORD, the fields HAVE to be at the choosen offsets. +** xerr_st 0 (0x34) scratcha +** sync_st 1 (0x05) sxfer +** wide_st 3 (0x03) scntl3 +*/ + +/* +** Last four bytes (script) +*/ +#define QU_REG scr0 +#define HS_REG scr1 +#define HS_PRT nc_scr1 +#define SS_REG scr2 +#define SS_PRT nc_scr2 +#define HF_REG scr3 +#define HF_PRT nc_scr3 + +/* +** Last four bytes (host) +*/ +#define actualquirks phys.header.status[0] +#define host_status phys.header.status[1] +#define scsi_status phys.header.status[2] +#define host_flags phys.header.status[3] + +/* +** Host flags +*/ +#define HF_IN_PM0 1u +#define HF_IN_PM1 (1u<<1) +#define HF_ACT_PM (1u<<2) +#define HF_DP_SAVED (1u<<3) +#define HF_PAR_ERR (1u<<4) +#define HF_DATA_ST (1u<<5) +#define HF_PM_TO_C (1u<<6) + +/* +** First four bytes (script) +*/ +#define xerr_st header.scr_st[0] +#define sync_st header.scr_st[1] +#define nego_st header.scr_st[2] +#define wide_st header.scr_st[3] + +/* +** First four bytes (host) +*/ +#define xerr_status phys.xerr_st +#define nego_status phys.nego_st + +/*========================================================== +** +** Declaration of structs: Data structure block +** +**========================================================== +** +** During execution of a ccb by the script processor, +** the DSA (data structure address) register points +** to this substructure of the ccb. +** This substructure contains the header with +** the script-processor-changable data and +** data blocks for the indirect move commands. +** +**---------------------------------------------------------- +*/ + +struct dsb { + + /* + ** Header. + */ + + struct head header; + + /* + ** Table data for Script + */ + + struct scr_tblsel select; + struct scr_tblmove smsg ; + struct scr_tblmove cmd ; + struct scr_tblmove sense ; + struct scr_tblmove data [MAX_SCATTER]; + + /* + ** Phase mismatch contexts. + ** We need two to handle correctly the + ** SAVED DATA POINTER. + */ + + struct pm_ctx pm0; + struct pm_ctx pm1; + +#ifdef SCSI_NCR_PROFILE_SUPPORT + /* + ** Disconnection counter + */ + u_int32 num_disc; +#endif +}; + + +/*======================================================================== +** +** Declaration of structs: Command control block. +** +**======================================================================== +*/ +struct ccb { + /*---------------------------------------------------------------- + ** This is the data structure which is pointed by the DSA + ** register when it is executed by the script processor. + ** It must be the first entry. + **---------------------------------------------------------------- + */ + struct dsb phys; + + /*---------------------------------------------------------------- + ** The general SCSI driver provides a + ** pointer to a control block. + **---------------------------------------------------------------- + */ + Scsi_Cmnd *cmd; /* SCSI command */ + u_long tlimit; /* Deadline for this job */ + int data_len; /* Total data length */ + + /*---------------------------------------------------------------- + ** Message areas. + ** We prepare a message to be sent after selection. + ** We may use a second one if the command is rescheduled + ** due to CHECK_CONDITION or QUEUE FULL status. + ** Contents are IDENTIFY and SIMPLE_TAG. + ** While negotiating sync or wide transfer, + ** a SDTR or WDTR message is appended. + **---------------------------------------------------------------- + */ + u_char scsi_smsg [8]; + u_char scsi_smsg2[8]; + + /*---------------------------------------------------------------- + ** Other fields. + **---------------------------------------------------------------- + */ + u_long p_ccb; /* BUS address of this CCB */ + u_char sensecmd[6]; /* Sense command */ + u_char tag; /* Tag for this transfer */ + /* 255 means no tag */ + u_char target; + u_char lun; + u_char queued; + u_char auto_sense; + ccb_p link_ccb; /* Host adapter CCB chain */ + ccb_p link_ccbh; /* Host adapter CCB hash chain */ + XPT_QUEHEAD link_ccbq; /* Link to unit CCB queue */ + u_int32 startp; /* Initial data pointer */ +}; + +#define CCB_PHYS(cp,lbl) (cp->p_ccb + offsetof(struct ccb, lbl)) + + +/*======================================================================== +** +** Declaration of structs: NCR device descriptor +** +**======================================================================== +*/ +struct ncb { + /*---------------------------------------------------------------- + ** Idle task and invalid task actions and their bus + ** addresses. + **---------------------------------------------------------------- + */ + struct action idletask; + struct action notask; + struct action bad_i_t_l; + struct action bad_i_t_l_q; + u_long p_idletask; + u_long p_notask; + u_long p_bad_i_t_l; + u_long p_bad_i_t_l_q; + + /*---------------------------------------------------------------- + ** Dummy lun table to protect us against target returning bad + ** lun number on reselection. + **---------------------------------------------------------------- + */ + u_int32 *badluntbl; /* Table physical address */ + u_int32 resel_badlun; /* SCRIPT handler BUS address */ + + /*---------------------------------------------------------------- + ** Bit 32-63 of the on-chip RAM bus address in LE format. + ** The START_RAM64 script loads the MMRS and MMWS from this + ** field. + **---------------------------------------------------------------- + */ + u_int32 scr_ram_seg; + + /*---------------------------------------------------------------- + ** CCBs management queues. + **---------------------------------------------------------------- + */ + Scsi_Cmnd *waiting_list; /* Commands waiting for a CCB */ + /* when lcb is not allocated. */ + Scsi_Cmnd *done_list; /* Commands waiting for done() */ + /* callback to be invoked. */ +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,93) + spinlock_t smp_lock; /* Lock for SMP threading */ +#endif + + /*---------------------------------------------------------------- + ** Chip and controller indentification. + **---------------------------------------------------------------- + */ + int unit; /* Unit number */ + char chip_name[8]; /* Chip name */ + char inst_name[16]; /* ncb instance name */ + + /*---------------------------------------------------------------- + ** Initial value of some IO register bits. + ** These values are assumed to have been set by BIOS, and may + ** be used for probing adapter implementation differences. + **---------------------------------------------------------------- + */ + u_char sv_scntl0, sv_scntl3, sv_dmode, sv_dcntl, sv_ctest3, sv_ctest4, + sv_ctest5, sv_gpcntl, sv_stest2, sv_stest4; + + /*---------------------------------------------------------------- + ** Actual initial value of IO register bits used by the + ** driver. They are loaded at initialisation according to + ** features that are to be enabled. + **---------------------------------------------------------------- + */ + u_char rv_scntl0, rv_scntl3, rv_dmode, rv_dcntl, rv_ctest3, rv_ctest4, + rv_ctest5, rv_stest2, rv_ccntl0, rv_ccntl1; + + /*---------------------------------------------------------------- + ** Target data. + ** Target control block bus address array used by the SCRIPT + ** on reselection. + **---------------------------------------------------------------- + */ + struct tcb target[MAX_TARGET]; + u_int32 *targtbl; + + /*---------------------------------------------------------------- + ** Virtual and physical bus addresses of the chip. + **---------------------------------------------------------------- + */ + u_long base_va; /* MMIO base virtual address */ + u_long base_ba; /* MMIO base bus address */ + u_long base_io; /* IO space base address */ + u_long base_ws; /* (MM)IO window size */ + u_long base2_ba; /* On-chip RAM bus address. */ + u_int irq; /* IRQ number */ + volatile /* Pointer to volatile for */ + struct ncr_reg *reg; /* memory mapped IO. */ + + /*---------------------------------------------------------------- + ** SCRIPTS virtual and physical bus addresses. + ** 'script' is loaded in the on-chip RAM if present. + ** 'scripth' stays in main memory for all chips except the + ** 53C896 that provides 8K on-chip RAM. + **---------------------------------------------------------------- + */ + struct script *script0; /* Copies of script and scripth */ + struct scripth *scripth0; /* relocated for this ncb. */ + u_long p_script; /* Actual script and scripth */ + u_long p_scripth; /* bus addresses. */ + u_long p_scripth0; + + /*---------------------------------------------------------------- + ** General controller parameters and configuration. + **---------------------------------------------------------------- + */ + u_short device_id; /* PCI device id */ + u_char revision_id; /* PCI device revision id */ + u_int features; /* Chip features map */ + u_char myaddr; /* SCSI id of the adapter */ + u_char maxburst; /* log base 2 of dwords burst */ + u_char maxwide; /* Maximum transfer width */ + u_char minsync; /* Minimum sync period factor */ + u_char maxsync; /* Maximum sync period factor */ + u_char maxoffs; /* Max scsi offset */ + u_char multiplier; /* Clock multiplier (1,2,4) */ + u_char clock_divn; /* Number of clock divisors */ + u_long clock_khz; /* SCSI clock frequency in KHz */ + + /*---------------------------------------------------------------- + ** Start queue management. + ** It is filled up by the host processor and accessed by the + ** SCRIPTS processor in order to start SCSI commands. + **---------------------------------------------------------------- + */ + u_int32 *squeue; /* Start queue */ + u_short squeueput; /* Next free slot of the queue */ + u_short actccbs; /* Number of allocated CCBs */ + u_short queuedepth; /* Start queue depth */ + + /*---------------------------------------------------------------- + ** Command completion queue. + ** It is the same size as the start queue to avoid overflow. + **---------------------------------------------------------------- + */ + u_short dqueueget; /* Next position to scan */ + u_int32 *dqueue; /* Completion (done) queue */ + + /*---------------------------------------------------------------- + ** Timeout handler. + **---------------------------------------------------------------- + */ + struct timer_list timer; /* Timer handler link header */ + u_long lasttime; + u_long settle_time; /* Resetting the SCSI BUS */ + + /*---------------------------------------------------------------- + ** Debugging and profiling. + **---------------------------------------------------------------- + */ + struct ncr_reg regdump; /* Register dump */ + u_long regtime; /* Time it has been done */ +#ifdef SCSI_NCR_PROFILE_SUPPORT + struct profile profile; /* Profiling data */ +#endif + + /*---------------------------------------------------------------- + ** Miscellaneous buffers accessed by the scripts-processor. + ** They shall be DWORD aligned, because they may be read or + ** written with a script command. + **---------------------------------------------------------------- + */ + u_char msgout[8]; /* Buffer for MESSAGE OUT */ + u_char msgin [8]; /* Buffer for MESSAGE IN */ + u_int32 lastmsg; /* Last SCSI message sent */ + u_char scratch; /* Scratch for SCSI receive */ + + /*---------------------------------------------------------------- + ** Miscellaneous configuration and status parameters. + **---------------------------------------------------------------- + */ + u_char scsi_mode; /* Current SCSI BUS mode */ + u_char order; /* Tag order to use */ + u_char verbose; /* Verbosity for this controller*/ + u_int32 ncr_cache; /* Used for cache test at init. */ + + /*---------------------------------------------------------------- + ** CCB lists and queue. + **---------------------------------------------------------------- + */ + ccb_p ccbh[CCB_HASH_SIZE]; /* CCB hashed by DSA value */ + struct ccb *ccbc; /* CCB chain */ + XPT_QUEHEAD free_ccbq; /* Queue of available CCBs */ + + /*---------------------------------------------------------------- + ** We need the LCB in order to handle disconnections and + ** to count active CCBs for task management. So, we use + ** a unique CCB for LUNs we donnot have the LCB yet. + ** This queue normally should have at most 1 element. + **---------------------------------------------------------------- + */ + XPT_QUEHEAD b0_ccbq; + + /*---------------------------------------------------------------- + ** We use a different scatter function for 896 rev 1. + **---------------------------------------------------------------- + */ + int (*scatter) (ccb_p, Scsi_Cmnd *); + + /*---------------------------------------------------------------- + ** Fields that should be removed or changed. + **---------------------------------------------------------------- + */ + struct usrcmd user; /* Command from user */ + u_char release_stage; /* Synchronisation stage on release */ +}; + +#define NCB_SCRIPT_PHYS(np,lbl) (np->p_script + offsetof (struct script, lbl)) +#define NCB_SCRIPTH_PHYS(np,lbl) (np->p_scripth + offsetof (struct scripth,lbl)) +#define NCB_SCRIPTH0_PHYS(np,lbl) (np->p_scripth0+offsetof (struct scripth,lbl)) + +/*========================================================== +** +** +** Script for NCR-Processor. +** +** Use ncr_script_fill() to create the variable parts. +** Use ncr_script_copy_and_bind() to make a copy and +** bind to physical addresses. +** +** +**========================================================== +** +** We have to know the offsets of all labels before +** we reach them (for forward jumps). +** Therefore we declare a struct here. +** If you make changes inside the script, +** DONT FORGET TO CHANGE THE LENGTHS HERE! +** +**---------------------------------------------------------- +*/ + +/* +** Script fragments which are loaded into the on-chip RAM +** of 825A, 875, 876, 895 and 896 chips. +*/ +struct script { + ncrcmd start [ 10]; + ncrcmd getjob_begin [ 4]; + ncrcmd getjob_end [ 4]; + ncrcmd select [ 4]; + ncrcmd wf_sel_done [ 2]; + ncrcmd send_ident [ 2]; + ncrcmd select2 [ 6]; + ncrcmd command [ 2]; + ncrcmd dispatch [ 26]; + ncrcmd sel_no_cmd [ 10]; + ncrcmd init [ 6]; + ncrcmd clrack [ 4]; + ncrcmd databreak [ 2]; +#ifdef SCSI_NCR_PROFILE_SUPPORT + ncrcmd dataphase [ 4]; +#else + ncrcmd dataphase [ 2]; +#endif + ncrcmd status [ 8]; + ncrcmd msg_in [ 2]; + ncrcmd msg_in2 [ 16]; + ncrcmd msg_bad [ 6]; + ncrcmd complete [ 8]; + ncrcmd complete2 [ 6]; + ncrcmd done [ 14]; + ncrcmd done_end [ 2]; + ncrcmd save_dp [ 8]; + ncrcmd restore_dp [ 4]; +#ifdef SCSI_NCR_PROFILE_SUPPORT + ncrcmd disconnect [ 32]; +#else + ncrcmd disconnect [ 20]; +#endif + ncrcmd idle [ 2]; + ncrcmd ungetjob [ 4]; + ncrcmd reselect [ 4]; + ncrcmd reselected [ 44]; + ncrcmd resel_tag [ 6]; + ncrcmd resel_go [ 6]; + ncrcmd resel_notag [ 4]; + ncrcmd resel_dsa [ 8]; + ncrcmd data_in [MAX_SCATTERL * SCR_SG_SIZE]; + ncrcmd data_in2 [ 4]; + ncrcmd data_out [MAX_SCATTERL * SCR_SG_SIZE]; + ncrcmd data_out2 [ 4]; + ncrcmd pm0_data [ 16]; + ncrcmd pm1_data [ 16]; + + /* Data area */ + ncrcmd saved_dsa [ 1]; + ncrcmd done_pos [ 1]; + ncrcmd startpos [ 1]; + ncrcmd targtbl [ 1]; +}; + +/* +** Script fragments which stay in main memory for all chips +** except for the 896 that support 8K on-chip RAM. +*/ +struct scripth { + ncrcmd start64 [ 2]; + ncrcmd select_no_atn [ 4]; + ncrcmd wf_sel_done_no_atn [ 4]; + ncrcmd cancel [ 4]; + ncrcmd msg_reject [ 8]; + ncrcmd msg_ign_residue [ 24]; + ncrcmd msg_extended [ 10]; + ncrcmd msg_ext_2 [ 10]; + ncrcmd msg_wdtr [ 14]; + ncrcmd send_wdtr [ 4]; + ncrcmd msg_ext_3 [ 10]; + ncrcmd msg_sdtr [ 14]; + ncrcmd send_sdtr [ 4]; + ncrcmd nego_bad_phase [ 4]; + ncrcmd msg_out_abort [ 12]; + ncrcmd msg_out [ 6]; + ncrcmd msg_out_done [ 4]; + ncrcmd no_data [ 16]; +#if MAX_SCATTERH != 0 + ncrcmd hdata_in [MAX_SCATTERH * SCR_SG_SIZE]; + ncrcmd hdata_in2 [ 2]; + ncrcmd hdata_out [MAX_SCATTERH * SCR_SG_SIZE]; + ncrcmd hdata_out2 [ 2]; +#endif + ncrcmd abort_resel [ 16]; + ncrcmd resend_ident [ 4]; + ncrcmd ident_break [ 4]; + ncrcmd ident_break_atn [ 4]; + ncrcmd sdata_in [ 6]; + ncrcmd data_io [ 2]; + ncrcmd data_io_com [ 8]; + ncrcmd data_io_out [ 10]; + ncrcmd bad_identify [ 12]; + ncrcmd bad_i_t_l [ 4]; + ncrcmd bad_i_t_l_q [ 4]; + ncrcmd bad_status [ 10]; + ncrcmd tweak_pmj [ 12]; + ncrcmd pm_handle [ 20]; + ncrcmd pm_handle1 [ 4]; + ncrcmd pm_save [ 4]; + ncrcmd pm0_save [ 10]; + ncrcmd pm1_save [ 10]; + + /* Data area */ + ncrcmd pm0_data_addr [ 1]; + ncrcmd pm1_data_addr [ 1]; + /* End of data area */ + + ncrcmd start_ram [ 1]; + ncrcmd script0_ba [ 4]; + + ncrcmd start_ram64 [ 3]; + ncrcmd script0_ba64 [ 3]; + ncrcmd scripth0_ba64 [ 6]; + ncrcmd ram_seg64 [ 1]; + + ncrcmd snooptest [ 6]; + ncrcmd snoopend [ 2]; +}; + +/*========================================================== +** +** +** Function headers. +** +** +**========================================================== +*/ + +static ccb_p ncr_alloc_ccb (ncb_p np); +static void ncr_complete (ncb_p np, ccb_p cp); +static void ncr_exception (ncb_p np); +static void ncr_free_ccb (ncb_p np, ccb_p cp); +static ccb_p ncr_ccb_from_dsa(ncb_p np, u_long dsa); +static void ncr_init_tcb (ncb_p np, u_char tn); +static lcb_p ncr_alloc_lcb (ncb_p np, u_char tn, u_char ln); +static lcb_p ncr_setup_lcb (ncb_p np, u_char tn, u_char ln, + u_char *inq_data); +static void ncr_getclock (ncb_p np, int mult); +static void ncr_selectclock (ncb_p np, u_char scntl3); +static ccb_p ncr_get_ccb (ncb_p np, u_char tn, u_char ln); +static void ncr_init (ncb_p np, int reset, char * msg, u_long code); +static void ncr_int_sbmc (ncb_p np); +static void ncr_int_par (ncb_p np, u_short sist); +static void ncr_int_ma (ncb_p np); +static void ncr_int_sir (ncb_p np); +static void ncr_int_sto (ncb_p np); +static void ncr_int_udc (ncb_p np); +static u_long ncr_lookup (char* id); +static void ncr_negotiate (struct ncb* np, struct tcb* tp); +#ifdef SCSI_NCR_PROFILE_SUPPORT +static void ncb_profile (ncb_p np, ccb_p cp); +#endif +static void ncr_script_copy_and_bind + (ncb_p np, ncrcmd *src, ncrcmd *dst, int len); +static void ncr_script_fill (struct script * scr, struct scripth * scripth); +static int ncr_scatter_896R1 (ccb_p cp, Scsi_Cmnd *cmd); +static int ncr_scatter (ccb_p cp, Scsi_Cmnd *cmd); +static void ncr_getsync (ncb_p np, u_char sfac, u_char *fakp, u_char *scntl3p); +static void ncr_setsync (ncb_p np, ccb_p cp, u_char scntl3, u_char sxfer); +static void ncr_setup_tags (ncb_p np, u_char tn, u_char ln); +static void ncr_setwide (ncb_p np, ccb_p cp, u_char wide, u_char ack); +static int ncr_show_msg (u_char * msg); +static int ncr_snooptest (ncb_p np); +static void ncr_timeout (ncb_p np); +static void ncr_wakeup (ncb_p np, u_long code); +static int ncr_wakeup_done (ncb_p np); +static void ncr_start_next_ccb (ncb_p np, lcb_p lp, int maxn); +static void ncr_put_start_queue(ncb_p np, ccb_p cp); +static void ncr_soft_reset (ncb_p np); +static void ncr_start_reset (ncb_p np); +static int ncr_reset_scsi_bus (ncb_p np, int enab_int, int settle_delay); + +#ifdef SCSI_NCR_USER_COMMAND_SUPPORT +static void ncr_usercmd (ncb_p np); +#endif + +static int ncr_attach (Scsi_Host_Template *tpnt, int unit, ncr_device *device); +static void ncr_free_resources(ncb_p np); + +static void insert_into_waiting_list(ncb_p np, Scsi_Cmnd *cmd); +static Scsi_Cmnd *retrieve_from_waiting_list(int to_remove, ncb_p np, Scsi_Cmnd *cmd); +static void process_waiting_list(ncb_p np, int sts); + +#define remove_from_waiting_list(np, cmd) \ + retrieve_from_waiting_list(1, (np), (cmd)) +#define requeue_waiting_list(np) process_waiting_list((np), DID_OK) +#define reset_waiting_list(np) process_waiting_list((np), DID_RESET) + +#ifdef SCSI_NCR_NVRAM_SUPPORT +static void ncr_get_nvram (ncr_device *devp, ncr_nvram *nvp); +static int ncr_get_Symbios_nvram (ncr_slot *np, Symbios_nvram *nvram); +static int ncr_get_Tekram_nvram (ncr_slot *np, Tekram_nvram *nvram); +#endif + +/*========================================================== +** +** +** Global static data. +** +** +**========================================================== +*/ + +static inline char *ncr_name (ncb_p np) +{ + return np->inst_name; +} + + +/*========================================================== +** +** +** Scripts for NCR-Processor. +** +** Use ncr_script_bind for binding to physical addresses. +** +** +**========================================================== +** +** NADDR generates a reference to a field of the controller data. +** PADDR generates a reference to another part of the script. +** RADDR generates a reference to a script processor register. +** FADDR generates a reference to a script processor register +** with offset. +** +**---------------------------------------------------------- +*/ + +#define RELOC_SOFTC 0x40000000 +#define RELOC_LABEL 0x50000000 +#define RELOC_REGISTER 0x60000000 +#if 0 +#define RELOC_KVAR 0x70000000 +#endif +#define RELOC_LABELH 0x80000000 +#define RELOC_MASK 0xf0000000 + +#define NADDR(label) (RELOC_SOFTC | offsetof(struct ncb, label)) +#define PADDR(label) (RELOC_LABEL | offsetof(struct script, label)) +#define PADDRH(label) (RELOC_LABELH | offsetof(struct scripth, label)) +#define RADDR(label) (RELOC_REGISTER | REG(label)) +#define FADDR(label,ofs)(RELOC_REGISTER | ((REG(label))+(ofs))) +#define KVAR(which) (RELOC_KVAR | (which)) + +#define SCR_DATA_ZERO 0xf00ff00f + +#ifdef RELOC_KVAR +#define SCRIPT_KVAR_JIFFIES (0) +#define SCRIPT_KVAR_FIRST SCRIPT_KVAR_JIFFIES +#define SCRIPT_KVAR_LAST SCRIPT_KVAR_JIFFIES +/* + * Kernel variables referenced in the scripts. + * THESE MUST ALL BE ALIGNED TO A 4-BYTE BOUNDARY. + */ +static void *script_kvars[] __initdata = + { (void *)&jiffies }; +#endif + +static struct script script0 __initdata = { +/*--------------------------< START >-----------------------*/ { + /* + ** This NOP will be patched with LED ON + ** SCR_REG_REG (gpreg, SCR_AND, 0xfe) + */ + SCR_NO_OP, + 0, + /* + ** Clear SIGP. + */ + SCR_FROM_REG (ctest2), + 0, + /* + ** Start the next job. + ** + ** @DSA = start point for this job. + ** SCRATCHA = address of this job in the start queue. + ** + ** We will restore startpos with SCRATCHA if we fails the + ** arbitration or if it is the idle job. + ** + ** The below GETJOB_BEGIN to GETJOB_END section of SCRIPTS + ** is a critical path. If it is partially executed, it then + ** may happen that the job address is not yet in the DSA + ** and the the next queue position points to the next JOB. + */ + SCR_LOAD_ABS (scratcha, 4), + PADDR (startpos), + SCR_LOAD_ABS (dsa, 4), + PADDR (startpos), + SCR_LOAD_REL (temp, 4), + 4, +}/*-------------------------< GETJOB_BEGIN >------------------*/,{ + SCR_STORE_ABS (temp, 4), + PADDR (startpos), + SCR_LOAD_REL (dsa, 4), + 0, +}/*-------------------------< GETJOB_END >--------------------*/,{ + SCR_LOAD_REL (temp, 4), + 0, + SCR_RETURN, + 0, + +}/*-------------------------< SELECT >----------------------*/,{ + /* + ** DSA contains the address of a scheduled + ** data structure. + ** + ** SCRATCHA contains the address of the start queue + ** entry which points to the next job. + ** + ** Set Initiator mode. + ** + ** (Target mode is left as an exercise for the reader) + */ + + SCR_CLR (SCR_TRG), + 0, + /* + ** And try to select this target. + */ + SCR_SEL_TBL_ATN ^ offsetof (struct dsb, select), + PADDR (ungetjob), + /* + ** Now there are 4 possibilities: + ** + ** (1) The ncr looses arbitration. + ** This is ok, because it will try again, + ** when the bus becomes idle. + ** (But beware of the timeout function!) + ** + ** (2) The ncr is reselected. + ** Then the script processor takes the jump + ** to the RESELECT label. + ** + ** (3) The ncr wins arbitration. + ** Then it will execute SCRIPTS instruction until + ** the next instruction that checks SCSI phase. + ** Then will stop and wait for selection to be + ** complete or selection time-out to occur. + ** + ** After having won arbitration, the ncr SCRIPTS + ** processor is able to execute instructions while + ** the SCSI core is performing SCSI selection. But + ** some script instruction that is not waiting for + ** a valid phase (or selection timeout) to occur + ** breaks the selection procedure, by probably + ** affecting timing requirements. + ** So we have to wait immediately for the next phase + ** or the selection to complete or time-out. + */ +}/*-------------------------< WF_SEL_DONE >----------------------*/,{ + SCR_INT ^ IFFALSE (WHEN (SCR_MSG_OUT)), + SIR_SEL_ATN_NO_MSG_OUT, +}/*-------------------------< SEND_IDENT >----------------------*/,{ + /* + ** Selection complete. + ** Send the IDENTIFY and SIMPLE_TAG messages + ** (and the M_X_SYNC_REQ / M_X_WIDE_REQ message) + */ + SCR_MOVE_TBL ^ SCR_MSG_OUT, + offsetof (struct dsb, smsg), +}/*-------------------------< SELECT2 >----------------------*/,{ + /* + ** load the savep (saved pointer) into + ** the actual data pointer. + */ + SCR_LOAD_REL (temp, 4), + offsetof (struct ccb, phys.header.savep), + /* + ** Initialize the status registers + */ + SCR_LOAD_REL (scr0, 4), + offsetof (struct ccb, phys.header.status), + /* + ** Anticipate the COMMAND phase. + ** This is the PHASE we expect at this point. + */ + SCR_JUMP ^ IFFALSE (WHEN (SCR_COMMAND)), + PADDR (sel_no_cmd), + +}/*-------------------------< COMMAND >--------------------*/,{ + /* + ** ... and send the command + */ + SCR_MOVE_TBL ^ SCR_COMMAND, + offsetof (struct dsb, cmd), + +}/*-----------------------< DISPATCH >----------------------*/,{ + /* + ** MSG_IN is the only phase that shall be + ** entered at least once for each (re)selection. + ** So we test it first. + */ + SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_IN)), + PADDR (msg_in), + SCR_JUMP ^ IFTRUE (IF (SCR_DATA_OUT)), + PADDR (dataphase), + SCR_JUMP ^ IFTRUE (IF (SCR_DATA_IN)), + PADDR (dataphase), + SCR_JUMP ^ IFTRUE (IF (SCR_STATUS)), + PADDR (status), + SCR_JUMP ^ IFTRUE (IF (SCR_COMMAND)), + PADDR (command), + SCR_JUMP ^ IFTRUE (IF (SCR_MSG_OUT)), + PADDRH (msg_out), + /* + ** Discard one illegal phase byte, if required. + */ + SCR_LOAD_REG (scratcha, XE_BAD_PHASE), + 0, + SCR_STORE_REL (scratcha, 1), + offsetof (struct ccb, xerr_status), + SCR_JUMPR ^ IFFALSE (IF (SCR_ILG_OUT)), + 8, + SCR_MOVE_ABS (1) ^ SCR_ILG_OUT, + NADDR (scratch), + SCR_JUMPR ^ IFFALSE (IF (SCR_ILG_IN)), + 8, + SCR_MOVE_ABS (1) ^ SCR_ILG_IN, + NADDR (scratch), + SCR_JUMP, + PADDR (dispatch), + +}/*---------------------< SEL_NO_CMD >----------------------*/,{ + /* + ** The target does not switch to command + ** phase after IDENTIFY has been sent. + ** + ** If it stays in MSG OUT phase send it + ** the IDENTIFY again. + */ + SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_OUT)), + PADDRH (resend_ident), + /* + ** If target does not switch to MSG IN phase + ** and we sent a negotiation, assert the + ** failure immediately. + */ + SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_IN)), + PADDR (dispatch), + SCR_FROM_REG (HS_REG), + 0, + SCR_INT ^ IFTRUE (DATA (HS_NEGOTIATE)), + SIR_NEGO_FAILED, + /* + ** Jump to dispatcher. + */ + SCR_JUMP, + PADDR (dispatch), + +}/*-------------------------< INIT >------------------------*/,{ + /* + ** Wait for the SCSI RESET signal to be + ** inactive before restarting operations, + ** since the chip may hang on SEL_ATN + ** if SCSI RESET is active. + */ + SCR_FROM_REG (sstat0), + 0, + SCR_JUMPR ^ IFTRUE (MASK (IRST, IRST)), + -8, + SCR_JUMP, + PADDR (start), +}/*-------------------------< CLRACK >----------------------*/,{ + /* + ** Terminate possible pending message phase. + */ + SCR_CLR (SCR_ACK), + 0, + SCR_JUMP, + PADDR (dispatch), + +}/*-------------------------< DATABREAK >-------------------*/,{ + /* + ** Jump to dispatcher. + */ + SCR_JUMP, + PADDR (dispatch), + +}/*-------------------------< DATAPHASE >------------------*/,{ +#ifdef SCSI_NCR_PROFILE_SUPPORT + SCR_REG_REG (HF_REG, SCR_OR, HF_DATA_ST), + 0, +#endif + SCR_RETURN, + 0, + +}/*-------------------------< STATUS >--------------------*/,{ + /* + ** get the status + */ + SCR_MOVE_ABS (1) ^ SCR_STATUS, + NADDR (scratch), + /* + ** save status to scsi_status. + ** mark as complete. + */ + SCR_TO_REG (SS_REG), + 0, + SCR_LOAD_REG (HS_REG, HS_COMPLETE), + 0, + SCR_JUMP, + PADDR (dispatch), +}/*-------------------------< MSG_IN >--------------------*/,{ + /* + ** Get the first byte of the message. + ** + ** The script processor doesn't negate the + ** ACK signal after this transfer. + */ + SCR_MOVE_ABS (1) ^ SCR_MSG_IN, + NADDR (msgin[0]), +}/*-------------------------< MSG_IN2 >--------------------*/,{ + /* + ** Handle this message. + */ + SCR_JUMP ^ IFTRUE (DATA (M_COMPLETE)), + PADDR (complete), + SCR_JUMP ^ IFTRUE (DATA (M_DISCONNECT)), + PADDR (disconnect), + SCR_JUMP ^ IFTRUE (DATA (M_SAVE_DP)), + PADDR (save_dp), + SCR_JUMP ^ IFTRUE (DATA (M_RESTORE_DP)), + PADDR (restore_dp), + SCR_JUMP ^ IFTRUE (DATA (M_EXTENDED)), + PADDRH (msg_extended), + SCR_JUMP ^ IFTRUE (DATA (M_NOOP)), + PADDR (clrack), + SCR_JUMP ^ IFTRUE (DATA (M_REJECT)), + PADDRH (msg_reject), + SCR_JUMP ^ IFTRUE (DATA (M_IGN_RESIDUE)), + PADDRH (msg_ign_residue), + /* + ** Rest of the messages left as + ** an exercise ... + ** + ** Unimplemented messages: + ** fall through to MSG_BAD. + */ +}/*-------------------------< MSG_BAD >------------------*/,{ + /* + ** unimplemented message - reject it. + */ + SCR_INT, + SIR_REJECT_TO_SEND, + SCR_SET (SCR_ATN), + 0, + SCR_JUMP, + PADDR (clrack), + +}/*-------------------------< COMPLETE >-----------------*/,{ + /* + ** Complete message. + ** + ** Copy the data pointer to LASTP in header. + */ + SCR_STORE_REL (temp, 4), + offsetof (struct ccb, phys.header.lastp), + /* + ** When we terminate the cycle by clearing ACK, + ** the target may disconnect immediately. + ** + ** We don't want to be told of an + ** "unexpected disconnect", + ** so we disable this feature. + */ + SCR_REG_REG (scntl2, SCR_AND, 0x7f), + 0, + /* + ** Terminate cycle ... + */ + SCR_CLR (SCR_ACK|SCR_ATN), + 0, + /* + ** ... and wait for the disconnect. + */ + SCR_WAIT_DISC, + 0, +}/*-------------------------< COMPLETE2 >-----------------*/,{ + /* + ** Save host status to header. + */ + SCR_STORE_REL (scr0, 4), + offsetof (struct ccb, phys.header.status), + + /* + ** If command resulted in not GOOD status, + ** call the C code if needed. + */ + SCR_FROM_REG (SS_REG), + 0, + SCR_CALL ^ IFFALSE (DATA (S_GOOD)), + PADDRH (bad_status), + +}/*------------------------< DONE >-----------------*/,{ + /* + ** Copy the DSA to the DONE QUEUE and + ** signal completion to the host. + ** If we are interrupted between DONE + ** and DONE_END, we must reset, otherwise + ** the completed CCB will be lost. + */ + SCR_STORE_ABS (dsa, 4), + PADDR (saved_dsa), + SCR_LOAD_ABS (dsa, 4), + PADDR (done_pos), + SCR_LOAD_ABS (scratcha, 4), + PADDR(saved_dsa), + SCR_STORE_REL (scratcha, 4), + 0, + /* + ** The instruction below reads the DONE QUEUE next + ** free position from memory. + ** In addition it ensures that all PCI posted writes + ** are flushed and so the DSA value of the done + ** CCB is visible by the CPU before INTFLY is raised. + */ + SCR_LOAD_REL (temp, 4), + 4, + SCR_INT_FLY, + 0, + SCR_STORE_ABS (temp, 4), + PADDR (done_pos), +}/*------------------------< DONE_END >-----------------*/,{ + SCR_JUMP, + PADDR (start), + +}/*-------------------------< SAVE_DP >------------------*/,{ + /* + ** Clear ACK immediately. + ** No need to delay it. + */ + SCR_CLR (SCR_ACK), + 0, + /* + ** Keep track we received a SAVE DP, so + ** we will switch to the other PM context + ** on the next PM since the DP may point + ** to the current PM context. + */ + SCR_REG_REG (HF_REG, SCR_OR, HF_DP_SAVED), + 0, + /* + ** SAVE_DP message: + ** Copy the data pointer to SAVEP in header. + */ + SCR_STORE_REL (temp, 4), + offsetof (struct ccb, phys.header.savep), + SCR_JUMP, + PADDR (dispatch), +}/*-------------------------< RESTORE_DP >---------------*/,{ + /* + ** RESTORE_DP message: + ** Copy SAVEP in header to actual data pointer. + */ + SCR_LOAD_REL (temp, 4), + offsetof (struct ccb, phys.header.savep), + SCR_JUMP, + PADDR (clrack), + +}/*-------------------------< DISCONNECT >---------------*/,{ + /* + ** DISCONNECTing ... + ** + ** disable the "unexpected disconnect" feature, + ** and remove the ACK signal. + */ + SCR_REG_REG (scntl2, SCR_AND, 0x7f), + 0, + SCR_CLR (SCR_ACK|SCR_ATN), + 0, + /* + ** Wait for the disconnect. + */ + SCR_WAIT_DISC, + 0, +#ifdef SCSI_NCR_PROFILE_SUPPORT + /* + ** Count the disconnects. + ** Disconnect without DATA PHASE having been + ** entered are counted in bits 8..15. + */ + SCR_LOAD_REL (scratcha, 4), + offsetof (struct ccb, phys.num_disc), + SCR_FROM_REG (HF_REG), + 0, + SCR_JUMPR ^ IFTRUE (MASK (HF_DATA_ST, HF_DATA_ST)), + 8, + SCR_REG_REG (scratcha1, SCR_ADD, 0x01), + 0, + SCR_REG_REG (scratcha, SCR_ADD, 0x01), + 0, + SCR_STORE_REL (scratcha, 4), + offsetof (struct ccb, phys.num_disc), +#endif + /* + ** Status is: DISCONNECTED. + */ + SCR_LOAD_REG (HS_REG, HS_DISCONNECT), + 0, + /* + ** Save host status to header. + */ + SCR_STORE_REL (scr0, 4), + offsetof (struct ccb, phys.header.status), + /* + ** If QUIRK_AUTOSAVE is set, + ** do an "save pointer" operation. + */ + SCR_FROM_REG (QU_REG), + 0, + SCR_JUMP ^ IFFALSE (MASK (QUIRK_AUTOSAVE, QUIRK_AUTOSAVE)), + PADDR (start), + /* + ** like SAVE_DP message: + ** Remember we saved the data pointer. + ** Copy data pointer to SAVEP in header. + */ + SCR_REG_REG (HF_REG, SCR_OR, HF_DP_SAVED), + 0, + SCR_STORE_REL (temp, 4), + offsetof (struct ccb, phys.header.savep), + SCR_JUMP, + PADDR (start), + +}/*-------------------------< IDLE >------------------------*/,{ + /* + ** Nothing to do? + ** Wait for reselect. + ** This NOP will be patched with LED OFF + ** SCR_REG_REG (gpreg, SCR_OR, 0x01) + */ + SCR_NO_OP, + 0, +}/*-------------------------< UNGETJOB >-----------------*/,{ + /* + ** We are not able to restart the SCRIPTS if we are + ** interrupted and these instruction haven't been + ** all executed. BTW, this is very unlikely to + ** happen, but we check that from the C code. + */ + SCR_LOAD_REG (dsa, 0xff), + 0, + SCR_STORE_ABS (scratcha, 4), + PADDR (startpos), +}/*-------------------------< RESELECT >--------------------*/,{ + /* + ** make the host status invalid. + */ + SCR_CLR (SCR_TRG), + 0, + /* + ** Sleep waiting for a reselection. + ** If SIGP is set, special treatment. + ** + ** Zu allem bereit .. + */ + SCR_WAIT_RESEL, + PADDR(start), +}/*-------------------------< RESELECTED >------------------*/,{ + /* + ** This NOP will be patched with LED ON + ** SCR_REG_REG (gpreg, SCR_AND, 0xfe) + */ + SCR_NO_OP, + 0, + /* + ** load the target id into the sdid + */ + SCR_REG_SFBR (ssid, SCR_AND, 0x8F), + 0, + SCR_TO_REG (sdid), + 0, + /* + ** load the target control block address + */ + SCR_LOAD_ABS (dsa, 4), + PADDR (targtbl), + SCR_SFBR_REG (dsa, SCR_SHL, 0), + 0, + SCR_REG_REG (dsa, SCR_SHL, 0), + 0, + SCR_REG_REG (dsa, SCR_AND, 0x3c), + 0, + SCR_LOAD_REL (dsa, 4), + 0, + /* + ** Load the synchronous transfer registers. + */ + SCR_LOAD_REL (scntl3, 1), + offsetof(struct tcb, wval), + SCR_LOAD_REL (sxfer, 1), + offsetof(struct tcb, sval), + /* + ** If MESSAGE IN phase as expected, + ** read the data directly from the BUS DATA lines. + ** This helps to support very old SCSI devices that + ** may reselect without sending an IDENTIFY. + */ + SCR_INT ^ IFFALSE (WHEN (SCR_MSG_IN)), + SIR_RESEL_NO_MSG_IN, + SCR_FROM_REG (sbdl), + 0, + /* + ** If message phase but not an IDENTIFY, + ** get some help from the C code. + ** Old SCSI device may behave so. + */ + SCR_INT ^ IFFALSE (MASK (0x80, 0x80)), + SIR_RESEL_NO_IDENTIFY, + /* + ** It is an IDENTIFY message, + ** Load the LUN control block address. + ** Avoid nasty address calculation if LUN #0. + */ + SCR_LOAD_REL (dsa, 4), + offsetof(struct tcb, b_luntbl), + SCR_JUMPR ^ IFTRUE (MASK (0x0, 0x3f)), + 24, + SCR_SFBR_REG (dsa, SCR_SHL, 0), + 0, + SCR_REG_REG (dsa, SCR_SHL, 0), + 0, + SCR_REG_REG (dsa, SCR_AND, 0xfc), + 0, + SCR_LOAD_REL (dsa, 4), + 0, + /* + ** Load the reselect task action for this LUN. + ** Load the tasks DSA array for this LUN. + ** Call the action. + */ + SCR_LOAD_REL (temp, 4), + offsetof(struct lcb, resel_task), + SCR_LOAD_REL (dsa, 4), + offsetof(struct lcb, b_tasktbl), + SCR_RETURN, + 0, + +}/*-------------------------< RESEL_TAG >-------------------*/,{ + /* + ** Read IDENTIFY + SIMPLE + TAG using a single MOVE. + ** Agressive optimization, is'nt it? + ** No need to test the SIMPLE TAG message, since the + ** driver only supports conformant devices for tags. ;-) + */ + SCR_MOVE_ABS (3) ^ SCR_MSG_IN, + NADDR (msgin), + /* + ** Read the TAG from the SIDL. + ** Still an aggressive optimization. ;-) + ** Compute the CCB indirect jump address which + ** is (#TAG*2 & 0xfc) due to tag numbering using + ** 1,3,5..MAXTAGS*2+1 actual values. + */ + SCR_REG_SFBR (sidl, SCR_SHL, 0), + 0, + /* + ** Retrieve the DSA of this task. + ** JUMP indirectly to the restart point of the CCB. + */ + SCR_SFBR_REG (dsa, SCR_AND, 0xfc), + 0, +}/*-------------------------< RESEL_GO >-------------------*/,{ + SCR_LOAD_REL (dsa, 4), + 0, + SCR_LOAD_REL (temp, 4), + offsetof(struct ccb, phys.header.go.restart), + SCR_RETURN, + 0, +}/*-------------------------< RESEL_NOTAG >-------------------*/,{ + /* + ** No tag expected. + ** Read an throw away the IDENTIFY. + */ + SCR_MOVE_ABS (1) ^ SCR_MSG_IN, + NADDR (msgin), + /* + ** JUMP indirectly to the restart point of the CCB. + */ + SCR_JUMP, + PADDR (resel_go), + +}/*-------------------------< RESEL_DSA >-------------------*/,{ + /* + ** Ack the IDENTIFY or TAG previously received. + */ + SCR_CLR (SCR_ACK), + 0, + /* + ** load the savep (saved pointer) into + ** the actual data pointer. + */ + SCR_LOAD_REL (temp, 4), + offsetof (struct ccb, phys.header.savep), + /* + ** Initialize the status registers + */ + SCR_LOAD_REL (scr0, 4), + offsetof (struct ccb, phys.header.status), + /* + ** Jump to dispatcher. + */ + SCR_JUMP, + PADDR (dispatch), + +}/*-------------------------< DATA_IN >--------------------*/,{ +/* +** Because the size depends on the +** #define MAX_SCATTERL parameter, +** it is filled in at runtime. +** +** ##===========< i=0; i========= +** || SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_IN)), +** || PADDR (databreak), +** || SCR_MOVE_TBL ^ SCR_DATA_IN, +** || offsetof (struct dsb, data[ i]), +** ##========================================== +** +**--------------------------------------------------------- +*/ +0 +}/*-------------------------< DATA_IN2 >-------------------*/,{ + SCR_CALL, + PADDR (databreak), + SCR_JUMP, + PADDRH (no_data), +}/*-------------------------< DATA_OUT >--------------------*/,{ +/* +** Because the size depends on the +** #define MAX_SCATTERL parameter, +** it is filled in at runtime. +** +** ##===========< i=0; i========= +** || SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_OUT)), +** || PADDR (databreak), +** || SCR_MOVE_TBL ^ SCR_DATA_OUT, +** || offsetof (struct dsb, data[ i]), +** ##========================================== +** +**--------------------------------------------------------- +*/ +0 +}/*-------------------------< DATA_OUT2 >-------------------*/,{ + SCR_CALL, + PADDR (databreak), + SCR_JUMP, + PADDRH (no_data), + +}/*-------------------------< PM0_DATA >--------------------*/,{ + /* + ** Keep track we are executing the PM0 DATA + ** mini-script. + */ + SCR_REG_REG (HF_REG, SCR_OR, HF_IN_PM0), + 0, + /* + ** MOVE the data according to the actual + ** DATA direction. + */ + SCR_JUMPR ^ IFFALSE (WHEN (SCR_DATA_IN)), + 16, + SCR_MOVE_TBL ^ SCR_DATA_IN, + offsetof (struct ccb, phys.pm0.sg), + SCR_JUMPR, + 8, + SCR_MOVE_TBL ^ SCR_DATA_OUT, + offsetof (struct ccb, phys.pm0.sg), + /* + ** Clear the flag that told we were in + ** the PM0 DATA mini-script. + */ + SCR_REG_REG (HF_REG, SCR_AND, (~HF_IN_PM0)), + 0, + /* + ** Return to the previous DATA script which + ** is guaranteed by design (if no bug) to be + ** the main DATA script for this transfer. + */ + SCR_LOAD_REL (temp, 4), + offsetof (struct ccb, phys.pm0.ret), + SCR_RETURN, + 0, +}/*-------------------------< PM1_DATA >--------------------*/,{ + /* + ** Keep track we are executing the PM1 DATA + ** mini-script. + */ + SCR_REG_REG (HF_REG, SCR_OR, HF_IN_PM1), + 0, + /* + ** MOVE the data according to the actual + ** DATA direction. + */ + SCR_JUMPR ^ IFFALSE (WHEN (SCR_DATA_IN)), + 16, + SCR_MOVE_TBL ^ SCR_DATA_IN, + offsetof (struct ccb, phys.pm1.sg), + SCR_JUMPR, + 8, + SCR_MOVE_TBL ^ SCR_DATA_OUT, + offsetof (struct ccb, phys.pm1.sg), + /* + ** Clear the flag that told we were in + ** the PM1 DATA mini-script. + */ + SCR_REG_REG (HF_REG, SCR_AND, (~HF_IN_PM1)), + 0, + /* + ** Return to the previous DATA script which + ** is guaranteed by design (if no bug) to be + ** the main DATA script for this transfer. + */ + SCR_LOAD_REL (temp, 4), + offsetof (struct ccb, phys.pm1.ret), + SCR_RETURN, + 0, + +}/*-------------------------< SAVED_DSA >-------------------*/,{ + SCR_DATA_ZERO, +}/*-------------------------< DONE_POS >--------------------*/,{ + SCR_DATA_ZERO, +}/*-------------------------< STARTPOS >--------------------*/,{ + SCR_DATA_ZERO, +}/*-------------------------< TARGTBL >---------------------*/,{ + SCR_DATA_ZERO, +}/*--------------------------------------------------------*/ +}; + +static struct scripth scripth0 __initdata = { +/*------------------------< START64 >-----------------------*/{ + /* + ** SCRIPT entry point for the 896. + ** For now, there is no specific stuff for that + ** chip at this point, but this may come. + */ + SCR_JUMP, + PADDR (init), +}/*------------------------< SELECT_NO_ATN >-----------------*/,{ + /* + ** Set Initiator mode. + ** And try to select this target without ATN. + */ + + SCR_CLR (SCR_TRG), + 0, + SCR_SEL_TBL ^ offsetof (struct dsb, select), + PADDR (ungetjob), +}/*------------------------< WF_SEL_DONE_NO_ATN >-----------------*/,{ + /* + ** Wait immediately for the next phase or + ** the selection to complete or time-out. + */ + SCR_JUMPR ^ IFFALSE (WHEN (SCR_MSG_OUT)), + 0, + SCR_JUMP, + PADDR (select2), + +}/*-------------------------< CANCEL >------------------------*/,{ + /* + ** Load the host status. + */ + SCR_LOAD_REG (HS_REG, HS_ABORTED), + 0, + SCR_JUMP, + PADDR (complete2), + +}/*-------------------------< MSG_REJECT >---------------*/,{ + /* + ** If a negotiation was in progress, + ** negotiation failed. + ** Otherwise just make host log this message + */ + SCR_FROM_REG (HS_REG), + 0, + SCR_INT ^ IFFALSE (DATA (HS_NEGOTIATE)), + SIR_REJECT_RECEIVED, + SCR_INT ^ IFTRUE (DATA (HS_NEGOTIATE)), + SIR_NEGO_FAILED, + SCR_JUMP, + PADDR (clrack), + +}/*-------------------------< MSG_IGN_RESIDUE >----------*/,{ + /* + ** Terminate cycle + */ + SCR_CLR (SCR_ACK), + 0, + SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)), + PADDR (dispatch), + /* + ** get residue size. + */ + SCR_MOVE_ABS (1) ^ SCR_MSG_IN, + NADDR (msgin[1]), + /* + ** Size is 0 .. ignore message. + */ + SCR_JUMP ^ IFTRUE (DATA (0)), + PADDR (clrack), + /* + ** Size is not 1 .. have to interrupt. + */ + SCR_JUMPR ^ IFFALSE (DATA (1)), + 40, + /* + ** Check for residue byte in swide register + */ + SCR_FROM_REG (scntl2), + 0, + SCR_JUMPR ^ IFFALSE (MASK (WSR, WSR)), + 16, + /* + ** There IS data in the swide register. + ** Discard it. + */ + SCR_REG_REG (scntl2, SCR_OR, WSR), + 0, + SCR_JUMP, + PADDR (clrack), + /* + ** Load again the size to the sfbr register. + */ + SCR_FROM_REG (scratcha), + 0, + SCR_INT, + SIR_IGN_RESIDUE, + SCR_JUMP, + PADDR (clrack), + +}/*-------------------------< MSG_EXTENDED >-------------*/,{ + /* + ** Terminate cycle + */ + SCR_CLR (SCR_ACK), + 0, + SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)), + PADDR (dispatch), + /* + ** get length. + */ + SCR_MOVE_ABS (1) ^ SCR_MSG_IN, + NADDR (msgin[1]), + /* + */ + SCR_JUMP ^ IFTRUE (DATA (3)), + PADDRH (msg_ext_3), + SCR_JUMP ^ IFFALSE (DATA (2)), + PADDR (msg_bad), +}/*-------------------------< MSG_EXT_2 >----------------*/,{ + SCR_CLR (SCR_ACK), + 0, + SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)), + PADDR (dispatch), + /* + ** get extended message code. + */ + SCR_MOVE_ABS (1) ^ SCR_MSG_IN, + NADDR (msgin[2]), + SCR_JUMP ^ IFTRUE (DATA (M_X_WIDE_REQ)), + PADDRH (msg_wdtr), + /* + ** unknown extended message + */ + SCR_JUMP, + PADDR (msg_bad) +}/*-------------------------< MSG_WDTR >-----------------*/,{ + SCR_CLR (SCR_ACK), + 0, + SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)), + PADDR (dispatch), + /* + ** get data bus width + */ + SCR_MOVE_ABS (1) ^ SCR_MSG_IN, + NADDR (msgin[3]), + /* + ** let the host do the real work. + */ + SCR_INT, + SIR_NEGO_WIDE, + /* + ** let the target fetch our answer. + */ + SCR_SET (SCR_ATN), + 0, + SCR_CLR (SCR_ACK), + 0, + SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_OUT)), + PADDRH (nego_bad_phase), + +}/*-------------------------< SEND_WDTR >----------------*/,{ + /* + ** Send the M_X_WIDE_REQ + */ + SCR_MOVE_ABS (4) ^ SCR_MSG_OUT, + NADDR (msgout), + SCR_JUMP, + PADDRH (msg_out_done), + +}/*-------------------------< MSG_EXT_3 >----------------*/,{ + SCR_CLR (SCR_ACK), + 0, + SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)), + PADDR (dispatch), + /* + ** get extended message code. + */ + SCR_MOVE_ABS (1) ^ SCR_MSG_IN, + NADDR (msgin[2]), + SCR_JUMP ^ IFTRUE (DATA (M_X_SYNC_REQ)), + PADDRH (msg_sdtr), + /* + ** unknown extended message + */ + SCR_JUMP, + PADDR (msg_bad) + +}/*-------------------------< MSG_SDTR >-----------------*/,{ + SCR_CLR (SCR_ACK), + 0, + SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)), + PADDR (dispatch), + /* + ** get period and offset + */ + SCR_MOVE_ABS (2) ^ SCR_MSG_IN, + NADDR (msgin[3]), + /* + ** let the host do the real work. + */ + SCR_INT, + SIR_NEGO_SYNC, + /* + ** let the target fetch our answer. + */ + SCR_SET (SCR_ATN), + 0, + SCR_CLR (SCR_ACK), + 0, + SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_OUT)), + PADDRH (nego_bad_phase), + +}/*-------------------------< SEND_SDTR >-------------*/,{ + /* + ** Send the M_X_SYNC_REQ + */ + SCR_MOVE_ABS (5) ^ SCR_MSG_OUT, + NADDR (msgout), + SCR_JUMP, + PADDRH (msg_out_done), + +}/*-------------------------< NEGO_BAD_PHASE >------------*/,{ + SCR_INT, + SIR_NEGO_PROTO, + SCR_JUMP, + PADDR (dispatch), + +}/*-------------------------< MSG_OUT_ABORT >-------------*/,{ + /* + ** After ABORT message, + ** + ** expect an immediate disconnect, ... + */ + SCR_REG_REG (scntl2, SCR_AND, 0x7f), + 0, + SCR_CLR (SCR_ACK|SCR_ATN), + 0, + SCR_WAIT_DISC, + 0, + SCR_INT, + SIR_MSG_OUT_DONE, + /* + ** ... and set the status to "ABORTED" + */ + SCR_LOAD_REG (HS_REG, HS_ABORTED), + 0, + SCR_JUMP, + PADDR (complete2), + +}/*-------------------------< MSG_OUT >-------------------*/,{ + /* + ** The target requests a message. + */ + SCR_MOVE_ABS (1) ^ SCR_MSG_OUT, + NADDR (msgout), + /* + ** If it was no ABORT message ... + */ + SCR_JUMP ^ IFTRUE (DATA (M_ABORT)), + PADDRH (msg_out_abort), + /* + ** ... wait for the next phase + ** if it's a message out, send it again, ... + */ + SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_OUT)), + PADDRH (msg_out), +}/*-------------------------< MSG_OUT_DONE >--------------*/,{ + /* + ** ... else clear the message ... + */ + SCR_INT, + SIR_MSG_OUT_DONE, + /* + ** ... and process the next phase + */ + SCR_JUMP, + PADDR (dispatch), + +}/*-------------------------< NO_DATA >--------------------*/,{ + /* + ** The target wants to tranfer too much data + ** or in the wrong direction. + ** Remember that in extended error. + */ + SCR_LOAD_REG (scratcha, XE_EXTRA_DATA), + 0, + SCR_STORE_REL (scratcha, 1), + offsetof (struct ccb, xerr_status), + /* + ** Discard one data byte, if required. + */ + SCR_JUMPR ^ IFFALSE (WHEN (SCR_DATA_OUT)), + 8, + SCR_MOVE_ABS (1) ^ SCR_DATA_OUT, + NADDR (scratch), + SCR_JUMPR ^ IFFALSE (IF (SCR_DATA_IN)), + 8, + SCR_MOVE_ABS (1) ^ SCR_DATA_IN, + NADDR (scratch), + /* + ** .. and repeat as required. + */ + SCR_CALL, + PADDR (databreak), + SCR_JUMP, + PADDRH (no_data), + +#if MAX_SCATTERH != 0 + +}/*-------------------------< HDATA_IN >-------------------*/,{ +/* +** Because the size depends on the +** #define MAX_SCATTERH parameter, +** it is filled in at runtime. +** +** ##==< i=MAX_SCATTERL; i== +** || SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_IN)), +** || PADDR (databreak), +** || SCR_MOVE_TBL ^ SCR_DATA_IN, +** || offsetof (struct dsb, data[ i]), +** ##=================================================== +** +**--------------------------------------------------------- +*/ +0 +}/*-------------------------< HDATA_IN2 >------------------*/,{ + SCR_JUMP, + PADDR (data_in), + +}/*-------------------------< HDATA_OUT >-------------------*/,{ +/* +** Because the size depends on the +** #define MAX_SCATTERH parameter, +** it is filled in at runtime. +** +** ##==< i=MAX_SCATTERL; i== +** || SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_OUT)), +** || PADDR (databreak), +** || SCR_MOVE_TBL ^ SCR_DATA_OUT, +** || offsetof (struct dsb, data[ i]), +** ##=================================================== +** +**--------------------------------------------------------- +*/ +0 +}/*-------------------------< HDATA_OUT2 >------------------*/,{ + SCR_JUMP, + PADDR (data_out), + +#endif /* MAX_SCATTERH */ + +}/*-------------------------< ABORT_RESEL >----------------*/,{ + SCR_SET (SCR_ATN), + 0, + SCR_CLR (SCR_ACK), + 0, + /* + ** send the abort/abortag/reset message + ** we expect an immediate disconnect + */ + SCR_REG_REG (scntl2, SCR_AND, 0x7f), + 0, + SCR_MOVE_ABS (1) ^ SCR_MSG_OUT, + NADDR (msgout), + SCR_CLR (SCR_ACK|SCR_ATN), + 0, + SCR_WAIT_DISC, + 0, + SCR_INT, + SIR_RESEL_ABORTED, + SCR_JUMP, + PADDR (start), +}/*-------------------------< RESEND_IDENT >-------------------*/,{ + /* + ** The target stays in MSG OUT phase after having acked + ** Identify [+ Tag [+ Extended message ]]. Targets shall + ** behave this way on parity error. + ** We must send it again all the messages. + */ + SCR_SET (SCR_ATN), /* Shall be asserted 2 deskew delays before the */ + 0, /* 1rst ACK = 90 ns. Hope the NCR is'nt too fast */ + SCR_JUMP, + PADDR (send_ident), +}/*-------------------------< IDENT_BREAK >-------------------*/,{ + SCR_CLR (SCR_ATN), + 0, + SCR_JUMP, + PADDR (select2), +}/*-------------------------< IDENT_BREAK_ATN >----------------*/,{ + SCR_SET (SCR_ATN), + 0, + SCR_JUMP, + PADDR (select2), +}/*-------------------------< SDATA_IN >-------------------*/,{ + SCR_MOVE_TBL ^ SCR_DATA_IN, + offsetof (struct dsb, sense), + SCR_CALL, + PADDR (databreak), + SCR_JUMP, + PADDRH (no_data), + +}/*-------------------------< DATA_IO >--------------------*/,{ + /* + ** We jump here if the data direction was unknown at the + ** time we had to queue the command to the scripts processor. + ** Pointers had been set as follow in this situation: + ** savep --> DATA_IO + ** lastp --> start pointer when DATA_IN + ** goalp --> goal pointer when DATA_IN + ** wlastp --> start pointer when DATA_OUT + ** wgoalp --> goal pointer when DATA_OUT + ** This script sets savep/lastp/goalp according to the + ** direction chosen by the target. + */ + SCR_JUMP ^ IFTRUE (WHEN (SCR_DATA_OUT)), + PADDRH(data_io_out), +}/*-------------------------< DATA_IO_COM >-----------------*/,{ + /* + ** Direction is DATA IN. + ** Warning: we jump here, even when phase is DATA OUT. + */ + SCR_LOAD_REL (scratcha, 4), + offsetof (struct ccb, phys.header.lastp), + SCR_STORE_REL (scratcha, 4), + offsetof (struct ccb, phys.header.savep), + + /* + ** Jump to the SCRIPTS according to actual direction. + */ + SCR_LOAD_REL (temp, 4), + offsetof (struct ccb, phys.header.savep), + SCR_RETURN, + 0, +}/*-------------------------< DATA_IO_OUT >-----------------*/,{ + /* + ** Direction is DATA OUT. + */ + SCR_LOAD_REL (scratcha, 4), + offsetof (struct ccb, phys.header.wlastp), + SCR_STORE_REL (scratcha, 4), + offsetof (struct ccb, phys.header.lastp), + SCR_LOAD_REL (scratcha, 4), + offsetof (struct ccb, phys.header.wgoalp), + SCR_STORE_REL (scratcha, 4), + offsetof (struct ccb, phys.header.goalp), + SCR_JUMP, + PADDRH(data_io_com), + +}/*-------------------------< BAD_IDENTIFY >---------------*/,{ + /* + ** If message phase but not an IDENTIFY, + ** get some help from the C code. + ** Old SCSI device may behave so. + */ + SCR_JUMPR ^ IFTRUE (MASK (0x80, 0x80)), + 16, + SCR_INT, + SIR_RESEL_NO_IDENTIFY, + SCR_JUMP, + PADDRH (abort_resel), + /* + ** Message is an IDENTIFY, but lun is unknown. + ** Read the message, since we got it directly + ** from the SCSI BUS data lines. + ** Signal problem to C code for logging the event. + ** Send a M_ABORT to clear all pending tasks. + */ + SCR_INT, + SIR_RESEL_BAD_LUN, + SCR_MOVE_ABS (1) ^ SCR_MSG_IN, + NADDR (msgin), + SCR_JUMP, + PADDRH (abort_resel), +}/*-------------------------< BAD_I_T_L >------------------*/,{ + /* + ** We donnot have a task for that I_T_L. + ** Signal problem to C code for logging the event. + ** Send a M_ABORT message. + */ + SCR_INT, + SIR_RESEL_BAD_I_T_L, + SCR_JUMP, + PADDRH (abort_resel), +}/*-------------------------< BAD_I_T_L_Q >----------------*/,{ + /* + ** We donnot have a task that matches the tag. + ** Signal problem to C code for logging the event. + ** Send a M_ABORTTAG message. + */ + SCR_INT, + SIR_RESEL_BAD_I_T_L_Q, + SCR_JUMP, + PADDRH (abort_resel), +}/*-------------------------< BAD_STATUS >-----------------*/,{ + /* + ** If command resulted in either QUEUE FULL, + ** CHECK CONDITION or COMMAND TERMINATED, + ** call the C code. + */ + SCR_LOAD_ABS (scratcha, 4), + PADDR (startpos), + SCR_INT ^ IFTRUE (DATA (S_QUEUE_FULL)), + SIR_BAD_STATUS, + SCR_INT ^ IFTRUE (DATA (S_CHECK_COND)), + SIR_BAD_STATUS, + SCR_INT ^ IFTRUE (DATA (S_TERMINATED)), + SIR_BAD_STATUS, + SCR_RETURN, + 0, + +}/*-------------------------< TWEAK_PMJ >------------------*/,{ + /* + ** Disable PM handling from SCRIPTS for the data phase + ** and so force PM to be handled from C code if HF_PM_TO_C + ** flag is set. + */ + SCR_FROM_REG(HF_REG), + 0, + SCR_JUMPR ^ IFTRUE (MASK (HF_PM_TO_C, HF_PM_TO_C)), + 16, + SCR_REG_REG (ccntl0, SCR_OR, ENPMJ), + 0, + SCR_RETURN, + 0, + SCR_REG_REG (ccntl0, SCR_AND, (~ENPMJ)), + 0, + SCR_RETURN, + 0, + +}/*-------------------------< PM_HANDLE >------------------*/,{ + /* + ** Phase mismatch handling. + ** + ** Since we have to deal with 2 SCSI data pointers + ** (current and saved), we need at least 2 contexts. + ** Each context (pm0 and pm1) has a saved area, a + ** SAVE mini-script and a DATA phase mini-script. + */ + /* + ** Get the PM handling flags. + */ + SCR_FROM_REG (HF_REG), + 0, + /* + ** If no flags (1rst PM for example), avoid + ** all the below heavy flags testing. + ** This makes the normal case a bit faster. + */ + SCR_JUMP ^ IFTRUE (MASK (0, (HF_IN_PM0 | HF_IN_PM1 | HF_DP_SAVED))), + PADDRH (pm_handle1), + /* + ** If we received a SAVE DP, switch to the + ** other PM context since the savep may point + ** to the current PM context. + */ + SCR_JUMPR ^ IFFALSE (MASK (HF_DP_SAVED, HF_DP_SAVED)), + 8, + SCR_REG_REG (sfbr, SCR_XOR, HF_ACT_PM), + 0, + /* + ** If we have been interrupt in a PM DATA mini-script, + ** we take the return address from the corresponding + ** saved area. + ** This ensure the return address always points to the + ** main DATA script for this transfer. + */ + SCR_JUMP ^ IFTRUE (MASK (0, (HF_IN_PM0 | HF_IN_PM1))), + PADDRH (pm_handle1), + SCR_JUMPR ^ IFFALSE (MASK (HF_IN_PM0, HF_IN_PM0)), + 16, + SCR_LOAD_REL (ia, 4), + offsetof(struct ccb, phys.pm0.ret), + SCR_JUMP, + PADDRH (pm_save), + SCR_LOAD_REL (ia, 4), + offsetof(struct ccb, phys.pm1.ret), + SCR_JUMP, + PADDRH (pm_save), +}/*-------------------------< PM_HANDLE1 >-----------------*/,{ + /* + ** Normal case. + ** Update the return address so that it + ** will point after the interrupted MOVE. + */ + SCR_REG_REG (ia, SCR_ADD, 8), + 0, + SCR_REG_REG (ia1, SCR_ADDC, 0), + 0, +}/*-------------------------< PM_SAVE >--------------------*/,{ + /* + ** Clear all the flags that told us if we were + ** interrupted in a PM DATA mini-script and/or + ** we received a SAVE DP. + */ + SCR_SFBR_REG (HF_REG, SCR_AND, (~(HF_IN_PM0|HF_IN_PM1|HF_DP_SAVED))), + 0, + /* + ** Choose the current PM context. + */ + SCR_JUMP ^ IFTRUE (MASK (HF_ACT_PM, HF_ACT_PM)), + PADDRH (pm1_save), +}/*-------------------------< PM0_SAVE >-------------------*/,{ + /* + ** Save the remaining byte count, the updated + ** address and the return address. + */ + SCR_STORE_REL (rbc, 4), + offsetof(struct ccb, phys.pm0.sg.size), + SCR_STORE_REL (ua, 4), + offsetof(struct ccb, phys.pm0.sg.addr), + SCR_STORE_REL (ia, 4), + offsetof(struct ccb, phys.pm0.ret), + /* + ** Set the current pointer at the PM0 DATA mini-script. + */ + SCR_LOAD_ABS (temp, 4), + PADDRH (pm0_data_addr), + SCR_JUMP, + PADDR (databreak), +}/*-------------------------< PM1_SAVE >-------------------*/,{ + /* + ** Save the remaining byte count, the updated + ** address and the return address. + */ + SCR_STORE_REL (rbc, 4), + offsetof(struct ccb, phys.pm1.sg.size), + SCR_STORE_REL (ua, 4), + offsetof(struct ccb, phys.pm1.sg.addr), + SCR_STORE_REL (ia, 4), + offsetof(struct ccb, phys.pm1.ret), + /* + ** Set the current pointer at the PM1 DATA mini-script. + */ + SCR_LOAD_ABS (temp, 4), + PADDRH (pm1_data_addr), + SCR_JUMP, + PADDR (databreak), +}/*-------------------------< PM0_DATA_ADDR >---------------*/,{ + SCR_DATA_ZERO, +}/*-------------------------< PM1_DATA_ADDR >---------------*/,{ + SCR_DATA_ZERO, +}/*-------------------------< START_RAM >-------------------*/,{ + /* + ** Load the script into on-chip RAM, + ** and jump to start point. + */ + SCR_COPY (sizeof (struct script)), +}/*-------------------------< SCRIPT0_BA >--------------------*/,{ + 0, + PADDR (start), + SCR_JUMP, + PADDR (init), + +}/*-------------------------< START_RAM64 >--------------------*/,{ + /* + ** Load the RAM and start for 64 bit PCI (896). + ** Both scripts (script and scripth) are loaded into + ** the RAM which is 8K (4K for 825A/875/895). + ** We also need to load some 32-63 bit segments + ** address of the SCRIPTS processor. + ** LOAD/STORE ABSOLUTE always refers to on-chip RAM + ** in our implementation. The main memory is + ** accessed using LOAD/STORE DSA RELATIVE. + */ + SCR_LOAD_REL (mmws, 4), + offsetof (struct ncb, scr_ram_seg), + SCR_COPY (sizeof(struct script)), +}/*-------------------------< SCRIPT0_BA64 >--------------------*/,{ + 0, + PADDR (start), + SCR_COPY (sizeof(struct scripth)), +}/*-------------------------< SCRIPTH0_BA64 >--------------------*/,{ + 0, + PADDRH (start64), + SCR_LOAD_REL (mmrs, 4), + offsetof (struct ncb, scr_ram_seg), + SCR_JUMP64, + PADDRH (start64), +}/*-------------------------< RAM_SEG64 >--------------------*/,{ + 0, +}/*-------------------------< SNOOPTEST >-------------------*/,{ + /* + ** Read the variable. + */ + SCR_LOAD_REL (scratcha, 4), + offsetof(struct ncb, ncr_cache), + SCR_STORE_REL (temp, 4), + offsetof(struct ncb, ncr_cache), + SCR_LOAD_REL (temp, 4), + offsetof(struct ncb, ncr_cache), +}/*-------------------------< SNOOPEND >-------------------*/,{ + /* + ** And stop. + */ + SCR_INT, + 99, +}/*--------------------------------------------------------*/ +}; + +/*========================================================== +** +** +** Fill in #define dependent parts of the script +** +** +**========================================================== +*/ + +__initfunc( +void ncr_script_fill (struct script * scr, struct scripth * scrh) +) +{ + int i; + ncrcmd *p; + +#if MAX_SCATTERH != 0 + p = scrh->hdata_in; + for (i=0; ihdata_in + sizeof (scrh->hdata_in)); +#endif + + p = scr->data_in; + for (i=MAX_SCATTERH; idata_in + sizeof (scr->data_in)); + +#if MAX_SCATTERH != 0 + p = scrh->hdata_out; + for (i=0; ihdata_out + sizeof (scrh->hdata_out)); +#endif + + p = scr->data_out; + for (i=MAX_SCATTERH; idata_out + sizeof (scr->data_out)); +} + +/*========================================================== +** +** +** Copy and rebind a script. +** +** +**========================================================== +*/ + +__initfunc( +static void ncr_script_copy_and_bind (ncb_p np,ncrcmd *src,ncrcmd *dst,int len) +) +{ + ncrcmd opcode, new, old, tmp1, tmp2; + ncrcmd *start, *end; + int relocs; + int opchanged = 0; + + start = src; + end = src + len/4; + + while (src < end) { + + opcode = *src++; + *dst++ = cpu_to_scr(opcode); + + /* + ** If we forget to change the length + ** in struct script, a field will be + ** padded with 0. This is an illegal + ** command. + */ + + if (opcode == 0) { + printk (KERN_INFO "%s: ERROR0 IN SCRIPT at %d.\n", + ncr_name(np), (int) (src-start-1)); + MDELAY (10000); + continue; + }; + + /* + ** We use the bogus value 0xf00ff00f ;-) + ** to reserve data area in SCRIPTS. + */ + if (opcode == SCR_DATA_ZERO) { + dst[-1] = 0; + continue; + } + + if (DEBUG_FLAGS & DEBUG_SCRIPT) + printk (KERN_INFO "%p: <%x>\n", + (src-1), (unsigned)opcode); + + /* + ** We don't have to decode ALL commands + */ + switch (opcode >> 28) { + + case 0xf: + /* + ** LOAD / STORE DSA relative, don't relocate. + */ + relocs = 0; + break; + case 0xe: + /* + ** LOAD / STORE absolute. + */ + relocs = 1; + break; + case 0xc: + /* + ** COPY has TWO arguments. + */ + relocs = 2; + tmp1 = src[0]; + tmp2 = src[1]; +#ifdef RELOC_KVAR + if ((tmp1 & RELOC_MASK) == RELOC_KVAR) + tmp1 = 0; + if ((tmp2 & RELOC_MASK) == RELOC_KVAR) + tmp2 = 0; +#endif + if ((tmp1 ^ tmp2) & 3) { + printk (KERN_ERR"%s: ERROR1 IN SCRIPT at %d.\n", + ncr_name(np), (int) (src-start-1)); + MDELAY (1000); + } + /* + ** If PREFETCH feature not enabled, remove + ** the NO FLUSH bit if present. + */ + if ((opcode & SCR_NO_FLUSH) && + !(np->features & FE_PFEN)) { + dst[-1] = cpu_to_scr(opcode & ~SCR_NO_FLUSH); + ++opchanged; + } + break; + + case 0x0: + /* + ** MOVE (absolute address) + */ + relocs = 1; + break; + + case 0x8: + /* + ** JUMP / CALL + ** dont't relocate if relative :-) + */ + if (opcode & 0x00800000) + relocs = 0; + else if ((opcode & 0xf8400000) == 0x80400000)/*JUMP64*/ + relocs = 2; + else + relocs = 1; + break; + + case 0x4: + case 0x5: + case 0x6: + case 0x7: + relocs = 1; + break; + + default: + relocs = 0; + break; + }; + + if (!relocs) { + *dst++ = cpu_to_scr(*src++); + continue; + } + while (relocs--) { + old = *src++; + + switch (old & RELOC_MASK) { + case RELOC_REGISTER: + new = (old & ~RELOC_MASK) + pcivtobus(np->base_ba); + break; + case RELOC_LABEL: + new = (old & ~RELOC_MASK) + np->p_script; + break; + case RELOC_LABELH: + new = (old & ~RELOC_MASK) + np->p_scripth; + break; + case RELOC_SOFTC: + new = (old & ~RELOC_MASK) + vtobus(np); + break; +#ifdef RELOC_KVAR + case RELOC_KVAR: + if (((old & ~RELOC_MASK) < SCRIPT_KVAR_FIRST) || + ((old & ~RELOC_MASK) > SCRIPT_KVAR_LAST)) + panic("ncr KVAR out of range"); + new = vtobus(script_kvars[old & ~RELOC_MASK]); +#endif + break; + case 0: + /* Don't relocate a 0 address. */ + if (old == 0) { + new = old; + break; + } + /* fall through */ + default: + panic("ncr_script_copy_and_bind: " + "weird relocation %x\n", old); + break; + } + + *dst++ = cpu_to_scr(new); + } + }; +} + +/*========================================================== +** +** +** Auto configuration: attach and init a host adapter. +** +** +**========================================================== +*/ + +/* +** Linux host data structure. +*/ + +struct host_data { + struct ncb *ncb; +}; + +/* +** Print something which allows to retrieve the controler type, unit, +** target, lun concerned by a kernel message. +*/ + +static void PRINT_TARGET(ncb_p np, int target) +{ + printk(KERN_INFO "%s-<%d,*>: ", ncr_name(np), target); +} + +static void PRINT_LUN(ncb_p np, int target, int lun) +{ + printk(KERN_INFO "%s-<%d,%d>: ", ncr_name(np), target, lun); +} + +static void PRINT_ADDR(Scsi_Cmnd *cmd) +{ + struct host_data *host_data = (struct host_data *) cmd->host->hostdata; + PRINT_LUN(host_data->ncb, cmd->target, cmd->lun); +} + +/*========================================================== +** +** NCR chip clock divisor table. +** Divisors are multiplied by 10,000,000 in order to make +** calculations more simple. +** +**========================================================== +*/ + +#define _5M 5000000 +static u_long div_10M[] = + {2*_5M, 3*_5M, 4*_5M, 6*_5M, 8*_5M, 12*_5M, 16*_5M}; + + +/*=============================================================== +** +** Prepare io register values used by ncr_init() according +** to selected and supported features. +** +** NCR chips allow burst lengths of 2, 4, 8, 16, 32, 64, 128 +** transfers. 32,64,128 are only supported by 825A, 875, 895 +** and 896 chips. +** We use log base 2 (burst length) as internal code, with +** value 0 meaning "burst disabled". +** +**=============================================================== +*/ + +/* + * Burst length from burst code. + */ +#define burst_length(bc) (!(bc))? 0 : 1 << (bc) + +/* + * Burst code from io register bits. + */ +#define burst_code(dmode, ctest4, ctest5) \ + (ctest4) & 0x80? 0 : (((dmode) & 0xc0) >> 6) + ((ctest5) & 0x04) + 1 + +/* + * Set initial io register bits from burst code. + */ +static inline void ncr_init_burst(ncb_p np, u_char bc) +{ + np->rv_ctest4 &= ~0x80; + np->rv_dmode &= ~(0x3 << 6); + np->rv_ctest5 &= ~0x4; + + if (!bc) { + np->rv_ctest4 |= 0x80; + } + else { + --bc; + np->rv_dmode |= ((bc & 0x3) << 6); + np->rv_ctest5 |= (bc & 0x4); + } +} + +#ifdef SCSI_NCR_NVRAM_SUPPORT + +/* +** Get target set-up from Symbios format NVRAM. +*/ + +__initfunc( +static void + ncr_Symbios_setup_target(ncb_p np, int target, Symbios_nvram *nvram) +) +{ + tcb_p tp = &np->target[target]; + Symbios_target *tn = &nvram->target[target]; + + tp->usrsync = tn->sync_period ? (tn->sync_period + 3) / 4 : 255; + tp->usrwide = tn->bus_width == 0x10 ? 1 : 0; + tp->usrtags = + (tn->flags & SYMBIOS_QUEUE_TAGS_ENABLED)? SCSI_NCR_MAX_TAGS : 0; + + if (!(tn->flags & SYMBIOS_DISCONNECT_ENABLE)) + tp->usrflag |= UF_NODISC; + if (!(tn->flags & SYMBIOS_SCAN_AT_BOOT_TIME)) + tp->usrflag |= UF_NOSCAN; +} + +/* +** Get target set-up from Tekram format NVRAM. +*/ + +__initfunc( +static void + ncr_Tekram_setup_target(ncb_p np, int target, Tekram_nvram *nvram) +) +{ + tcb_p tp = &np->target[target]; + struct Tekram_target *tn = &nvram->target[target]; + int i; + + if (tn->flags & TEKRAM_SYNC_NEGO) { + i = tn->sync_index & 0xf; + tp->usrsync = i < 12 ? Tekram_sync[i] : 255; + } + + tp->usrwide = (tn->flags & TEKRAM_WIDE_NEGO) ? 1 : 0; + + if (tn->flags & TEKRAM_TAGGED_COMMANDS) { + tp->usrtags = 2 << nvram->max_tags_index; + } + + if (!(tn->flags & TEKRAM_DISCONNECT_ENABLE)) + tp->usrflag = UF_NODISC; + + /* If any device does not support parity, we will not use this option */ + if (!(tn->flags & TEKRAM_PARITY_CHECK)) + np->rv_scntl0 &= ~0x0a; /* SCSI parity checking disabled */ +} +#endif /* SCSI_NCR_NVRAM_SUPPORT */ + +__initfunc( +static int ncr_prepare_setting(ncb_p np, ncr_nvram *nvram) +) +{ + u_char burst_max; + u_long period; + int i; + + /* + ** Save assumed BIOS setting + */ + + np->sv_scntl0 = INB(nc_scntl0) & 0x0a; + np->sv_scntl3 = INB(nc_scntl3) & 0x07; + np->sv_dmode = INB(nc_dmode) & 0xce; + np->sv_dcntl = INB(nc_dcntl) & 0xa8; + np->sv_ctest3 = INB(nc_ctest3) & 0x01; + np->sv_ctest4 = INB(nc_ctest4) & 0x80; + np->sv_ctest5 = INB(nc_ctest5) & 0x24; + np->sv_gpcntl = INB(nc_gpcntl); + np->sv_stest2 = INB(nc_stest2) & 0x20; + np->sv_stest4 = INB(nc_stest4); + + /* + ** Wide ? + */ + + np->maxwide = (np->features & FE_WIDE)? 1 : 0; + + /* + ** Get the frequency of the chip's clock. + ** Find the right value for scntl3. + */ + + if (np->features & FE_QUAD) + np->multiplier = 4; + else if (np->features & FE_DBLR) + np->multiplier = 2; + else + np->multiplier = 1; + + np->clock_khz = (np->features & FE_CLK80)? 80000 : 40000; + np->clock_khz *= np->multiplier; + + if (np->clock_khz != 40000) + ncr_getclock(np, np->multiplier); + + /* + * Divisor to be used for async (timer pre-scaler). + */ + i = np->clock_divn - 1; + while (--i >= 0) { + if (10ul * SCSI_NCR_MIN_ASYNC * np->clock_khz > div_10M[i]) { + ++i; + break; + } + } + np->rv_scntl3 = i+1; + + /* + * Minimum synchronous period factor supported by the chip. + * Btw, 'period' is in tenths of nanoseconds. + */ + + period = (4 * div_10M[0] + np->clock_khz - 1) / np->clock_khz; + if (period <= 250) np->minsync = 10; + else if (period <= 303) np->minsync = 11; + else if (period <= 500) np->minsync = 12; + else np->minsync = (period + 40 - 1) / 40; + + /* + * Check against chip SCSI standard support (SCSI-2,ULTRA,ULTRA2). + */ + + if (np->minsync < 25 && !(np->features & (FE_ULTRA|FE_ULTRA2))) + np->minsync = 25; + else if (np->minsync < 12 && !(np->features & FE_ULTRA2)) + np->minsync = 12; + + /* + * Maximum synchronous period factor supported by the chip. + */ + + period = (11 * div_10M[np->clock_divn - 1]) / (4 * np->clock_khz); + np->maxsync = period > 2540 ? 254 : period / 10; + + /* + ** 64 bit (53C896) ? + */ + if (np->features & FE_64BIT) +#if BITS_PER_LONG > 32 + np->rv_ccntl1 |= (XTIMOD | EXTIBMV); +#else + np->rv_ccntl1 |= (DDAC); +#endif + + /* + ** Phase mismatch handled by SCRIPTS (53C896) ? + */ + if (np->features & FE_NOPM) + np->rv_ccntl0 |= (ENPMJ); + + /* + ** Prepare initial value of other IO registers + */ +#if defined SCSI_NCR_TRUST_BIOS_SETTING + np->rv_scntl0 = np->sv_scntl0; + np->rv_dmode = np->sv_dmode; + np->rv_dcntl = np->sv_dcntl; + np->rv_ctest3 = np->sv_ctest3; + np->rv_ctest4 = np->sv_ctest4; + np->rv_ctest5 = np->sv_ctest5; + burst_max = burst_code(np->sv_dmode, np->sv_ctest4, np->sv_ctest5); +#else + + /* + ** Select burst length (dwords) + */ + burst_max = driver_setup.burst_max; + if (burst_max == 255) + burst_max = burst_code(np->sv_dmode, np->sv_ctest4, np->sv_ctest5); + if (burst_max > 7) + burst_max = 7; + if (burst_max > np->maxburst) + burst_max = np->maxburst; + + /* + ** DEL 352 - 53C810 Rev x11 - Part Number 609-0392140 - ITEM 2. + ** This chip and the 860 Rev 1 may wrongly use PCI cache line + ** based transactions on LOAD/STORE instructions. So we have + ** to prevent these chips from using such PCI transactions in + ** this driver. The generic sym53c8xx driver that does not use + ** LOAD/STORE instructions does not need this work-around. + */ + if ((np->device_id == PCI_DEVICE_ID_NCR_53C810 && + np->revision_id >= 0x10 && np->revision_id <= 0x11) || + (np->device_id == PCI_DEVICE_ID_NCR_53C860 && + np->revision_id <= 0x1)) + np->features &= ~(FE_WRIE|FE_ERL|FE_ERMP); + + /* + ** Select all supported special features. + ** If we are using on-board RAM for scripts, prefetch (PFEN) + ** does not help, but burst op fetch (BOF) does. + ** Disabling PFEN makes sure BOF will be used. + */ + if (np->features & FE_ERL) + np->rv_dmode |= ERL; /* Enable Read Line */ + if (np->features & FE_BOF) + np->rv_dmode |= BOF; /* Burst Opcode Fetch */ + if (np->features & FE_ERMP) + np->rv_dmode |= ERMP; /* Enable Read Multiple */ +#ifdef SCSI_NCR_OPTIMIZE_896 + if ((np->features & FE_PFEN) && !np->base2_ba) +#else + if (np->features & FE_PFEN) +#endif + np->rv_dcntl |= PFEN; /* Prefetch Enable */ + if (np->features & FE_CLSE) + np->rv_dcntl |= CLSE; /* Cache Line Size Enable */ + if (np->features & FE_WRIE) + np->rv_ctest3 |= WRIE; /* Write and Invalidate */ + if (np->features & FE_DFS) + np->rv_ctest5 |= DFS; /* Dma Fifo Size */ + + /* + ** Select some other + */ + if (driver_setup.master_parity) + np->rv_ctest4 |= MPEE; /* Master parity checking */ + if (driver_setup.scsi_parity) + np->rv_scntl0 |= 0x0a; /* full arb., ena parity, par->ATN */ + +#ifdef SCSI_NCR_NVRAM_SUPPORT + /* + ** Get parity checking, host ID and verbose mode from NVRAM + **/ + if (nvram) { + switch(nvram->type) { + case SCSI_NCR_TEKRAM_NVRAM: + np->myaddr = nvram->data.Tekram.host_id & 0x0f; + break; + case SCSI_NCR_SYMBIOS_NVRAM: + if (!(nvram->data.Symbios.flags & SYMBIOS_PARITY_ENABLE)) + np->rv_scntl0 &= ~0x0a; + np->myaddr = nvram->data.Symbios.host_id & 0x0f; + if (nvram->data.Symbios.flags & SYMBIOS_VERBOSE_MSGS) + np->verbose += 1; + break; + } + } +#endif + /* + ** Get SCSI addr of host adapter (set by bios?). + */ + if (np->myaddr == 255) { + np->myaddr = INB(nc_scid) & 0x07; + if (!np->myaddr) + np->myaddr = SCSI_NCR_MYADDR; + } + +#endif /* SCSI_NCR_TRUST_BIOS_SETTING */ + + /* + * Prepare initial io register bits for burst length + */ + ncr_init_burst(np, burst_max); + + /* + ** Set differential mode and LED support. + ** Ignore these features for boards known to use a + ** specific GPIO wiring (Tekram only for now) and + ** for the 896 that drives the LED directly. + ** Probe initial setting of GPREG and GPCNTL for + ** other ones. + */ + if (!nvram || nvram->type != SCSI_NCR_TEKRAM_NVRAM) { + switch(driver_setup.diff_support) { + case 3: + if (INB(nc_gpreg) & 0x08) + break; + case 2: + np->rv_stest2 |= 0x20; + break; + case 1: + np->rv_stest2 |= (np->sv_stest2 & 0x20); + break; + default: + break; + } + } + if ((driver_setup.led_pin || + (nvram && nvram->type == SCSI_NCR_SYMBIOS_NVRAM)) && + !(np->features & FE_LEDC) && !(np->sv_gpcntl & 0x01)) + np->features |= FE_LED0; + + /* + ** Set irq mode. + */ + switch(driver_setup.irqm & 3) { + case 2: + np->rv_dcntl |= IRQM; + break; + case 1: + np->rv_dcntl |= (np->sv_dcntl & IRQM); + break; + default: + break; + } + + /* + ** Configure targets according to driver setup. + ** If NVRAM present get targets setup from NVRAM. + ** Allow to override sync, wide and NOSCAN from + ** boot command line. + */ + for (i = 0 ; i < MAX_TARGET ; i++) { + tcb_p tp = &np->target[i]; + + tp->usrsync = 255; +#ifdef SCSI_NCR_NVRAM_SUPPORT + if (nvram) { + switch(nvram->type) { + case SCSI_NCR_TEKRAM_NVRAM: + ncr_Tekram_setup_target(np, i, &nvram->data.Tekram); + break; + case SCSI_NCR_SYMBIOS_NVRAM: + ncr_Symbios_setup_target(np, i, &nvram->data.Symbios); + break; + } + if (driver_setup.use_nvram & 0x2) + tp->usrsync = driver_setup.default_sync; + if (driver_setup.use_nvram & 0x4) + tp->usrwide = driver_setup.max_wide; + if (driver_setup.use_nvram & 0x8) + tp->usrflag &= ~UF_NOSCAN; + } + else { +#else + if (1) { +#endif + tp->usrsync = driver_setup.default_sync; + tp->usrwide = driver_setup.max_wide; + tp->usrtags = SCSI_NCR_MAX_TAGS; + if (!driver_setup.disconnection) + np->target[i].usrflag = UF_NODISC; + } + } + + /* + ** Announce all that stuff to user. + */ + + i = nvram ? nvram->type : 0; + printk(KERN_INFO "%s: %sID %d, Fast-%d%s%s\n", ncr_name(np), + i == SCSI_NCR_SYMBIOS_NVRAM ? "Symbios format NVRAM, " : + (i == SCSI_NCR_TEKRAM_NVRAM ? "Tekram format NVRAM, " : ""), + np->myaddr, + np->minsync < 12 ? 40 : (np->minsync < 25 ? 20 : 10), + (np->rv_scntl0 & 0xa) ? ", Parity Checking" : ", NO Parity", + (np->rv_stest2 & 0x20) ? ", Differential" : ""); + + if (bootverbose > 1) { + printk (KERN_INFO "%s: initial SCNTL3/DMODE/DCNTL/CTEST3/4/5 = " + "(hex) %02x/%02x/%02x/%02x/%02x/%02x\n", + ncr_name(np), np->sv_scntl3, np->sv_dmode, np->sv_dcntl, + np->sv_ctest3, np->sv_ctest4, np->sv_ctest5); + + printk (KERN_INFO "%s: final SCNTL3/DMODE/DCNTL/CTEST3/4/5 = " + "(hex) %02x/%02x/%02x/%02x/%02x/%02x\n", + ncr_name(np), np->rv_scntl3, np->rv_dmode, np->rv_dcntl, + np->rv_ctest3, np->rv_ctest4, np->rv_ctest5); + } + + if (bootverbose && np->base2_ba) + printk (KERN_INFO "%s: on-chip RAM at 0x%lx\n", + ncr_name(np), np->base2_ba); + + return 0; +} + + +#ifdef SCSI_NCR_DEBUG_NVRAM + +__initfunc( +void ncr_display_Symbios_nvram(ncb_p np, Symbios_nvram *nvram) +) +{ + int i; + + /* display Symbios nvram host data */ + printk(KERN_DEBUG "%s: HOST ID=%d%s%s%s%s%s\n", + ncr_name(np), nvram->host_id & 0x0f, + (nvram->flags & SYMBIOS_SCAM_ENABLE) ? " SCAM" :"", + (nvram->flags & SYMBIOS_PARITY_ENABLE) ? " PARITY" :"", + (nvram->flags & SYMBIOS_VERBOSE_MSGS) ? " VERBOSE" :"", + (nvram->flags & SYMBIOS_CHS_MAPPING) ? " CHS_ALT" :"", + (nvram->flags1 & SYMBIOS_SCAN_HI_LO) ? " HI_LO" :""); + + /* display Symbios nvram drive data */ + for (i = 0 ; i < 15 ; i++) { + struct Symbios_target *tn = &nvram->target[i]; + printk(KERN_DEBUG "%s-%d:%s%s%s%s WIDTH=%d SYNC=%d TMO=%d\n", + ncr_name(np), i, + (tn->flags & SYMBIOS_DISCONNECT_ENABLE) ? " DISC" : "", + (tn->flags & SYMBIOS_SCAN_AT_BOOT_TIME) ? " SCAN_BOOT" : "", + (tn->flags & SYMBIOS_SCAN_LUNS) ? " SCAN_LUNS" : "", + (tn->flags & SYMBIOS_QUEUE_TAGS_ENABLED)? " TCQ" : "", + tn->bus_width, + tn->sync_period / 4, + tn->timeout); + } +} + +static u_char Tekram_boot_delay[7] __initdata = {3, 5, 10, 20, 30, 60, 120}; + +__initfunc( +void ncr_display_Tekram_nvram(ncb_p np, Tekram_nvram *nvram) +) +{ + int i, tags, boot_delay; + char *rem; + + /* display Tekram nvram host data */ + tags = 2 << nvram->max_tags_index; + boot_delay = 0; + if (nvram->boot_delay_index < 6) + boot_delay = Tekram_boot_delay[nvram->boot_delay_index]; + switch((nvram->flags & TEKRAM_REMOVABLE_FLAGS) >> 6) { + default: + case 0: rem = ""; break; + case 1: rem = " REMOVABLE=boot device"; break; + case 2: rem = " REMOVABLE=all"; break; + } + + printk(KERN_DEBUG + "%s: HOST ID=%d%s%s%s%s%s%s%s%s%s BOOT DELAY=%d tags=%d\n", + ncr_name(np), nvram->host_id & 0x0f, + (nvram->flags1 & SYMBIOS_SCAM_ENABLE) ? " SCAM" :"", + (nvram->flags & TEKRAM_MORE_THAN_2_DRIVES) ? " >2DRIVES" :"", + (nvram->flags & TEKRAM_DRIVES_SUP_1GB) ? " >1GB" :"", + (nvram->flags & TEKRAM_RESET_ON_POWER_ON) ? " RESET" :"", + (nvram->flags & TEKRAM_ACTIVE_NEGATION) ? " ACT_NEG" :"", + (nvram->flags & TEKRAM_IMMEDIATE_SEEK) ? " IMM_SEEK" :"", + (nvram->flags & TEKRAM_SCAN_LUNS) ? " SCAN_LUNS" :"", + (nvram->flags1 & TEKRAM_F2_F6_ENABLED) ? " F2_F6" :"", + rem, boot_delay, tags); + + /* display Tekram nvram drive data */ + for (i = 0; i <= 15; i++) { + int sync, j; + struct Tekram_target *tn = &nvram->target[i]; + j = tn->sync_index & 0xf; + sync = j < 12 ? Tekram_sync[j] : 255; + printk(KERN_DEBUG "%s-%d:%s%s%s%s%s%s PERIOD=%d\n", + ncr_name(np), i, + (tn->flags & TEKRAM_PARITY_CHECK) ? " PARITY" : "", + (tn->flags & TEKRAM_SYNC_NEGO) ? " SYNC" : "", + (tn->flags & TEKRAM_DISCONNECT_ENABLE) ? " DISC" : "", + (tn->flags & TEKRAM_START_CMD) ? " START" : "", + (tn->flags & TEKRAM_TAGGED_COMMANDS) ? " TCQ" : "", + (tn->flags & TEKRAM_WIDE_NEGO) ? " WIDE" : "", + sync); + } +} +#endif /* SCSI_NCR_DEBUG_NVRAM */ + +/* +** Host attach and initialisations. +** +** Allocate host data and ncb structure. +** Request IO region and remap MMIO region. +** Do chip initialization. +** If all is OK, install interrupt handling and +** start the timer daemon. +*/ + +__initfunc( +static int ncr_attach (Scsi_Host_Template *tpnt, int unit, ncr_device *device) +) +{ + struct host_data *host_data; + ncb_p np = 0; + struct Scsi_Host *instance = 0; + u_long flags = 0; + ncr_nvram *nvram = device->nvram; + int i; + +#ifdef __sparc__ +printk(KERN_INFO "ncr53c%s-%d: rev=0x%02x, base=0x%lx, io_port=0x%lx, irq=0x%x\n", + device->chip.name, unit, device->chip.revision_id, device->slot.base, + device->slot.io_port, device->slot.irq); +#else +printk(KERN_INFO NAME53C "%s-%d: rev=0x%02x, base=0x%lx, io_port=0x%lx, irq=%d\n", + device->chip.name, unit, device->chip.revision_id, device->slot.base, + device->slot.io_port, device->slot.irq); +#endif + + /* + ** Allocate host_data structure + */ + if (!(instance = scsi_register(tpnt, sizeof(*host_data)))) + goto attach_error; + host_data = (struct host_data *) instance->hostdata; + + /* + ** Allocate the host control block. + */ + np = m_calloc(sizeof(struct ncb), "NCB", MEMO_WARN); + if (!np) + goto attach_error; + NCR_INIT_LOCK_NCB(np); + host_data->ncb = np; + + /* + ** Store input informations in the host data structure. + */ + strncpy(np->chip_name, device->chip.name, sizeof(np->chip_name) - 1); + np->unit = unit; + np->verbose = driver_setup.verbose; + sprintf(np->inst_name, NAME53C "%s-%d", np->chip_name, np->unit); + np->device_id = device->chip.device_id; + np->revision_id = device->chip.revision_id; + np->features = device->chip.features; + np->clock_divn = device->chip.nr_divisor; + np->maxoffs = device->chip.offset_max; + np->maxburst = device->chip.burst_max; + np->myaddr = device->host_id; + + /* + ** Allocate the start queue. + */ + np->squeue = (ncrcmd *) + m_calloc(sizeof(ncrcmd)*(MAX_START*2), "SQUEUE", MEMO_WARN); + if (!np->squeue) + goto attach_error; + + /* + ** Allocate the done queue. + */ + np->dqueue = (ncrcmd *) + m_calloc(sizeof(ncrcmd)*(MAX_START*2), "DQUEUE", MEMO_WARN); + if (!np->dqueue) + goto attach_error; + + /* + ** Allocate the target bus address array. + */ + np->targtbl = (u_int32 *) m_calloc(256, "TARGTBL", MEMO_WARN); + if (!np->targtbl) + goto attach_error; + + /* + ** Allocate SCRIPTS areas + */ + np->script0 = (struct script *) + m_calloc(sizeof(struct script), "SCRIPT", MEMO_WARN); + if (!np->script0) + goto attach_error; + np->scripth0 = (struct scripth *) + m_calloc(sizeof(struct scripth), "SCRIPTH", MEMO_WARN); + if (!np->scripth0) + goto attach_error; + + /* + ** Initialyze the CCB free queue and, + ** allocate some CCB. We need at least ONE. + */ + xpt_que_init(&np->free_ccbq); + xpt_que_init(&np->b0_ccbq); + if (!ncr_alloc_ccb(np)) + goto attach_error; + + /* + ** Initialize timer structure + ** + */ + init_timer(&np->timer); + np->timer.data = (unsigned long) np; + np->timer.function = sym53c8xx_timeout; + + /* + ** Try to map the controller chip to + ** virtual and physical memory. + */ + + np->base_ba = device->slot.base; + np->base_ws = (np->features & FE_IO256)? 256 : 128; + np->base2_ba = (np->features & FE_RAM)? device->slot.base_2 : 0; + +#ifndef NCR_IOMAPPED + np->base_va = remap_pci_mem(np->base_ba, np->base_ws); + if (!np->base_va) { + printk(KERN_ERR "%s: can't map PCI MMIO region\n",ncr_name(np)); + goto attach_error; + } + else if (bootverbose > 1) + printk(KERN_INFO "%s: using memory mapped IO\n", ncr_name(np)); + + /* + ** Make the controller's registers available. + ** Now the INB INW INL OUTB OUTW OUTL macros + ** can be used safely. + */ + + np->reg = (struct ncr_reg *) np->base_va; + +#endif /* !defined NCR_IOMAPPED */ + + /* + ** Try to map the controller chip into iospace. + */ + + if (device->slot.io_port) { + request_region(device->slot.io_port, np->base_ws, NAME53C8XX); + np->base_io = device->slot.io_port; + } + +#ifdef SCSI_NCR_NVRAM_SUPPORT + if (nvram) { + switch(nvram->type) { + case SCSI_NCR_SYMBIOS_NVRAM: +#ifdef SCSI_NCR_DEBUG_NVRAM + ncr_display_Symbios_nvram(np, &nvram->data.Symbios); +#endif + break; + case SCSI_NCR_TEKRAM_NVRAM: +#ifdef SCSI_NCR_DEBUG_NVRAM + ncr_display_Tekram_nvram(np, &nvram->data.Tekram); +#endif + break; + default: + nvram = 0; +#ifdef SCSI_NCR_DEBUG_NVRAM + printk(KERN_DEBUG "%s: NVRAM: None or invalid data.\n", ncr_name(np)); +#endif + } + } +#endif + + /* + ** Do chip dependent initialization. + */ + if (np->base2_ba && sizeof(struct script) > 4096) { + printk(KERN_ERR "%s: script too large.\n", ncr_name(np)); + goto attach_error; + } + (void) ncr_prepare_setting(np, nvram); + + /* + ** Patch script to physical addresses + */ + ncr_script_fill (&script0, &scripth0); + + np->p_script = vtobus(np->script0); + np->p_scripth = vtobus(np->scripth0); + np->p_scripth0 = np->p_scripth; + + if (np->base2_ba) { + np->p_script = pcivtobus(np->base2_ba); + if (np->features & FE_RAM8K) { + np->p_scripth = np->p_script + 4096; +#if BITS_PER_LONG > 32 + np->scr_ram_seg = cpu_to_scr(np->base2_ba >> 32); +#endif + } + } + + ncr_script_copy_and_bind (np, (ncrcmd *) &script0, (ncrcmd *) np->script0, sizeof(struct script)); + ncr_script_copy_and_bind (np, (ncrcmd *) &scripth0, (ncrcmd *) np->scripth0, sizeof(struct scripth)); + + /* + ** Patch some variables in SCRIPTS + */ + np->scripth0->pm0_data_addr[0] = + cpu_to_scr(NCB_SCRIPT_PHYS(np, pm0_data)); + np->scripth0->pm1_data_addr[0] = + cpu_to_scr(NCB_SCRIPT_PHYS(np, pm1_data)); + + np->scripth0->script0_ba[0] = cpu_to_scr(vtobus(np->script0)); + np->scripth0->script0_ba64[0] = cpu_to_scr(vtobus(np->script0)); + np->scripth0->scripth0_ba64[0] = cpu_to_scr(vtobus(np->scripth0)); + np->scripth0->ram_seg64[0] = np->scr_ram_seg; + + /* + ** Prepare the idle and invalid task actions. + */ + np->idletask.start = cpu_to_scr(NCB_SCRIPT_PHYS (np, idle)); + np->idletask.restart = cpu_to_scr(NCB_SCRIPTH_PHYS (np, bad_i_t_l)); + np->p_idletask = vtobus(&np->idletask); + + np->notask.start = cpu_to_scr(NCB_SCRIPT_PHYS (np, idle)); + np->notask.restart = cpu_to_scr(NCB_SCRIPTH_PHYS (np, bad_i_t_l)); + np->p_notask = vtobus(&np->notask); + + np->bad_i_t_l.start = cpu_to_scr(NCB_SCRIPT_PHYS (np, idle)); + np->bad_i_t_l.restart = cpu_to_scr(NCB_SCRIPTH_PHYS (np, bad_i_t_l)); + np->p_bad_i_t_l = vtobus(&np->bad_i_t_l); + + np->bad_i_t_l_q.start = cpu_to_scr(NCB_SCRIPT_PHYS (np, idle)); + np->bad_i_t_l_q.restart = cpu_to_scr(NCB_SCRIPTH_PHYS (np,bad_i_t_l_q)); + np->p_bad_i_t_l_q = vtobus(&np->bad_i_t_l_q); + + /* + ** Allocate and prepare the bad lun table. + */ + np->badluntbl = m_calloc(256, "BADLUNTBL", MEMO_WARN); + if (!np->badluntbl) + goto attach_error; + + assert (offsetof(struct lcb, resel_task) == 0); + np->resel_badlun = cpu_to_scr(NCB_SCRIPTH_PHYS(np, bad_identify)); + + for (i = 0 ; i < 64 ; i++) + np->badluntbl[i] = cpu_to_scr(vtobus(&np->resel_badlun)); + + /* + ** Prepare the target bus address array. + */ + np->script0->targtbl[0] = cpu_to_scr(vtobus(np->targtbl)); + for (i = 0 ; i < MAX_TARGET ; i++) { + np->targtbl[i] = cpu_to_scr(vtobus(&np->target[i])); + np->target[i].b_luntbl = cpu_to_scr(vtobus(np->badluntbl)); + } + + /* + ** Patch the script for LED support. + */ + + if (np->features & FE_LED0) { + np->script0->idle[0] = + cpu_to_scr(SCR_REG_REG(gpreg, SCR_OR, 0x01)); + np->script0->reselected[0] = + cpu_to_scr(SCR_REG_REG(gpreg, SCR_AND, 0xfe)); + np->script0->start[0] = + cpu_to_scr(SCR_REG_REG(gpreg, SCR_AND, 0xfe)); + } + + /* + ** DEL 472 - 53C896 Rev 1 - Part Number 609-0393055 - ITEM 5. + */ + if (np->device_id == PCI_DEVICE_ID_NCR_53C896 && + np->revision_id <= 0x1 && (np->features & FE_NOPM)) { + np->scatter = ncr_scatter_896R1; +#ifndef SCSI_NCR_PROFILE_SUPPORT +#define XXX 0 +#else +#define XXX 3 +#endif + np->script0->dataphase[XXX] = cpu_to_scr(SCR_JUMP); + np->script0->dataphase[XXX+1] = + cpu_to_scr(NCB_SCRIPTH_PHYS (np, tweak_pmj)); +#undef XXX + } + else +#ifdef DEBUG_896R1 + np->scatter = ncr_scatter_896R1; +#else + np->scatter = ncr_scatter; +#endif + + /* + ** Reset chip. + ** We should use ncr_soft_reset(), but we donnot want to do + ** so, since we may not be safe if ABRT interrupt occurs due + ** to the BIOS or previous O/S having enable this interrupt. + */ + OUTB (nc_istat, SRST); + UDELAY(10); + OUTB (nc_istat, 0); + + /* + ** Now check the cache handling of the pci chipset. + */ + + if (ncr_snooptest (np)) { + printk (KERN_ERR "CACHE INCORRECTLY CONFIGURED.\n"); + goto attach_error; + }; + + /* + ** Install the interrupt handler. + */ + if (request_irq(device->slot.irq, sym53c8xx_intr, + ((driver_setup.irqm & 0x10) ? 0 : SA_SHIRQ) | +#if LINUX_VERSION_CODE < LinuxVersionCode(2,2,0) + ((driver_setup.irqm & 0x20) ? 0 : SA_INTERRUPT), +#else + 0, +#endif + NAME53C8XX, np)) { + printk(KERN_ERR "%s: request irq %d failure\n", + ncr_name(np), device->slot.irq); + goto attach_error; + } + np->irq = device->slot.irq; + + /* + ** After SCSI devices have been opened, we cannot + ** reset the bus safely, so we do it here. + ** Interrupt handler does the real work. + ** Process the reset exception, + ** if interrupts are not enabled yet. + ** Then enable disconnects. + */ + NCR_LOCK_NCB(np, flags); + if (ncr_reset_scsi_bus(np, 0, driver_setup.settle_delay) != 0) { + printk(KERN_ERR "%s: FATAL ERROR: CHECK SCSI BUS - CABLES, TERMINATION, DEVICE POWER etc.!\n", ncr_name(np)); + + NCR_UNLOCK_NCB(np, flags); + goto attach_error; + } + ncr_exception (np); + + /* + ** The middle-level SCSI driver does not + ** wait for devices to settle. + ** Wait synchronously if more than 2 seconds. + */ + if (driver_setup.settle_delay > 2) { + printk(KERN_INFO "%s: waiting %d seconds for scsi devices to settle...\n", + ncr_name(np), driver_setup.settle_delay); + MDELAY (1000 * driver_setup.settle_delay); + } + + /* + ** start the timeout daemon + */ + np->lasttime=0; + ncr_timeout (np); + + /* + ** use SIMPLE TAG messages by default + */ +#ifdef SCSI_NCR_ALWAYS_SIMPLE_TAG + np->order = M_SIMPLE_TAG; +#endif + + /* + ** Done. + */ + if (!first_host) + first_host = instance; + + /* + ** Fill Linux host instance structure + ** and return success. + */ + instance->max_channel = 0; + instance->max_id = np->maxwide ? 16 : 8; + instance->max_lun = SCSI_NCR_MAX_LUN; +#ifndef NCR_IOMAPPED + instance->base = (char *) np->reg; +#endif + instance->irq = np->irq; + instance->unique_id = np->base_io; + instance->io_port = np->base_io; + instance->n_io_port = np->base_ws; + instance->dma_channel = 0; + instance->select_queue_depths = sym53c8xx_select_queue_depths; + + NCR_UNLOCK_NCB(np, flags); + + /* + ** Now let the generic SCSI driver + ** look for the SCSI devices on the bus .. + */ + return 0; + +attach_error: + if (!instance) return -1; + printk(KERN_INFO "%s: giving up ...\n", ncr_name(np)); + if (np) + ncr_free_resources(np); + scsi_unregister(instance); + + return -1; + } + + +/* +** Free controller resources. +*/ +static void ncr_free_resources(ncb_p np) +{ + ccb_p cp; + tcb_p tp; + lcb_p lp; + int target, lun; + + if (np->irq) + free_irq(np->irq, np); + if (np->base_io) + release_region(np->base_io, np->base_ws); +#ifndef NCR_IOMAPPED + if (np->base_va) + unmap_pci_mem(np->base_va, np->base_ws); +#endif + if (np->scripth0) + m_free(np->scripth0, sizeof(struct scripth), "SCRIPTH"); + if (np->script0) + m_free(np->script0, sizeof(struct script), "SCRIPT"); + if (np->squeue) + m_free(np->squeue, sizeof(ncrcmd)*(MAX_START*2), "SQUEUE"); + if (np->dqueue) + m_free(np->dqueue, sizeof(ncrcmd)*(MAX_START*2),"DQUEUE"); + + while ((cp = np->ccbc) != NULL) { + np->ccbc = cp->link_ccb; + m_free(cp, sizeof(*cp), "CCB"); + } + + if (np->badluntbl) + m_free(np->badluntbl, 256,"BADLUNTBL"); + + for (target = 0; target < MAX_TARGET ; target++) { + tp = &np->target[target]; + for (lun = 0 ; lun < MAX_LUN ; lun++) { + lp = tp->lp[lun]; + if (!lp) + continue; + if (lp->tasktbl != &lp->tasktbl_0) + m_free(lp->tasktbl, 256, "TASKTBL"); + m_free(lp, sizeof(*lp), "LCB"); + } + } + + m_free(np, sizeof(*np), "NCB"); +} + + +/*========================================================== +** +** +** Done SCSI commands list management. +** +** We donnot enter the scsi_done() callback immediately +** after a command has been seen as completed but we +** insert it into a list which is flushed outside any kind +** of driver critical section. +** This allows to do minimal stuff under interrupt and +** inside critical sections and to also avoid locking up +** on recursive calls to driver entry points under SMP. +** In fact, the only kernel point which is entered by the +** driver with a driver lock set is get_free_pages(GFP_ATOMIC...) +** that shall not reenter the driver under any circumstance. +** +**========================================================== +*/ +static inline void ncr_queue_done_cmd(ncb_p np, Scsi_Cmnd *cmd) +{ + cmd->host_scribble = (char *) np->done_list; + np->done_list = cmd; +} + +static inline void ncr_flush_done_cmds(Scsi_Cmnd *lcmd) +{ + Scsi_Cmnd *cmd; + + while (lcmd) { + cmd = lcmd; + lcmd = (Scsi_Cmnd *) cmd->host_scribble; + cmd->scsi_done(cmd); + } +} + + +/*========================================================== +** +** +** Start execution of a SCSI command. +** This is called from the generic SCSI driver. +** +** +**========================================================== +*/ +static int ncr_queue_command (ncb_p np, Scsi_Cmnd *cmd) +{ +/* Scsi_Device *device = cmd->device; */ + tcb_p tp = &np->target[cmd->target]; + lcb_p lp = tp->lp[cmd->lun]; + ccb_p cp; + + int segments; + u_char nego, idmsg, *msgptr; + u_int msglen; + int direction; + u_int32 lastp, goalp; + + /*--------------------------------------------- + ** + ** Some shortcuts ... + ** + **--------------------------------------------- + */ + if ((cmd->target == np->myaddr ) || + (cmd->target >= MAX_TARGET) || + (cmd->lun >= MAX_LUN )) { + return(DID_BAD_TARGET); + } + + /*--------------------------------------------- + ** + ** Complete the 1st TEST UNIT READY command + ** with error condition if the device is + ** flagged NOSCAN, in order to speed up + ** the boot. + ** + **--------------------------------------------- + */ + if (cmd->cmnd[0] == 0 && (tp->usrflag & UF_NOSCAN)) { + tp->usrflag &= ~UF_NOSCAN; + return DID_BAD_TARGET; + } + + if (DEBUG_FLAGS & DEBUG_TINY) { + PRINT_ADDR(cmd); + printk ("CMD=%x ", cmd->cmnd[0]); + } + + /*--------------------------------------------------- + ** + ** Assign a ccb / bind cmd. + ** If resetting, shorten settle_time if necessary + ** in order to avoid spurious timeouts. + ** If resetting or no free ccb, + ** insert cmd into the waiting list. + ** + **---------------------------------------------------- + */ + if (np->settle_time && cmd->timeout_per_command >= HZ && + np->settle_time > jiffies + cmd->timeout_per_command - HZ) { + np->settle_time = jiffies + cmd->timeout_per_command - HZ; + } + + if (np->settle_time || !(cp=ncr_get_ccb (np, cmd->target, cmd->lun))) { + insert_into_waiting_list(np, cmd); + return(DID_OK); + } + cp->cmd = cmd; + + /*--------------------------------------------------- + ** + ** Enable tagged queue if asked by scsi ioctl + ** + **---------------------------------------------------- + */ +#if 0 /* This stuff was only usefull for linux-1.2.13 */ + if (lp && !lp->numtags && cmd->device && cmd->device->tagged_queue) { + lp->numtags = tp->usrtags; + ncr_setup_tags (np, cp->target, cp->lun); + } +#endif + +#ifdef SCSI_NCR_PROFILE_SUPPORT + cp->phys.num_disc = 0; +#endif + + /*--------------------------------------------------- + ** + ** negotiation required? + ** + **--------------------------------------------------- + */ + + nego = 0; + + if ((!tp->widedone || !tp->period) && !tp->nego_cp && tp->inq_done && lp) { + + /* + ** negotiate wide transfers ? + */ + + if (!tp->widedone) { + if (tp->inq_byte7 & INQ7_WIDE16) { + nego = NS_WIDE; + } else + tp->widedone=1; + }; + + /* + ** negotiate synchronous transfers? + */ + + if (!nego && !tp->period) { + if (tp->inq_byte7 & INQ7_SYNC) { + nego = NS_SYNC; + } else { + tp->period =0xffff; + PRINT_TARGET(np, cp->target); + printk ("target did not report SYNC.\n"); + }; + }; + + /* + ** remember nego is pending for the target. + ** Avoid to start a nego for all queued commands + ** when tagged command queuing is enabled. + */ + + if (nego) + tp->nego_cp = cp; + }; + + /*---------------------------------------------------- + ** + ** Build the identify / tag / sdtr message + ** + **---------------------------------------------------- + */ + + idmsg = M_IDENTIFY | cp->lun; + + if (cp ->tag != NO_TAG || (lp && !(tp->usrflag & UF_NODISC))) + idmsg |= 0x40; + + msgptr = cp->scsi_smsg; + msglen = 0; + msgptr[msglen++] = idmsg; + + if (cp->tag != NO_TAG) { + char order = np->order; + + /* + ** Force ordered tag if necessary to avoid timeouts + ** and to preserve interactivity. + */ + if (lp && lp->tags_stime + (3*HZ) <= jiffies) { + if (lp->tags_smap) { + order = M_ORDERED_TAG; + if ((DEBUG_FLAGS & DEBUG_TAGS)||bootverbose>2){ + PRINT_ADDR(cmd); + printk("ordered tag forced.\n"); + } + } + lp->tags_stime = jiffies; + lp->tags_smap = lp->tags_umap; + } + + if (order == 0) { + /* + ** Ordered write ops, unordered read ops. + */ + switch (cmd->cmnd[0]) { + case 0x08: /* READ_SMALL (6) */ + case 0x28: /* READ_BIG (10) */ + case 0xa8: /* READ_HUGE (12) */ + order = M_SIMPLE_TAG; + break; + default: + order = M_ORDERED_TAG; + } + } + msgptr[msglen++] = order; + /* + ** Actual tags are numbered 1,3,5,..2*MAXTAGS+1, + ** since we may have to deal with devices that have + ** problems with #TAG 0 or too great #TAG numbers. + */ + msgptr[msglen++] = (cp->tag << 1) + 1; + } + + switch (nego) { + case NS_SYNC: + msgptr[msglen++] = M_EXTENDED; + msgptr[msglen++] = 3; + msgptr[msglen++] = M_X_SYNC_REQ; + msgptr[msglen++] = tp->maxoffs ? tp->minsync : 0; + msgptr[msglen++] = tp->maxoffs; + if (DEBUG_FLAGS & DEBUG_NEGO) { + PRINT_ADDR(cp->cmd); + printk ("sync msgout: "); + ncr_show_msg (&cp->scsi_smsg [msglen-5]); + printk (".\n"); + }; + break; + case NS_WIDE: + msgptr[msglen++] = M_EXTENDED; + msgptr[msglen++] = 2; + msgptr[msglen++] = M_X_WIDE_REQ; + msgptr[msglen++] = tp->usrwide; + if (DEBUG_FLAGS & DEBUG_NEGO) { + PRINT_ADDR(cp->cmd); + printk ("wide msgout: "); + ncr_show_msg (&cp->scsi_smsg [msglen-4]); + printk (".\n"); + }; + break; + }; + + cp->host_flags = 0; + + /*---------------------------------------------------- + ** + ** Build the data descriptors + ** + **---------------------------------------------------- + */ + + segments = np->scatter (cp, cp->cmd); + + if (segments < 0) { + ncr_free_ccb(np, cp); + return(DID_ERROR); + } + + /*---------------------------------------------------- + ** + ** Determine xfer direction. + ** + **---------------------------------------------------- + */ + if (!cp->data_len) + direction = 0; + else { + switch((int) cmd->cmnd[0]) { + case 0x08: /* READ(6) 08 */ + case 0x28: /* READ(10) 28 */ + case 0xA8: /* READ(12) A8 */ + direction = XFER_IN; + break; + case 0x0A: /* WRITE(6) 0A */ + case 0x2A: /* WRITE(10) 2A */ + case 0xAA: /* WRITE(12) AA */ + direction = XFER_OUT; + break; + default: + direction = (XFER_IN|XFER_OUT); + break; + } + } + + /*---------------------------------------------------- + ** + ** Set the DATA POINTER. + ** + **---------------------------------------------------- + */ + + /* + ** Default to no data transfer. + */ + lastp = goalp = NCB_SCRIPTH_PHYS (np, no_data); + + /* + ** Compute data out pointers, if needed. + */ + if (direction & XFER_OUT) { + goalp = NCB_SCRIPT_PHYS (np, data_out2) + 8; +#if MAX_SCATTERH != 0 + if (segments <= MAX_SCATTERL) + lastp = goalp - 8 - (segments * (SCR_SG_SIZE*4)); + else { + lastp = NCB_SCRIPTH_PHYS (np, hdata_out2); + lastp -= (segments - MAX_SCATTERL) * (SCR_SG_SIZE*4); + } +#else + lastp = goalp - 8 - (segments * (SCR_SG_SIZE*4)); +#endif + /* + ** If actual data direction is unknown, save pointers + ** in header. The SCRIPTS will swap them to current + ** if target decision will be data out. + */ + if (direction & XFER_IN) { + cp->phys.header.wgoalp = cpu_to_scr(goalp); + cp->phys.header.wlastp = cpu_to_scr(lastp); + } + } + + /* + ** Compute data in pointers, if needed. + */ + if (direction & XFER_IN) { + goalp = NCB_SCRIPT_PHYS (np, data_in2) + 8; +#if MAX_SCATTERH != 0 + if (segments <= MAX_SCATTERL) + lastp = goalp - 8 - (segments * (SCR_SG_SIZE*4)); + else { + lastp = NCB_SCRIPTH_PHYS (np, hdata_in2); + lastp -= (segments - MAX_SCATTERL) * (SCR_SG_SIZE*4); + } +#else + lastp = goalp - 8 - (segments * (SCR_SG_SIZE*4)); +#endif + } + + /* + ** Set all pointers values needed by SCRIPTS. + ** If direction is unknown, start at data_io. + */ + cp->phys.header.lastp = cpu_to_scr(lastp); + cp->phys.header.goalp = cpu_to_scr(goalp); + + if ((direction & (XFER_IN|XFER_OUT)) == (XFER_IN|XFER_OUT)) + cp->phys.header.savep = + cpu_to_scr(NCB_SCRIPTH_PHYS (np, data_io)); + else + cp->phys.header.savep= cpu_to_scr(lastp); + + /* + ** Save the initial data pointer in order to be able + ** to redo the command. + */ + cp->startp = cp->phys.header.savep; + + /*---------------------------------------------------- + ** + ** fill in ccb + ** + **---------------------------------------------------- + ** + ** + ** physical -> virtual backlink + ** Generic SCSI command + */ + + /* + ** Startqueue + */ + cp->phys.header.go.start = cpu_to_scr(NCB_SCRIPT_PHYS (np,select)); + cp->phys.header.go.restart = cpu_to_scr(NCB_SCRIPT_PHYS (np,resel_dsa)); + /* + ** select + */ + cp->phys.select.sel_id = cp->target; + cp->phys.select.sel_scntl3 = tp->wval; + cp->phys.select.sel_sxfer = tp->sval; + /* + ** message + */ + cp->phys.smsg.addr = cpu_to_scr(CCB_PHYS (cp, scsi_smsg)); + cp->phys.smsg.size = cpu_to_scr(msglen); + + /* + ** command + */ + cp->phys.cmd.addr = cpu_to_scr(vtobus (&cmd->cmnd[0])); + cp->phys.cmd.size = cpu_to_scr(cmd->cmd_len); + + /* + ** status + */ + cp->actualquirks = tp->quirks; + cp->host_status = nego ? HS_NEGOTIATE : HS_BUSY; + cp->scsi_status = S_ILLEGAL; + + cp->xerr_status = XE_OK; + cp->nego_status = nego; + + /*---------------------------------------------------- + ** + ** Critical region: start this job. + ** + **---------------------------------------------------- + */ + + /* + ** activate this job. + */ + + /* Compute a time limit greater than the middle-level driver one */ + if (cmd->timeout_per_command > 0) + cp->tlimit = jiffies + cmd->timeout_per_command + HZ; + else + cp->tlimit = jiffies + 86400 * HZ;/* No timeout=24 hours */ + + /* + ** insert next CCBs into start queue. + ** 2 max at a time is enough to flush the CCB wait queue. + */ + cp->auto_sense = 0; + if (lp) + ncr_start_next_ccb(np, lp, 2); + else + ncr_put_start_queue(np, cp); + + /* + ** Command is successfully queued. + */ + + return(DID_OK); +} + + +/*========================================================== +** +** +** Insert a CCB into the start queue and wake up the +** SCRIPTS processor. +** +** +**========================================================== +*/ + +static void ncr_start_next_ccb(ncb_p np, lcb_p lp, int maxn) +{ + XPT_QUEHEAD *qp; + ccb_p cp; + + while (maxn-- && lp->queuedccbs < lp->queuedepth) { + qp = xpt_remque_head(&lp->wait_ccbq); + if (!qp) + break; + ++lp->queuedccbs; + cp = xpt_que_entry(qp, struct ccb, link_ccbq); + xpt_insque_tail(qp, &lp->busy_ccbq); + lp->tasktbl[cp->tag == NO_TAG ? 0 : cp->tag] = + cpu_to_scr(cp->p_ccb); + ncr_put_start_queue(np, cp); + } +} + +static void ncr_put_start_queue(ncb_p np, ccb_p cp) +{ + u_short qidx; + + /* + ** insert into start queue. + */ + qidx = np->squeueput + 2; + if (qidx >= MAX_START*2) qidx = 0; + + np->squeue [qidx] = cpu_to_scr(np->p_idletask); + MEMORY_BARRIER(); + np->squeue [np->squeueput] = cpu_to_scr(cp->p_ccb); + + np->squeueput = qidx; + cp->queued = 1; + + if (DEBUG_FLAGS & DEBUG_QUEUE) + printk ("%s: queuepos=%d.\n", ncr_name (np), np->squeueput); + + /* + ** Script processor may be waiting for reselect. + ** Wake it up. + */ + MEMORY_BARRIER(); + OUTB (nc_istat, SIGP); +} + + +/*========================================================== +** +** Soft reset the chip. +** +** Some 896 and 876 chip revisions may hang-up if we set +** the SRST (soft reset) bit at the wrong time when SCRIPTS +** are running. +** So, we need to abort the current operation prior to +** soft resetting the chip. +** +**========================================================== +*/ + +static void ncr_soft_reset(ncb_p np) +{ + u_char istat; + int i; + + OUTB (nc_istat, CABRT); + for (i = 1000000 ; i ; --i) { + istat = INB (nc_istat); + if (istat & SIP) { + INW (nc_sist); + continue; + } + if (istat & DIP) { + OUTB (nc_istat, 0); + INB (nc_dstat); + break; + } + } + if (!i) + printk("%s: unable to abort current chip operation.\n", + ncr_name(np)); + OUTB (nc_istat, SRST); + UDELAY(10); + OUTB (nc_istat, 0); +} + +/*========================================================== +** +** +** Start reset process. +** If reset in progress do nothing. +** The interrupt handler will reinitialize the chip. +** The timeout handler will wait for settle_time before +** clearing it and so resuming command processing. +** +** +**========================================================== +*/ +static void ncr_start_reset(ncb_p np) +{ + if (!np->settle_time) { + (void) ncr_reset_scsi_bus(np, 1, driver_setup.settle_delay); + } + } + +static int ncr_reset_scsi_bus(ncb_p np, int enab_int, int settle_delay) +{ + u_int32 term; + int retv = 0; + + np->settle_time = jiffies + settle_delay * HZ; + + if (bootverbose > 1) + printk("%s: resetting, " + "command processing suspended for %d seconds\n", + ncr_name(np), settle_delay); + + ncr_soft_reset(np); /* Soft reset the chip */ + UDELAY (2000); /* The 895/6 need time for the bus mode to settle */ + if (enab_int) + OUTW (nc_sien, RST); + /* + ** Enable Tolerant, reset IRQD if present and + ** properly set IRQ mode, prior to resetting the bus. + */ + OUTB (nc_stest3, TE); + OUTB (nc_dcntl, (np->rv_dcntl & IRQM)); + OUTB (nc_scntl1, CRST); + UDELAY (200); + + if (!driver_setup.bus_check) + goto out; + /* + ** Check for no terminators or SCSI bus shorts to ground. + ** Read SCSI data bus, data parity bits and control signals. + ** We are expecting RESET to be TRUE and other signals to be + ** FALSE. + */ + term = INB(nc_sstat0); /* rst, sdp0 */ + term = ((term & 2) << 7) + ((term & 1) << 16); + term |= ((INB(nc_sstat2) & 0x01) << 25) | /* sdp1 */ + (INW(nc_sbdl) << 9) | /* d15-0 */ + INB(nc_sbcl); /* req, ack, bsy, sel, atn, msg, cd, io */ + + if (!(np->features & FE_WIDE)) + term &= 0x3ffff; + + if (term != (2<<7)) { + printk("%s: suspicious SCSI data while resetting the BUS.\n", + ncr_name(np)); + printk("%s: %sdp0,d7-0,rst,req,ack,bsy,sel,atn,msg,c/d,i/o = " + "0x%lx, expecting 0x%lx\n", + ncr_name(np), + (np->features & FE_WIDE) ? "dp1,d15-8," : "", + (u_long)term, (u_long)(2<<7)); + if (driver_setup.bus_check == 1) + retv = 1; + } +out: + OUTB (nc_scntl1, 0); + return retv; +} + +/*========================================================== +** +** +** Reset the SCSI BUS. +** This is called from the generic SCSI driver. +** +** +**========================================================== +*/ +static int ncr_reset_bus (ncb_p np, Scsi_Cmnd *cmd, int sync_reset) +{ +/* Scsi_Device *device = cmd->device; */ + ccb_p cp; + int found; + +/* + * Return immediately if reset is in progress. + */ + if (np->settle_time) { + return SCSI_RESET_PUNT; + } +/* + * Start the reset process. + * The script processor is then assumed to be stopped. + * Commands will now be queued in the waiting list until a settle + * delay of 2 seconds will be completed. + */ + ncr_start_reset(np); +/* + * First, look in the wakeup list + */ + for (found=0, cp=np->ccbc; cp; cp=cp->link_ccb) { + /* + ** look for the ccb of this command. + */ + if (cp->host_status == HS_IDLE) continue; + if (cp->cmd == cmd) { + found = 1; + break; + } + } +/* + * Then, look in the waiting list + */ + if (!found && retrieve_from_waiting_list(0, np, cmd)) + found = 1; +/* + * Wake-up all awaiting commands with DID_RESET. + */ + reset_waiting_list(np); +/* + * Wake-up all pending commands with HS_RESET -> DID_RESET. + */ + ncr_wakeup(np, HS_RESET); +/* + * If the involved command was not in a driver queue, and the + * scsi driver told us reset is synchronous, and the command is not + * currently in the waiting list, complete it with DID_RESET status, + * in order to keep it alive. + */ + if (!found && sync_reset && !retrieve_from_waiting_list(0, np, cmd)) { + SetScsiResult(cmd, DID_RESET, 0); + ncr_queue_done_cmd(np, cmd); + } + + return SCSI_RESET_SUCCESS; +} + +/*========================================================== +** +** +** Abort an SCSI command. +** This is called from the generic SCSI driver. +** +** +**========================================================== +*/ +static int ncr_abort_command (ncb_p np, Scsi_Cmnd *cmd) +{ +/* Scsi_Device *device = cmd->device; */ + ccb_p cp; + int found; + int retv; + +/* + * First, look for the scsi command in the waiting list + */ + if (remove_from_waiting_list(np, cmd)) { + SetScsiResult(cmd, DID_ABORT, 0); + ncr_queue_done_cmd(np, cmd); + return SCSI_ABORT_SUCCESS; + } + +/* + * Then, look in the wakeup list + */ + for (found=0, cp=np->ccbc; cp; cp=cp->link_ccb) { + /* + ** look for the ccb of this command. + */ + if (cp->host_status == HS_IDLE) continue; + if (cp->cmd == cmd) { + found = 1; + break; + } + } + + if (!found) { + return SCSI_ABORT_NOT_RUNNING; + } + + if (np->settle_time) { + return SCSI_ABORT_SNOOZE; + } + + /* + ** If the CCB is active, patch schedule jumps for the + ** script to abort the command. + */ + + cp->tlimit = 0; + switch(cp->host_status) { + case HS_BUSY: + case HS_NEGOTIATE: + printk ("%s: abort ccb=%p (cancel)\n", ncr_name (np), cp); + cp->phys.header.go.start = + cpu_to_scr(NCB_SCRIPTH_PHYS (np, cancel)); + retv = SCSI_ABORT_PENDING; + break; + case HS_DISCONNECT: + cp->phys.header.go.restart = + cpu_to_scr(NCB_SCRIPTH_PHYS (np, bad_i_t_l_q)); + retv = SCSI_ABORT_PENDING; + break; + default: + retv = SCSI_ABORT_NOT_RUNNING; + break; + + } + + /* + ** If there are no requests, the script + ** processor will sleep on SEL_WAIT_RESEL. + ** Let's wake it up, since it may have to work. + */ + OUTB (nc_istat, SIGP); + + return retv; +} + +/*========================================================== +** +** Linux release module stuff. +** +** Called before unloading the module +** Detach the host. +** We have to free resources and halt the NCR chip +** +**========================================================== +*/ + +#ifdef MODULE +static int ncr_detach(ncb_p np) +{ + int i; + + printk("%s: detaching ...\n", ncr_name(np)); + +/* +** Stop the ncr_timeout process +** Set release_stage to 1 and wait that ncr_timeout() set it to 2. +*/ + np->release_stage = 1; + for (i = 50 ; i && np->release_stage != 2 ; i--) MDELAY (100); + if (np->release_stage != 2) + printk("%s: the timer seems to be already stopped\n", + ncr_name(np)); + else np->release_stage = 2; + +/* +** Reset NCR chip. +** We should use ncr_soft_reset(), but we donnot want to do +** so, since we may not be safe if interrupts occur. +*/ + + printk("%s: resetting chip\n", ncr_name(np)); + OUTB (nc_istat, SRST); + UDELAY (100); + OUTB (nc_istat, 0 ); + +/* +** Restore bios setting for automatic clock detection. +*/ + OUTB(nc_dmode, np->sv_dmode); + OUTB(nc_dcntl, np->sv_dcntl); + OUTB(nc_ctest3, np->sv_ctest3); + OUTB(nc_ctest4, np->sv_ctest4); + OUTB(nc_ctest5, np->sv_ctest5); + OUTB(nc_gpcntl, np->sv_gpcntl); + OUTB(nc_stest2, np->sv_stest2); + + ncr_selectclock(np, np->sv_scntl3); +/* +** Free host resources +*/ + ncr_free_resources(np); + + return 1; +} +#endif + +/*========================================================== +** +** +** Complete execution of a SCSI command. +** Signal completion to the generic SCSI driver. +** +** +**========================================================== +*/ + +void ncr_complete (ncb_p np, ccb_p cp) +{ + Scsi_Cmnd *cmd; + tcb_p tp; + lcb_p lp; + + /* + ** Sanity check + */ + if (!cp || !cp->cmd) + return; + + /* + ** Gather profiling data + */ +#ifdef SCSI_NCR_PROFILE_SUPPORT + ncb_profile (np, cp); +#endif + + if (DEBUG_FLAGS & DEBUG_TINY) + printk ("CCB=%lx STAT=%x/%x\n", (unsigned long)cp, + cp->host_status,cp->scsi_status); + + /* + ** Get command, target and lun pointers. + */ + + cmd = cp->cmd; + cp->cmd = NULL; + tp = &np->target[cp->target]; + lp = tp->lp[cp->lun]; + + /* + ** We donnot queue more than 1 ccb per target + ** with negotiation at any time. If this ccb was + ** used for negotiation, clear this info in the tcb. + */ + + if (cp == tp->nego_cp) + tp->nego_cp = 0; + + /* + ** If auto-sense performed, change scsi status. + */ + if (cp->auto_sense) { + cp->scsi_status = cp->auto_sense; + } + + /* + ** Check for parity errors. + */ + + if (cp->host_flags & HF_PAR_ERR) { + PRINT_ADDR(cmd); + printk ("unrecovered SCSI parity error.\n"); + if (cp->host_status==HS_COMPLETE) + cp->host_status = HS_FAIL; + } + + /* + ** Check for extended errors. + */ + + if (cp->xerr_status != XE_OK) { + PRINT_ADDR(cmd); + switch (cp->xerr_status) { + case XE_EXTRA_DATA: + printk ("extraneous data discarded.\n"); + break; + case XE_BAD_PHASE: + printk ("illegal scsi phase (4/5).\n"); + break; + default: + printk ("extended error %d.\n", cp->xerr_status); + break; + } + if (cp->host_status==HS_COMPLETE) + cp->host_status = HS_FAIL; + } + + /* + ** Print out any error for debugging purpose. + */ + if (DEBUG_FLAGS & (DEBUG_RESULT|DEBUG_TINY)) { + if (cp->host_status!=HS_COMPLETE || cp->scsi_status!=S_GOOD) { + PRINT_ADDR(cmd); + printk ("ERROR: cmd=%x host_status=%x scsi_status=%x\n", + cmd->cmnd[0], cp->host_status, cp->scsi_status); + } + } + + /* + ** Check the status. + */ + if ( (cp->host_status == HS_COMPLETE) + && (cp->scsi_status == S_GOOD || + cp->scsi_status == S_COND_MET)) { + /* + ** All went well (GOOD status). + ** CONDITION MET status is returned on + ** `Pre-Fetch' or `Search data' success. + */ + SetScsiResult(cmd, DID_OK, cp->scsi_status); + + /* + ** @RESID@ + ** Could dig out the correct value for resid, + ** but it would be quite complicated. + */ + /* if (cp->phys.header.lastp != cp->phys.header.goalp) */ + + /* + ** Allocate the lcb if not yet. + */ + if (!lp) + ncr_alloc_lcb (np, cp->target, cp->lun); + + /* + ** On standard INQUIRY response (EVPD and CmDt + ** not set), setup logical unit according to + ** announced capabilities (we need the 1rst 7 bytes). + */ + if (cmd->cmnd[0] == 0x12 && !(cmd->cmnd[1] & 0x3) && + cmd->cmnd[4] >= 7 && !cmd->use_sg) { + ncr_setup_lcb (np, cp->target, cp->lun, + (char *) cmd->request_buffer); + } + + tp->bytes += cp->data_len; + tp->transfers ++; + + /* + ** If tags was reduced due to queue full, + ** increase tags if 1000 good status received. + */ + if (lp && lp->usetags && lp->numtags < lp->maxtags) { + ++lp->num_good; + if (lp->num_good >= 1000) { + lp->num_good = 0; + ++lp->numtags; + ncr_setup_tags (np, cp->target, cp->lun); + } + } + } else if ((cp->host_status == HS_COMPLETE) + && (cp->scsi_status == S_CHECK_COND)) { + /* + ** Check condition code + */ + SetScsiResult(cmd, DID_OK, S_CHECK_COND); + + if (DEBUG_FLAGS & (DEBUG_RESULT|DEBUG_TINY)) { + u_char * p = (u_char*) & cmd->sense_buffer; + int i; + PRINT_ADDR(cmd); + printk ("sense data:"); + for (i=0; i<14; i++) printk (" %x", *p++); + printk (".\n"); + } + + } else if ((cp->host_status == HS_COMPLETE) + && (cp->scsi_status == S_BUSY || + cp->scsi_status == S_QUEUE_FULL)) { + + /* + ** Target is busy. + */ + SetScsiResult(cmd, DID_OK, cp->scsi_status); + + } else if ((cp->host_status == HS_SEL_TIMEOUT) + || (cp->host_status == HS_TIMEOUT)) { + + /* + ** No response + */ + SetScsiResult(cmd, DID_TIME_OUT, cp->scsi_status); + + } else if (cp->host_status == HS_RESET) { + + /* + ** SCSI bus reset + */ + SetScsiResult(cmd, DID_RESET, cp->scsi_status); + + } else if (cp->host_status == HS_ABORTED) { + + /* + ** Transfer aborted + */ + SetScsiResult(cmd, DID_ABORT, cp->scsi_status); + + } else { + + /* + ** Other protocol messes + */ + PRINT_ADDR(cmd); + printk ("COMMAND FAILED (%x %x) @%p.\n", + cp->host_status, cp->scsi_status, cp); + + SetScsiResult(cmd, DID_ERROR, cp->scsi_status); + } + + /* + ** trace output + */ + + if (tp->usrflag & UF_TRACE) { + u_char * p; + int i; + PRINT_ADDR(cmd); + printk (" CMD:"); + p = (u_char*) &cmd->cmnd[0]; + for (i=0; icmd_len; i++) printk (" %x", *p++); + + if (cp->host_status==HS_COMPLETE) { + switch (cp->scsi_status) { + case S_GOOD: + printk (" GOOD"); + break; + case S_CHECK_COND: + printk (" SENSE:"); + p = (u_char*) &cmd->sense_buffer; + for (i=0; i<14; i++) + printk (" %x", *p++); + break; + default: + printk (" STAT: %x\n", cp->scsi_status); + break; + } + } else printk (" HOSTERROR: %x", cp->host_status); + printk ("\n"); + } + + /* + ** Free this ccb + */ + ncr_free_ccb (np, cp); + + /* + ** requeue awaiting scsi commands for this lun. + */ + if (lp && lp->queuedccbs < lp->queuedepth && + !xpt_que_empty(&lp->wait_ccbq)) + ncr_start_next_ccb(np, lp, 2); + + /* + ** requeue awaiting scsi commands for this controller. + */ + if (np->waiting_list) + requeue_waiting_list(np); + + /* + ** signal completion to generic driver. + */ + ncr_queue_done_cmd(np, cmd); +} + +/*========================================================== +** +** +** Signal all (or one) control block done. +** +** +**========================================================== +*/ + +/* +** The NCR has completed CCBs. +** Look at the DONE QUEUE. +*/ +int ncr_wakeup_done (ncb_p np) +{ + ccb_p cp; + int i, n; + u_long dsa; + + n = 0; + i = np->dqueueget; + while (1) { + dsa = scr_to_cpu(np->dqueue[i]); + if (!dsa) + break; + np->dqueue[i] = 0; + if ((i = i+2) >= MAX_START*2) + i = 0; + + cp = ncr_ccb_from_dsa(np, dsa); + if (cp) { + ncr_complete (np, cp); + ++n; + } + else + printk (KERN_ERR "%s: bad DSA (%lx) in done queue.\n", + ncr_name(np), dsa); + } + np->dqueueget = i; + + return n; +} + +/* +** Complete all active CCBs. +*/ +void ncr_wakeup (ncb_p np, u_long code) +{ + ccb_p cp = np->ccbc; + + while (cp) { + if (cp->host_status != HS_IDLE) { + cp->host_status = code; + ncr_complete (np, cp); + } + cp = cp->link_ccb; + } +} + +/*========================================================== +** +** +** Start NCR chip. +** +** +**========================================================== +*/ + +void ncr_init (ncb_p np, int reset, char * msg, u_long code) +{ + int i; + u_long phys; + + /* + ** Reset chip if asked, otherwise just clear fifos. + */ + + if (reset) + ncr_soft_reset(np); + else { + OUTB (nc_stest3, TE|CSF); + OUTONB (nc_ctest3, CLF); + } + + /* + ** Message. + */ + + if (msg) printk (KERN_INFO "%s: restart (%s).\n", ncr_name (np), msg); + + /* + ** Clear Start Queue + */ + phys = vtobus(np->squeue); + np->queuedepth = MAX_START - 1; /* 1 entry needed as end marker */ + for (i = 0; i < MAX_START*2; i += 2) { + np->squeue[i] = cpu_to_scr(np->p_idletask); + np->squeue[i+1] = cpu_to_scr(phys + (i+2)*4); + } + np->squeue[MAX_START*2-1] = cpu_to_scr(phys); + + + /* + ** Start at first entry. + */ + np->squeueput = 0; + np->script0->startpos[0] = cpu_to_scr(phys); + + /* + ** Clear Done Queue + */ + phys = vtobus(np->dqueue); + for (i = 0; i < MAX_START*2; i += 2) { + np->dqueue[i] = 0; + np->dqueue[i+1] = cpu_to_scr(phys + (i+2)*4); + } + np->dqueue[MAX_START*2-1] = cpu_to_scr(phys); + + /* + ** Start at first entry. + */ + np->script0->done_pos[0] = cpu_to_scr(phys); + np->dqueueget = 0; + + /* + ** Wakeup all pending jobs. + */ + ncr_wakeup (np, code); + + /* + ** Init chip. + */ + + OUTB (nc_istat, 0x00 ); /* Remove Reset, abort */ + UDELAY (2000); /* The 895 needs time for the bus mode to settle */ + + OUTB (nc_scntl0, np->rv_scntl0 | 0xc0); + /* full arb., ena parity, par->ATN */ + OUTB (nc_scntl1, 0x00); /* odd parity, and remove CRST!! */ + + ncr_selectclock(np, np->rv_scntl3); /* Select SCSI clock */ + + OUTB (nc_scid , RRE|np->myaddr); /* Adapter SCSI address */ + OUTW (nc_respid, 1ul<myaddr); /* Id to respond to */ + OUTB (nc_istat , SIGP ); /* Signal Process */ + OUTB (nc_dmode , np->rv_dmode); /* Burst length, dma mode */ + OUTB (nc_ctest5, np->rv_ctest5); /* Large fifo + large burst */ + + OUTB (nc_dcntl , NOCOM|np->rv_dcntl); /* Protect SFBR */ + OUTB (nc_ctest3, np->rv_ctest3); /* Write and invalidate */ + OUTB (nc_ctest4, np->rv_ctest4); /* Master parity checking */ + + OUTB (nc_stest2, EXT|np->rv_stest2); /* Extended Sreq/Sack filtering */ + OUTB (nc_stest3, TE); /* TolerANT enable */ + OUTB (nc_stime0, 0x0c); /* HTH disabled STO 0.25 sec */ + + /* + ** DEL 441 - 53C876 Rev 5 - Part Number 609-0392787/2788 - ITEM 2. + ** Disable overlapped arbitration. + ** The 896 Rev 1 needs also this work-around to be applied. + */ + if (np->device_id == PCI_DEVICE_ID_NCR_53C875 && + np->revision_id >= 0x10 && np->revision_id <= 0x15) + OUTB (nc_ctest0, (1<<5)); + else if (np->device_id == PCI_DEVICE_ID_NCR_53C896 && + np->revision_id <= 0x1) + np->rv_ccntl0 |= DPR; + + /* + ** If 64 bit (53C896) enable 40 bit address table + ** indirect addressing for MOVE. + */ + + if (np->features & FE_64BIT) { + OUTB (nc_ccntl1, np->rv_ccntl1); + } + + /* + ** If phase mismatch handled by scripts (53C896), + ** set PM jump addresses. + */ + + if (np->features & FE_NOPM) { + printk(KERN_INFO "%s: handling phase mismatch from SCRIPTS.\n", + ncr_name(np)); + OUTB (nc_ccntl0, np->rv_ccntl0); + OUTL (nc_pmjad1, NCB_SCRIPTH_PHYS (np, pm_handle)); + OUTL (nc_pmjad2, NCB_SCRIPTH_PHYS (np, pm_handle)); + } + + /* + ** Enable GPIO0 pin for writing if LED support from SCRIPTS. + ** Also set GPIO5 and clear GPIO6 if hardware LED control. + */ + + if (np->features & FE_LED0) + OUTB(nc_gpcntl, INB(nc_gpcntl) & ~0x01); + else if (np->features & FE_LEDC) + OUTB(nc_gpcntl, (INB(nc_gpcntl) & ~0x41) | 0x20); + + + /* + ** enable ints + */ + + OUTW (nc_sien , STO|HTH|MA|SGE|UDC|RST|PAR); + OUTB (nc_dien , MDPE|BF|SSI|SIR|IID); + + /* + ** For 895/6 enable SBMC interrupt and save current SCSI bus mode. + */ + if (np->features & FE_ULTRA2) { + OUTONW (nc_sien, SBMC); + np->scsi_mode = INB (nc_stest4) & SMODE; + } + + /* + ** Fill in target structure. + ** Reinitialize usrsync. + ** Reinitialize usrwide. + ** Prepare sync negotiation according to actual SCSI bus mode. + */ + + for (i=0;itarget[i]; + + tp->sval = 0; + tp->wval = np->rv_scntl3; + + if (tp->usrsync != 255) { + if (tp->usrsync <= np->maxsync) { + if (tp->usrsync < np->minsync) { + tp->usrsync = np->minsync; + } + } + else + tp->usrsync = 255; + }; + + if (tp->usrwide > np->maxwide) + tp->usrwide = np->maxwide; + + ncr_negotiate (np, tp); + } + + /* + ** Start script processor. + */ + MEMORY_BARRIER(); + if (np->base2_ba) { + if (bootverbose) + printk ("%s: Downloading SCSI SCRIPTS.\n", + ncr_name(np)); + if (np->features & FE_RAM8K) + phys = NCB_SCRIPTH0_PHYS (np, start_ram64); + else + phys = NCB_SCRIPTH_PHYS (np, start_ram); + } + else + phys = NCB_SCRIPT_PHYS (np, init); + + OUTL (nc_dsa, vtobus(np)); + OUTL (nc_dsp, phys); +} + +/*========================================================== +** +** Prepare the negotiation values for wide and +** synchronous transfers. +** +**========================================================== +*/ + +static void ncr_negotiate (struct ncb* np, struct tcb* tp) +{ + /* + ** minsync unit is 4ns ! + */ + + u_long minsync = tp->usrsync; + + /* + ** SCSI bus mode limit + */ + + if (np->scsi_mode && np->scsi_mode == SMODE_SE) { + if (minsync < 12) minsync = 12; + } + + /* + ** our limit .. + */ + + if (minsync < np->minsync) + minsync = np->minsync; + + /* + ** divider limit + */ + + if (minsync > np->maxsync) + minsync = 255; + + tp->minsync = minsync; + tp->maxoffs = (minsync<255 ? np->maxoffs : 0); + + /* + ** period=0: has to negotiate sync transfer + */ + + tp->period=0; + + /* + ** widedone=0: has to negotiate wide transfer + */ + tp->widedone=0; +} + +/*========================================================== +** +** Get clock factor and sync divisor for a given +** synchronous factor period. +** Returns the clock factor (in sxfer) and scntl3 +** synchronous divisor field. +** +**========================================================== +*/ + +static void ncr_getsync(ncb_p np, u_char sfac, u_char *fakp, u_char *scntl3p) +{ + u_long clk = np->clock_khz; /* SCSI clock frequency in kHz */ + int div = np->clock_divn; /* Number of divisors supported */ + u_long fak; /* Sync factor in sxfer */ + u_long per; /* Period in tenths of ns */ + u_long kpc; /* (per * clk) */ + + /* + ** Compute the synchronous period in tenths of nano-seconds + */ + if (sfac <= 10) per = 250; + else if (sfac == 11) per = 303; + else if (sfac == 12) per = 500; + else per = 40 * sfac; + + /* + ** Look for the greatest clock divisor that allows an + ** input speed faster than the period. + */ + kpc = per * clk; + while (--div >= 0) + if (kpc >= (div_10M[div] << 2)) break; + + /* + ** Calculate the lowest clock factor that allows an output + ** speed not faster than the period. + */ + fak = (kpc - 1) / div_10M[div] + 1; + +#if 0 /* This optimization does not seem very usefull */ + + per = (fak * div_10M[div]) / clk; + + /* + ** Why not to try the immediate lower divisor and to choose + ** the one that allows the fastest output speed ? + ** We dont want input speed too much greater than output speed. + */ + if (div >= 1 && fak < 8) { + u_long fak2, per2; + fak2 = (kpc - 1) / div_10M[div-1] + 1; + per2 = (fak2 * div_10M[div-1]) / clk; + if (per2 < per && fak2 <= 8) { + fak = fak2; + per = per2; + --div; + } + } +#endif + + if (fak < 4) fak = 4; /* Should never happen, too bad ... */ + + /* + ** Compute and return sync parameters for the ncr + */ + *fakp = fak - 4; + *scntl3p = ((div+1) << 4) + (sfac < 25 ? 0x80 : 0); +} + + +/*========================================================== +** +** Set actual values, sync status and patch all ccbs of +** a target according to new sync/wide agreement. +** +**========================================================== +*/ + +static void ncr_set_sync_wide_status (ncb_p np, u_char target) +{ + ccb_p cp; + tcb_p tp = &np->target[target]; + + /* + ** set actual value and sync_status + */ + OUTB (nc_sxfer, tp->sval); + OUTB (nc_scntl3, tp->wval); + + /* + ** patch ALL ccbs of this target. + */ + for (cp = np->ccbc; cp; cp = cp->link_ccb) { + if (cp->host_status == HS_IDLE) + continue; + if (cp->target != target) + continue; + cp->phys.select.sel_scntl3 = tp->wval; + cp->phys.select.sel_sxfer = tp->sval; + }; +} + +/*========================================================== +** +** Switch sync mode for current job and it's target +** +**========================================================== +*/ + +static void ncr_setsync (ncb_p np, ccb_p cp, u_char scntl3, u_char sxfer) +{ + tcb_p tp; + u_char target = INB (nc_sdid) & 0x0f; + u_char idiv; + + assert (cp); + if (!cp) return; + + assert (target == (cp->target & 0xf)); + + tp = &np->target[target]; + + if (!scntl3 || !(sxfer & 0x1f)) + scntl3 = np->rv_scntl3; + scntl3 = (scntl3 & 0xf0) | (tp->wval & EWS) | (np->rv_scntl3 & 0x07); + + /* + ** Deduce the value of controller sync period from scntl3. + ** period is in tenths of nano-seconds. + */ + + idiv = ((scntl3 >> 4) & 0x7); + if ((sxfer & 0x1f) && idiv) + tp->period = (((sxfer>>5)+4)*div_10M[idiv-1])/np->clock_khz; + else + tp->period = 0xffff; + + /* + ** Stop there if sync parameters are unchanged + */ + if (tp->sval == sxfer && tp->wval == scntl3) return; + tp->sval = sxfer; + tp->wval = scntl3; + + /* + ** Bells and whistles ;-) + */ + PRINT_TARGET(np, target); + if (sxfer & 0x01f) { + unsigned f10 = 100000 << (tp->widedone ? tp->widedone -1 : 0); + unsigned mb10 = (f10 + tp->period/2) / tp->period; + char *scsi; + + /* + ** Disable extended Sreq/Sack filtering + */ + if (tp->period <= 2000) OUTOFFB (nc_stest2, EXT); + + /* + ** Bells and whistles ;-) + */ + if (tp->period < 500) scsi = "FAST-40"; + else if (tp->period < 1000) scsi = "FAST-20"; + else if (tp->period < 2000) scsi = "FAST-10"; + else scsi = "FAST-5"; + + printk ("%s %sSCSI %d.%d MB/s (%d ns, offset %d)\n", scsi, + tp->widedone > 1 ? "WIDE " : "", + mb10 / 10, mb10 % 10, tp->period / 10, sxfer & 0x1f); + } else + printk ("%sasynchronous.\n", tp->widedone > 1 ? "wide " : ""); + + /* + ** set actual value and sync_status + ** patch ALL ccbs of this target. + */ + ncr_set_sync_wide_status(np, target); +} + +/*========================================================== +** +** Switch wide mode for current job and it's target +** SCSI specs say: a SCSI device that accepts a WDTR +** message shall reset the synchronous agreement to +** asynchronous mode. +** +**========================================================== +*/ + +static void ncr_setwide (ncb_p np, ccb_p cp, u_char wide, u_char ack) +{ + u_short target = INB (nc_sdid) & 0x0f; + tcb_p tp; + u_char scntl3; + u_char sxfer; + + assert (cp); + if (!cp) return; + + assert (target == (cp->target & 0xf)); + + tp = &np->target[target]; + tp->widedone = wide+1; + scntl3 = (tp->wval & (~EWS)) | (wide ? EWS : 0); + + sxfer = ack ? 0 : tp->sval; + + /* + ** Stop there if sync/wide parameters are unchanged + */ + if (tp->sval == sxfer && tp->wval == scntl3) return; + tp->sval = sxfer; + tp->wval = scntl3; + + /* + ** Bells and whistles ;-) + */ + if (bootverbose >= 2) { + PRINT_TARGET(np, target); + if (scntl3 & EWS) + printk ("WIDE SCSI (16 bit) enabled.\n"); + else + printk ("WIDE SCSI disabled.\n"); + } + + /* + ** set actual value and sync_status + ** patch ALL ccbs of this target. + */ + ncr_set_sync_wide_status(np, target); +} + +/*========================================================== +** +** Switch tagged mode for a target. +** +**========================================================== +*/ + +static void ncr_setup_tags (ncb_p np, u_char tn, u_char ln) +{ + tcb_p tp = &np->target[tn]; + lcb_p lp = tp->lp[ln]; + u_char reqtags, maxdepth; + + /* + ** Just in case ... + */ + if ((!tp) || (!lp)) + return; + + /* + ** If SCSI device queue depth is not yet set, leave here. + */ + if (!lp->scdev_depth) + return; + + /* + ** Donnot allow more tags than the SCSI driver can queue + ** for this device. + ** Donnot allow more tags than we can handle. + */ + maxdepth = lp->scdev_depth; + if (maxdepth > lp->maxnxs) maxdepth = lp->maxnxs; + if (lp->maxtags > maxdepth) lp->maxtags = maxdepth; + if (lp->numtags > maxdepth) lp->numtags = maxdepth; + + /* + ** only devices conformant to ANSI Version >= 2 + ** only devices capable of tagged commands + ** only if enabled by user .. + */ + if ((lp->inq_byte7 & INQ7_QUEUE) && lp->numtags > 1) { + reqtags = lp->numtags; + } else { + reqtags = 1; + }; + + /* + ** Update max number of tags + */ + lp->numtags = reqtags; + if (lp->numtags > lp->maxtags) + lp->maxtags = lp->numtags; + + /* + ** If we want to switch tag mode, we must wait + ** for no CCB to be active. + */ + if (reqtags > 1 && lp->usetags) { /* Stay in tagged mode */ + if (lp->queuedepth == reqtags) /* Already announced */ + return; + lp->queuedepth = reqtags; + } + else if (reqtags <= 1 && !lp->usetags) { /* Stay in untagged mode */ + lp->queuedepth = reqtags; + return; + } + else { /* Want to switch tag mode */ + if (lp->busyccbs) /* If not yet safe, return */ + return; + lp->queuedepth = reqtags; + lp->usetags = reqtags > 1 ? 1 : 0; + } + + /* + ** Patch the lun mini-script, according to tag mode. + */ + lp->resel_task = lp->usetags? + cpu_to_scr(NCB_SCRIPT_PHYS(np, resel_tag)) : + cpu_to_scr(NCB_SCRIPT_PHYS(np, resel_notag)); + + /* + ** Announce change to user. + */ + if (bootverbose) { + PRINT_LUN(np, tn, ln); + if (lp->usetags) + printk("tagged command queue depth set to %d\n", reqtags); + else + printk("tagged command queueing disabled\n"); + } +} + +/*---------------------------------------------------- +** +** handle user commands +** +**---------------------------------------------------- +*/ + +#ifdef SCSI_NCR_USER_COMMAND_SUPPORT + +static void ncr_usercmd (ncb_p np) +{ + u_char t; + tcb_p tp; + + switch (np->user.cmd) { + + case 0: return; + + case UC_SETSYNC: + for (t=0; tuser.target>>t)&1)) continue; + tp = &np->target[t]; + tp->usrsync = np->user.data; + ncr_negotiate (np, tp); + }; + break; + + case UC_SETTAGS: + for (t=0; tuser.target>>t)&1)) continue; + np->target[t].usrtags = np->user.data; + for (ln = 0; ln < MAX_LUN; ln++) { + lcb_p lp = np->target[t].lp[ln]; + if (!lp) + continue; + lp->maxtags = lp->numtags = np->user.data; + ncr_setup_tags (np, t, ln); + } + }; + break; + + case UC_SETDEBUG: +#ifdef SCSI_NCR_DEBUG_INFO_SUPPORT + ncr_debug = np->user.data; +#endif + break; + + case UC_SETORDER: + np->order = np->user.data; + break; + + case UC_SETVERBOSE: + np->verbose = np->user.data; + break; + + case UC_SETWIDE: + for (t=0; tuser.target>>t)&1)) continue; + tp = &np->target[t]; + size = np->user.data; + if (size > np->maxwide) size=np->maxwide; + tp->usrwide = size; + ncr_negotiate (np, tp); + }; + break; + + case UC_SETFLAG: + for (t=0; tuser.target>>t)&1)) continue; + tp = &np->target[t]; + tp->usrflag = np->user.data; + }; + break; + +#ifdef SCSI_NCR_PROFILE_SUPPORT + case UC_CLEARPROF: + bzero(&np->profile, sizeof(np->profile)); + break; +#endif + } + np->user.cmd=0; +} +#endif + +/*========================================================== +** +** +** ncr timeout handler. +** +** +**========================================================== +** +** Misused to keep the driver running when +** interrupts are not configured correctly. +** +**---------------------------------------------------------- +*/ + +static void ncr_timeout (ncb_p np) +{ + u_long thistime = jiffies; + + /* + ** If release process in progress, let's go + ** Set the release stage from 1 to 2 to synchronize + ** with the release process. + */ + + if (np->release_stage) { + if (np->release_stage == 1) np->release_stage = 2; + return; + } + + np->timer.expires = jiffies + SCSI_NCR_TIMER_INTERVAL; + add_timer(&np->timer); + + /* + ** If we are resetting the ncr, wait for settle_time before + ** clearing it. Then command processing will be resumed. + */ + if (np->settle_time) { + if (np->settle_time <= thistime) { + if (bootverbose > 1) + printk("%s: command processing resumed\n", ncr_name(np)); + np->settle_time = 0; + requeue_waiting_list(np); + } + return; + } + + /* + ** Nothing to do for now, but that may come. + */ + if (np->lasttime + 4*HZ < thistime) { + np->lasttime = thistime; + } + +#ifdef SCSI_NCR_BROKEN_INTR + if (INB(nc_istat) & (INTF|SIP|DIP)) { + + /* + ** Process pending interrupts. + */ + if (DEBUG_FLAGS & DEBUG_TINY) printk ("{"); + ncr_exception (np); + if (DEBUG_FLAGS & DEBUG_TINY) printk ("}"); + } +#endif /* SCSI_NCR_BROKEN_INTR */ +} + +/*========================================================== +** +** log message for real hard errors +** +** "ncr0 targ 0?: ERROR (ds:si) (so-si-sd) (sxfer/scntl3) @ name (dsp:dbc)." +** " reg: r0 r1 r2 r3 r4 r5 r6 ..... rf." +** +** exception register: +** ds: dstat +** si: sist +** +** SCSI bus lines: +** so: control lines as driver by NCR. +** si: control lines as seen by NCR. +** sd: scsi data lines as seen by NCR. +** +** wide/fastmode: +** sxfer: (see the manual) +** scntl3: (see the manual) +** +** current script command: +** dsp: script adress (relative to start of script). +** dbc: first word of script command. +** +** First 16 register of the chip: +** r0..rf +** +**========================================================== +*/ + +static void ncr_log_hard_error(ncb_p np, u_short sist, u_char dstat) +{ + u_int32 dsp; + int script_ofs; + int script_size; + char *script_name; + u_char *script_base; + int i; + + dsp = INL (nc_dsp); + + if (dsp > np->p_script && dsp <= np->p_script + sizeof(struct script)) { + script_ofs = dsp - np->p_script; + script_size = sizeof(struct script); + script_base = (u_char *) np->script0; + script_name = "script"; + } + else if (np->p_scripth < dsp && + dsp <= np->p_scripth + sizeof(struct scripth)) { + script_ofs = dsp - np->p_scripth; + script_size = sizeof(struct scripth); + script_base = (u_char *) np->scripth0; + script_name = "scripth"; + } else { + script_ofs = dsp; + script_size = 0; + script_base = 0; + script_name = "mem"; + } + + printk ("%s:%d: ERROR (%x:%x) (%x-%x-%x) (%x/%x) @ (%s %x:%08x).\n", + ncr_name (np), (unsigned)INB (nc_sdid)&0x0f, dstat, sist, + (unsigned)INB (nc_socl), (unsigned)INB (nc_sbcl), (unsigned)INB (nc_sbdl), + (unsigned)INB (nc_sxfer),(unsigned)INB (nc_scntl3), script_name, script_ofs, + (unsigned)INL (nc_dbc)); + + if (((script_ofs & 3) == 0) && + (unsigned)script_ofs < script_size) { + printk ("%s: script cmd = %08x\n", ncr_name(np), + scr_to_cpu((int) *(ncrcmd *)(script_base + script_ofs))); + } + + printk ("%s: regdump:", ncr_name(np)); + for (i=0; i<16;i++) + printk (" %02x", (unsigned)INB_OFF(i)); + printk (".\n"); +} + +/*============================================================ +** +** ncr chip exception handler. +** +**============================================================ +** +** In normal situations, interrupt conditions occur one at +** a time. But when something bad happens on the SCSI BUS, +** the chip may raise several interrupt flags before +** stopping and interrupting the CPU. The additionnal +** interrupt flags are stacked in some extra registers +** after the SIP and/or DIP flag has been raised in the +** ISTAT. After the CPU has read the interrupt condition +** flag from SIST or DSTAT, the chip unstacks the other +** interrupt flags and sets the corresponding bits in +** SIST or DSTAT. Since the chip starts stacking once the +** SIP or DIP flag is set, there is a small window of time +** where the stacking does not occur. +** +** Typically, multiple interrupt conditions may happen in +** the following situations: +** +** - SCSI parity error + Phase mismatch (PAR|MA) +** When an parity error is detected in input phase +** and the device switches to msg-in phase inside a +** block MOV. +** - SCSI parity error + Unexpected disconnect (PAR|UDC) +** When a stupid device does not want to handle the +** recovery of an SCSI parity error. +** - Some combinations of STO, PAR, UDC, ... +** When using non compliant SCSI stuff, when user is +** doing non compliant hot tampering on the BUS, when +** something really bad happens to a device, etc ... +** +** The heuristic suggested by SYMBIOS to handle +** multiple interrupts is to try unstacking all +** interrupts conditions and to handle them on some +** priority based on error severity. +** This will work when the unstacking has been +** successful, but we cannot be 100 % sure of that, +** since the CPU may have been faster to unstack than +** the chip is able to stack. Hmmm ... But it seems that +** such a situation is very unlikely to happen. +** +** If this happen, for example STO catched by the CPU +** then UDC happenning before the CPU have restarted +** the SCRIPTS, the driver may wrongly complete the +** same command on UDC, since the SCRIPTS didn't restart +** and the DSA still points to the same command. +** We avoid this situation by setting the DSA to an +** invalid value when the CCB is completed and before +** restarting the SCRIPTS. +** +** Another issue is that we need some section of our +** recovery procedures to be somehow uninterruptible and +** that the SCRIPTS processor does not provides such a +** feature. For this reason, we handle recovery preferently +** from the C code and check against some SCRIPTS +** critical sections from the C code. +** +** Hopefully, the interrupt handling of the driver is now +** able to resist to weird BUS error conditions, but donnot +** ask me for any guarantee that it will never fail. :-) +** Use at your own decision and risk. +** +**============================================================ +*/ + +void ncr_exception (ncb_p np) +{ + u_char istat, istatc; + u_char dstat; + u_short sist; + int i; + +#ifdef SCSI_NCR_OPTIMIZE_896_1 + /* + ** This optimization when used with a 896 that handles + ** phase mismatch from the SCRIPTS allows to only do + ** PCI memory writes transactions from the CPU and so to + ** take advantage of PCI posted writes. + ** Who wants his 500 MHz CPU to wait several micro-seconds + ** for the PCI BUS to be granted when this can be avoided? + ** I don't, even for my slow 233 MHz PII. :-) + ** + ** We assume we have been called for command completion. + ** If no completion found, go with normal handling. + ** Ordering is ensured by the SCRIPTS performing a read + ** from main memory prior to raising INTFLY. + ** We have to raise SIGP since the chip may be currently + ** going to a wait reselect instruction. IMO, SIGP should + ** not be clearable in ISTAT since it can be polled and + ** cleared by reading CTEST2. This tiny chip misdesign is a + ** penalty here. + ** + ** The MA interrupt and interrupt sharing may also have + ** adverse effects on this optimization, so we only want + ** to use it if it is enabled by user. + ** (BTW, this optimization seems to even have some goodness + ** with my 895 that unfortunately suffers of the MA int.). + */ + if (driver_setup.optimize & 1) { + OUTB(nc_istat, (INTF | SIGP)); + if (ncr_wakeup_done (np)) { +#ifdef SCSI_NCR_PROFILE_SUPPORT + ++np->profile.num_fly; +#endif + return; + } + } +#endif /* SCSI_NCR_OPTIMIZE_896_1 */ + + /* + ** interrupt on the fly ? + */ + istat = INB (nc_istat); + if (istat & INTF) { + OUTB (nc_istat, (istat & SIGP) | INTF); + if (DEBUG_FLAGS & DEBUG_TINY) printk ("F "); + (void)ncr_wakeup_done (np); +#ifdef SCSI_NCR_PROFILE_SUPPORT + ++np->profile.num_fly; +#endif + }; + + if (!(istat & (SIP|DIP))) + return; + +#ifdef SCSI_NCR_PROFILE_SUPPORT + ++np->profile.num_int; +#endif + +#if 0 /* We should never get this one */ + if (istat & CABRT) + OUTB (nc_istat, CABRT); +#endif + + /* + ** Steinbach's Guideline for Systems Programming: + ** Never test for an error condition you don't know how to handle. + */ + + /*======================================================== + ** PAR and MA interrupts may occur at the same time, + ** and we need to know of both in order to handle + ** this situation properly. We try to unstack SCSI + ** interrupts for that reason. BTW, I dislike a LOT + ** such a loop inside the interrupt routine. + ** Even if DMA interrupt stacking is very unlikely to + ** happen, we also try unstacking these ones, since + ** this has no performance impact. + **========================================================= + */ + sist = 0; + dstat = 0; + istatc = istat; + do { + if (istatc & SIP) + sist |= INW (nc_sist); + if (istatc & DIP) + dstat |= INB (nc_dstat); + istatc = INB (nc_istat); + istat |= istatc; + } while (istatc & (SIP|DIP)); + + if (DEBUG_FLAGS & DEBUG_TINY) + printk ("<%d|%x:%x|%x:%x>", + (int)INB(nc_scr0), + dstat,sist, + (unsigned)INL(nc_dsp), + (unsigned)INL(nc_dbc)); + + /*======================================================== + ** First, interrupts we want to service cleanly. + ** + ** Phase mismatch (MA) is the most frequent interrupt + ** for chip earlier than the 896 and so we have to service + ** it as quickly as possible. + ** A SCSI parity error (PAR) may be combined with a phase + ** mismatch condition (MA). + ** Programmed interrupts (SIR) are used to call the C code + ** from SCRIPTS. + ** The single step interrupt (SSI) is not used in this + ** driver. + **========================================================= + */ + + if (!(sist & (STO|GEN|HTH|SGE|UDC|SBMC|RST)) && + !(dstat & (MDPE|BF|ABRT|IID))) { + if (sist & PAR) ncr_int_par (np, sist); + else if (sist & MA) ncr_int_ma (np); + else if (dstat & SIR) ncr_int_sir (np); + else if (dstat & SSI) OUTONB (nc_dcntl, (STD|NOCOM)); + else goto unknown_int; + return; + }; + + /*======================================================== + ** Now, interrupts that donnot happen in normal + ** situations and that we may need to recover from. + ** + ** On SCSI RESET (RST), we reset everything. + ** On SCSI BUS MODE CHANGE (SBMC), we complete all + ** active CCBs with RESET status, prepare all devices + ** for negotiating again and restart the SCRIPTS. + ** On STO and UDC, we complete the CCB with the corres- + ** ponding status and restart the SCRIPTS. + **========================================================= + */ + + if (sist & RST) { + ncr_init (np, 1, bootverbose ? "scsi reset" : NULL, HS_RESET); + return; + }; + + OUTB (nc_ctest3, np->rv_ctest3 | CLF); /* clear dma fifo */ + OUTB (nc_stest3, TE|CSF); /* clear scsi fifo */ + + if (!(sist & (GEN|HTH|SGE)) && + !(dstat & (MDPE|BF|ABRT|IID))) { + if (sist & SBMC) ncr_int_sbmc (np); + else if (sist & STO) ncr_int_sto (np); + else if (sist & UDC) ncr_int_udc (np); + else goto unknown_int; + return; + }; + + /*========================================================= + ** Now, interrupts we are not able to recover cleanly. + ** + ** Do the register dump. + ** Log message for hard errors. + ** Reset everything. + **========================================================= + */ + if (jiffies - np->regtime > 10*HZ) { + np->regtime = jiffies; + for (i = 0; iregdump); i++) + ((char*)&np->regdump)[i] = INB_OFF(i); + np->regdump.nc_dstat = dstat; + np->regdump.nc_sist = sist; + }; + + ncr_log_hard_error(np, sist, dstat); + + if ((sist & (GEN|HTH|SGE)) || + (dstat & (MDPE|BF|ABRT|IID))) { + ncr_start_reset(np); + return; + }; + +unknown_int: + /*========================================================= + ** We just miss the cause of the interrupt. :( + ** Print a message. The timeout will do the real work. + **========================================================= + */ + printk( "%s: unknown interrupt(s) ignored, " + "ISTAT=0x%x DSTAT=0x%x SIST=0x%x\n", + ncr_name(np), istat, dstat, sist); +} + + +/*========================================================== +** +** generic recovery from scsi interrupt +** +**========================================================== +** +** The doc says that when the chip gets an SCSI interrupt, +** it tries to stop in an orderly fashion, by completing +** an instruction fetch that had started or by flushing +** the DMA fifo for a write to memory that was executing. +** Such a fashion is not enough to know if the instruction +** that was just before the current DSP value has been +** executed or not. +** +** There are 3 small SCRIPTS sections that deal with the +** start queue and the done queue that may break any +** assomption from the C code if we are interrupted +** inside, so we reset if it happens. Btw, since these +** SCRIPTS sections are executed while the SCRIPTS hasn't +** started SCSI operations, it is very unlikely to happen. +** +** All the driver data structures are supposed to be +** allocated from the same 4 GB memory window, so there +** is a 1 to 1 relationship between DSA and driver data +** structures. Since we are careful :) to invalidate the +** DSA when we complete a command or when the SCRIPTS +** pushes a DSA into a queue, we can trust it when it +** points to a CCB. +** +**---------------------------------------------------------- +*/ +static void ncr_recover_scsi_int (ncb_p np, u_char hsts) +{ + u_int32 dsp = INL (nc_dsp); + u_int32 dsa = INL (nc_dsa); + u_char scntl1 = INB (nc_scntl1); + ccb_p cp = ncr_ccb_from_dsa(np, dsa); + + /* + ** If we are connected to the SCSI BUS, we only + ** can reset the BUS. + */ + if (scntl1 & ISCON) + goto reset_all; + + /* + ** If we haven't been interrupted inside the SCRIPTS + ** critical pathes, we can safely restart the SCRIPTS + ** and trust the DSA value if it matches a CCB. + */ + if ((!(dsp > NCB_SCRIPT_PHYS (np, getjob_begin) && + dsp < NCB_SCRIPT_PHYS (np, getjob_end) + 1)) && + (!(dsp > NCB_SCRIPT_PHYS (np, ungetjob) && + dsp < NCB_SCRIPT_PHYS (np, reselect) + 1)) && + (!(dsp > NCB_SCRIPT_PHYS (np, done) && + dsp < NCB_SCRIPT_PHYS (np, done_end) + 1))) { + if (cp) { + cp->host_status = hsts; + ncr_complete (np, cp); + } + OUTL (nc_dsa, DSA_INVALID); + OUTB (nc_ctest3, np->rv_ctest3 | CLF); /* clear dma fifo */ + OUTB (nc_stest3, TE|CSF); /* clear scsi fifo */ + OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, start)); + } + else + goto reset_all; + + return; + +reset_all: + ncr_start_reset(np); +} + +/*========================================================== +** +** ncr chip exception handler for selection timeout +** +**========================================================== +** +** There seems to be a bug in the 53c810. +** Although a STO-Interrupt is pending, +** it continues executing script commands. +** But it will fail and interrupt (IID) on +** the next instruction where it's looking +** for a valid phase. +** +**---------------------------------------------------------- +*/ + +void ncr_int_sto (ncb_p np) +{ + u_int32 dsp = INL (nc_dsp); + + if (DEBUG_FLAGS & DEBUG_TINY) printk ("T"); + + if (dsp == NCB_SCRIPT_PHYS (np, wf_sel_done) + 8 || + dsp == NCB_SCRIPTH_PHYS (np, wf_sel_done_no_atn) + 8 || + !(driver_setup.recovery & 1)) + ncr_recover_scsi_int(np, HS_SEL_TIMEOUT); + else + ncr_start_reset(np); +} + +/*========================================================== +** +** ncr chip exception handler for unexpected disconnect +** +**========================================================== +** +**---------------------------------------------------------- +*/ +void ncr_int_udc (ncb_p np) +{ + printk ("%s: unexpected disconnect\n", ncr_name(np)); + ncr_recover_scsi_int(np, HS_UNEXPECTED); +} + +/*========================================================== +** +** ncr chip exception handler for SCSI bus mode change +** +**========================================================== +** +** spi2-r12 11.2.3 says a transceiver mode change must +** generate a reset event and a device that detects a reset +** event shall initiate a hard reset. It says also that a +** device that detects a mode change shall set data transfer +** mode to eight bit asynchronous, etc... +** So, just resetting should be enough. +** +** +**---------------------------------------------------------- +*/ + +static void ncr_int_sbmc (ncb_p np) +{ + u_char scsi_mode = INB (nc_stest4) & SMODE; + + printk("%s: SCSI bus mode change from %x to %x.\n", + ncr_name(np), np->scsi_mode, scsi_mode); + + np->scsi_mode = scsi_mode; + + + /* + ** Suspend command processing for 1 second and + ** reinitialize all except the chip. + */ + np->settle_time = jiffies + HZ; + ncr_init (np, 0, bootverbose ? "scsi mode change" : NULL, HS_RESET); +} + +/*========================================================== +** +** ncr chip exception handler for SCSI parity error. +** +**========================================================== +** +** When the chip detects a SCSI parity error and is +** currently executing a (CH)MOV instruction, it does +** not interrupt immediately, but tries to finish the +** transfer of the current scatter entry before +** interrupting. The following situations may occur: +** +** - The complete scatter entry has been transferred +** without the device having changed phase. +** The chip will then interrupt with the DSP pointing +** to the instruction that follows the MOV. +** +** - A phase mismatch occurs before the MOV finished +** and phase errors are to be handled by the C code. +** The chip will then interrupt with both PAR and MA +** conditions set. +** +** - A phase mismatch occurs before the MOV finished +** and phase errors are to be handled by SCRIPTS (896). +** The chip will load the DSP with the phase mismatch +** JUMP address and interrupt the host processor. +** +**---------------------------------------------------------- +*/ + +static void ncr_int_par (ncb_p np, u_short sist) +{ + u_char hsts = INB (HS_PRT); + u_int32 dsp = INL (nc_dsp); + u_int32 dbc = INL (nc_dbc); + u_int32 dsa = INL (nc_dsa); + u_char sbcl = INB (nc_sbcl); + u_char cmd = dbc >> 24; + int phase = cmd & 7; + + printk("%s: SCSI parity error detected: SCR1=%d DBC=%x SBCL=%x\n", + ncr_name(np), hsts, dbc, sbcl); + + /* + ** Check that the chip is connected to the SCSI BUS. + */ + if (!(INB (nc_scntl1) & ISCON)) { + if (!(driver_setup.recovery & 1)) { + ncr_recover_scsi_int(np, HS_FAIL); + return; + } + goto reset_all; + } + + /* + ** If the nexus is not clearly identified, reset the bus. + ** We will try to do better later. + */ + if (!ncr_ccb_from_dsa(np, dsa)) + goto reset_all; + + /* + ** Check instruction was a MOV, direction was INPUT and + ** ATN is asserted. + */ + if ((cmd & 0xc0) || !(phase & 1) || !(sbcl & 0x8)) + goto reset_all; + + /* + ** Keep track of the parity error. + */ + OUTONB (HF_PRT, HF_PAR_ERR); + + /* + ** Prepare the message to send to the device. + */ + np->msgout[0] = (phase == 7) ? M_PARITY : M_ID_ERROR; + + /* + ** If the old phase was DATA IN phase, we have to deal with + ** the 3 situations described above. + ** For other input phases (MSG IN and STATUS), the device + ** must resend the whole thing that failed parity checking + ** or signal error. So, jumping to dispatcher should be OK. + */ + if (phase == 1) { + /* Phase mismatch handled by SCRIPTS */ + if (dsp == NCB_SCRIPTH_PHYS (np, pm_handle)) + OUTL (nc_dsp, dsp); + /* Phase mismatch handled by the C code */ + else if (sist & MA) + ncr_int_ma (np); + /* No phase mismatch occurred */ + else { + OUTL (nc_temp, dsp); + OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, databreak)); + } + } + else + OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, clrack)); + return; + +reset_all: + ncr_start_reset(np); + return; +} + +/*========================================================== +** +** +** ncr chip exception handler for phase errors. +** +** +**========================================================== +** +** We have to construct a new transfer descriptor, +** to transfer the rest of the current block. +** +**---------------------------------------------------------- +*/ + +static void ncr_int_ma (ncb_p np) +{ + u_int32 dbc; + u_int32 rest; + u_int32 dsp; + u_int32 dsa; + u_int32 nxtdsp; + u_int32 *vdsp; + u_int32 oadr, olen; + u_int32 *tblp; + u_int32 newcmd; + u_int delta; + u_char cmd; + u_char hflags, hflags0; + struct pm_ctx *pm; + ccb_p cp; + +#ifdef SCSI_NCR_PROFILE_SUPPORT + ++np->profile.num_break; +#endif + + dsp = INL (nc_dsp); + dbc = INL (nc_dbc); + dsa = INL (nc_dsa); + + cmd = dbc >> 24; + rest = dbc & 0xffffff; + delta = 0; + + /* + ** locate matching cp. + */ + cp = ncr_ccb_from_dsa(np, dsa); + + /* + ** Donnot take into account dma fifo and various buffers in + ** DATA IN phase since the chip flushes everything before + ** raising the MA interrupt for interrupted INPUT phases. + */ + if ((cmd & 7) != 1) { + u_int32 dfifo; + u_char ss0, ss2; + + /* + ** Read DFIFO, CTEST[4-6] using 1 PCI bus ownership. + */ + dfifo = INL(nc_dfifo); + + /* + ** Calculate remaining bytes in DMA fifo. + ** (CTEST5 = dfifo >> 16) + */ + if (dfifo & (DFS << 16)) + delta = ((((dfifo >> 8) & 0x300) | + (dfifo & 0xff)) - rest) & 0x3ff; + else + delta = ((dfifo & 0xff) - rest) & 0x7f; + + /* + ** The data in the dma fifo has not been transfered to + ** the target -> add the amount to the rest + ** and clear the data. + ** Check the sstat2 register in case of wide transfer. + */ + rest += delta; + ss0 = INB (nc_sstat0); + if (ss0 & OLF) rest++; + if (ss0 & ORF) rest++; + if (cp && (cp->phys.select.sel_scntl3 & EWS)) { + ss2 = INB (nc_sstat2); + if (ss2 & OLF1) rest++; + if (ss2 & ORF1) rest++; + }; + + /* + ** Clear fifos. + */ + OUTB (nc_ctest3, np->rv_ctest3 | CLF); /* dma fifo */ + OUTB (nc_stest3, TE|CSF); /* scsi fifo */ + }; + + /* + ** log the information + */ + + if (DEBUG_FLAGS & (DEBUG_TINY|DEBUG_PHASE)) + printk ("P%x%x RL=%d D=%d ", cmd&7, INB(nc_sbcl)&7, + (unsigned) rest, (unsigned) delta); + + /* + ** try to find the interrupted script command, + ** and the address at which to continue. + */ + vdsp = 0; + nxtdsp = 0; + if (dsp > np->p_script && + dsp <= np->p_script + sizeof(struct script)) { + vdsp = (u_int32 *)((char*)np->script0 + (dsp-np->p_script-8)); + nxtdsp = dsp; + } + else if (dsp > np->p_scripth && + dsp <= np->p_scripth + sizeof(struct scripth)) { + vdsp = (u_int32 *)((char*)np->scripth0 + (dsp-np->p_scripth-8)); + nxtdsp = dsp; + } + + /* + ** log the information + */ + if (DEBUG_FLAGS & DEBUG_PHASE) { + printk ("\nCP=%p DSP=%x NXT=%x VDSP=%p CMD=%x ", + cp, (unsigned)dsp, (unsigned)nxtdsp, vdsp, cmd); + }; + + if (!vdsp) { + printk ("%s: interrupted SCRIPT address not found.\n", + ncr_name (np)); + goto reset_all; + } + + if (!cp) { + printk ("%s: SCSI phase error fixup: CCB already dequeued.\n", + ncr_name (np)); + goto reset_all; + } + + /* + ** get old startaddress and old length. + */ + + oadr = scr_to_cpu(vdsp[1]); + + if (cmd & 0x10) { /* Table indirect */ + tblp = (u_int32 *) ((char*) &cp->phys + oadr); + olen = scr_to_cpu(tblp[0]); + oadr = scr_to_cpu(tblp[1]); + } else { + tblp = (u_int32 *) 0; + olen = scr_to_cpu(vdsp[0]) & 0xffffff; + }; + + if (DEBUG_FLAGS & DEBUG_PHASE) { + printk ("OCMD=%x\nTBLP=%p OLEN=%x OADR=%x\n", + (unsigned) (scr_to_cpu(vdsp[0]) >> 24), + tblp, + (unsigned) olen, + (unsigned) oadr); + }; + + /* + ** check cmd against assumed interrupted script command. + */ + + if (cmd != (scr_to_cpu(vdsp[0]) >> 24)) { + PRINT_ADDR(cp->cmd); + printk ("internal error: cmd=%02x != %02x=(vdsp[0] >> 24)\n", + (unsigned)cmd, (unsigned)scr_to_cpu(vdsp[0]) >> 24); + + goto reset_all; + }; + + /* + ** if old phase not dataphase, leave here. + */ + + if (cmd & 0x06) { + PRINT_ADDR(cp->cmd); + printk ("phase change %x-%x %d@%08x resid=%d.\n", + cmd&7, INB(nc_sbcl)&7, (unsigned)olen, + (unsigned)oadr, (unsigned)rest); + goto unexpected_phase; + }; + + /* + ** Choose the correct PM save area. + ** + ** Look at the PM_SAVE SCRIPT if you want to understand + ** this stuff. The equivalent code is implemented in + ** SCRIPTS for the 896 that is able to handle PM from + ** the SCRIPTS processor. + */ + + hflags0 = INB (HF_PRT); + hflags = hflags0; + + if (hflags & (HF_IN_PM0 | HF_IN_PM1 | HF_DP_SAVED)) { + if (hflags & HF_IN_PM0) + nxtdsp = scr_to_cpu(cp->phys.pm0.ret); + else if (hflags & HF_IN_PM1) + nxtdsp = scr_to_cpu(cp->phys.pm1.ret); + + if (hflags & HF_DP_SAVED) + hflags ^= HF_ACT_PM; + } + + if (!(hflags & HF_ACT_PM)) { + pm = &cp->phys.pm0; + newcmd = NCB_SCRIPT_PHYS(np, pm0_data); + } + else { + pm = &cp->phys.pm1; + newcmd = NCB_SCRIPT_PHYS(np, pm1_data); + } + + hflags &= ~(HF_IN_PM0 | HF_IN_PM1 | HF_DP_SAVED); + if (hflags != hflags0) + OUTB (HF_PRT, hflags); + + /* + ** fillin the phase mismatch context + */ + + pm->sg.addr = cpu_to_scr(oadr + olen - rest); + pm->sg.size = cpu_to_scr(rest); + pm->ret = cpu_to_scr(nxtdsp); + + if (DEBUG_FLAGS & DEBUG_PHASE) { + PRINT_ADDR(cp->cmd); + printk ("PM %x %x %x / %x %x %x.\n", + hflags0, hflags, newcmd, + (unsigned)scr_to_cpu(pm->sg.addr), + (unsigned)scr_to_cpu(pm->sg.size), + (unsigned)scr_to_cpu(pm->ret)); + } + + /* + ** fake the return address (to the patch). + ** and restart script processor at dispatcher. + */ + + OUTL (nc_temp, newcmd); + OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, databreak)); + return; + + /* + ** Unexpected phase changes that occurs when the current phase + ** is not a DATA IN or DATA OUT phase are due to error conditions. + ** Such event may only happen when the SCRIPTS is using a + ** multibyte SCSI MOVE. + ** + ** Phase change Some possible cause + ** + ** COMMAND --> MSG IN SCSI parity error detected by target. + ** COMMAND --> STATUS Bad command or refused by target. + ** MSG OUT --> MSG IN Message rejected by target. + ** MSG OUT --> COMMAND Bogus target that discards extended + ** negotiation messages. + ** + ** The code below does not care of the new phase and so + ** trusts the target. Why to annoy it ? + ** If the interrupted phase is COMMAND phase, we restart at + ** dispatcher. + ** If a target does not get all the messages after selection, + ** the code assumes blindly that the target discards extended + ** messages and clears the negotiation status. + ** If the target does not want all our response to negotiation, + ** we force a SIR_NEGO_PROTO interrupt (it is a hack that avoids + ** bloat for such a should_not_happen situation). + ** In all other situation, we reset the BUS. + ** Are these assumptions reasonnable ? (Wait and see ...) + */ +unexpected_phase: + dsp -= 8; + nxtdsp = 0; + + switch (cmd & 7) { + case 2: /* COMMAND phase */ + nxtdsp = NCB_SCRIPT_PHYS (np, dispatch); + break; +#if 0 + case 3: /* STATUS phase */ + nxtdsp = NCB_SCRIPT_PHYS (np, dispatch); + break; +#endif + case 6: /* MSG OUT phase */ + /* + ** If the device may want to use untagged when we want + ** tagged, we prepare an IDENTIFY without disc. granted, + ** since we will not be able to handle reselect. + ** Otherwise, we just don't care. + */ + if (dsp == NCB_SCRIPT_PHYS (np, send_ident)) { + if (cp->tag != NO_TAG && olen - rest <= 3) { + cp->host_status = HS_BUSY; + np->msgout[0] = M_IDENTIFY | cp->lun; + nxtdsp = NCB_SCRIPTH_PHYS (np, ident_break_atn); + } + else + nxtdsp = NCB_SCRIPTH_PHYS (np, ident_break); + } + else if (dsp == NCB_SCRIPTH_PHYS (np, send_wdtr) || + dsp == NCB_SCRIPTH_PHYS (np, send_sdtr)) { + nxtdsp = NCB_SCRIPTH_PHYS (np, nego_bad_phase); + } + break; +#if 0 + case 7: /* MSG IN phase */ + nxtdsp = NCB_SCRIPT_PHYS (np, clrack); + break; +#endif + } + + if (nxtdsp) { + OUTL (nc_dsp, nxtdsp); + return; + } + +reset_all: + ncr_start_reset(np); +} + +/*========================================================== +** +** ncr chip handler for QUEUE FULL and CHECK CONDITION +** +**========================================================== +** +** On QUEUE FULL status, we set the actual tagged command +** queue depth to the number of disconnected CCBs that is +** hopefully a good value to avoid further QUEUE FULL. +** +** On CHECK CONDITION or COMMAND TERMINATED, we use the +** CCB of the failed command for performing a REQUEST +** SENSE SCSI command. +** +** We do not want to change the order commands will be +** actually queued to the device after we received a +** QUEUE FULL status. We also want to properly deal with +** contingent allegiance condition. For these reasons, +** we remove from the start queue all commands for this +** LUN that haven't been yet queued to the device and +** put them back in the correponding LUN queue, then +** requeue the CCB that failed in front of the LUN queue. +** I just hope this not to be performed too often. :) +** +**---------------------------------------------------------- +*/ + +static void ncr_sir_to_redo(ncb_p np, int num, ccb_p cp) +{ + Scsi_Cmnd *cmd = cp->cmd; + tcb_p tp = &np->target[cp->target]; + lcb_p lp = tp->lp[cp->lun]; + ccb_p cp2; + int busyccbs = 1; + u_int32 startp; + u_char s_status = INB (SS_PRT); + + /* + ** Remove all CCBs queued to the chip for that LUN and put + ** them back in the LUN CCB wait queue. + */ + if (lp) { + int i = np->squeueput; + int j = (INL (nc_scratcha) - vtobus(np->squeue)) / 4; + int k = np->squeueput; + + busyccbs = lp->queuedccbs; + while (1) { + if (i == j) + break; + if (i == 0) + i = MAX_START*2; + i = i - 2; + cp2 = ncr_ccb_from_dsa(np, scr_to_cpu(np->squeue[i])); + if (!cp2) + continue; + if (cp2->target != cp->target || cp2->lun != cp->lun) + continue; + xpt_remque(&cp2->link_ccbq); + xpt_insque_head(&cp2->link_ccbq, &lp->wait_ccbq); + --lp->queuedccbs; + cp2->queued = 0; + np->squeue[i] = DSA_INVALID; + k = i; + } + + /* + ** Requeue the interrupted CCB in front of + ** the LUN CCB wait queue. + */ + xpt_remque(&cp->link_ccbq); + xpt_insque_head(&cp->link_ccbq, &lp->wait_ccbq); + --lp->queuedccbs; + cp->queued = 0; + + /* + ** Repair the startqueue if necessary. + */ + if (k != np->squeueput) { + j = k; + while (1) { + j += 2; + if (j >= MAX_START*2) + j = 0; + if (np->squeue[j] == DSA_INVALID) + continue; + np->squeue[k] = np->squeue[j]; + if (j == np->squeueput) + break; + k += 2; + if (k >= MAX_START*2) + k = 0; + } + np->squeueput = k; + } + } + + /* + ** Now we can restart the SCRIPTS processor safely. + */ + MEMORY_BARRIER(); + OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, start)); + + switch(s_status) { + default: /* Just for safety, should never happen */ + case S_QUEUE_FULL: + if (!lp || !lp->queuedccbs) { + ncr_complete(np, cp); + break; + } + if (bootverbose >= 1) { + PRINT_ADDR(cmd); + printk ("QUEUE FULL! %d busy, %d disconnected CCBs\n", + busyccbs, lp->queuedccbs); + } + /* + ** Decrease number of tags to the number of + ** disconnected commands. + */ + if (lp->queuedccbs < lp->numtags) { + lp->numtags = lp->queuedccbs; + lp->num_good = 0; + ncr_setup_tags (np, cp->target, cp->lun); + } + /* + ** Repair the offending CCB. + */ + cp->phys.header.savep = cp->startp; + cp->host_status = HS_BUSY; + cp->scsi_status = S_ILLEGAL; + cp->host_flags &= HF_PM_TO_C; + + break; + + case S_TERMINATED: + case S_CHECK_COND: + /* + ** If we were requesting sense, give up. + */ + if (cp->auto_sense) { + ncr_complete(np, cp); + break; + } + + /* + ** Device returned CHECK CONDITION status. + ** Prepare all needed data strutures for getting + ** sense data. + */ + + /* + ** identify message + */ + cp->scsi_smsg2[0] = M_IDENTIFY | cp->lun; + cp->phys.smsg.addr = cpu_to_scr(CCB_PHYS (cp, scsi_smsg2)); + cp->phys.smsg.size = cpu_to_scr(1); + + /* + ** sense command + */ + cp->phys.cmd.addr = cpu_to_scr(CCB_PHYS (cp, sensecmd)); + cp->phys.cmd.size = cpu_to_scr(6); + + /* + ** patch requested size into sense command + */ + cp->sensecmd[0] = 0x03; + cp->sensecmd[1] = cp->lun << 5; + cp->sensecmd[4] = sizeof(cmd->sense_buffer); + + /* + ** sense data + */ + cp->phys.sense.addr = + cpu_to_scr(vtobus (&cmd->sense_buffer[0])); + cp->phys.sense.size = + cpu_to_scr(sizeof(cmd->sense_buffer)); + + /* + ** requeue the command. + */ + startp = cpu_to_scr(NCB_SCRIPTH_PHYS (np, sdata_in)); + + cp->phys.header.savep = startp; + cp->phys.header.goalp = startp + 24; + cp->phys.header.lastp = startp; + cp->phys.header.wgoalp = startp + 24; + cp->phys.header.wlastp = startp; + + cp->host_status = HS_BUSY; + cp->scsi_status = S_ILLEGAL; + cp->host_flags = 0; + cp->auto_sense = s_status; + + cp->phys.header.go.start = + cpu_to_scr(NCB_SCRIPT_PHYS (np, select)); + + /* + ** Select without ATN for quirky devices. + */ + if (tp->quirks & QUIRK_NOMSG) + cp->phys.header.go.start = + cpu_to_scr(NCB_SCRIPTH_PHYS (np, select_no_atn)); + + /* + ** If lp not yet allocated, requeue the command. + */ + if (!lp) + ncr_put_start_queue(np, cp); + break; + } + + /* + ** requeue awaiting scsi commands for this lun. + */ + if (lp) + ncr_start_next_ccb(np, lp, 1); + + return; +} + + +/*========================================================== +** +** +** ncr chip exception handler for programmed interrupts. +** +** +**========================================================== +*/ + +static int ncr_show_msg (u_char * msg) +{ + u_char i; + printk ("%x",*msg); + if (*msg==M_EXTENDED) { + for (i=1;i<8;i++) { + if (i-1>msg[1]) break; + printk ("-%x",msg[i]); + }; + return (i+1); + } else if ((*msg & 0xf0) == 0x20) { + printk ("-%x",msg[1]); + return (2); + }; + return (1); +} + + +void ncr_int_sir (ncb_p np) +{ + u_char scntl3; + u_char chg, ofs, per, fak, wide; + u_char num = INB (nc_dsps); + ccb_p cp=0; + u_long dsa = INL (nc_dsa); + u_char target = INB (nc_sdid) & 0x0f; + tcb_p tp = &np->target[target]; + + if (DEBUG_FLAGS & DEBUG_TINY) printk ("I#%d", num); + + switch (num) { + case SIR_SEL_ATN_NO_MSG_OUT: + /* + ** The device didn't go to MSG OUT phase after having + ** been selected with ATN. We donnot want to handle + ** that. + */ + printk ("%s:%d: No MSG OUT phase after selection with ATN.\n", + ncr_name (np), target); + goto out_stuck; + case SIR_RESEL_NO_MSG_IN: + case SIR_RESEL_NO_IDENTIFY: + /* + ** If devices reselecting without sending an IDENTIFY + ** message still exist, this should help. + ** We just assume lun=0, 1 CCB, no tag. + */ + if (tp->lp[0]) { + OUTL (nc_dsa, scr_to_cpu(tp->lp[0]->tasktbl[0])); + OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, resel_go)); + return; + } + case SIR_RESEL_BAD_LUN: + np->msgout[0] = M_RESET; + goto out; + case SIR_RESEL_BAD_I_T_L: + np->msgout[0] = M_ABORT; + goto out; + case SIR_RESEL_BAD_I_T_L_Q: + np->msgout[0] = M_ABORT_TAG; + goto out; + case SIR_RESEL_ABORTED: + np->lastmsg = np->msgout[0]; + np->msgout[0] = M_NOOP; + printk ("%s:%d: message %d sent on bad reselection.\n", + ncr_name (np), target, np->lastmsg); + goto out; + case SIR_MSG_OUT_DONE: + np->lastmsg = np->msgout[0]; + np->msgout[0] = M_NOOP; + /* Should we really care of that */ + if (np->lastmsg == M_PARITY || np->lastmsg == M_ID_ERROR) + OUTOFFB (HF_PRT, HF_PAR_ERR); + goto out; + case SIR_BAD_STATUS: + cp = ncr_ccb_from_dsa(np, dsa); + if (!cp) + goto out; + ncr_sir_to_redo(np, num, cp); + return; + default: + /* + ** lookup the ccb + */ + cp = ncr_ccb_from_dsa(np, dsa); + if (!cp) + goto out; + } + + switch (num) { +/*----------------------------------------------------------------------------- +** +** Was Sie schon immer ueber transfermode negotiation wissen wollten ... +** +** We try to negotiate sync and wide transfer only after +** a successfull inquire command. We look at byte 7 of the +** inquire data to determine the capabilities of the target. +** +** When we try to negotiate, we append the negotiation message +** to the identify and (maybe) simple tag message. +** The host status field is set to HS_NEGOTIATE to mark this +** situation. +** +** If the target doesn't answer this message immidiately +** (as required by the standard), the SIR_NEGO_FAIL interrupt +** will be raised eventually. +** The handler removes the HS_NEGOTIATE status, and sets the +** negotiated value to the default (async / nowide). +** +** If we receive a matching answer immediately, we check it +** for validity, and set the values. +** +** If we receive a Reject message immediately, we assume the +** negotiation has failed, and fall back to standard values. +** +** If we receive a negotiation message while not in HS_NEGOTIATE +** state, it's a target initiated negotiation. We prepare a +** (hopefully) valid answer, set our parameters, and send back +** this answer to the target. +** +** If the target doesn't fetch the answer (no message out phase), +** we assume the negotiation has failed, and fall back to default +** settings. +** +** When we set the values, we adjust them in all ccbs belonging +** to this target, in the controller's register, and in the "phys" +** field of the controller's struct ncb. +** +** Possible cases: hs sir msg_in value send goto +** We try to negotiate: +** -> target doesnt't msgin NEG FAIL noop defa. - dispatch +** -> target rejected our msg NEG FAIL reject defa. - dispatch +** -> target answered (ok) NEG SYNC sdtr set - clrack +** -> target answered (!ok) NEG SYNC sdtr defa. REJ--->msg_bad +** -> target answered (ok) NEG WIDE wdtr set - clrack +** -> target answered (!ok) NEG WIDE wdtr defa. REJ--->msg_bad +** -> any other msgin NEG FAIL noop defa. - dispatch +** +** Target tries to negotiate: +** -> incoming message --- SYNC sdtr set SDTR - +** -> incoming message --- WIDE wdtr set WDTR - +** We sent our answer: +** -> target doesn't msgout --- PROTO ? defa. - dispatch +** +**----------------------------------------------------------------------------- +*/ + + case SIR_NEGO_FAILED: + /*------------------------------------------------------- + ** + ** Negotiation failed. + ** Target doesn't send an answer message, + ** or target rejected our message. + ** + ** Remove negotiation request. + ** + **------------------------------------------------------- + */ + OUTB (HS_PRT, HS_BUSY); + + /* fall through */ + + case SIR_NEGO_PROTO: + /*------------------------------------------------------- + ** + ** Negotiation failed. + ** Target doesn't fetch the answer message. + ** + **------------------------------------------------------- + */ + + if (DEBUG_FLAGS & DEBUG_NEGO) { + PRINT_ADDR(cp->cmd); + printk ("negotiation failed sir=%x status=%x.\n", + num, cp->nego_status); + }; + + /* + ** any error in negotiation: + ** fall back to default mode. + */ + switch (cp->nego_status) { + + case NS_SYNC: + ncr_setsync (np, cp, 0, 0xe0); + break; + + case NS_WIDE: + ncr_setwide (np, cp, 0, 0); + break; + + }; + np->msgin [0] = M_NOOP; + np->msgout[0] = M_NOOP; + cp->nego_status = 0; + break; + + case SIR_NEGO_SYNC: + /* + ** Synchronous request message received. + */ + + if (DEBUG_FLAGS & DEBUG_NEGO) { + PRINT_ADDR(cp->cmd); + printk ("sync msgin: "); + (void) ncr_show_msg (np->msgin); + printk (".\n"); + }; + + /* + ** get requested values. + */ + + chg = 0; + per = np->msgin[3]; + ofs = np->msgin[4]; + if (ofs==0) per=255; + + /* + ** if target sends SDTR message, + ** it CAN transfer synch. + */ + + if (ofs) + tp->inq_byte7 |= INQ7_SYNC; + + /* + ** check values against driver limits. + */ + + if (per < np->minsync) + {chg = 1; per = np->minsync;} + if (per < tp->minsync) + {chg = 1; per = tp->minsync;} + if (ofs > tp->maxoffs) + {chg = 1; ofs = tp->maxoffs;} + + /* + ** Check against controller limits. + */ + fak = 7; + scntl3 = 0; + if (ofs != 0) { + ncr_getsync(np, per, &fak, &scntl3); + if (fak > 7) { + chg = 1; + ofs = 0; + } + } + if (ofs == 0) { + fak = 7; + per = 0; + scntl3 = 0; + tp->minsync = 0; + } + + if (DEBUG_FLAGS & DEBUG_NEGO) { + PRINT_ADDR(cp->cmd); + printk ("sync: per=%d scntl3=0x%x ofs=%d fak=%d chg=%d.\n", + per, scntl3, ofs, fak, chg); + } + + if (INB (HS_PRT) == HS_NEGOTIATE) { + OUTB (HS_PRT, HS_BUSY); + switch (cp->nego_status) { + + case NS_SYNC: + /* + ** This was an answer message + */ + if (chg) { + /* + ** Answer wasn't acceptable. + */ + ncr_setsync (np, cp, 0, 0xe0); + OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, msg_bad)); + } else { + /* + ** Answer is ok. + */ + ncr_setsync (np, cp, scntl3, (fak<<5)|ofs); + OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, clrack)); + }; + return; + + case NS_WIDE: + ncr_setwide (np, cp, 0, 0); + break; + }; + }; + + /* + ** It was a request. Set value and + ** prepare an answer message + */ + + ncr_setsync (np, cp, scntl3, (fak<<5)|ofs); + + np->msgout[0] = M_EXTENDED; + np->msgout[1] = 3; + np->msgout[2] = M_X_SYNC_REQ; + np->msgout[3] = per; + np->msgout[4] = ofs; + + cp->nego_status = NS_SYNC; + + if (DEBUG_FLAGS & DEBUG_NEGO) { + PRINT_ADDR(cp->cmd); + printk ("sync msgout: "); + (void) ncr_show_msg (np->msgout); + printk (".\n"); + } + + if (!ofs) { + OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, msg_bad)); + return; + } + np->msgin [0] = M_NOOP; + + break; + + case SIR_NEGO_WIDE: + /* + ** Wide request message received. + */ + if (DEBUG_FLAGS & DEBUG_NEGO) { + PRINT_ADDR(cp->cmd); + printk ("wide msgin: "); + (void) ncr_show_msg (np->msgin); + printk (".\n"); + }; + + /* + ** get requested values. + */ + + chg = 0; + wide = np->msgin[3]; + + /* + ** if target sends WDTR message, + ** it CAN transfer wide. + */ + + if (wide) + tp->inq_byte7 |= INQ7_WIDE16; + + /* + ** check values against driver limits. + */ + + if (wide > tp->usrwide) + {chg = 1; wide = tp->usrwide;} + + if (DEBUG_FLAGS & DEBUG_NEGO) { + PRINT_ADDR(cp->cmd); + printk ("wide: wide=%d chg=%d.\n", wide, chg); + } + + if (INB (HS_PRT) == HS_NEGOTIATE) { + OUTB (HS_PRT, HS_BUSY); + switch (cp->nego_status) { + + case NS_WIDE: + /* + ** This was an answer message + */ + if (chg) { + /* + ** Answer wasn't acceptable. + */ + ncr_setwide (np, cp, 0, 1); + OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, msg_bad)); + } else { + /* + ** Answer is ok. + */ + ncr_setwide (np, cp, wide, 1); + OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, clrack)); + }; + return; + + case NS_SYNC: + ncr_setsync (np, cp, 0, 0xe0); + break; + }; + }; + + /* + ** It was a request, set value and + ** prepare an answer message + */ + + ncr_setwide (np, cp, wide, 1); + + np->msgout[0] = M_EXTENDED; + np->msgout[1] = 2; + np->msgout[2] = M_X_WIDE_REQ; + np->msgout[3] = wide; + + np->msgin [0] = M_NOOP; + + cp->nego_status = NS_WIDE; + + if (DEBUG_FLAGS & DEBUG_NEGO) { + PRINT_ADDR(cp->cmd); + printk ("wide msgout: "); + (void) ncr_show_msg (np->msgin); + printk (".\n"); + } + break; + +/*-------------------------------------------------------------------- +** +** Processing of special messages +** +**-------------------------------------------------------------------- +*/ + + case SIR_REJECT_RECEIVED: + /*----------------------------------------------- + ** + ** We received a M_REJECT message. + ** + **----------------------------------------------- + */ + + PRINT_ADDR(cp->cmd); + printk ("M_REJECT received (%x:%x).\n", + (unsigned)scr_to_cpu(np->lastmsg), np->msgout[0]); + break; + + case SIR_REJECT_TO_SEND: + /*----------------------------------------------- + ** + ** We received an unknown message + ** + **----------------------------------------------- + */ + + PRINT_ADDR(cp->cmd); + printk ("M_REJECT to send for "); + (void) ncr_show_msg (np->msgin); + printk (".\n"); + np->msgout[0] = M_REJECT; + break; + +/*-------------------------------------------------------------------- +** +** Processing of special messages +** +**-------------------------------------------------------------------- +*/ + + case SIR_IGN_RESIDUE: + /*----------------------------------------------- + ** + ** We received an IGNORE RESIDUE message, + ** which couldn't be handled by the script. + ** + **----------------------------------------------- + */ + + PRINT_ADDR(cp->cmd); + printk ("M_IGN_RESIDUE received, but not yet implemented.\n"); + break; +#if 0 + case SIR_MISSING_SAVE: + /*----------------------------------------------- + ** + ** We received an DISCONNECT message, + ** but the datapointer wasn't saved before. + ** + **----------------------------------------------- + */ + + PRINT_ADDR(cp->cmd); + printk ("M_DISCONNECT received, but datapointer not saved: " + "data=%x save=%x goal=%x.\n", + (unsigned) INL (nc_temp), + (unsigned) scr_to_cpu(np->header.savep), + (unsigned) scr_to_cpu(np->header.goalp)); + break; +#endif + }; + +out: + OUTONB (nc_dcntl, (STD|NOCOM)); +out_stuck: +} + +/*========================================================== +** +** +** Aquire a control block +** +** +**========================================================== +*/ + +static ccb_p ncr_get_ccb (ncb_p np, u_char tn, u_char ln) +{ + tcb_p tp = &np->target[tn]; + lcb_p lp = tp->lp[ln]; + u_char tag = NO_TAG; + XPT_QUEHEAD *qp; + ccb_p cp = (ccb_p) 0; + + /* + ** Allocate a new CCB if needed. + */ + if (xpt_que_empty(&np->free_ccbq)) + (void) ncr_alloc_ccb(np); + + /* + ** Look for a free CCB + */ + qp = xpt_remque_head(&np->free_ccbq); + if (!qp) + goto out; + cp = xpt_que_entry(qp, struct ccb, link_ccbq); + + /* + ** If the LCB is not yet available and we already + ** have queued a CCB for a LUN without LCB, + ** give up. Otherwise all is fine. :-) + */ + if (!lp) { + if (xpt_que_empty(&np->b0_ccbq)) + xpt_insque_head(&cp->link_ccbq, &np->b0_ccbq); + else + goto out_free; + } else { + /* + ** Tune tag mode if asked by user. + */ + if (lp->queuedepth != lp->numtags) { + ncr_setup_tags(np, tn, ln); + } + + /* + ** Get a tag for this nexus if required. + ** Keep from using more tags than we can handle. + */ + if (lp->usetags) { + if (lp->busyccbs < lp->maxnxs) { + tag = lp->cb_tags[lp->ia_tag]; + ++lp->ia_tag; + if (lp->ia_tag == SCSI_NCR_MAX_TAGS) + lp->ia_tag = 0; + lp->tags_umap |= (((tagmap_t) 1) << tag); + } + else + goto out_free; + } + + /* + ** Put the CCB in the LUN wait queue and + ** count it as busy. + */ + xpt_insque_tail(&cp->link_ccbq, &lp->wait_ccbq); + ++lp->busyccbs; + } + + /* + ** Remember all informations needed to free this CCB. + */ + cp->tag = tag; + cp->target = tn; + cp->lun = ln; + + if (DEBUG_FLAGS & DEBUG_TAGS) { + PRINT_LUN(np, tn, ln); + printk ("ccb @%p using tag %d.\n", cp, tag); + } + +out: + return cp; +out_free: + xpt_insque_head(&cp->link_ccbq, &np->free_ccbq); + return (ccb_p) 0; +} + +/*========================================================== +** +** +** Release one control block +** +** +**========================================================== +*/ + +static void ncr_free_ccb (ncb_p np, ccb_p cp) +{ + tcb_p tp = &np->target[cp->target]; + lcb_p lp = tp->lp[cp->lun]; + + if (DEBUG_FLAGS & DEBUG_TAGS) { + PRINT_LUN(np, cp->target, cp->lun); + printk ("ccb @%p freeing tag %d.\n", cp, cp->tag); + } + + /* + ** If lun control block available, make available + ** the task slot and the tag if any. + ** Decrement counters. + */ + if (lp) { + if (cp->tag != NO_TAG) { + lp->cb_tags[lp->if_tag++] = cp->tag; + if (lp->if_tag == SCSI_NCR_MAX_TAGS) + lp->if_tag = 0; + lp->tags_umap &= ~(((tagmap_t) 1) << cp->tag); + lp->tags_smap &= lp->tags_umap; + lp->tasktbl[cp->tag] = cpu_to_scr(np->p_bad_i_t_l_q); + } else { + lp->tasktbl[0] = cpu_to_scr(np->p_bad_i_t_l); + } + --lp->busyccbs; + if (cp->queued) { + --lp->queuedccbs; + } + } + + /* + ** Make this CCB available. + */ + xpt_remque(&cp->link_ccbq); + xpt_insque_head(&cp->link_ccbq, &np->free_ccbq); + cp -> host_status = HS_IDLE; + cp -> queued = 0; +} + +/*------------------------------------------------------------------------ +** Allocate a CCB and initialize its fixed part. +**------------------------------------------------------------------------ +**------------------------------------------------------------------------ +*/ +static ccb_p ncr_alloc_ccb(ncb_p np) +{ + ccb_p cp = 0; + int hcode; + + /* + ** Allocate memory for this CCB. + */ + cp = m_calloc(sizeof(struct ccb), "CCB", MEMO_WARN); + if (!cp) + return 0; + + /* + ** Count it and initialyze it. + */ + np->actccbs++; + + /* + ** Remember virtual and bus address of this ccb. + */ + cp->p_ccb = vtobus(cp); + + /* + ** Insert this ccb into the hashed list. + */ + hcode = CCB_HASH_CODE(cp->p_ccb); + cp->link_ccbh = np->ccbh[hcode]; + np->ccbh[hcode] = cp; + + /* + ** Initialyze the start and restart actions. + */ + cp->phys.header.go.start = cpu_to_scr(NCB_SCRIPT_PHYS (np, idle)); + cp->phys.header.go.restart = cpu_to_scr(NCB_SCRIPTH_PHYS(np,bad_i_t_l)); + + /* + ** Chain into wakeup list and free ccb queue. + */ + cp->link_ccb = np->ccbc; + np->ccbc = cp; + + xpt_insque_head(&cp->link_ccbq, &np->free_ccbq); + + return cp; +} + +/*------------------------------------------------------------------------ +** Look up a CCB from a DSA value. +**------------------------------------------------------------------------ +**------------------------------------------------------------------------ +*/ +static ccb_p ncr_ccb_from_dsa(ncb_p np, u_long dsa) +{ + int hcode; + ccb_p cp; + + hcode = CCB_HASH_CODE(dsa); + cp = np->ccbh[hcode]; + while (cp) { + if (cp->p_ccb == dsa) + break; + cp = cp->link_ccbh; + } + + return cp; +} + +/*========================================================== +** +** +** Allocation of resources for Targets/Luns/Tags. +** +** +**========================================================== +*/ + + +/*------------------------------------------------------------------------ +** Target control block initialisation. +**------------------------------------------------------------------------ +** This data structure is fully initialized after a SCSI command +** has been successfully completed for this target. +**------------------------------------------------------------------------ +*/ +static void ncr_init_tcb (ncb_p np, u_char tn) +{ + tcb_p tp = &np->target[tn]; + + /* + ** Already bone. + */ + if (tp->luntbl) + return; + /* + ** Allocate the lcb bus address array. + */ + tp->luntbl = m_calloc(256, "LUNTBL", MEMO_WARN); + if (!tp->luntbl) + return; + + /* + ** Compute the bus address of this table. + */ + tp->b_luntbl = cpu_to_scr(vtobus(tp->luntbl)); + + /* + ** Check some alignments required by the chip. + */ + assert (( (offsetof(struct ncr_reg, nc_sxfer) ^ + offsetof(struct tcb , sval )) &3) == 0); + assert (( (offsetof(struct ncr_reg, nc_scntl3) ^ + offsetof(struct tcb , wval )) &3) == 0); +} + +/*------------------------------------------------------------------------ +** Lun control block allocation and initialization. +**------------------------------------------------------------------------ +** This data structure is allocated and initialized after a SCSI +** command has been successfully completed for this target/lun. +**------------------------------------------------------------------------ +*/ +static lcb_p ncr_alloc_lcb (ncb_p np, u_char tn, u_char ln) +{ + tcb_p tp = &np->target[tn]; + lcb_p lp = tp->lp[ln]; + + /* + ** Already done, return. + */ + if (lp) + return lp; + + /* + ** Initialize the target control block if not yet. + */ + ncr_init_tcb(np, tn); + if (!tp->luntbl) + goto fail; + + /* + ** Allocate the lcb. + */ + lp = m_calloc(sizeof(struct lcb), "LCB", MEMO_WARN); + if (!lp) + goto fail; + tp->lp[ln] = lp; + + /* + ** Make it available to the chip. + */ + tp->luntbl[ln] = cpu_to_scr(vtobus(lp)); + + /* + ** Initialize the CCB queue headers. + */ + xpt_que_init(&lp->busy_ccbq); + xpt_que_init(&lp->wait_ccbq); + + /* + ** Set max CCBs to 1 and use the default task array + ** by default. + */ + lp->maxnxs = 1; + lp->tasktbl = &lp->tasktbl_0; + lp->b_tasktbl = cpu_to_scr(vtobus(lp->tasktbl)); + lp->tasktbl[0] = cpu_to_scr(np->p_notask); + lp->resel_task = cpu_to_scr(NCB_SCRIPT_PHYS(np, resel_notag)); + + /* + ** Initialize command queuing control. + */ + lp->busyccbs = 1; + lp->queuedccbs = 1; + lp->queuedepth = 1; +fail: + return lp; +} + + +/*------------------------------------------------------------------------ +** Lun control block setup on INQUIRY data received. +**------------------------------------------------------------------------ +** We only support WIDE, SYNC for targets and CMDQ for logical units. +** This setup is done on each INQUIRY since we are expecting user +** will play with CHANGE DEFINITION commands. :-) +**------------------------------------------------------------------------ +*/ +static lcb_p ncr_setup_lcb (ncb_p np, u_char tn, u_char ln, u_char *inq_data) +{ + tcb_p tp = &np->target[tn]; + lcb_p lp = tp->lp[ln]; + u_char inq_byte7; + int i; + + /* + ** If no lcb, try to allocate it. + */ + if (!lp && !(lp = ncr_alloc_lcb(np, tn, ln))) + goto fail; + + /* + ** Get device quirks from a speciality table. + */ + tp->quirks = ncr_lookup (inq_data); + if (tp->quirks && bootverbose) { + PRINT_LUN(np, tn, ln); + printk ("quirks=%x.\n", tp->quirks); + } + + /* + ** Evaluate trustable target/unit capabilities. + ** We only believe device version >= SCSI-2 that + ** use appropriate response data format (2). + ** But it seems that some CCS devices also + ** support SYNC and I donnot want to frustrate + ** anybody. ;-) + */ + inq_byte7 = 0; + if ((inq_data[2] & 0x7) >= 2 && (inq_data[3] & 0xf) == 2) + inq_byte7 = inq_data[7]; + else if ((inq_data[2] & 0x7) == 1 && (inq_data[3] & 0xf) == 1) + inq_byte7 = INQ7_SYNC; + + /* + ** Throw away announced LUN capabilities if we are told + ** that there is no real device supported by the logical unit. + */ + if ((inq_data[0] & 0xe0) > 0x20 || (inq_data[0] & 0x1f) == 0x1f) + inq_byte7 &= (INQ7_SYNC | INQ7_WIDE16); + + /* + ** If user is wanting SYNC, force this feature. + */ + if (driver_setup.force_sync_nego) + inq_byte7 |= INQ7_SYNC; + + /* + ** Prepare negotiation if SIP capabilities have changed. + */ + tp->inq_done = 1; + if ((inq_byte7 ^ tp->inq_byte7) & (INQ7_SYNC | INQ7_WIDE16)) { + tp->inq_byte7 = inq_byte7; + ncr_negotiate(np, tp); + } + + /* + ** If unit supports tagged commands, allocate and + ** initialyze the task table if not yet. + */ + if ((inq_byte7 & INQ7_QUEUE) && lp->tasktbl == &lp->tasktbl_0) { + lp->tasktbl = m_calloc(256, "TASKTBL", MEMO_WARN); + if (!lp->tasktbl) { + lp->tasktbl = &lp->tasktbl_0; + goto fail; + } + lp->b_tasktbl = cpu_to_scr(vtobus(lp->tasktbl)); + for (i = 0 ; i < 64 ; i++) + lp->tasktbl[i] = cpu_to_scr(np->p_notask); + for (i = 0 ; i < SCSI_NCR_MAX_TAGS ; i++) + lp->cb_tags[i] = i; + lp->maxnxs = SCSI_NCR_MAX_TAGS; + lp->tags_stime = jiffies; + } + + /* + ** Adjust tagged queueing status if needed. + */ + if ((inq_byte7 ^ lp->inq_byte7) & INQ7_QUEUE) { + lp->inq_byte7 = inq_byte7; + lp->numtags = lp->maxtags; + ncr_setup_tags (np, tn, ln); + } + +fail: + return lp; +} + +/*========================================================== +** +** +** Build Scatter Gather Block +** +** +**========================================================== +** +** The transfer area may be scattered among +** several non adjacent physical pages. +** +** We may use MAX_SCATTER blocks. +** +**---------------------------------------------------------- +*/ + +/* +** We try to reduce the number of interrupts caused +** by unexpected phase changes due to disconnects. +** A typical harddisk may disconnect before ANY block. +** If we wanted to avoid unexpected phase changes at all +** we had to use a break point every 512 bytes. +** Of course the number of scatter/gather blocks is +** limited. +** Under Linux, the scatter/gatter blocks are provided by +** the generic driver. We just have to copy addresses and +** sizes to the data segment array. +*/ + +/* +** For 64 bit systems, we use the 8 upper bits of the size field +** to provide bus address bits 32-39 to the SCRIPTS processor. +** This allows the 896 to access up to 1 tera-bytes of memory. +** For 32 bit chips on 64 bit systems, we must be provided with +** memory addresses that fit into the first 32 bit bus address +** range and so, this does not matter and we expect an error from +** the chip if this ever happen. +** +** We use a separate function for the case Linux does not provide +** a scatter list in order to allow better code optimization +** for the case we have a scatter list (BTW, for now this just wastes +** about 40 bytes of code for x86, but my guess is that the scatter +** code will get more complex later). +*/ + +#if BITS_PER_LONG > 32 +#define SCATTER_ONE(data, badd, len) \ + (data)->addr = cpu_to_scr(badd); \ + (data)->size = cpu_to_scr((((badd) >> 8) & 0xff000000) + len); +#else +#define SCATTER_ONE(data, badd, len) \ + (data)->addr = cpu_to_scr(badd); \ + (data)->size = cpu_to_scr(len); +#endif + +#define CROSS_16MB(p, n) (((((u_long) p) + n - 1) ^ ((u_long) p)) & ~0xffffff) + +static int ncr_scatter_no_sglist(ccb_p cp, Scsi_Cmnd *cmd) +{ + struct scr_tblmove *data = &cp->phys.data[MAX_SCATTER-1]; + int segment; + + cp->data_len = cmd->request_bufflen; + + if (cmd->request_bufflen) { + u_long baddr = vtobus(cmd->request_buffer); + SCATTER_ONE(data, baddr, cmd->request_bufflen); + if (CROSS_16MB(baddr, cmd->request_bufflen)) { + cp->host_flags |= HF_PM_TO_C; +#ifdef DEBUG_896R1 +printk("He! we are crossing a 16 MB boundary (0x%lx, 0x%x)\n", + baddr, cmd->request_bufflen); +#endif + } + segment = 1; + } + else + segment = 0; + + return segment; +} + +/* +** DEL 472 - 53C896 Rev 1 - Part Number 609-0393055 - ITEM 5. +** +** We disable data phase mismatch handling from SCRIPTS for data +** transfers that contains scatter/gather entries that cross +** a 16 MB boundary. +** We use a different scatter function for 896 rev. 1 that needs +** such a work-around. Doing so, we do not affect performance for +** other chips. +** This problem should not be triggered for disk IOs under Linux, +** since such IOs are performed using pages and buffers that are +** nicely power-of-two sized and aligned. But, since this may change +** at any time, a work-around was required. +*/ +static int ncr_scatter_896R1(ccb_p cp, Scsi_Cmnd *cmd) +{ + int segn; + int use_sg = (int) cmd->use_sg; + + cp->data_len = 0; + + if (!use_sg) + segn = ncr_scatter_no_sglist(cp, cmd); + else if (use_sg > MAX_SCATTER) + segn = -1; + else { + struct scatterlist *scatter = (struct scatterlist *)cmd->buffer; + struct scr_tblmove *data = &cp->phys.data[MAX_SCATTER - use_sg]; + + for (segn = 0; segn < use_sg; segn++) { + u_long baddr = vtobus(scatter[segn].address); + SCATTER_ONE(&data[segn], + baddr, + scatter[segn].length); + if (CROSS_16MB(baddr, scatter[segn].length)) { + cp->host_flags |= HF_PM_TO_C; +#ifdef DEBUG_896R1 +printk("He! we are crossing a 16 MB boundary (0x%lx, 0x%x)\n", + baddr, scatter[segn].length); +#endif + } + cp->data_len += scatter[segn].length; + } + } + + return segn; +} + +static int ncr_scatter(ccb_p cp, Scsi_Cmnd *cmd) +{ + int segment; + int use_sg = (int) cmd->use_sg; + + cp->data_len = 0; + + if (!use_sg) + segment = ncr_scatter_no_sglist(cp, cmd); + else if (use_sg > MAX_SCATTER) + segment = -1; + else { + struct scatterlist *scatter = (struct scatterlist *)cmd->buffer; + struct scr_tblmove *data = &cp->phys.data[MAX_SCATTER - use_sg]; + + for (segment = 0; segment < use_sg; segment++) { + u_long baddr = vtobus(scatter[segment].address); + SCATTER_ONE(&data[segment], + baddr, + scatter[segment].length); + cp->data_len += scatter[segment].length; + } + } + + return segment; +} + +/*========================================================== +** +** +** Test the pci bus snoop logic :-( +** +** Has to be called with interrupts disabled. +** +** +**========================================================== +*/ + +#ifndef NCR_IOMAPPED +__initfunc( +static int ncr_regtest (struct ncb* np) +) +{ + register volatile u_int32 data; + /* + ** ncr registers may NOT be cached. + ** write 0xffffffff to a read only register area, + ** and try to read it back. + */ + data = 0xffffffff; + OUTL_OFF(offsetof(struct ncr_reg, nc_dstat), data); + data = INL_OFF(offsetof(struct ncr_reg, nc_dstat)); +#if 1 + if (data == 0xffffffff) { +#else + if ((data & 0xe2f0fffd) != 0x02000080) { +#endif + printk ("CACHE TEST FAILED: reg dstat-sstat2 readback %x.\n", + (unsigned) data); + return (0x10); + }; + return (0); +} +#endif + +__initfunc( +static int ncr_snooptest (struct ncb* np) +) +{ + u_int32 ncr_rd, ncr_wr, ncr_bk, host_rd, host_wr, pc; + int i, err=0; +#ifndef NCR_IOMAPPED + if (np->reg) { + err |= ncr_regtest (np); + if (err) return (err); + } +#endif + /* + ** init + */ + pc = NCB_SCRIPTH0_PHYS (np, snooptest); + host_wr = 1; + ncr_wr = 2; + /* + ** Set memory and register. + */ + np->ncr_cache = cpu_to_scr(host_wr); + OUTL (nc_temp, ncr_wr); + /* + ** Start script (exchange values) + */ + OUTL (nc_dsa, vtobus(np)); + OUTL (nc_dsp, pc); + /* + ** Wait 'til done (with timeout) + */ + for (i=0; incr_cache); + ncr_rd = INL (nc_scratcha); + ncr_bk = INL (nc_temp); + + /* + ** check for timeout + */ + if (i>=NCR_SNOOP_TIMEOUT) { + printk ("CACHE TEST FAILED: timeout.\n"); + return (0x20); + }; + /* + ** Check termination position. + */ + if (pc != NCB_SCRIPTH0_PHYS (np, snoopend)+8) { + printk ("CACHE TEST FAILED: script execution failed.\n"); + printk ("start=%08lx, pc=%08lx, end=%08lx\n", + (u_long) NCB_SCRIPTH0_PHYS (np, snooptest), (u_long) pc, + (u_long) NCB_SCRIPTH0_PHYS (np, snoopend) +8); + return (0x40); + }; + /* + ** Show results. + */ + if (host_wr != ncr_rd) { + printk ("CACHE TEST FAILED: host wrote %d, ncr read %d.\n", + (int) host_wr, (int) ncr_rd); + err |= 1; + }; + if (host_rd != ncr_wr) { + printk ("CACHE TEST FAILED: ncr wrote %d, host read %d.\n", + (int) ncr_wr, (int) host_rd); + err |= 2; + }; + if (ncr_bk != ncr_wr) { + printk ("CACHE TEST FAILED: ncr wrote %d, read back %d.\n", + (int) ncr_wr, (int) ncr_bk); + err |= 4; + }; + return (err); +} + +/*========================================================== +** +** +** Profiling the drivers and targets performance. +** +** +**========================================================== +*/ + +#ifdef SCSI_NCR_PROFILE_SUPPORT + +static void ncb_profile (ncb_p np, ccb_p cp) +{ + int num_disc = (cp->phys.num_disc & 0xff); + int num_disc0 = (cp->phys.num_disc >> 8); + + ++np->profile.num_trans; + np->profile.num_disc += num_disc; + np->profile.num_disc0 += num_disc0; + np->profile.num_kbytes += (cp->data_len >> 10); +#if 000 + if (num_disc > num_disc0) { + if (cp->data_len <= 1024) + np->profile.num_br1k += (num_disc - num_disc0); + else if (cp->data_len <= 2048) + np->profile.num_br2k += (num_disc - num_disc0); + else if (cp->data_len <= 4096) + np->profile.num_br4k += (num_disc - num_disc0); + else if (cp->data_len <= 8192) + np->profile.num_br8k += (num_disc - num_disc0); + else + np->profile.num_brnk += (num_disc - num_disc0); + } +#endif +} + +#endif /* SCSI_NCR_PROFILE_SUPPORT */ + +/*========================================================== +** +** +** Device lookup. +** +** @GENSCSI@ should be integrated to scsiconf.c +** +** +**========================================================== +*/ + +struct table_entry { + char * manufacturer; + char * model; + char * version; + u_long info; +}; + +static struct table_entry device_tab[] = +{ +#if 0 + {"", "", "", QUIRK_NOMSG}, +#endif + {"SONY", "SDT-5000", "3.17", QUIRK_NOMSG}, + {"WangDAT", "Model 2600", "01.7", QUIRK_NOMSG}, + {"WangDAT", "Model 3200", "02.2", QUIRK_NOMSG}, + {"WangDAT", "Model 1300", "02.4", QUIRK_NOMSG}, + {"", "", "", 0} /* catch all: must be last entry. */ +}; + +static u_long ncr_lookup(char * id) +{ + struct table_entry * p = device_tab; + char *d, *r, c; + + for (;;p++) { + + d = id+8; + r = p->manufacturer; + while ((c=*r++)) if (c!=*d++) break; + if (c) continue; + + d = id+16; + r = p->model; + while ((c=*r++)) if (c!=*d++) break; + if (c) continue; + + d = id+32; + r = p->version; + while ((c=*r++)) if (c!=*d++) break; + if (c) continue; + + return (p->info); + } +} + +/*========================================================== +** +** Determine the ncr's clock frequency. +** This is essential for the negotiation +** of the synchronous transfer rate. +** +**========================================================== +** +** Note: we have to return the correct value. +** THERE IS NO SAFE DEFAULT VALUE. +** +** Most NCR/SYMBIOS boards are delivered with a 40 Mhz clock. +** 53C860 and 53C875 rev. 1 support fast20 transfers but +** do not have a clock doubler and so are provided with a +** 80 MHz clock. All other fast20 boards incorporate a doubler +** and so should be delivered with a 40 MHz clock. +** The recent fast40 chips (895/896) use a 40 Mhz base clock +** and provide a clock quadrupler (160 Mhz). The code below +** tries to deal as cleverly as possible with all this stuff. +** +**---------------------------------------------------------- +*/ + +/* + * Select NCR SCSI clock frequency + */ +static void ncr_selectclock(ncb_p np, u_char scntl3) +{ + if (np->multiplier < 2) { + OUTB(nc_scntl3, scntl3); + return; + } + + if (bootverbose >= 2) + printk ("%s: enabling clock multiplier\n", ncr_name(np)); + + OUTB(nc_stest1, DBLEN); /* Enable clock multiplier */ + if (np->multiplier > 2) { /* Poll bit 5 of stest4 for quadrupler */ + int i = 20; + while (!(INB(nc_stest4) & LCKFRQ) && --i > 0) + UDELAY (20); + if (!i) + printk("%s: the chip cannot lock the frequency\n", ncr_name(np)); + } else /* Wait 20 micro-seconds for doubler */ + UDELAY (20); + OUTB(nc_stest3, HSC); /* Halt the scsi clock */ + OUTB(nc_scntl3, scntl3); + OUTB(nc_stest1, (DBLEN|DBLSEL));/* Select clock multiplier */ + OUTB(nc_stest3, 0x00); /* Restart scsi clock */ +} + + +/* + * calculate NCR SCSI clock frequency (in KHz) + */ +__initfunc( +static unsigned ncrgetfreq (ncb_p np, int gen) +) +{ + unsigned ms = 0; + + /* + * Measure GEN timer delay in order + * to calculate SCSI clock frequency + * + * This code will never execute too + * many loop iterations (if DELAY is + * reasonably correct). It could get + * too low a delay (too high a freq.) + * if the CPU is slow executing the + * loop for some reason (an NMI, for + * example). For this reason we will + * if multiple measurements are to be + * performed trust the higher delay + * (lower frequency returned). + */ + OUTB (nc_stest1, 0); /* make sure clock doubler is OFF */ + OUTW (nc_sien , 0); /* mask all scsi interrupts */ + (void) INW (nc_sist); /* clear pending scsi interrupt */ + OUTB (nc_dien , 0); /* mask all dma interrupts */ + (void) INW (nc_sist); /* another one, just to be sure :) */ + OUTB (nc_scntl3, 4); /* set pre-scaler to divide by 3 */ + OUTB (nc_stime1, 0); /* disable general purpose timer */ + OUTB (nc_stime1, gen); /* set to nominal delay of 1<= 2) + printk ("%s: Delay (GEN=%d): %u msec\n", ncr_name(np), gen, ms); + /* + * adjust for prescaler, and convert into KHz + */ + return ms ? ((1 << gen) * 4340) / ms : 0; +} + +/* + * Get/probe NCR SCSI clock frequency + */ +__initfunc( +static void ncr_getclock (ncb_p np, int mult) +) +{ + unsigned char scntl3 = INB(nc_scntl3); + unsigned char stest1 = INB(nc_stest1); + unsigned f1; + + np->multiplier = 1; + f1 = 40000; + + /* + ** True with 875/895/896 with clock multiplier selected + */ + if (mult > 1 && (stest1 & (DBLEN+DBLSEL)) == DBLEN+DBLSEL) { + if (bootverbose >= 2) + printk ("%s: clock multiplier found\n", ncr_name(np)); + np->multiplier = mult; + } + + /* + ** If multiplier not found or scntl3 not 7,5,3, + ** reset chip and get frequency from general purpose timer. + ** Otherwise trust scntl3 BIOS setting. + */ + if (np->multiplier != mult || (scntl3 & 7) < 3 || !(scntl3 & 1)) { + unsigned f2; + + (void) ncrgetfreq (np, 11); /* throw away first result */ + f1 = ncrgetfreq (np, 11); + f2 = ncrgetfreq (np, 11); + + if (bootverbose) + printk ("%s: NCR clock is %uKHz, %uKHz\n", ncr_name(np), f1, f2); + + if (f1 > f2) f1 = f2; /* trust lower result */ + + if (f1 < 45000) f1 = 40000; + else if (f1 < 55000) f1 = 50000; + else f1 = 80000; + + if (f1 < 80000 && mult > 1) { + if (bootverbose >= 2) + printk ("%s: clock multiplier assumed\n", ncr_name(np)); + np->multiplier = mult; + } + } else { + if ((scntl3 & 7) == 3) f1 = 40000; + else if ((scntl3 & 7) == 5) f1 = 80000; + else f1 = 160000; + + f1 /= np->multiplier; + } + + /* + ** Compute controller synchronous parameters. + */ + f1 *= np->multiplier; + np->clock_khz = f1; +} + +/*===================== LINUX ENTRY POINTS SECTION ==========================*/ + +#ifndef uchar +#define uchar unsigned char +#endif + +#ifndef ushort +#define ushort unsigned short +#endif + +#ifndef ulong +#define ulong unsigned long +#endif + +/* --------------------------------------------------------------------- +** +** Driver setup from the boot command line +** +** --------------------------------------------------------------------- +*/ + +#ifdef MODULE +#define ARG_SEP ' ' +#else +#define ARG_SEP ',' +#endif + +#define OPT_TAGS 1 +#define OPT_MASTER_PARITY 2 +#define OPT_SCSI_PARITY 3 +#define OPT_DISCONNECTION 4 +#define OPT_SPECIAL_FEATURES 5 +#define OPT_ULTRA_SCSI 6 +#define OPT_FORCE_SYNC_NEGO 7 +#define OPT_REVERSE_PROBE 8 +#define OPT_DEFAULT_SYNC 9 +#define OPT_VERBOSE 10 +#define OPT_DEBUG 11 +#define OPT_BURST_MAX 12 +#define OPT_LED_PIN 13 +#define OPT_MAX_WIDE 14 +#define OPT_SETTLE_DELAY 15 +#define OPT_DIFF_SUPPORT 16 +#define OPT_IRQM 17 +#define OPT_PCI_FIX_UP 18 +#define OPT_BUS_CHECK 19 +#define OPT_OPTIMIZE 20 +#define OPT_RECOVERY 21 +#define OPT_SAFE_SETUP 22 +#define OPT_USE_NVRAM 23 +#define OPT_EXCLUDE 24 + +static char setup_token[] __initdata = + "tags:" "mpar:" + "spar:" "disc:" + "specf:" "ultra:" + "fsn:" "revprob:" + "sync:" "verb:" + "debug:" "burst:" + "led:" "wide:" + "settle:" "diff:" + "irqm:" "pcifix:" + "buschk:" "optim:" + "recovery:" + "safe:" "nvram:" + "excl:"; + +#ifdef MODULE +#define ARG_SEP ' ' +#else +#define ARG_SEP ',' +#endif + +__initfunc( +static int get_setup_token(char *p) +) +{ + char *cur = setup_token; + char *pc; + int i = 0; + + while (cur != NULL && (pc = strchr(cur, ':')) != NULL) { + ++pc; + ++i; + if (!strncmp(p, cur, pc - cur)) + return i; + cur = pc; + } + return 0; +} + + +__initfunc( +void sym53c8xx_setup(char *str, int *ints) +) +{ +#ifdef SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT + char *cur = str; + char *pc, *pv; + int i, val, c; + int xi = 0; + + while (cur != NULL && (pc = strchr(cur, ':')) != NULL) { + char *pe; + + val = 0; + pv = pc; + c = *++pv; + + if (c == 'n') + val = 0; + else if (c == 'y') + val = 1; + else + val = (int) simple_strtoul(pv, &pe, 0); + + switch (get_setup_token(cur)) { + case OPT_TAGS: + driver_setup.default_tags = val; + if (pe && *pe == '/') { + i = 0; + while (*pe && *pe != ARG_SEP && + i < sizeof(driver_setup.tag_ctrl)-1) { + driver_setup.tag_ctrl[i++] = *pe++; + } + driver_setup.tag_ctrl[i] = '\0'; + } + break; + case OPT_MASTER_PARITY: + driver_setup.master_parity = val; + break; + case OPT_SCSI_PARITY: + driver_setup.scsi_parity = val; + break; + case OPT_DISCONNECTION: + driver_setup.disconnection = val; + break; + case OPT_SPECIAL_FEATURES: + driver_setup.special_features = val; + break; + case OPT_ULTRA_SCSI: + driver_setup.ultra_scsi = val; + break; + case OPT_FORCE_SYNC_NEGO: + driver_setup.force_sync_nego = val; + break; + case OPT_REVERSE_PROBE: + driver_setup.reverse_probe = val; + break; + case OPT_DEFAULT_SYNC: + driver_setup.default_sync = val; + break; + case OPT_VERBOSE: + driver_setup.verbose = val; + break; + case OPT_DEBUG: + driver_setup.debug = val; + break; + case OPT_BURST_MAX: + driver_setup.burst_max = val; + break; + case OPT_LED_PIN: + driver_setup.led_pin = val; + break; + case OPT_MAX_WIDE: + driver_setup.max_wide = val? 1:0; + break; + case OPT_SETTLE_DELAY: + driver_setup.settle_delay = val; + break; + case OPT_DIFF_SUPPORT: + driver_setup.diff_support = val; + break; + case OPT_IRQM: + driver_setup.irqm = val; + break; + case OPT_PCI_FIX_UP: + driver_setup.pci_fix_up = val; + break; + case OPT_BUS_CHECK: + driver_setup.bus_check = val; + break; + case OPT_OPTIMIZE: + driver_setup.optimize = val; + break; + case OPT_RECOVERY: + driver_setup.recovery = val; + break; + case OPT_USE_NVRAM: + driver_setup.use_nvram = val; + break; + case OPT_SAFE_SETUP: + memcpy(&driver_setup, &driver_safe_setup, + sizeof(driver_setup)); + break; + case OPT_EXCLUDE: + if (xi < SCSI_NCR_MAX_EXCLUDES) + driver_setup.excludes[xi++] = val; + break; + default: + printk("sym53c8xx_setup: unexpected boot option '%.*s' ignored\n", (int)(pc-cur+1), cur); + break; + } + + if ((cur = strchr(cur, ARG_SEP)) != NULL) + ++cur; + } +#endif /* SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT */ +} + +static int sym53c8xx_pci_init(Scsi_Host_Template *tpnt, + uchar bus, uchar device_fn, ncr_device *device); + +/* +** Linux entry point for SYM53C8XX devices detection routine. +** +** Called by the middle-level scsi drivers at initialization time, +** or at module installation. +** +** Read the PCI configuration and try to attach each +** detected NCR board. +** +** If NVRAM is present, try to attach boards according to +** the used defined boot order. +** +** Returns the number of boards successfully attached. +*/ + +__initfunc( +static void ncr_print_driver_setup(void) +) +{ +#define YesNo(y) y ? 'y' : 'n' + printk (NAME53C8XX ": setup=disc:%c,specf:%d,ultra:%d,tags:%d,sync:%d," + "burst:%d,wide:%c,diff:%d,revprob:%c,buschk:0x%x\n", + YesNo(driver_setup.disconnection), + driver_setup.special_features, + driver_setup.ultra_scsi, + driver_setup.default_tags, + driver_setup.default_sync, + driver_setup.burst_max, + YesNo(driver_setup.max_wide), + driver_setup.diff_support, + YesNo(driver_setup.reverse_probe), + driver_setup.bus_check); + + printk (NAME53C8XX ": setup=mpar:%c,spar:%c,fsn=%c,verb:%d,debug:0x%x," + "led:%c,settle:%d,irqm:0x%x,nvram:0x%x,pcifix:0x%x\n", + YesNo(driver_setup.master_parity), + YesNo(driver_setup.scsi_parity), + YesNo(driver_setup.force_sync_nego), + driver_setup.verbose, + driver_setup.debug, + YesNo(driver_setup.led_pin), + driver_setup.settle_delay, + driver_setup.irqm, + driver_setup.use_nvram, + driver_setup.pci_fix_up); +#undef YesNo +} + +/*=================================================================== +** SYM53C8XX devices description table and chip ids list. +**=================================================================== +*/ + +static ncr_chip ncr_chip_table[] __initdata = SCSI_NCR_CHIP_TABLE; +static ushort ncr_chip_ids[] __initdata = SCSI_NCR_CHIP_IDS; + +#ifdef SCSI_NCR_PQS_PDS_SUPPORT +/*=================================================================== +** Detect all NCR PQS/PDS boards and keep track of their bus nr. +** +** The NCR PQS or PDS card is constructed as a DEC bridge +** behind which sit a proprietary NCR memory controller and +** four or two 53c875s as separate devices. In its usual mode +** of operation, the 875s are slaved to the memory controller +** for all transfers. We can tell if an 875 is part of a +** PQS/PDS or not since if it is, it will be on the same bus +** as the memory controller. To operate with the Linux +** driver, the memory controller is disabled and the 875s +** freed to function independently. The only wrinkle is that +** the preset SCSI ID (which may be zero) must be read in from +** a special configuration space register of the 875 +**=================================================================== +*/ +#define SCSI_NCR_MAX_PQS_BUS 16 +static int pqs_bus[SCSI_NCR_MAX_PQS_BUS] __initdata = { 0 }; + +__initfunc( +static void ncr_detect_pqs_pds(void) +) +{ + short index; + + for(index=0; index < SCSI_NCR_MAX_PQS_BUS; index ++) { + u_char tmp, bus, device_fn; + + if (pcibios_find_device(0x101a, 0x0009, index, &bus, + &device_fn) != PCIBIOS_SUCCESSFUL) { + pqs_bus[index] = -1; + break; + } + printk(KERN_INFO NAME53C8XX ": NCR PQS/PDS memory controller detected on bus %d\n", bus); + pcibios_read_config_byte(bus, device_fn, 0x44, &tmp); + /* bit 1: allow individual 875 configuration */ + tmp |= 0x2; + pcibios_write_config_byte(bus, device_fn, 0x44, tmp); + pcibios_read_config_byte(bus, device_fn, 0x45, &tmp); + /* bit 2: drive individual 875 interrupts to the bus */ + tmp |= 0x4; + pcibios_write_config_byte(bus, device_fn, 0x45, tmp); + + pqs_bus[index] = bus; + } +} +#endif /* SCSI_NCR_PQS_PDS_SUPPORT */ + +/*=================================================================== +** Detect all 53c8xx hosts and then attach them. +** +** If we are using NVRAM, once all hosts are detected, we need to +** check any NVRAM for boot order in case detect and boot order +** differ and attach them using the order in the NVRAM. +** +** If no NVRAM is found or data appears invalid attach boards in +** the the order they are detected. +**=================================================================== +*/ +__initfunc( +int sym53c8xx_detect(Scsi_Host_Template *tpnt) +) +{ + int i, j, chips, hosts, count; + u_char bus, device_fn; + short index; + int attach_count = 0; + ncr_device *devtbl, *devp; +#ifdef SCSI_NCR_NVRAM_SUPPORT + ncr_nvram nvram0, nvram, *nvp; +#endif + + /* + ** PCI is required. + */ +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,92) + if (!pci_present()) +#else + if (!pcibios_present()) +#endif + return 0; + + /* + ** Initialize driver general stuff. + */ +#ifdef SCSI_NCR_PROC_INFO_SUPPORT + tpnt->proc_dir = &proc_scsi_sym53c8xx; + tpnt->proc_info = sym53c8xx_proc_info; +#endif + +#if defined(SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT) && defined(MODULE) +if (sym53c8xx) + sym53c8xx_setup(sym53c8xx, (int *) 0); +#endif +#ifdef SCSI_NCR_DEBUG_INFO_SUPPORT + ncr_debug = driver_setup.debug; +#endif + + if (initverbose >= 2) + ncr_print_driver_setup(); + + /* + ** Allocate the device table since we donnot want to + ** overflow the kernel stack. + ** 1 x 4K PAGE is enough for more than 40 devices for i386. + */ + devtbl = m_calloc(PAGE_SIZE, "devtbl", MEMO_WARN); + if (!devtbl) + return 0; + + /* + ** Detect all NCR PQS/PDS memory controllers. + */ +#ifdef SCSI_NCR_PQS_PDS_SUPPORT + ncr_detect_pqs_pds(); +#endif + + /* + ** Detect all 53c8xx hosts. + ** Save the first Symbios NVRAM content if any + ** for the boot order. + */ + chips = sizeof(ncr_chip_ids) / sizeof(ncr_chip_ids[0]); + hosts = PAGE_SIZE / sizeof(*devtbl); +#ifdef SCSI_NCR_NVRAM_SUPPORT + nvp = (driver_setup.use_nvram & 0x1) ? &nvram0 : 0; +#endif + j = 0; + index = 0; + count = 0; + while (1) { + char *msg = ""; + if (count >= hosts) + break; + if (j >= chips) + break; + i = driver_setup.reverse_probe ? chips - 1 - j : j; + if (pcibios_find_device(PCI_VENDOR_ID_NCR, ncr_chip_ids[i], + index, &bus, &device_fn)) { + ++j; + index = 0; + continue; + } + ++index; + devp = &devtbl[count]; + devp->host_id = 255; + devp->attach_done = 0; + if (sym53c8xx_pci_init(tpnt, bus, device_fn, devp)) { + continue; + } + ++count; +#ifdef SCSI_NCR_NVRAM_SUPPORT + if (nvp) { + ncr_get_nvram(devp, nvp); + switch(nvp->type) { + case SCSI_NCR_SYMBIOS_NVRAM: + /* + * Switch to the other nvram buffer, so that + * nvram0 will contain the first Symbios + * format NVRAM content with boot order. + */ + nvp = &nvram; + msg = "with Symbios NVRAM"; + break; + case SCSI_NCR_TEKRAM_NVRAM: + msg = "with Tekram NVRAM"; + break; + } + } +#endif +#ifdef SCSI_NCR_PQS_PDS_SUPPORT + if (devp->pqs_pds) + msg = "(NCR PQS/PDS)"; +#endif + printk(KERN_INFO NAME53C8XX ": 53c%s detected %s\n", + devp->chip.name, msg); + } + + /* + ** If we have found a SYMBIOS NVRAM, use first the NVRAM boot + ** sequence as device boot order. + ** check devices in the boot record against devices detected. + ** attach devices if we find a match. boot table records that + ** do not match any detected devices will be ignored. + ** devices that do not match any boot table will not be attached + ** here but will attempt to be attached during the device table + ** rescan. + */ +#ifdef SCSI_NCR_NVRAM_SUPPORT + if (!nvp || nvram0.type != SCSI_NCR_SYMBIOS_NVRAM) + goto next; + for (i = 0; i < 4; i++) { + Symbios_host *h = &nvram0.data.Symbios.host[i]; + for (j = 0 ; j < count ; j++) { + devp = &devtbl[j]; + if (h->device_fn != devp->slot.device_fn || + h->bus_nr != devp->slot.bus || + h->device_id != devp->chip.device_id) + continue; + if (devp->attach_done) + continue; + if (h->flags & SYMBIOS_INIT_SCAN_AT_BOOT) { + ncr_get_nvram(devp, nvp); + if (!ncr_attach (tpnt, attach_count, devp)) + attach_count++; + } + else if (!(driver_setup.use_nvram & 0x80)) + printk(KERN_INFO NAME53C8XX + ": 53c%s state OFF thus not attached\n", + devp->chip.name); + else + continue; + + devp->attach_done = 1; + break; + } + } +next: +#endif + + /* + ** Rescan device list to make sure all boards attached. + ** Devices without boot records will not be attached yet + ** so try to attach them here. + */ + for (i= 0; i < count; i++) { + devp = &devtbl[i]; + if (!devp->attach_done) { +#ifdef SCSI_NCR_NVRAM_SUPPORT + ncr_get_nvram(devp, nvp); +#endif + if (!ncr_attach (tpnt, attach_count, devp)) + attach_count++; + } + } + + m_free(devtbl, PAGE_SIZE, "devtbl"); + + return attach_count; +} + +/*=================================================================== +** Generically read a base address from the PCI configuration space. +** Return the offset immediately after the base address that has +** been read. Btw, we blindly assume that the high 32 bits of 64 bit +** base addresses are set to zero on 32 bit architectures. +**=================================================================== +*/ +#if LINUX_VERSION_CODE <= LinuxVersionCode(2,1,92) +__initfunc( +static int +pci_read_base_address(u_char bus, u_char device_fn, int offset, u_long *base) +) +{ + u_int32 tmp; + + pcibios_read_config_dword(bus, device_fn, offset, &tmp); + *base = tmp; + offset += sizeof(u_int32); + if ((tmp & 0x7) == 0x4) { +#if BITS_PER_LONG > 32 + pcibios_read_config_dword(bus, device_fn, offset, &tmp); + *base |= (((u_long)tmp) << 32); +#endif + offset += sizeof(u_int32); + } + return offset; +} +#else /* LINUX_VERSION_CODE > LinuxVersionCode(2,1,92) */ +__initfunc( +static int +pci_get_base_address(struct pci_dev *pdev, int index, u_long *base) +) +{ + *base = pdev->base_address[index++]; + if ((*base & 0x7) == 0x4) { +#if BITS_PER_LONG > 32 + *base |= (((u_long)pdev->base_address[index]) << 32); +#endif + ++index; + } + return index; +} +#endif + +/*=================================================================== +** Read and check the PCI configuration for any detected NCR +** boards and save data for attaching after all boards have +** been detected. +**=================================================================== +*/ +__initfunc( +static int sym53c8xx_pci_init(Scsi_Host_Template *tpnt, + uchar bus, uchar device_fn, ncr_device *device) +) +{ + u_short vendor_id, device_id, command; + u_char cache_line_size, latency_timer; + u_char suggested_cache_line_size = 0; + u_char revision; +#if LINUX_VERSION_CODE > LinuxVersionCode(2,1,92) + struct pci_dev *pdev; + u_int irq; +#else + u_char irq; +#endif + u_long base, base_2, io_port; + int i; + ncr_chip *chip; + + printk(KERN_INFO NAME53C8XX ": at PCI bus %d, device %d, function %d\n", + bus, (int) (device_fn & 0xf8) >> 3, (int) device_fn & 7); + /* + ** Read info from the PCI config space. + ** pcibios_read_config_xxx() functions are assumed to be used for + ** successfully detected PCI devices. + */ +#if LINUX_VERSION_CODE > LinuxVersionCode(2,1,92) + pdev = pci_find_slot(bus, device_fn); + vendor_id = pdev->vendor; + device_id = pdev->device; + irq = pdev->irq; + i = 0; + i = pci_get_base_address(pdev, i, &io_port); + i = pci_get_base_address(pdev, i, &base); + (void) pci_get_base_address(pdev, i, &base_2); +#else + pcibios_read_config_word(bus, device_fn, PCI_VENDOR_ID, &vendor_id); + pcibios_read_config_word(bus, device_fn, PCI_DEVICE_ID, &device_id); + pcibios_read_config_byte(bus, device_fn, PCI_INTERRUPT_LINE, &irq); + i = PCI_BASE_ADDRESS_0; + i = pci_read_base_address(bus, device_fn, i, &io_port); + i = pci_read_base_address(bus, device_fn, i, &base); + (void) pci_read_base_address(bus, device_fn, i, &base_2); +#endif + pcibios_read_config_word(bus, device_fn, PCI_COMMAND, &command); + pcibios_read_config_byte(bus, device_fn, PCI_CLASS_REVISION, &revision); + pcibios_read_config_byte(bus, device_fn, PCI_CACHE_LINE_SIZE, + &cache_line_size); + pcibios_read_config_byte(bus, device_fn, PCI_LATENCY_TIMER, + &latency_timer); + +#ifdef SCSI_NCR_PQS_PDS_SUPPORT + /* + ** Match the BUS number for PQS/PDS devices. + ** Read the SCSI ID from a special register mapped + ** into the configuration space of the individual + ** 875s. This register is set up by the PQS bios + */ + for(i = 0; i < SCSI_NCR_MAX_PQS_BUS && pqs_bus[i] != -1; i++) { + u_char tmp; + if (pqs_bus[i] == bus) { + pcibios_read_config_byte(bus, device_fn, 0x84, &tmp); + device->pqs_pds = 1; + device->host_id = tmp; + break; + } + } +#endif /* SCSI_NCR_PQS_PDS_SUPPORT */ + + /* + ** If user excludes this chip, donnot initialize it. + */ + for (i = 0 ; i < SCSI_NCR_MAX_EXCLUDES ; i++) { + if (driver_setup.excludes[i] == + (io_port & PCI_BASE_ADDRESS_IO_MASK)) + return -1; + } + /* + ** Check if the chip is supported + */ + chip = 0; + for (i = 0; i < sizeof(ncr_chip_table)/sizeof(ncr_chip_table[0]); i++) { + if (device_id != ncr_chip_table[i].device_id) + continue; + if (revision > ncr_chip_table[i].revision_id) + continue; + if (!(ncr_chip_table[i].features & FE_LDSTR)) + continue; + chip = &device->chip; + memcpy(chip, &ncr_chip_table[i], sizeof(*chip)); + chip->revision_id = revision; + break; + } + +#if defined(__i386__) + /* + ** Ignore Symbios chips controlled by SISL RAID controller. + ** This controller sets value 0x52414944 at RAM end - 16. + */ + if (chip && (base_2 & PCI_BASE_ADDRESS_MEM_MASK)) { + unsigned int ram_size, ram_val; + u_long ram_ptr; + + if (chip->features & FE_RAM8K) + ram_size = 8192; + else + ram_size = 4096; + + ram_ptr = remap_pci_mem(base_2 & PCI_BASE_ADDRESS_MEM_MASK, + ram_size); + if (ram_ptr) { + ram_val = readl_raw(ram_ptr + ram_size - 16); + unmap_pci_mem(ram_ptr, ram_size); + if (ram_val == 0x52414944) { + printk(NAME53C8XX": not initializing, " + "driven by SISL RAID controller.\n"); + return -1; + } + } + } +#endif + + if (!chip) { + printk(NAME53C8XX ": not initializing, device not supported\n"); + return -1; + } + +#ifdef __powerpc__ + /* + ** Fix-up for power/pc. + ** Should not be performed by the driver. + */ + if ((command & (PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) + != (PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) { + printk(NAME53C8XX ": setting%s%s...\n", + (command & PCI_COMMAND_IO) ? "" : " PCI_COMMAND_IO", + (command & PCI_COMMAND_MEMORY) ? "" : " PCI_COMMAND_MEMORY"); + command |= (PCI_COMMAND_IO | PCI_COMMAND_MEMORY); + pcibios_write_config_word(bus, device_fn, PCI_COMMAND, command); + } + +#if LINUX_VERSION_CODE < LinuxVersionCode(2,2,0) + if ( is_prep ) { + if (io_port >= 0x10000000) { + printk(NAME53C8XX ": reallocating io_port (Wacky IBM)"); + io_port = (io_port & 0x00FFFFFF) | 0x01000000; + pcibios_write_config_dword(bus, device_fn, + PCI_BASE_ADDRESS_0, io_port); + } + if (base >= 0x10000000) { + printk(NAME53C8XX ": reallocating base (Wacky IBM)"); + base = (base & 0x00FFFFFF) | 0x01000000; + pcibios_write_config_dword(bus, device_fn, + PCI_BASE_ADDRESS_1, base); + } + if (base_2 >= 0x10000000) { + printk(NAME53C8XX ": reallocating base2 (Wacky IBM)"); + base_2 = (base_2 & 0x00FFFFFF) | 0x01000000; + pcibios_write_config_dword(bus, device_fn, + PCI_BASE_ADDRESS_2, base_2); + } + } +#endif +#endif /* __powerpc__ */ + +#ifdef __sparc__ + /* + ** Fix-ups for sparc. + ** + ** I wrote: Should not be performed by the driver, + ** Guy wrote: but how can OBP know each and every PCI card, + ** if they don't use Fcode? + ** I replied: no need to know each and every PCI card, just + ** be skilled enough to understand the PCI specs. + */ + + /* + ** PCI configuration is based on configuration registers being + ** coherent with hardware and software resource identifications. + ** This is fairly simple, but seems still too complex for Sparc. + */ + base = __pa(base); + base_2 = __pa(base_2); + + if (!cache_line_size) + suggested_cache_line_size = 16; + +#endif /* __sparc__ */ + +#if defined(__i386__) && !defined(MODULE) + if (!cache_line_size) { +#if LINUX_VERSION_CODE < LinuxVersionCode(2,1,75) + extern char x86; + switch(x86) { +#else + switch(boot_cpu_data.x86) { +#endif + case 4: suggested_cache_line_size = 4; break; + case 6: + case 5: suggested_cache_line_size = 8; break; + } + } +#endif /* __i386__ */ + + /* + ** Check availability of IO space, memory space. + ** Enable master capability if not yet. + */ +#ifdef NCR_IOMAPPED + if (!(command & PCI_COMMAND_IO) || !(io_port & 1)) { + printk(NAME53C8XX ": I/O base address (0x%lx) disabled.\n", + (long) io_port); + io_port = 0; + } +#endif + if (!(command & PCI_COMMAND_MEMORY)) { + printk(NAME53C8XX ": PCI_COMMAND_MEMORY not set.\n"); + base = 0; + base_2 = 0; + } + io_port &= PCI_BASE_ADDRESS_IO_MASK; + base &= PCI_BASE_ADDRESS_MEM_MASK; + base_2 &= PCI_BASE_ADDRESS_MEM_MASK; + +#ifdef NCR_IOMAPPED + if (io_port && check_region (io_port, 128)) { + printk(NAME53C8XX ": IO region 0x%lx[0..127] is in use\n", + (long) io_port); + io_port = 0; + } + if (!io_port) + return -1; +#else + if (!base) { + printk(NAME53C8XX ": MMIO base address disabled.\n"); + return -1; + } +#endif + + /* + ** Set MASTER capable and PARITY bit, if not yet. + */ + if ((command & (PCI_COMMAND_MASTER | PCI_COMMAND_PARITY)) + != (PCI_COMMAND_MASTER | PCI_COMMAND_PARITY)) { + printk(NAME53C8XX ": setting%s%s...(fix-up)\n", + (command & PCI_COMMAND_MASTER) ? "" : " PCI_COMMAND_MASTER", + (command & PCI_COMMAND_PARITY) ? "" : " PCI_COMMAND_PARITY"); + command |= (PCI_COMMAND_MASTER | PCI_COMMAND_PARITY); + pcibios_write_config_word(bus, device_fn, PCI_COMMAND, command); + } + + /* + ** Fix some features according to driver setup. + */ + if (!(driver_setup.special_features & 1)) + chip->features &= ~FE_SPECIAL_SET; + else { + if (driver_setup.special_features & 2) + chip->features &= ~FE_WRIE; + if (driver_setup.special_features & 4) + chip->features &= ~FE_NOPM; + } + if (driver_setup.ultra_scsi < 2 && (chip->features & FE_ULTRA2)) { + chip->features |= FE_ULTRA; + chip->features &= ~FE_ULTRA2; + } + if (driver_setup.ultra_scsi < 1) + chip->features &= ~FE_ULTRA; + if (!driver_setup.max_wide) + chip->features &= ~FE_WIDE; + +#ifdef SCSI_NCR_PCI_FIX_UP_SUPPORT + /* + ** Try to fix up PCI config according to wished features. + */ + if ((driver_setup.pci_fix_up & 1) && (chip->features & FE_CLSE) && + !cache_line_size && suggested_cache_line_size) { + cache_line_size = suggested_cache_line_size; + pcibios_write_config_byte(bus, device_fn, + PCI_CACHE_LINE_SIZE, cache_line_size); + printk(NAME53C8XX ": PCI_CACHE_LINE_SIZE set to %d (fix-up).\n", + cache_line_size); + } + + if ((driver_setup.pci_fix_up & 2) && cache_line_size && + (chip->features & FE_WRIE) && !(command & PCI_COMMAND_INVALIDATE)) { + printk(NAME53C8XX": setting PCI_COMMAND_INVALIDATE (fix-up)\n"); + command |= PCI_COMMAND_INVALIDATE; + pcibios_write_config_word(bus, device_fn, PCI_COMMAND, command); + } + + /* + ** Tune PCI LATENCY TIMER according to burst max length transfer. + ** (latency timer >= burst length + 6, we add 10 to be quite sure) + */ + + if ((driver_setup.pci_fix_up & 4) && chip->burst_max) { + uchar lt = (1 << chip->burst_max) + 6 + 10; + if (latency_timer < lt) { + latency_timer = lt; + printk(NAME53C8XX + ": setting PCI_LATENCY_TIMER to %d (fix-up).\n", + latency_timer); + pcibios_write_config_byte(bus, device_fn, + PCI_LATENCY_TIMER, latency_timer); + } + } + +#endif /* SCSI_NCR_PCI_FIX_UP_SUPPORT */ + + /* + ** Initialise ncr_device structure with items required by ncr_attach. + */ + device->slot.bus = bus; + device->slot.device_fn = device_fn; + device->slot.base = base; + device->slot.base_2 = base_2; + device->slot.io_port = io_port; + device->slot.irq = irq; + device->attach_done = 0; + + return 0; +} + + +/*=================================================================== +** Detect and try to read SYMBIOS and TEKRAM NVRAM. +** +** Data can be used to order booting of boards. +** +** Data is saved in ncr_device structure if NVRAM found. This +** is then used to find drive boot order for ncr_attach(). +** +** NVRAM data is passed to Scsi_Host_Template later during +** ncr_attach() for any device set up. +*=================================================================== +*/ +#ifdef SCSI_NCR_NVRAM_SUPPORT +__initfunc(static void ncr_get_nvram(ncr_device *devp, ncr_nvram *nvp)) +{ + devp->nvram = nvp; + if (!nvp) + return; + /* + ** Get access to chip IO registers + */ +#ifdef NCR_IOMAPPED + request_region(devp->slot.io_port, 128, NAME53C8XX); + devp->slot.base_io = devp->slot.io_port; +#else + devp->slot.reg = (struct ncr_reg *) remap_pci_mem(devp->slot.base, 128); + if (!devp->slot.reg) + return; +#endif + + /* + ** Try to read SYMBIOS nvram. + ** Try to read TEKRAM nvram if Symbios nvram not found. + */ + if (!ncr_get_Symbios_nvram(&devp->slot, &nvp->data.Symbios)) + nvp->type = SCSI_NCR_SYMBIOS_NVRAM; + else if (!ncr_get_Tekram_nvram(&devp->slot, &nvp->data.Tekram)) + nvp->type = SCSI_NCR_TEKRAM_NVRAM; + else { + nvp->type = 0; + devp->nvram = 0; + } + + /* + ** Release access to chip IO registers + */ +#ifdef NCR_IOMAPPED + release_region(devp->slot.base_io, 128); +#else + unmap_pci_mem((u_long) devp->slot.reg, 128ul); +#endif + +} +#endif /* SCSI_NCR_NVRAM_SUPPORT */ + +/* +** Linux select queue depths function +*/ + +#define DEF_DEPTH (driver_setup.default_tags) +#define ALL_TARGETS -2 +#define NO_TARGET -1 +#define ALL_LUNS -2 +#define NO_LUN -1 + +static int device_queue_depth(ncb_p np, int target, int lun) +{ + int c, h, t, u, v; + char *p = driver_setup.tag_ctrl; + char *ep; + + h = -1; + t = NO_TARGET; + u = NO_LUN; + while ((c = *p++) != 0) { + v = simple_strtoul(p, &ep, 0); + switch(c) { + case '/': + ++h; + t = ALL_TARGETS; + u = ALL_LUNS; + break; + case 't': + if (t != target) + t = (target == v) ? v : NO_TARGET; + u = ALL_LUNS; + break; + case 'u': + if (u != lun) + u = (lun == v) ? v : NO_LUN; + break; + case 'q': + if (h == np->unit && + (t == ALL_TARGETS || t == target) && + (u == ALL_LUNS || u == lun)) + return v; + break; + case '-': + t = ALL_TARGETS; + u = ALL_LUNS; + break; + default: + break; + } + p = ep; + } + return DEF_DEPTH; +} + +static void sym53c8xx_select_queue_depths(struct Scsi_Host *host, struct scsi_device *devlist) +{ + struct scsi_device *device; + + for (device = devlist; device; device = device->next) { + ncb_p np; + tcb_p tp; + lcb_p lp; + int numtags; + + if (device->host != host) + continue; + + np = ((struct host_data *) host->hostdata)->ncb; + tp = &np->target[device->id]; + lp = tp->lp[device->lun]; + + /* + ** Select queue depth from driver setup. + ** Donnot use more than configured by user. + ** Use at least 2. + ** Donnot use more than our maximum. + */ + numtags = device_queue_depth(np, device->id, device->lun); + if (numtags > tp->usrtags) + numtags = tp->usrtags; + if (!device->tagged_supported) + numtags = 1; + device->queue_depth = numtags; + if (device->queue_depth < 2) + device->queue_depth = 2; + if (device->queue_depth > SCSI_NCR_MAX_TAGS) + device->queue_depth = SCSI_NCR_MAX_TAGS; + + /* + ** Since the queue depth is not tunable under Linux, + ** we need to know this value in order not to + ** announce stupid things to user. + */ + if (lp) { + lp->numtags = lp->maxtags = numtags; + lp->scdev_depth = device->queue_depth; + } + ncr_setup_tags (np, device->id, device->lun); + +#ifdef DEBUG_SYM53C8XX +printk("sym53c8xx_select_queue_depth: host=%d, id=%d, lun=%d, depth=%d\n", + np->unit, device->id, device->lun, device->queue_depth); +#endif + } +} + +/* +** Linux entry point for info() function +*/ +const char *sym53c8xx_info (struct Scsi_Host *host) +{ + return SCSI_NCR_DRIVER_NAME; +} + +/* +** Linux entry point of queuecommand() function +*/ + +int sym53c8xx_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *)) +{ + ncb_p np = ((struct host_data *) cmd->host->hostdata)->ncb; + unsigned long flags; + int sts; + +#ifdef DEBUG_SYM53C8XX +printk("sym53c8xx_queue_command\n"); +#endif + + cmd->scsi_done = done; + cmd->host_scribble = NULL; + cmd->SCp.ptr = NULL; + cmd->SCp.buffer = NULL; + + NCR_LOCK_NCB(np, flags); + + if ((sts = ncr_queue_command(np, cmd)) != DID_OK) { + SetScsiResult(cmd, sts, 0); +#ifdef DEBUG_SYM53C8XX +printk("sym53c8xx : command not queued - result=%d\n", sts); +#endif + } +#ifdef DEBUG_SYM53C8XX + else +printk("sym53c8xx : command successfully queued\n"); +#endif + + NCR_UNLOCK_NCB(np, flags); + + if (sts != DID_OK) + done(cmd); + + return sts; +} + +/* +** Linux entry point of the interrupt handler. +** Since linux versions > 1.3.70, we trust the kernel for +** passing the internal host descriptor as 'dev_id'. +** Otherwise, we scan the host list and call the interrupt +** routine for each host that uses this IRQ. +*/ + +static void sym53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs) +{ + unsigned long flags; + ncb_p np = (ncb_p) dev_id; + Scsi_Cmnd *done_list; + +#ifdef DEBUG_SYM53C8XX + printk("sym53c8xx : interrupt received\n"); +#endif + + if (DEBUG_FLAGS & DEBUG_TINY) printk ("["); + + NCR_LOCK_NCB(np, flags); + ncr_exception(np); + done_list = np->done_list; + np->done_list = 0; + NCR_UNLOCK_NCB(np, flags); + + if (DEBUG_FLAGS & DEBUG_TINY) printk ("]\n"); + + if (done_list) { + NCR_LOCK_SCSI_DONE(np, flags); + ncr_flush_done_cmds(done_list); + NCR_UNLOCK_SCSI_DONE(np, flags); + } +} + +/* +** Linux entry point of the timer handler +*/ + +static void sym53c8xx_timeout(unsigned long npref) +{ + ncb_p np = (ncb_p) npref; + unsigned long flags; + Scsi_Cmnd *done_list; + + NCR_LOCK_NCB(np, flags); + ncr_timeout((ncb_p) np); + done_list = np->done_list; + np->done_list = 0; + NCR_UNLOCK_NCB(np, flags); + + if (done_list) { + NCR_LOCK_SCSI_DONE(np, flags); + ncr_flush_done_cmds(done_list); + NCR_UNLOCK_SCSI_DONE(np, flags); + } +} + +/* +** Linux entry point of reset() function +*/ + +#if defined SCSI_RESET_SYNCHRONOUS && defined SCSI_RESET_ASYNCHRONOUS +int sym53c8xx_reset(Scsi_Cmnd *cmd, unsigned int reset_flags) +#else +int sym53c8xx_reset(Scsi_Cmnd *cmd) +#endif +{ + ncb_p np = ((struct host_data *) cmd->host->hostdata)->ncb; + int sts; + unsigned long flags; + Scsi_Cmnd *done_list; + +#if defined SCSI_RESET_SYNCHRONOUS && defined SCSI_RESET_ASYNCHRONOUS + printk("sym53c8xx_reset: pid=%lu reset_flags=%x serial_number=%ld serial_number_at_timeout=%ld\n", + cmd->pid, reset_flags, cmd->serial_number, cmd->serial_number_at_timeout); +#else + printk("sym53c8xx_reset: command pid %lu\n", cmd->pid); +#endif + + NCR_LOCK_NCB(np, flags); + + /* + * We have to just ignore reset requests in some situations. + */ +#if defined SCSI_RESET_NOT_RUNNING + if (cmd->serial_number != cmd->serial_number_at_timeout) { + sts = SCSI_RESET_NOT_RUNNING; + goto out; + } +#endif + /* + * If the mid-level driver told us reset is synchronous, it seems + * that we must call the done() callback for the involved command, + * even if this command was not queued to the low-level driver, + * before returning SCSI_RESET_SUCCESS. + */ + +#if defined SCSI_RESET_SYNCHRONOUS && defined SCSI_RESET_ASYNCHRONOUS + sts = ncr_reset_bus(np, cmd, + (reset_flags & (SCSI_RESET_SYNCHRONOUS | SCSI_RESET_ASYNCHRONOUS)) == SCSI_RESET_SYNCHRONOUS); +#else + sts = ncr_reset_bus(np, cmd, 0); +#endif + + /* + * Since we always reset the controller, when we return success, + * we add this information to the return code. + */ +#if defined SCSI_RESET_HOST_RESET + if (sts == SCSI_RESET_SUCCESS) + sts |= SCSI_RESET_HOST_RESET; +#endif + +out: + done_list = np->done_list; + np->done_list = 0; + NCR_UNLOCK_NCB(np, flags); + + ncr_flush_done_cmds(done_list); + + return sts; +} + +/* +** Linux entry point of abort() function +*/ + +int sym53c8xx_abort(Scsi_Cmnd *cmd) +{ + ncb_p np = ((struct host_data *) cmd->host->hostdata)->ncb; + int sts; + unsigned long flags; + Scsi_Cmnd *done_list; + +#if defined SCSI_RESET_SYNCHRONOUS && defined SCSI_RESET_ASYNCHRONOUS + printk("sym53c8xx_abort: pid=%lu serial_number=%ld serial_number_at_timeout=%ld\n", + cmd->pid, cmd->serial_number, cmd->serial_number_at_timeout); +#else + printk("sym53c8xx_abort: command pid %lu\n", cmd->pid); +#endif + + NCR_LOCK_NCB(np, flags); + +#if defined SCSI_RESET_SYNCHRONOUS && defined SCSI_RESET_ASYNCHRONOUS + /* + * We have to just ignore abort requests in some situations. + */ + if (cmd->serial_number != cmd->serial_number_at_timeout) { + sts = SCSI_ABORT_NOT_RUNNING; + goto out; + } +#endif + + sts = ncr_abort_command(np, cmd); +out: + done_list = np->done_list; + np->done_list = 0; + NCR_UNLOCK_NCB(np, flags); + + ncr_flush_done_cmds(done_list); + + return sts; +} + + +#ifdef MODULE +int sym53c8xx_release(struct Scsi_Host *host) +{ +#ifdef DEBUG_SYM53C8XX +printk("sym53c8xx : release\n"); +#endif + ncr_detach(((struct host_data *) host->hostdata)->ncb); + + return 1; +} +#endif + + +/* +** Scsi command waiting list management. +** +** It may happen that we cannot insert a scsi command into the start queue, +** in the following circumstances. +** Too few preallocated ccb(s), +** maxtags < cmd_per_lun of the Linux host control block, +** etc... +** Such scsi commands are inserted into a waiting list. +** When a scsi command complete, we try to requeue the commands of the +** waiting list. +*/ + +#define next_wcmd host_scribble + +static void insert_into_waiting_list(ncb_p np, Scsi_Cmnd *cmd) +{ + Scsi_Cmnd *wcmd; + +#ifdef DEBUG_WAITING_LIST + printk("%s: cmd %lx inserted into waiting list\n", ncr_name(np), (u_long) cmd); +#endif + cmd->next_wcmd = 0; + if (!(wcmd = np->waiting_list)) np->waiting_list = cmd; + else { + while ((wcmd->next_wcmd) != 0) + wcmd = (Scsi_Cmnd *) wcmd->next_wcmd; + wcmd->next_wcmd = (char *) cmd; + } +} + +static Scsi_Cmnd *retrieve_from_waiting_list(int to_remove, ncb_p np, Scsi_Cmnd *cmd) +{ + Scsi_Cmnd **pcmd = &np->waiting_list; + + while (*pcmd) { + if (cmd == *pcmd) { + if (to_remove) { + *pcmd = (Scsi_Cmnd *) cmd->next_wcmd; + cmd->next_wcmd = 0; + } +#ifdef DEBUG_WAITING_LIST + printk("%s: cmd %lx retrieved from waiting list\n", ncr_name(np), (u_long) cmd); +#endif + return cmd; + } + pcmd = (Scsi_Cmnd **) &(*pcmd)->next_wcmd; + } + return 0; +} + +static void process_waiting_list(ncb_p np, int sts) +{ + Scsi_Cmnd *waiting_list, *wcmd; + + waiting_list = np->waiting_list; + np->waiting_list = 0; + +#ifdef DEBUG_WAITING_LIST + if (waiting_list) printk("%s: waiting_list=%lx processing sts=%d\n", ncr_name(np), (u_long) waiting_list, sts); +#endif + while ((wcmd = waiting_list) != 0) { + waiting_list = (Scsi_Cmnd *) wcmd->next_wcmd; + wcmd->next_wcmd = 0; + if (sts == DID_OK) { +#ifdef DEBUG_WAITING_LIST + printk("%s: cmd %lx trying to requeue\n", ncr_name(np), (u_long) wcmd); +#endif + sts = ncr_queue_command(np, wcmd); + } + if (sts != DID_OK) { +#ifdef DEBUG_WAITING_LIST + printk("%s: cmd %lx done forced sts=%d\n", ncr_name(np), (u_long) wcmd, sts); +#endif + SetScsiResult(wcmd, sts, 0); + ncr_queue_done_cmd(np, wcmd); + } + } +} + +#undef next_wcmd + +#ifdef SCSI_NCR_PROC_INFO_SUPPORT + +/*========================================================================= +** Proc file system stuff +** +** A read operation returns profile information. +** A write operation is a control command. +** The string is parsed in the driver code and the command is passed +** to the ncr_usercmd() function. +**========================================================================= +*/ + +#ifdef SCSI_NCR_USER_COMMAND_SUPPORT + +#define is_digit(c) ((c) >= '0' && (c) <= '9') +#define digit_to_bin(c) ((c) - '0') +#define is_space(c) ((c) == ' ' || (c) == '\t') + +static int skip_spaces(char *ptr, int len) +{ + int cnt, c; + + for (cnt = len; cnt > 0 && (c = *ptr++) && is_space(c); cnt--); + + return (len - cnt); +} + +static int get_int_arg(char *ptr, int len, u_long *pv) +{ + int cnt, c; + u_long v; + + for (v = 0, cnt = len; cnt > 0 && (c = *ptr++) && is_digit(c); cnt--) { + v = (v * 10) + digit_to_bin(c); + } + + if (pv) + *pv = v; + + return (len - cnt); +} + +static int is_keyword(char *ptr, int len, char *verb) +{ + int verb_len = strlen(verb); + + if (len >= strlen(verb) && !memcmp(verb, ptr, verb_len)) + return verb_len; + else + return 0; + +} + +#define SKIP_SPACES(min_spaces) \ + if ((arg_len = skip_spaces(ptr, len)) < (min_spaces)) \ + return -EINVAL; \ + ptr += arg_len; len -= arg_len; + +#define GET_INT_ARG(v) \ + if (!(arg_len = get_int_arg(ptr, len, &(v)))) \ + return -EINVAL; \ + ptr += arg_len; len -= arg_len; + + +/* +** Parse a control command +*/ + +static int ncr_user_command(ncb_p np, char *buffer, int length) +{ + char *ptr = buffer; + int len = length; + struct usrcmd *uc = &np->user; + int arg_len; + u_long target; + + bzero(uc, sizeof(*uc)); + + if (len > 0 && ptr[len-1] == '\n') + --len; + + if ((arg_len = is_keyword(ptr, len, "setsync")) != 0) + uc->cmd = UC_SETSYNC; + else if ((arg_len = is_keyword(ptr, len, "settags")) != 0) + uc->cmd = UC_SETTAGS; + else if ((arg_len = is_keyword(ptr, len, "setorder")) != 0) + uc->cmd = UC_SETORDER; + else if ((arg_len = is_keyword(ptr, len, "setverbose")) != 0) + uc->cmd = UC_SETVERBOSE; + else if ((arg_len = is_keyword(ptr, len, "setwide")) != 0) + uc->cmd = UC_SETWIDE; + else if ((arg_len = is_keyword(ptr, len, "setdebug")) != 0) + uc->cmd = UC_SETDEBUG; + else if ((arg_len = is_keyword(ptr, len, "setflag")) != 0) + uc->cmd = UC_SETFLAG; + else if ((arg_len = is_keyword(ptr, len, "clearprof")) != 0) + uc->cmd = UC_CLEARPROF; + else + arg_len = 0; + +#ifdef DEBUG_PROC_INFO +printk("ncr_user_command: arg_len=%d, cmd=%ld\n", arg_len, uc->cmd); +#endif + + if (!arg_len) + return -EINVAL; + ptr += arg_len; len -= arg_len; + + switch(uc->cmd) { + case UC_SETSYNC: + case UC_SETTAGS: + case UC_SETWIDE: + case UC_SETFLAG: + SKIP_SPACES(1); + if ((arg_len = is_keyword(ptr, len, "all")) != 0) { + ptr += arg_len; len -= arg_len; + uc->target = ~0; + } else { + GET_INT_ARG(target); + uc->target = (1<cmd) { + case UC_SETVERBOSE: + case UC_SETSYNC: + case UC_SETTAGS: + case UC_SETWIDE: + SKIP_SPACES(1); + GET_INT_ARG(uc->data); +#ifdef DEBUG_PROC_INFO +printk("ncr_user_command: data=%ld\n", uc->data); +#endif + break; + case UC_SETORDER: + SKIP_SPACES(1); + if ((arg_len = is_keyword(ptr, len, "simple"))) + uc->data = M_SIMPLE_TAG; + else if ((arg_len = is_keyword(ptr, len, "ordered"))) + uc->data = M_ORDERED_TAG; + else if ((arg_len = is_keyword(ptr, len, "default"))) + uc->data = 0; + else + return -EINVAL; + break; + case UC_SETDEBUG: + while (len > 0) { + SKIP_SPACES(1); + if ((arg_len = is_keyword(ptr, len, "alloc"))) + uc->data |= DEBUG_ALLOC; + else if ((arg_len = is_keyword(ptr, len, "phase"))) + uc->data |= DEBUG_PHASE; + else if ((arg_len = is_keyword(ptr, len, "poll"))) + uc->data |= DEBUG_POLL; + else if ((arg_len = is_keyword(ptr, len, "queue"))) + uc->data |= DEBUG_QUEUE; + else if ((arg_len = is_keyword(ptr, len, "result"))) + uc->data |= DEBUG_RESULT; + else if ((arg_len = is_keyword(ptr, len, "scatter"))) + uc->data |= DEBUG_SCATTER; + else if ((arg_len = is_keyword(ptr, len, "script"))) + uc->data |= DEBUG_SCRIPT; + else if ((arg_len = is_keyword(ptr, len, "tiny"))) + uc->data |= DEBUG_TINY; + else if ((arg_len = is_keyword(ptr, len, "timing"))) + uc->data |= DEBUG_TIMING; + else if ((arg_len = is_keyword(ptr, len, "nego"))) + uc->data |= DEBUG_NEGO; + else if ((arg_len = is_keyword(ptr, len, "tags"))) + uc->data |= DEBUG_TAGS; + else if ((arg_len = is_keyword(ptr, len, "freeze"))) + uc->data |= DEBUG_FREEZE; + else if ((arg_len = is_keyword(ptr, len, "restart"))) + uc->data |= DEBUG_RESTART; + else + return -EINVAL; + ptr += arg_len; len -= arg_len; + } +#ifdef DEBUG_PROC_INFO +printk("ncr_user_command: data=%ld\n", uc->data); +#endif + break; + case UC_SETFLAG: + while (len > 0) { + SKIP_SPACES(1); + if ((arg_len = is_keyword(ptr, len, "trace"))) + uc->data |= UF_TRACE; + else if ((arg_len = is_keyword(ptr, len, "no_disc"))) + uc->data |= UF_NODISC; + else + return -EINVAL; + ptr += arg_len; len -= arg_len; + } + break; + default: + break; + } + + if (len) + return -EINVAL; + else { + long flags; + + NCR_LOCK_NCB(np, flags); + ncr_usercmd (np); + NCR_UNLOCK_NCB(np, flags); + } + return length; +} + +#endif /* SCSI_NCR_USER_COMMAND_SUPPORT */ + +#ifdef SCSI_NCR_USER_INFO_SUPPORT + +struct info_str +{ + char *buffer; + int length; + int offset; + int pos; +}; + +static void copy_mem_info(struct info_str *info, char *data, int len) +{ + if (info->pos + len > info->length) + len = info->length - info->pos; + + if (info->pos + len < info->offset) { + info->pos += len; + return; + } + if (info->pos < info->offset) { + data += (info->offset - info->pos); + len -= (info->offset - info->pos); + } + + if (len > 0) { + memcpy(info->buffer + info->pos, data, len); + info->pos += len; + } +} + +static int copy_info(struct info_str *info, char *fmt, ...) +{ + va_list args; + char buf[81]; + int len; + + va_start(args, fmt); + len = vsprintf(buf, fmt, args); + va_end(args); + + copy_mem_info(info, buf, len); + return len; +} + +/* +** Copy formatted profile information into the input buffer. +*/ + +#define to_ms(t) ((t) * 1000 / HZ) + +static int ncr_host_info(ncb_p np, char *ptr, off_t offset, int len) +{ + struct info_str info; + + info.buffer = ptr; + info.length = len; + info.offset = offset; + info.pos = 0; + + copy_info(&info, "General information:\n"); + copy_info(&info, " Chip " NAME53C "%s, ", np->chip_name); + copy_info(&info, "device id 0x%x, ", np->device_id); + copy_info(&info, "revision id 0x%x\n", np->revision_id); + + copy_info(&info, " IO port address 0x%lx, ", (u_long) np->base_io); + copy_info(&info, "IRQ number %d\n", (int) np->irq); + +#ifndef NCR_IOMAPPED + if (np->reg) + copy_info(&info, " Using memory mapped IO at virtual address 0x%lx\n", + (u_long) np->reg); +#endif + copy_info(&info, " Synchronous period factor %d, ", (int) np->minsync); + copy_info(&info, "max commands per lun %d\n", SCSI_NCR_MAX_TAGS); + + if (driver_setup.debug || driver_setup.verbose > 1) { + copy_info(&info, " Debug flags 0x%x, ", driver_setup.debug); + copy_info(&info, "verbosity level %d\n", driver_setup.verbose); + } + +#ifdef SCSI_NCR_PROFILE_SUPPORT + copy_info(&info, "Profiling information:\n"); + copy_info(&info, " %-12s = %lu\n", "num_fly", np->profile.num_fly); + copy_info(&info, " %-12s = %lu\n", "num_trans",np->profile.num_trans); + copy_info(&info, " %-12s = %lu\n", "num_disc", np->profile.num_disc); + copy_info(&info, " %-12s = %lu\n", "num_disc0",np->profile.num_disc0); + copy_info(&info, " %-12s = %lu\n", "num_break",np->profile.num_break); +#if 000 + copy_info(&info, " %-12s = %lu\n", "num_br1k",np->profile.num_br1k); + copy_info(&info, " %-12s = %lu\n", "num_br2k",np->profile.num_br2k); + copy_info(&info, " %-12s = %lu\n", "num_br4k",np->profile.num_br4k); + copy_info(&info, " %-12s = %lu\n", "num_br8k",np->profile.num_br8k); + copy_info(&info, " %-12s = %lu\n", "num_brnk",np->profile.num_brnk); +#endif + copy_info(&info, " %-12s = %lu\n", "num_int", np->profile.num_int); + copy_info(&info, " %-12s = %lu\n","num_kbytes",np->profile.num_kbytes); +#endif + + return info.pos > info.offset? info.pos - info.offset : 0; +} + +#endif /* SCSI_NCR_USER_INFO_SUPPORT */ + +/* +** Entry point of the scsi proc fs of the driver. +** - func = 0 means read (returns profile data) +** - func = 1 means write (parse user control command) +*/ + +static int sym53c8xx_proc_info(char *buffer, char **start, off_t offset, + int length, int hostno, int func) +{ + struct Scsi_Host *host; + struct host_data *host_data; + ncb_p ncb = 0; + int retv; + +#ifdef DEBUG_PROC_INFO +printk("sym53c8xx_proc_info: hostno=%d, func=%d\n", hostno, func); +#endif + + for (host = first_host; host; host = host->next) { + if (host->hostt != first_host->hostt) + continue; + if (host->host_no == hostno) { + host_data = (struct host_data *) host->hostdata; + ncb = host_data->ncb; + break; + } + } + + if (!ncb) + return -EINVAL; + + if (func) { +#ifdef SCSI_NCR_USER_COMMAND_SUPPORT + retv = ncr_user_command(ncb, buffer, length); +#else + retv = -EINVAL; +#endif + } + else { + if (start) + *start = buffer; +#ifdef SCSI_NCR_USER_INFO_SUPPORT + retv = ncr_host_info(ncb, buffer, offset, length); +#else + retv = -EINVAL; +#endif + } + + return retv; +} + + +/*========================================================================= +** End of proc file system stuff +**========================================================================= +*/ +#endif + + +#ifdef SCSI_NCR_NVRAM_SUPPORT + +/* --------------------------------------------------------------------- +** +** Try reading Symbios format nvram +** +** --------------------------------------------------------------------- +** +** GPOI0 - data in/data out +** GPIO1 - clock +** +** return 0 if NVRAM data OK, 1 if NVRAM data not OK +** --------------------------------------------------------------------- +*/ + +#define SET_BIT 0 +#define CLR_BIT 1 +#define SET_CLK 2 +#define CLR_CLK 3 + +static u_short nvram_read_data(ncr_slot *np, u_char *data, int len, u_char *gpreg, u_char *gpcntl); +static void nvram_start(ncr_slot *np, u_char *gpreg); +static void nvram_write_byte(ncr_slot *np, u_char *ack_data, u_char write_data, u_char *gpreg, u_char *gpcntl); +static void nvram_read_byte(ncr_slot *np, u_char *read_data, u_char ack_data, u_char *gpreg, u_char *gpcntl); +static void nvram_readAck(ncr_slot *np, u_char *read_bit, u_char *gpreg, u_char *gpcntl); +static void nvram_writeAck(ncr_slot *np, u_char write_bit, u_char *gpreg, u_char *gpcntl); +static void nvram_doBit(ncr_slot *np, u_char *read_bit, u_char write_bit, u_char *gpreg); +static void nvram_stop(ncr_slot *np, u_char *gpreg); +static void nvram_setBit(ncr_slot *np, u_char write_bit, u_char *gpreg, int bit_mode); + +__initfunc( +static int ncr_get_Symbios_nvram (ncr_slot *np, Symbios_nvram *nvram) +) +{ + static u_char Symbios_trailer[6] = {0xfe, 0xfe, 0, 0, 0, 0}; + u_char gpcntl, gpreg; + u_char old_gpcntl, old_gpreg; + u_short csum; + u_char ack_data; + int retv = 1; + + /* save current state of GPCNTL and GPREG */ + old_gpreg = INB (nc_gpreg); + old_gpcntl = INB (nc_gpcntl); + gpcntl = old_gpcntl & 0xfc; + + /* set up GPREG & GPCNTL to set GPIO0 and GPIO1 in to known state */ + OUTB (nc_gpreg, old_gpreg); + OUTB (nc_gpcntl, gpcntl); + + /* this is to set NVRAM into a known state with GPIO0/1 both low */ + gpreg = old_gpreg; + nvram_setBit(np, 0, &gpreg, CLR_CLK); + nvram_setBit(np, 0, &gpreg, CLR_BIT); + + /* now set NVRAM inactive with GPIO0/1 both high */ + nvram_stop(np, &gpreg); + + /* activate NVRAM */ + nvram_start(np, &gpreg); + + /* write device code and random address MSB */ + nvram_write_byte(np, &ack_data, + 0xa0 | ((SYMBIOS_NVRAM_ADDRESS >> 7) & 0x0e), &gpreg, &gpcntl); + if (ack_data & 0x01) + goto out; + + /* write random address LSB */ + nvram_write_byte(np, &ack_data, + (SYMBIOS_NVRAM_ADDRESS & 0x7f) << 1, &gpreg, &gpcntl); + if (ack_data & 0x01) + goto out; + + /* regenerate START state to set up for reading */ + nvram_start(np, &gpreg); + + /* rewrite device code and address MSB with read bit set (lsb = 0x01) */ + nvram_write_byte(np, &ack_data, + 0xa1 | ((SYMBIOS_NVRAM_ADDRESS >> 7) & 0x0e), &gpreg, &gpcntl); + if (ack_data & 0x01) + goto out; + + /* now set up GPIO0 for inputting data */ + gpcntl |= 0x01; + OUTB (nc_gpcntl, gpcntl); + + /* input all active data - only part of total NVRAM */ + csum = nvram_read_data(np, + (u_char *) nvram, sizeof(*nvram), &gpreg, &gpcntl); + + /* finally put NVRAM back in inactive mode */ + gpcntl &= 0xfe; + OUTB (nc_gpcntl, gpcntl); + nvram_stop(np, &gpreg); + +#ifdef SCSI_NCR_DEBUG_NVRAM +printk("sym53c8xx: NvRAM marker=%x trailer=%x %x %x %x %x %x byte_count=%d/%d checksum=%x/%x\n", + nvram->start_marker, + nvram->trailer[0], nvram->trailer[1], nvram->trailer[2], + nvram->trailer[3], nvram->trailer[4], nvram->trailer[5], + nvram->byte_count, sizeof(*nvram) - 12, + nvram->checksum, csum); +#endif + + /* check valid NVRAM signature, verify byte count and checksum */ + if (nvram->type == 0 && + !memcmp(nvram->trailer, Symbios_trailer, 6) && + nvram->byte_count == sizeof(*nvram) - 12 && + csum == nvram->checksum) + retv = 0; +out: + /* return GPIO0/1 to original states after having accessed NVRAM */ + OUTB (nc_gpcntl, old_gpcntl); + OUTB (nc_gpreg, old_gpreg); + + return retv; +} + +/* + * Read Symbios NvRAM data and compute checksum. + */ +__initfunc( +static u_short nvram_read_data(ncr_slot *np, u_char *data, int len, u_char *gpreg, u_char *gpcntl) +) +{ + int x; + u_short csum; + + for (x = 0; x < len; x++) + nvram_read_byte(np, &data[x], (x == (len - 1)), gpreg, gpcntl); + + for (x = 6, csum = 0; x < len - 6; x++) + csum += data[x]; + + return csum; +} + +/* + * Send START condition to NVRAM to wake it up. + */ +__initfunc( +static void nvram_start(ncr_slot *np, u_char *gpreg) +) +{ + nvram_setBit(np, 1, gpreg, SET_BIT); + nvram_setBit(np, 0, gpreg, SET_CLK); + nvram_setBit(np, 0, gpreg, CLR_BIT); + nvram_setBit(np, 0, gpreg, CLR_CLK); +} + +/* + * WRITE a byte to the NVRAM and then get an ACK to see it was accepted OK, + * GPIO0 must already be set as an output + */ +__initfunc( +static void nvram_write_byte(ncr_slot *np, u_char *ack_data, u_char write_data, u_char *gpreg, u_char *gpcntl) +) +{ + int x; + + for (x = 0; x < 8; x++) + nvram_doBit(np, 0, (write_data >> (7 - x)) & 0x01, gpreg); + + nvram_readAck(np, ack_data, gpreg, gpcntl); +} + +/* + * READ a byte from the NVRAM and then send an ACK to say we have got it, + * GPIO0 must already be set as an input + */ +__initfunc( +static void nvram_read_byte(ncr_slot *np, u_char *read_data, u_char ack_data, u_char *gpreg, u_char *gpcntl) +) +{ + int x; + u_char read_bit; + + *read_data = 0; + for (x = 0; x < 8; x++) { + nvram_doBit(np, &read_bit, 1, gpreg); + *read_data |= ((read_bit & 0x01) << (7 - x)); + } + + nvram_writeAck(np, ack_data, gpreg, gpcntl); +} + +/* + * Output an ACK to the NVRAM after reading, + * change GPIO0 to output and when done back to an input + */ +__initfunc( +static void nvram_writeAck(ncr_slot *np, u_char write_bit, u_char *gpreg, u_char *gpcntl) +) +{ + OUTB (nc_gpcntl, *gpcntl & 0xfe); + nvram_doBit(np, 0, write_bit, gpreg); + OUTB (nc_gpcntl, *gpcntl); +} + +/* + * Input an ACK from NVRAM after writing, + * change GPIO0 to input and when done back to an output + */ +__initfunc( +static void nvram_readAck(ncr_slot *np, u_char *read_bit, u_char *gpreg, u_char *gpcntl) +) +{ + OUTB (nc_gpcntl, *gpcntl | 0x01); + nvram_doBit(np, read_bit, 1, gpreg); + OUTB (nc_gpcntl, *gpcntl); +} + +/* + * Read or write a bit to the NVRAM, + * read if GPIO0 input else write if GPIO0 output + */ +__initfunc( +static void nvram_doBit(ncr_slot *np, u_char *read_bit, u_char write_bit, u_char *gpreg) +) +{ + nvram_setBit(np, write_bit, gpreg, SET_BIT); + nvram_setBit(np, 0, gpreg, SET_CLK); + if (read_bit) + *read_bit = INB (nc_gpreg); + nvram_setBit(np, 0, gpreg, CLR_CLK); + nvram_setBit(np, 0, gpreg, CLR_BIT); +} + +/* + * Send STOP condition to NVRAM - puts NVRAM to sleep... ZZzzzz!! + */ +__initfunc( +static void nvram_stop(ncr_slot *np, u_char *gpreg) +) +{ + nvram_setBit(np, 0, gpreg, SET_CLK); + nvram_setBit(np, 1, gpreg, SET_BIT); +} + +/* + * Set/clear data/clock bit in GPIO0 + */ +__initfunc( +static void nvram_setBit(ncr_slot *np, u_char write_bit, u_char *gpreg, int bit_mode) +) +{ + UDELAY (5); + switch (bit_mode){ + case SET_BIT: + *gpreg |= write_bit; + break; + case CLR_BIT: + *gpreg &= 0xfe; + break; + case SET_CLK: + *gpreg |= 0x02; + break; + case CLR_CLK: + *gpreg &= 0xfd; + break; + + } + OUTB (nc_gpreg, *gpreg); + UDELAY (5); +} + +#undef SET_BIT 0 +#undef CLR_BIT 1 +#undef SET_CLK 2 +#undef CLR_CLK 3 + + +/* --------------------------------------------------------------------- +** +** Try reading Tekram format nvram +** +** --------------------------------------------------------------------- +** +** GPOI0 - data in +** GPIO1 - data out +** GPIO2 - clock +** GPIO4 - chip select +** +** return 0 if NVRAM data OK, 1 if NVRAM data not OK +** --------------------------------------------------------------------- +*/ + +static u_short Tnvram_read_data(ncr_slot *np, u_short *data, int len, u_char *gpreg); +static void Tnvram_Send_Command(ncr_slot *np, u_short write_data, u_char *read_bit, u_char *gpreg); +static void Tnvram_Read_Word(ncr_slot *np, u_short *nvram_data, u_char *gpreg); +static void Tnvram_Read_Bit(ncr_slot *np, u_char *read_bit, u_char *gpreg); +static void Tnvram_Write_Bit(ncr_slot *np, u_char write_bit, u_char *gpreg); +static void Tnvram_Stop(ncr_slot *np, u_char *gpreg); +static void Tnvram_Clk(ncr_slot *np, u_char *gpreg); + +__initfunc( +static int ncr_get_Tekram_nvram (ncr_slot *np, Tekram_nvram *nvram) +) +{ + u_char gpcntl, gpreg; + u_char old_gpcntl, old_gpreg; + u_short csum; + + /* save current state of GPCNTL and GPREG */ + old_gpreg = INB (nc_gpreg); + old_gpcntl = INB (nc_gpcntl); + + /* set up GPREG & GPCNTL to set GPIO0/1/2/4 in to known state, 0 in, + 1/2/4 out */ + gpreg = old_gpreg & 0xe9; + OUTB (nc_gpreg, gpreg); + gpcntl = (old_gpcntl & 0xe9) | 0x09; + OUTB (nc_gpcntl, gpcntl); + + /* input all of NVRAM, 64 words */ + csum = Tnvram_read_data(np, (u_short *) nvram, + sizeof(*nvram) / sizeof(short), &gpreg); + + /* return GPIO0/1/2/4 to original states after having accessed NVRAM */ + OUTB (nc_gpcntl, old_gpcntl); + OUTB (nc_gpreg, old_gpreg); + + /* check data valid */ + if (csum != 0x1234) + return 1; + + return 0; +} + +/* + * Read Tekram NvRAM data and compute checksum. + */ +__initfunc( +static u_short Tnvram_read_data(ncr_slot *np, u_short *data, int len, u_char *gpreg) +) +{ + u_char read_bit; + u_short csum; + int x; + + for (x = 0, csum = 0; x < len; x++) { + + /* output read command and address */ + Tnvram_Send_Command(np, 0x180 | x, &read_bit, gpreg); + if (read_bit & 0x01) + return 0; /* Force bad checksum */ + + Tnvram_Read_Word(np, &data[x], gpreg); + csum += data[x]; + + Tnvram_Stop(np, gpreg); + } + + return csum; +} + +/* + * Send read command and address to NVRAM + */ +__initfunc( +static void Tnvram_Send_Command(ncr_slot *np, u_short write_data, u_char *read_bit, u_char *gpreg) +) +{ + int x; + + /* send 9 bits, start bit (1), command (2), address (6) */ + for (x = 0; x < 9; x++) + Tnvram_Write_Bit(np, (u_char) (write_data >> (8 - x)), gpreg); + + *read_bit = INB (nc_gpreg); +} + +/* + * READ a byte from the NVRAM + */ +__initfunc( +static void Tnvram_Read_Word(ncr_slot *np, u_short *nvram_data, u_char *gpreg) +) +{ + int x; + u_char read_bit; + + *nvram_data = 0; + for (x = 0; x < 16; x++) { + Tnvram_Read_Bit(np, &read_bit, gpreg); + + if (read_bit & 0x01) + *nvram_data |= (0x01 << (15 - x)); + else + *nvram_data &= ~(0x01 << (15 - x)); + } +} + +/* + * Read bit from NVRAM + */ +__initfunc( +static void Tnvram_Read_Bit(ncr_slot *np, u_char *read_bit, u_char *gpreg) +) +{ + UDELAY (2); + Tnvram_Clk(np, gpreg); + *read_bit = INB (nc_gpreg); +} + +/* + * Write bit to GPIO0 + */ +__initfunc( +static void Tnvram_Write_Bit(ncr_slot *np, u_char write_bit, u_char *gpreg) +) +{ + if (write_bit & 0x01) + *gpreg |= 0x02; + else + *gpreg &= 0xfd; + + *gpreg |= 0x10; + + OUTB (nc_gpreg, *gpreg); + UDELAY (2); + + Tnvram_Clk(np, gpreg); +} + +/* + * Send STOP condition to NVRAM - puts NVRAM to sleep... ZZZzzz!! + */ +__initfunc( +static void Tnvram_Stop(ncr_slot *np, u_char *gpreg) +) +{ + *gpreg &= 0xef; + OUTB (nc_gpreg, *gpreg); + UDELAY (2); + + Tnvram_Clk(np, gpreg); +} + +/* + * Pulse clock bit in GPIO0 + */ +__initfunc( +static void Tnvram_Clk(ncr_slot *np, u_char *gpreg) +) +{ + OUTB (nc_gpreg, *gpreg | 0x04); + UDELAY (2); + OUTB (nc_gpreg, *gpreg); +} + +#endif /* SCSI_NCR_NVRAM_SUPPORT */ + +/* +** Module stuff +*/ + +#ifdef MODULE +Scsi_Host_Template driver_template = SYM53C8XX; +#include "scsi_module.c" +#endif diff -ur --new-file old/linux/drivers/scsi/sym53c8xx.h new/linux/drivers/scsi/sym53c8xx.h --- old/linux/drivers/scsi/sym53c8xx.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/scsi/sym53c8xx.h Tue May 11 19:36:50 1999 @@ -0,0 +1,116 @@ +/****************************************************************************** +** High Performance device driver for the Symbios 53C896 controller. +** +** Copyright (C) 1998 Gerard Roudier +** +** This driver also supports all the Symbios 53C8XX controller family, +** except 53C810 revisions < 16, 53C825 revisions < 16 and all +** revisions of 53C815 controllers. +** +** This driver is based on the Linux port of the FreeBSD ncr driver. +** +** Copyright (C) 1994 Wolfgang Stanglmeier +** +**----------------------------------------------------------------------------- +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +**----------------------------------------------------------------------------- +** +** The Linux port of the FreeBSD ncr driver has been achieved in +** november 1995 by: +** +** Gerard Roudier +** +** Being given that this driver originates from the FreeBSD version, and +** in order to keep synergy on both, any suggested enhancements and corrections +** received on Linux are automatically a potential candidate for the FreeBSD +** version. +** +** The original driver has been written for 386bsd and FreeBSD by +** Wolfgang Stanglmeier +** Stefan Esser +** +**----------------------------------------------------------------------------- +** +** Major contributions: +** -------------------- +** +** NVRAM detection and reading. +** Copyright (C) 1997 Richard Waltham +** +******************************************************************************* +*/ + +#ifndef SYM53C8XX_H +#define SYM53C8XX_H + +#include "sym53c8xx_defs.h" + +/* +** Define Scsi_Host_Template parameters +** +** Used by hosts.c and sym53c8xx.c with module configuration. +*/ + +#if defined(HOSTS_C) || defined(MODULE) + +#include + +int sym53c8xx_abort(Scsi_Cmnd *); +int sym53c8xx_detect(Scsi_Host_Template *tpnt); +const char *sym53c8xx_info(struct Scsi_Host *host); +int sym53c8xx_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); +int sym53c8xx_reset(Scsi_Cmnd *, unsigned int); + +#ifdef MODULE +int sym53c8xx_release(struct Scsi_Host *); +#else +#define sym53c8xx_release NULL +#endif + + +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,75) + +#define SYM53C8XX { name: "", \ + detect: sym53c8xx_detect, \ + release: sym53c8xx_release, \ + info: sym53c8xx_info, \ + queuecommand: sym53c8xx_queue_command,\ + abort: sym53c8xx_abort, \ + reset: sym53c8xx_reset, \ + bios_param: scsicam_bios_param, \ + can_queue: SCSI_NCR_CAN_QUEUE, \ + this_id: 7, \ + sg_tablesize: SCSI_NCR_SG_TABLESIZE, \ + cmd_per_lun: SCSI_NCR_CMD_PER_LUN, \ + use_clustering: DISABLE_CLUSTERING} + +#else + +#define SYM53C8XX { NULL, NULL, NULL, NULL, \ + NULL, sym53c8xx_detect, \ + sym53c8xx_release, sym53c8xx_info, NULL, \ + sym53c8xx_queue_command,sym53c8xx_abort, \ + sym53c8xx_reset, NULL, scsicam_bios_param, \ + SCSI_NCR_CAN_QUEUE, 7, \ + SCSI_NCR_SG_TABLESIZE, SCSI_NCR_CMD_PER_LUN, \ + 0, 0, DISABLE_CLUSTERING} + +#endif /* LINUX_VERSION_CODE */ + +#endif /* defined(HOSTS_C) || defined(MODULE) */ + +#endif /* SYM53C8XX_H */ diff -ur --new-file old/linux/drivers/scsi/sym53c8xx_defs.h new/linux/drivers/scsi/sym53c8xx_defs.h --- old/linux/drivers/scsi/sym53c8xx_defs.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/scsi/sym53c8xx_defs.h Tue May 11 19:36:31 1999 @@ -0,0 +1,1195 @@ +/****************************************************************************** +** High Performance device driver for the Symbios 53C896 controller. +** +** Copyright (C) 1998 Gerard Roudier +** +** This driver also supports all the Symbios 53C8XX controller family, +** except 53C810 revisions < 16, 53C825 revisions < 16 and all +** revisions of 53C815 controllers. +** +** This driver is based on the Linux port of the FreeBSD ncr driver. +** +** Copyright (C) 1994 Wolfgang Stanglmeier +** +**----------------------------------------------------------------------------- +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +**----------------------------------------------------------------------------- +** +** The Linux port of the FreeBSD ncr driver has been achieved in +** november 1995 by: +** +** Gerard Roudier +** +** Being given that this driver originates from the FreeBSD version, and +** in order to keep synergy on both, any suggested enhancements and corrections +** received on Linux are automatically a potential candidate for the FreeBSD +** version. +** +** The original driver has been written for 386bsd and FreeBSD by +** Wolfgang Stanglmeier +** Stefan Esser +** +**----------------------------------------------------------------------------- +** +** Major contributions: +** -------------------- +** +** NVRAM detection and reading. +** Copyright (C) 1997 Richard Waltham +** +******************************************************************************* +*/ + +#ifndef SYM53C8XX_DEFS_H +#define SYM53C8XX_DEFS_H + +/* +** Check supported Linux versions +*/ + +#if !defined(LINUX_VERSION_CODE) +#include +#endif +#include + +#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s)) + +/* + * NCR PQS/PDS special device support. + */ +#ifdef CONFIG_SCSI_NCR53C8XX_PQS_PDS +#define SCSI_NCR_PQS_PDS_SUPPORT +#endif + +/* + * No more an option, enabled by default. + */ +#ifndef CONFIG_SCSI_NCR53C8XX_NVRAM_DETECT +#define CONFIG_SCSI_NCR53C8XX_NVRAM_DETECT +#endif + +/* +** These options are not tunable from 'make config' +*/ +#define SCSI_NCR_PROC_INFO_SUPPORT + +/* +** If you want a driver as small as possible, donnot define the +** following options. +*/ +#define SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT +#define SCSI_NCR_DEBUG_INFO_SUPPORT +#define SCSI_NCR_PCI_FIX_UP_SUPPORT +#ifdef SCSI_NCR_PROC_INFO_SUPPORT +# ifdef CONFIG_SCSI_NCR53C8XX_PROFILE +# define SCSI_NCR_PROFILE_SUPPORT +# endif +# define SCSI_NCR_USER_COMMAND_SUPPORT +# define SCSI_NCR_USER_INFO_SUPPORT +#endif + +/*========================================================== +** +** nvram settings - #define SCSI_NCR_NVRAM_SUPPORT to enable +** +**========================================================== +*/ + +#ifdef CONFIG_SCSI_NCR53C8XX_NVRAM_DETECT +#define SCSI_NCR_NVRAM_SUPPORT +/* #define SCSI_NCR_DEBUG_NVRAM */ +#endif + +/* --------------------------------------------------------------------- +** Take into account kernel configured parameters. +** Most of these options can be overridden at startup by a command line. +** --------------------------------------------------------------------- +*/ + +/* + * For Ultra2 SCSI support option, use special features and allow 40Mhz + * synchronous data transfers. + * + * Value 5 (default) means: + * bit 0 : all features enabled, except: + * bit 1 : PCI Write And Invalidate. + * bit 2 : Data Phase Mismatch handling from SCRIPTS. + * + * Use boot options ncr53c8xx=specf:1 if you want all chip features to be + * enabled by the driver. + */ +#define SCSI_NCR_SETUP_SPECIAL_FEATURES (3) +#define SCSI_NCR_SETUP_ULTRA_SCSI (2) +#define SCSI_NCR_MAX_SYNC (40) + +/* + * Allow tags from 2 to 64, default 8 + */ +#ifdef CONFIG_SCSI_NCR53C8XX_MAX_TAGS +#if CONFIG_SCSI_NCR53C8XX_MAX_TAGS < 2 +#define SCSI_NCR_MAX_TAGS (2) +#elif CONFIG_SCSI_NCR53C8XX_MAX_TAGS > 64 +#define SCSI_NCR_MAX_TAGS (64) +#else +#define SCSI_NCR_MAX_TAGS CONFIG_SCSI_NCR53C8XX_MAX_TAGS +#endif +#else +#define SCSI_NCR_MAX_TAGS (8) +#endif + +/* + * Allow tagged command queuing support if configured with default number + * of tags set to max (see above). + */ +#ifdef CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS +#define SCSI_NCR_SETUP_DEFAULT_TAGS CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS +#elif defined CONFIG_SCSI_NCR53C8XX_TAGGED_QUEUE +#define SCSI_NCR_SETUP_DEFAULT_TAGS SCSI_NCR_MAX_TAGS +#else +#define SCSI_NCR_SETUP_DEFAULT_TAGS (0) +#endif + +/* + * Use normal IO if configured. Forced for alpha and ppc. + */ +#if defined(CONFIG_SCSI_NCR53C8XX_IOMAPPED) +#define SCSI_NCR_IOMAPPED +#elif defined(__alpha__) || defined(__powerpc__) +#define SCSI_NCR_IOMAPPED +#elif defined(__sparc__) +#undef SCSI_NCR_IOMAPPED +#endif + +/* + * Sync transfer frequency at startup. + * Allow from 5Mhz to 40Mhz default 20 Mhz. + */ +#ifndef CONFIG_SCSI_NCR53C8XX_SYNC +#define CONFIG_SCSI_NCR53C8XX_SYNC (20) +#elif CONFIG_SCSI_NCR53C8XX_SYNC > SCSI_NCR_MAX_SYNC +#undef CONFIG_SCSI_NCR53C8XX_SYNC +#define CONFIG_SCSI_NCR53C8XX_SYNC SCSI_NCR_MAX_SYNC +#endif + +#if CONFIG_SCSI_NCR53C8XX_SYNC == 0 +#define SCSI_NCR_SETUP_DEFAULT_SYNC (255) +#elif CONFIG_SCSI_NCR53C8XX_SYNC <= 5 +#define SCSI_NCR_SETUP_DEFAULT_SYNC (50) +#elif CONFIG_SCSI_NCR53C8XX_SYNC <= 20 +#define SCSI_NCR_SETUP_DEFAULT_SYNC (250/(CONFIG_SCSI_NCR53C8XX_SYNC)) +#elif CONFIG_SCSI_NCR53C8XX_SYNC <= 33 +#define SCSI_NCR_SETUP_DEFAULT_SYNC (11) +#else +#define SCSI_NCR_SETUP_DEFAULT_SYNC (10) +#endif + +/* + * Disallow disconnections at boot-up + */ +#ifdef CONFIG_SCSI_NCR53C8XX_NO_DISCONNECT +#define SCSI_NCR_SETUP_DISCONNECTION (0) +#else +#define SCSI_NCR_SETUP_DISCONNECTION (1) +#endif + +/* + * Force synchronous negotiation for all targets + */ +#ifdef CONFIG_SCSI_NCR53C8XX_FORCE_SYNC_NEGO +#define SCSI_NCR_SETUP_FORCE_SYNC_NEGO (1) +#else +#define SCSI_NCR_SETUP_FORCE_SYNC_NEGO (0) +#endif + +/* + * Disable master parity checking (flawed hardwares need that) + */ +#ifdef CONFIG_SCSI_NCR53C8XX_DISABLE_MPARITY_CHECK +#define SCSI_NCR_SETUP_MASTER_PARITY (0) +#else +#define SCSI_NCR_SETUP_MASTER_PARITY (1) +#endif + +/* + * Disable scsi parity checking (flawed devices may need that) + */ +#ifdef CONFIG_SCSI_NCR53C8XX_DISABLE_PARITY_CHECK +#define SCSI_NCR_SETUP_SCSI_PARITY (0) +#else +#define SCSI_NCR_SETUP_SCSI_PARITY (1) +#endif + +/* + * Vendor specific stuff + */ +#ifdef CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT +#define SCSI_NCR_SETUP_LED_PIN (1) +#define SCSI_NCR_SETUP_DIFF_SUPPORT (3) +#else +#define SCSI_NCR_SETUP_LED_PIN (0) +#define SCSI_NCR_SETUP_DIFF_SUPPORT (0) +#endif + +/* + * Settle time after reset at boot-up + */ +#define SCSI_NCR_SETUP_SETTLE_TIME (2) + +/* +** Other parameters not configurable with "make config" +** Avoid to change these constants, unless you know what you are doing. +*/ + +#define SCSI_NCR_ALWAYS_SIMPLE_TAG +#define SCSI_NCR_MAX_SCATTER (127) +#define SCSI_NCR_MAX_TARGET (16) + +/* No need to use a too large adapter queue */ +#if SCSI_NCR_MAX_TAGS <= 32 +#define SCSI_NCR_CAN_QUEUE (7*SCSI_NCR_MAX_TAGS) +#else +#define SCSI_NCR_CAN_QUEUE (250) +#endif + +#define SCSI_NCR_CMD_PER_LUN (SCSI_NCR_MAX_TAGS) +#define SCSI_NCR_SG_TABLESIZE (SCSI_NCR_MAX_SCATTER) + +#define SCSI_NCR_TIMER_INTERVAL (HZ) + +#if 1 /* defined CONFIG_SCSI_MULTI_LUN */ +#define SCSI_NCR_MAX_LUN (8) +#else +#define SCSI_NCR_MAX_LUN (1) +#endif + +#ifndef HOSTS_C + +/* +** IO functions definition for big/little endian support. +** For now, the NCR is only supported in little endian addressing mode, +** and big endian byte ordering is only supported for the PPC. +** MMIO is not used on PPC. +*/ + +#ifdef __BIG_ENDIAN + +#if LINUX_VERSION_CODE < LinuxVersionCode(2,1,0) +#error "BIG ENDIAN byte ordering needs kernel version >= 2.1.0" +#endif + +#if defined(__powerpc__) +#define inw_l2b inw +#define inl_l2b inl +#define outw_b2l outw +#define outl_b2l outl +#elif defined(__sparc__) +#define readw_l2b readw +#define readl_l2b readl +#define writew_b2l writew +#define writel_b2l writel +#else +#error "Support for BIG ENDIAN is only available for PowerPC and SPARC" +#endif + +#else /* little endian */ + +#if defined(__i386__) /* i386 implements full FLAT memory/MMIO model */ +#define inw_raw inw +#define inl_raw inl +#define outw_raw outw +#define outl_raw outl +#define readb_raw(a) (*(volatile unsigned char *) (a)) +#define readw_raw(a) (*(volatile unsigned short *) (a)) +#define readl_raw(a) (*(volatile unsigned int *) (a)) +#define writeb_raw(b,a) ((*(volatile unsigned char *) (a)) = (b)) +#define writew_raw(b,a) ((*(volatile unsigned short *) (a)) = (b)) +#define writel_raw(b,a) ((*(volatile unsigned int *) (a)) = (b)) + +#else /* Other little-endian (for now alpha) */ +#define inw_raw inw +#define inl_raw inl +#define outw_raw outw +#define outl_raw outl +#define readw_raw readw +#define readl_raw readl +#define writew_raw writew +#define writel_raw writel + +#endif +#endif + +#ifdef SCSI_NCR_BIG_ENDIAN +#error "The NCR in BIG ENDIAN addressing mode is not (yet) supported" +#endif + +/* +** NCR53C8XX Device Ids +*/ + +#ifndef PCI_DEVICE_ID_NCR_53C810 +#define PCI_DEVICE_ID_NCR_53C810 1 +#endif + +#ifndef PCI_DEVICE_ID_NCR_53C810AP +#define PCI_DEVICE_ID_NCR_53C810AP 5 +#endif + +#ifndef PCI_DEVICE_ID_NCR_53C815 +#define PCI_DEVICE_ID_NCR_53C815 4 +#endif + +#ifndef PCI_DEVICE_ID_NCR_53C820 +#define PCI_DEVICE_ID_NCR_53C820 2 +#endif + +#ifndef PCI_DEVICE_ID_NCR_53C825 +#define PCI_DEVICE_ID_NCR_53C825 3 +#endif + +#ifndef PCI_DEVICE_ID_NCR_53C860 +#define PCI_DEVICE_ID_NCR_53C860 6 +#endif + +#ifndef PCI_DEVICE_ID_NCR_53C875 +#define PCI_DEVICE_ID_NCR_53C875 0xf +#endif + +#ifndef PCI_DEVICE_ID_NCR_53C875J +#define PCI_DEVICE_ID_NCR_53C875J 0x8f +#endif + +#ifndef PCI_DEVICE_ID_NCR_53C885 +#define PCI_DEVICE_ID_NCR_53C885 0xd +#endif + +#ifndef PCI_DEVICE_ID_NCR_53C895 +#define PCI_DEVICE_ID_NCR_53C895 0xc +#endif + +#ifndef PCI_DEVICE_ID_NCR_53C896 +#define PCI_DEVICE_ID_NCR_53C896 0xb +#endif + +/* +** NCR53C8XX devices features table. +*/ +typedef struct { + unsigned short device_id; + unsigned short revision_id; + char *name; + unsigned char burst_max; + unsigned char offset_max; + unsigned char nr_divisor; + unsigned int features; +#define FE_LED0 (1<<0) +#define FE_WIDE (1<<1) +#define FE_ULTRA (1<<2) +#define FE_ULTRA2 (1<<3) +#define FE_DBLR (1<<4) +#define FE_QUAD (1<<5) +#define FE_ERL (1<<6) +#define FE_CLSE (1<<7) +#define FE_WRIE (1<<8) +#define FE_ERMP (1<<9) +#define FE_BOF (1<<10) +#define FE_DFS (1<<11) +#define FE_PFEN (1<<12) +#define FE_LDSTR (1<<13) +#define FE_RAM (1<<14) +#define FE_CLK80 (1<<15) +#define FE_RAM8K (1<<16) +#define FE_64BIT (1<<17) +#define FE_IO256 (1<<18) +#define FE_NOPM (1<<19) +#define FE_LEDC (1<<20) +#define FE_CACHE_SET (FE_ERL|FE_CLSE|FE_WRIE|FE_ERMP) +#define FE_SCSI_SET (FE_WIDE|FE_ULTRA|FE_ULTRA2|FE_DBLR|FE_QUAD|F_CLK80) +#define FE_SPECIAL_SET (FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM) +} ncr_chip; + +/* +** DEL 397 - 53C875 Rev 3 - Part Number 609-0392410 - ITEM 3. +** Memory Read transaction terminated by a retry followed by +** Memory Read Line command. +*/ +#define FE_CACHE0_SET (FE_CACHE_SET & ~FE_ERL) + +/* +** DEL 397 - 53C875 Rev 3 - Part Number 609-0392410 - ITEM 5. +** On paper, this errata is harmless. But it is a good reason for +** using a shorter programmed burst length (64 DWORDS instead of 128). +*/ + +#define SCSI_NCR_CHIP_TABLE \ +{ \ + {PCI_DEVICE_ID_NCR_53C810, 0x0f, "810", 4, 8, 4, \ + FE_ERL} \ + , \ + {PCI_DEVICE_ID_NCR_53C810, 0xff, "810a", 4, 8, 4, \ + FE_CACHE_SET|FE_LDSTR|FE_PFEN|FE_BOF} \ + , \ + {PCI_DEVICE_ID_NCR_53C815, 0xff, "815", 4, 8, 4, \ + FE_ERL|FE_BOF} \ + , \ + {PCI_DEVICE_ID_NCR_53C820, 0xff, "820", 4, 8, 4, \ + FE_WIDE|FE_ERL} \ + , \ + {PCI_DEVICE_ID_NCR_53C825, 0x0f, "825", 4, 8, 4, \ + FE_WIDE|FE_ERL|FE_BOF} \ + , \ + {PCI_DEVICE_ID_NCR_53C825, 0xff, "825a", 6, 8, 4, \ + FE_WIDE|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM} \ + , \ + {PCI_DEVICE_ID_NCR_53C860, 0xff, "860", 4, 8, 5, \ + FE_ULTRA|FE_CLK80|FE_CACHE_SET|FE_BOF|FE_LDSTR|FE_PFEN} \ + , \ + {PCI_DEVICE_ID_NCR_53C875, 0x01, "875", 6, 16, 5, \ + FE_WIDE|FE_ULTRA|FE_CLK80|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}\ + , \ + {PCI_DEVICE_ID_NCR_53C875, 0x0f, "875", 6, 16, 5, \ + FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}\ + , \ + {PCI_DEVICE_ID_NCR_53C875, 0xff, "876", 6, 16, 5, \ + FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}\ + , \ + {PCI_DEVICE_ID_NCR_53C875J,0xff, "875J", 6, 16, 5, \ + FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}\ + , \ + {PCI_DEVICE_ID_NCR_53C885, 0xff, "885", 6, 16, 5, \ + FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}\ + , \ + {PCI_DEVICE_ID_NCR_53C895, 0xff, "895", 6, 31, 7, \ + FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}\ + , \ + {PCI_DEVICE_ID_NCR_53C896, 0xff, "896", 7, 31, 7, \ + FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM|\ + FE_RAM8K|FE_64BIT|FE_IO256|FE_NOPM|FE_LEDC}\ +} + +/* + * List of supported NCR chip ids + */ +#define SCSI_NCR_CHIP_IDS \ +{ \ + PCI_DEVICE_ID_NCR_53C810, \ + PCI_DEVICE_ID_NCR_53C815, \ + PCI_DEVICE_ID_NCR_53C820, \ + PCI_DEVICE_ID_NCR_53C825, \ + PCI_DEVICE_ID_NCR_53C860, \ + PCI_DEVICE_ID_NCR_53C875, \ + PCI_DEVICE_ID_NCR_53C875J, \ + PCI_DEVICE_ID_NCR_53C885, \ + PCI_DEVICE_ID_NCR_53C895, \ + PCI_DEVICE_ID_NCR_53C896 \ +} + +/* +** Initial setup. +** Can be overriden at startup by a command line. +*/ +#define SCSI_NCR_DRIVER_SETUP \ +{ \ + SCSI_NCR_SETUP_MASTER_PARITY, \ + SCSI_NCR_SETUP_SCSI_PARITY, \ + SCSI_NCR_SETUP_DISCONNECTION, \ + SCSI_NCR_SETUP_SPECIAL_FEATURES, \ + SCSI_NCR_SETUP_ULTRA_SCSI, \ + SCSI_NCR_SETUP_FORCE_SYNC_NEGO, \ + 0, \ + 0, \ + 1, \ + 1, \ + SCSI_NCR_SETUP_DEFAULT_TAGS, \ + SCSI_NCR_SETUP_DEFAULT_SYNC, \ + 0x00, \ + 7, \ + SCSI_NCR_SETUP_LED_PIN, \ + 1, \ + SCSI_NCR_SETUP_SETTLE_TIME, \ + SCSI_NCR_SETUP_DIFF_SUPPORT, \ + 0, \ + 1, \ + 0, \ + 0 \ +} + +/* +** Boot fail safe setup. +** Override initial setup from boot command line: +** ncr53c8xx=safe:y +*/ +#define SCSI_NCR_DRIVER_SAFE_SETUP \ +{ \ + 0, \ + 1, \ + 0, \ + 0, \ + 0, \ + 0, \ + 0, \ + 0, \ + 1, \ + 2, \ + 0, \ + 255, \ + 0x00, \ + 255, \ + 0, \ + 0, \ + 10, \ + 1, \ + 1, \ + 1, \ + 0, \ + 0 \ +} + +/**************** ORIGINAL CONTENT of ncrreg.h from FreeBSD ******************/ + +/*----------------------------------------------------------------- +** +** The ncr 53c810 register structure. +** +**----------------------------------------------------------------- +*/ + +struct ncr_reg { +/*00*/ u_char nc_scntl0; /* full arb., ena parity, par->ATN */ + +/*01*/ u_char nc_scntl1; /* no reset */ + #define ISCON 0x10 /* connected to scsi */ + #define CRST 0x08 /* force reset */ + +/*02*/ u_char nc_scntl2; /* no disconnect expected */ + #define SDU 0x80 /* cmd: disconnect will raise error */ + #define CHM 0x40 /* sta: chained mode */ + #define WSS 0x08 /* sta: wide scsi send [W]*/ + #define WSR 0x01 /* sta: wide scsi received [W]*/ + +/*03*/ u_char nc_scntl3; /* cnf system clock dependent */ + #define EWS 0x08 /* cmd: enable wide scsi [W]*/ + #define ULTRA 0x80 /* cmd: ULTRA enable */ + +/*04*/ u_char nc_scid; /* cnf host adapter scsi address */ + #define RRE 0x40 /* r/w:e enable response to resel. */ + #define SRE 0x20 /* r/w:e enable response to select */ + +/*05*/ u_char nc_sxfer; /* ### Sync speed and count */ + +/*06*/ u_char nc_sdid; /* ### Destination-ID */ + +/*07*/ u_char nc_gpreg; /* ??? IO-Pins */ + +/*08*/ u_char nc_sfbr; /* ### First byte in phase */ + +/*09*/ u_char nc_socl; + #define CREQ 0x80 /* r/w: SCSI-REQ */ + #define CACK 0x40 /* r/w: SCSI-ACK */ + #define CBSY 0x20 /* r/w: SCSI-BSY */ + #define CSEL 0x10 /* r/w: SCSI-SEL */ + #define CATN 0x08 /* r/w: SCSI-ATN */ + #define CMSG 0x04 /* r/w: SCSI-MSG */ + #define CC_D 0x02 /* r/w: SCSI-C_D */ + #define CI_O 0x01 /* r/w: SCSI-I_O */ + +/*0a*/ u_char nc_ssid; + +/*0b*/ u_char nc_sbcl; + +/*0c*/ u_char nc_dstat; + #define DFE 0x80 /* sta: dma fifo empty */ + #define MDPE 0x40 /* int: master data parity error */ + #define BF 0x20 /* int: script: bus fault */ + #define ABRT 0x10 /* int: script: command aborted */ + #define SSI 0x08 /* int: script: single step */ + #define SIR 0x04 /* int: script: interrupt instruct. */ + #define IID 0x01 /* int: script: illegal instruct. */ + +/*0d*/ u_char nc_sstat0; + #define ILF 0x80 /* sta: data in SIDL register lsb */ + #define ORF 0x40 /* sta: data in SODR register lsb */ + #define OLF 0x20 /* sta: data in SODL register lsb */ + #define AIP 0x10 /* sta: arbitration in progress */ + #define LOA 0x08 /* sta: arbitration lost */ + #define WOA 0x04 /* sta: arbitration won */ + #define IRST 0x02 /* sta: scsi reset signal */ + #define SDP 0x01 /* sta: scsi parity signal */ + +/*0e*/ u_char nc_sstat1; + #define FF3210 0xf0 /* sta: bytes in the scsi fifo */ + +/*0f*/ u_char nc_sstat2; + #define ILF1 0x80 /* sta: data in SIDL register msb[W]*/ + #define ORF1 0x40 /* sta: data in SODR register msb[W]*/ + #define OLF1 0x20 /* sta: data in SODL register msb[W]*/ + #define DM 0x04 /* sta: DIFFSENS mismatch (895/6 only) */ + #define LDSC 0x02 /* sta: disconnect & reconnect */ + +/*10*/ u_int32 nc_dsa; /* --> Base page */ + +/*14*/ u_char nc_istat; /* --> Main Command and status */ + #define CABRT 0x80 /* cmd: abort current operation */ + #define SRST 0x40 /* mod: reset chip */ + #define SIGP 0x20 /* r/w: message from host to ncr */ + #define SEM 0x10 /* r/w: message between host + ncr */ + #define CON 0x08 /* sta: connected to scsi */ + #define INTF 0x04 /* sta: int on the fly (reset by wr)*/ + #define SIP 0x02 /* sta: scsi-interrupt */ + #define DIP 0x01 /* sta: host/script interrupt */ + +/*15*/ u_char nc_istat1; /* 896 only */ +/*16*/ u_char nc_mbox0; /* 896 only */ +/*17*/ u_char nc_mbox1; /* 896 only */ + +/*18*/ u_char nc_ctest0; +/*19*/ u_char nc_ctest1; + +/*1a*/ u_char nc_ctest2; + #define CSIGP 0x40 + +/*1b*/ u_char nc_ctest3; + #define FLF 0x08 /* cmd: flush dma fifo */ + #define CLF 0x04 /* cmd: clear dma fifo */ + #define FM 0x02 /* mod: fetch pin mode */ + #define WRIE 0x01 /* mod: write and invalidate enable */ + +/*1c*/ u_int32 nc_temp; /* ### Temporary stack */ + +/*20*/ u_char nc_dfifo; +/*21*/ u_char nc_ctest4; + #define BDIS 0x80 /* mod: burst disable */ + #define MPEE 0x08 /* mod: master parity error enable */ + +/*22*/ u_char nc_ctest5; + #define DFS 0x20 /* mod: dma fifo size */ +/*23*/ u_char nc_ctest6; + +/*24*/ u_int32 nc_dbc; /* ### Byte count and command */ +/*28*/ u_int32 nc_dnad; /* ### Next command register */ +/*2c*/ u_int32 nc_dsp; /* --> Script Pointer */ +/*30*/ u_int32 nc_dsps; /* --> Script pointer save/opcode#2 */ + +/*34*/ u_char nc_scratcha; /* Temporary register a */ +/*35*/ u_char nc_scratcha1; +/*36*/ u_char nc_scratcha2; +/*37*/ u_char nc_scratcha3; + +/*38*/ u_char nc_dmode; + #define BL_2 0x80 /* mod: burst length shift value +2 */ + #define BL_1 0x40 /* mod: burst length shift value +1 */ + #define ERL 0x08 /* mod: enable read line */ + #define ERMP 0x04 /* mod: enable read multiple */ + #define BOF 0x02 /* mod: burst op code fetch */ + +/*39*/ u_char nc_dien; +/*3a*/ u_char nc_dwt; + +/*3b*/ u_char nc_dcntl; /* --> Script execution control */ + #define CLSE 0x80 /* mod: cache line size enable */ + #define PFF 0x40 /* cmd: pre-fetch flush */ + #define PFEN 0x20 /* mod: pre-fetch enable */ + #define SSM 0x10 /* mod: single step mode */ + #define IRQM 0x08 /* mod: irq mode (1 = totem pole !) */ + #define STD 0x04 /* cmd: start dma mode */ + #define IRQD 0x02 /* mod: irq disable */ + #define NOCOM 0x01 /* cmd: protect sfbr while reselect */ + +/*3c*/ u_int32 nc_adder; + +/*40*/ u_short nc_sien; /* -->: interrupt enable */ +/*42*/ u_short nc_sist; /* <--: interrupt status */ + #define SBMC 0x1000/* sta: SCSI Bus Mode Change (895/6 only) */ + #define STO 0x0400/* sta: timeout (select) */ + #define GEN 0x0200/* sta: timeout (general) */ + #define HTH 0x0100/* sta: timeout (handshake) */ + #define MA 0x80 /* sta: phase mismatch */ + #define CMP 0x40 /* sta: arbitration complete */ + #define SEL 0x20 /* sta: selected by another device */ + #define RSL 0x10 /* sta: reselected by another device*/ + #define SGE 0x08 /* sta: gross error (over/underflow)*/ + #define UDC 0x04 /* sta: unexpected disconnect */ + #define RST 0x02 /* sta: scsi bus reset detected */ + #define PAR 0x01 /* sta: scsi parity error */ + +/*44*/ u_char nc_slpar; +/*45*/ u_char nc_swide; +/*46*/ u_char nc_macntl; +/*47*/ u_char nc_gpcntl; +/*48*/ u_char nc_stime0; /* cmd: timeout for select&handshake*/ +/*49*/ u_char nc_stime1; /* cmd: timeout user defined */ +/*4a*/ u_short nc_respid; /* sta: Reselect-IDs */ + +/*4c*/ u_char nc_stest0; + +/*4d*/ u_char nc_stest1; + #define DBLEN 0x08 /* clock doubler running */ + #define DBLSEL 0x04 /* clock doubler selected */ + + +/*4e*/ u_char nc_stest2; + #define ROF 0x40 /* reset scsi offset (after gross error!) */ + #define EXT 0x02 /* extended filtering */ + +/*4f*/ u_char nc_stest3; + #define TE 0x80 /* c: tolerAnt enable */ + #define HSC 0x20 /* c: Halt SCSI Clock */ + #define CSF 0x02 /* c: clear scsi fifo */ + +/*50*/ u_short nc_sidl; /* Lowlevel: latched from scsi data */ +/*52*/ u_char nc_stest4; + #define SMODE 0xc0 /* SCSI bus mode (895/6 only) */ + #define SMODE_HVD 0x40 /* High Voltage Differential */ + #define SMODE_SE 0x80 /* Single Ended */ + #define SMODE_LVD 0xc0 /* Low Voltage Differential */ + #define LCKFRQ 0x20 /* Frequency Lock (895/6 only) */ + +/*53*/ u_char nc_53_; +/*54*/ u_short nc_sodl; /* Lowlevel: data out to scsi data */ +/*56*/ u_char nc_ccntl0; /* Chip Control 0 (896) */ + #define ENPMJ 0x80 /* Enable Phase Mismatch Jump */ + #define PMJCTL 0x40 /* Phase Mismatch Jump Control */ + #define ENNDJ 0x20 /* Enable Non Data PM Jump */ + #define DISFC 0x10 /* Disable Auto FIFO Clear */ + #define DILS 0x02 /* Disable Internal Load/Store */ + #define DPR 0x01 /* Disable Pipe Req */ + +/*57*/ u_char nc_ccntl1; /* Chip Control 1 (896) */ + #define ZMOD 0x80 /* High Impedance Mode */ + #define DDAC 0x08 /* Disable Dual Address Cycle */ + #define XTIMOD 0x04 /* 64-bit Table Ind. Indexing Mode */ + #define EXTIBMV 0x02 /* Enable 64-bit Table Ind. BMOV */ + #define EXDBMV 0x01 /* Enable 64-bit Direct BMOV */ + +/*58*/ u_short nc_sbdl; /* Lowlevel: data from scsi data */ +/*5a*/ u_short nc_5a_; + +/*5c*/ u_char nc_scr0; /* Working register B */ +/*5d*/ u_char nc_scr1; /* */ +/*5e*/ u_char nc_scr2; /* */ +/*5f*/ u_char nc_scr3; /* */ + +/*60*/ u_char nc_scrx[64]; /* Working register C-R */ +/*a0*/ u_int32 nc_mmrs; /* Memory Move Read Selector */ +/*a4*/ u_int32 nc_mmws; /* Memory Move Write Selector */ +/*a8*/ u_int32 nc_sfs; /* Script Fetch Selector */ +/*ac*/ u_int32 nc_drs; /* DSA Relative Selector */ +/*b0*/ u_int32 nc_sbms; /* Static Block Move Selector */ +/*b4*/ u_int32 nc_dbms; /* Dynamic Block Move Selector */ +/*b8*/ u_int32 nc_dnad64; /* DMA Next Address 64 */ +/*bc*/ u_int32 nc_bc_; + +/*c0*/ u_int32 nc_pmjad1; /* Phase Mismatch Jump Address 1 */ +/*c4*/ u_int32 nc_pmjad2; /* Phase Mismatch Jump Address 2 */ +/*c8*/ u_int32 nc_rbc; /* Remaining Byte Count */ +/*cc*/ u_int32 nc_ua; /* Updated Address */ +/*d0*/ u_int32 nc_esa; /* Entry Storage Address */ +/*d4*/ u_char nc_ia; /* Instruction Address */ +/*d5*/ u_char nc_ia1; +/*d6*/ u_char nc_ia2; +/*d7*/ u_char nc_ia3; +/*d8*/ u_int32 nc_sbc; /* SCSI Byte Count (3 bytes only) */ +/*dc*/ u_int32 nc_csbc; /* Cumulative SCSI Byte Count */ +}; + +/*----------------------------------------------------------- +** +** Utility macros for the script. +** +**----------------------------------------------------------- +*/ + +#define REGJ(p,r) (offsetof(struct ncr_reg, p ## r)) +#define REG(r) REGJ (nc_, r) + +#ifndef TARGET_MODE +#define TARGET_MODE 0 +#endif + +typedef u_int32 ncrcmd; + +/*----------------------------------------------------------- +** +** SCSI phases +** +**----------------------------------------------------------- +*/ + +#define SCR_DATA_OUT 0x00000000 +#define SCR_DATA_IN 0x01000000 +#define SCR_COMMAND 0x02000000 +#define SCR_STATUS 0x03000000 +#define SCR_ILG_OUT 0x04000000 +#define SCR_ILG_IN 0x05000000 +#define SCR_MSG_OUT 0x06000000 +#define SCR_MSG_IN 0x07000000 + +/*----------------------------------------------------------- +** +** Data transfer via SCSI. +** +**----------------------------------------------------------- +** +** MOVE_ABS (LEN) +** <> +** +** MOVE_IND (LEN) +** <> +** +** MOVE_TBL +** <> +** +**----------------------------------------------------------- +*/ + +#define SCR_MOVE_ABS(l) ((0x08000000 ^ (TARGET_MODE << 1ul)) | (l)) +#define SCR_MOVE_IND(l) ((0x28000000 ^ (TARGET_MODE << 1ul)) | (l)) +#define SCR_MOVE_TBL (0x18000000 ^ (TARGET_MODE << 1ul)) + +struct scr_tblmove { + u_int32 size; + u_int32 addr; +}; + +/*----------------------------------------------------------- +** +** Selection +** +**----------------------------------------------------------- +** +** SEL_ABS | SCR_ID (0..7) [ | REL_JMP] +** <> +** +** SEL_TBL | << dnad_offset>> [ | REL_JMP] +** <> +** +**----------------------------------------------------------- +*/ + +#define SCR_SEL_ABS 0x40000000 +#define SCR_SEL_ABS_ATN 0x41000000 +#define SCR_SEL_TBL 0x42000000 +#define SCR_SEL_TBL_ATN 0x43000000 + +struct scr_tblsel { + u_char sel_0; + u_char sel_sxfer; + u_char sel_id; + u_char sel_scntl3; +}; + +#define SCR_JMP_REL 0x04000000 +#define SCR_ID(id) (((u_int32)(id)) << 16) + +/*----------------------------------------------------------- +** +** Waiting for Disconnect or Reselect +** +**----------------------------------------------------------- +** +** WAIT_DISC +** dummy: <> +** +** WAIT_RESEL +** <> +** +**----------------------------------------------------------- +*/ + +#define SCR_WAIT_DISC 0x48000000 +#define SCR_WAIT_RESEL 0x50000000 + +/*----------------------------------------------------------- +** +** Bit Set / Reset +** +**----------------------------------------------------------- +** +** SET (flags {|.. }) +** +** CLR (flags {|.. }) +** +**----------------------------------------------------------- +*/ + +#define SCR_SET(f) (0x58000000 | (f)) +#define SCR_CLR(f) (0x60000000 | (f)) + +#define SCR_CARRY 0x00000400 +#define SCR_TRG 0x00000200 +#define SCR_ACK 0x00000040 +#define SCR_ATN 0x00000008 + + + + +/*----------------------------------------------------------- +** +** Memory to memory move +** +**----------------------------------------------------------- +** +** COPY (bytecount) +** << source_address >> +** << destination_address >> +** +** SCR_COPY sets the NO FLUSH option by default. +** SCR_COPY_F does not set this option. +** +** For chips which do not support this option, +** ncr_copy_and_bind() will remove this bit. +**----------------------------------------------------------- +*/ + +#define SCR_NO_FLUSH 0x01000000 + +#define SCR_COPY(n) (0xc0000000 | SCR_NO_FLUSH | (n)) +#define SCR_COPY_F(n) (0xc0000000 | (n)) + +/*----------------------------------------------------------- +** +** Register move and binary operations +** +**----------------------------------------------------------- +** +** SFBR_REG (reg, op, data) reg = SFBR op data +** << 0 >> +** +** REG_SFBR (reg, op, data) SFBR = reg op data +** << 0 >> +** +** REG_REG (reg, op, data) reg = reg op data +** << 0 >> +** +**----------------------------------------------------------- +** On 810A, 860, 825A, 875, 895 and 896 chips the content +** of SFBR register can be used as data (SCR_SFBR_DATA). +** The 896 has additionnal IO registers starting at +** offset 0x80. Bit 7 of register offset is stored in +** bit 7 of the SCRIPTS instruction first DWORD. +**----------------------------------------------------------- +*/ + +#define SCR_REG_OFS(ofs) ((((ofs) & 0x7f) << 16ul) + ((ofs) & 0x80)) + +#define SCR_SFBR_REG(reg,op,data) \ + (0x68000000 | (SCR_REG_OFS(REG(reg))) | (op) | (((data)&0xff)<<8ul)) + +#define SCR_REG_SFBR(reg,op,data) \ + (0x70000000 | (SCR_REG_OFS(REG(reg))) | (op) | (((data)&0xff)<<8ul)) + +#define SCR_REG_REG(reg,op,data) \ + (0x78000000 | (SCR_REG_OFS(REG(reg))) | (op) | (((data)&0xff)<<8ul)) + + +#define SCR_LOAD 0x00000000 +#define SCR_SHL 0x01000000 +#define SCR_OR 0x02000000 +#define SCR_XOR 0x03000000 +#define SCR_AND 0x04000000 +#define SCR_SHR 0x05000000 +#define SCR_ADD 0x06000000 +#define SCR_ADDC 0x07000000 + +#define SCR_SFBR_DATA (0x00800000>>8ul) /* Use SFBR as data */ + +/*----------------------------------------------------------- +** +** FROM_REG (reg) SFBR = reg +** << 0 >> +** +** TO_REG (reg) reg = SFBR +** << 0 >> +** +** LOAD_REG (reg, data) reg = +** << 0 >> +** +** LOAD_SFBR(data) SFBR = +** << 0 >> +** +**----------------------------------------------------------- +*/ + +#define SCR_FROM_REG(reg) \ + SCR_REG_SFBR(reg,SCR_OR,0) + +#define SCR_TO_REG(reg) \ + SCR_SFBR_REG(reg,SCR_OR,0) + +#define SCR_LOAD_REG(reg,data) \ + SCR_REG_REG(reg,SCR_LOAD,data) + +#define SCR_LOAD_SFBR(data) \ + (SCR_REG_SFBR (gpreg, SCR_LOAD, data)) + +/*----------------------------------------------------------- +** +** LOAD from memory to register. +** STORE from register to memory. +** +** Only supported by 810A, 860, 825A, 875, 895 and 896. +** +**----------------------------------------------------------- +** +** LOAD_ABS (LEN) +** <> +** +** LOAD_REL (LEN) (DSA relative) +** <> +** +**----------------------------------------------------------- +*/ + +#define SCR_REG_OFS2(ofs) (((ofs) & 0xff) << 16ul) +#define SCR_NO_FLUSH2 0x02000000 +#define SCR_DSA_REL2 0x10000000 + +#define SCR_LOAD_R(reg, how, n) \ + (0xe1000000 | how | (SCR_REG_OFS2(REG(reg))) | (n)) + +#define SCR_STORE_R(reg, how, n) \ + (0xe0000000 | how | (SCR_REG_OFS2(REG(reg))) | (n)) + +#define SCR_LOAD_ABS(reg, n) SCR_LOAD_R(reg, SCR_NO_FLUSH2, n) +#define SCR_LOAD_REL(reg, n) SCR_LOAD_R(reg, SCR_NO_FLUSH2|SCR_DSA_REL2, n) +#define SCR_LOAD_ABS_F(reg, n) SCR_LOAD_R(reg, 0, n) +#define SCR_LOAD_REL_F(reg, n) SCR_LOAD_R(reg, SCR_DSA_REL2, n) + +#define SCR_STORE_ABS(reg, n) SCR_STORE_R(reg, SCR_NO_FLUSH2, n) +#define SCR_STORE_REL(reg, n) SCR_STORE_R(reg, SCR_NO_FLUSH2|SCR_DSA_REL2,n) +#define SCR_STORE_ABS_F(reg, n) SCR_STORE_R(reg, 0, n) +#define SCR_STORE_REL_F(reg, n) SCR_STORE_R(reg, SCR_DSA_REL2, n) + + +/*----------------------------------------------------------- +** +** Waiting for Disconnect or Reselect +** +**----------------------------------------------------------- +** +** JUMP [ | IFTRUE/IFFALSE ( ... ) ] +** <
> +** +** JUMPR [ | IFTRUE/IFFALSE ( ... ) ] +** <> +** +** CALL [ | IFTRUE/IFFALSE ( ... ) ] +** <
> +** +** CALLR [ | IFTRUE/IFFALSE ( ... ) ] +** <> +** +** RETURN [ | IFTRUE/IFFALSE ( ... ) ] +** <> +** +** INT [ | IFTRUE/IFFALSE ( ... ) ] +** <> +** +** INT_FLY [ | IFTRUE/IFFALSE ( ... ) ] +** <> +** +** Conditions: +** WHEN (phase) +** IF (phase) +** CARRY +** DATA (data, mask) +** +**----------------------------------------------------------- +*/ + +#define SCR_NO_OP 0x80000000 +#define SCR_JUMP 0x80080000 +#define SCR_JUMP64 0x80480000 +#define SCR_JUMPR 0x80880000 +#define SCR_CALL 0x88080000 +#define SCR_CALLR 0x88880000 +#define SCR_RETURN 0x90080000 +#define SCR_INT 0x98080000 +#define SCR_INT_FLY 0x98180000 + +#define IFFALSE(arg) (0x00080000 | (arg)) +#define IFTRUE(arg) (0x00000000 | (arg)) + +#define WHEN(phase) (0x00030000 | (phase)) +#define IF(phase) (0x00020000 | (phase)) + +#define DATA(D) (0x00040000 | ((D) & 0xff)) +#define MASK(D,M) (0x00040000 | (((M ^ 0xff) & 0xff) << 8ul)|((D) & 0xff)) + +#define CARRYSET (0x00200000) + +/*----------------------------------------------------------- +** +** SCSI constants. +** +**----------------------------------------------------------- +*/ + +/* +** Messages +*/ + +#define M_COMPLETE (0x00) +#define M_EXTENDED (0x01) +#define M_SAVE_DP (0x02) +#define M_RESTORE_DP (0x03) +#define M_DISCONNECT (0x04) +#define M_ID_ERROR (0x05) +#define M_ABORT (0x06) +#define M_REJECT (0x07) +#define M_NOOP (0x08) +#define M_PARITY (0x09) +#define M_LCOMPLETE (0x0a) +#define M_FCOMPLETE (0x0b) +#define M_RESET (0x0c) +#define M_ABORT_TAG (0x0d) +#define M_CLEAR_QUEUE (0x0e) +#define M_INIT_REC (0x0f) +#define M_REL_REC (0x10) +#define M_TERMINATE (0x11) +#define M_SIMPLE_TAG (0x20) +#define M_HEAD_TAG (0x21) +#define M_ORDERED_TAG (0x22) +#define M_IGN_RESIDUE (0x23) +#define M_IDENTIFY (0x80) + +#define M_X_MODIFY_DP (0x00) +#define M_X_SYNC_REQ (0x01) +#define M_X_WIDE_REQ (0x03) + +/* +** Status +*/ + +#define S_GOOD (0x00) +#define S_CHECK_COND (0x02) +#define S_COND_MET (0x04) +#define S_BUSY (0x08) +#define S_INT (0x10) +#define S_INT_COND_MET (0x14) +#define S_CONFLICT (0x18) +#define S_TERMINATED (0x20) +#define S_QUEUE_FULL (0x28) +#define S_ILLEGAL (0xff) +#define S_SENSE (0x80) + +/* + * End of ncrreg from FreeBSD + */ + +#endif /* !defined HOSTS_C */ + +#endif /* defined SYM53C8XX_DEFS_H */ diff -ur --new-file old/linux/drivers/scsi/wd33c93.c new/linux/drivers/scsi/wd33c93.c --- old/linux/drivers/scsi/wd33c93.c Mon May 11 20:31:41 1998 +++ new/linux/drivers/scsi/wd33c93.c Tue Apr 13 01:18:26 1999 @@ -1457,6 +1457,8 @@ if (tmp == cmd) { if (prev) prev->host_scribble = cmd->host_scribble; + else + hostdata->input_Q = (Scsi_Cmnd *)cmd->host_scribble; cmd->host_scribble = NULL; cmd->result = DID_ABORT << 16; printk("scsi%d: Abort - removing command %ld from input_Q. ", diff -ur --new-file old/linux/drivers/sound/Config.in new/linux/drivers/sound/Config.in --- old/linux/drivers/sound/Config.in Fri Jan 15 07:59:47 1999 +++ new/linux/drivers/sound/Config.in Mon Mar 8 00:22:06 1999 @@ -12,7 +12,7 @@ dep_tristate 'Ensoniq AudioPCI (ES1370)' CONFIG_SOUND_ES1370 $CONFIG_SOUND if [ "$CONFIG_SOUND_ES1370" = "y" ]; then bool 'Joystick support at boot time' CONFIG_SOUND_ES1370_JOYPORT_BOOT -fi +fi dep_tristate 'Creative Ensoniq AudioPCI 97 (ES1371)' CONFIG_SOUND_ES1371 $CONFIG_SOUND if [ "$CONFIG_SOUND_ES1371" = "y" ]; then bool 'Joystick support at boot time' CONFIG_SOUND_ES1371_JOYPORT_BOOT @@ -75,6 +75,10 @@ dep_tristate 'OSS sound modules' CONFIG_SOUND_OSS $CONFIG_SOUND if [ "$CONFIG_SOUND_OSS" = "y" -o "$CONFIG_SOUND_OSS" = "m" ]; then + if [ "$CONFIG_SOUND_OSS" = "y" ]; then + bool 'Persistent DMA buffers' CONFIG_SOUND_DMAP + fi + dep_tristate 'ProAudioSpectrum 16 support' CONFIG_SOUND_PAS $CONFIG_SOUND_OSS if [ "$CONFIG_SOUND_PAS" = "y" ]; then int 'PAS16 IRQ 3, 4, 5, 7, 9, 10, 11, 12, 14 or 15' CONFIG_PAS_IRQ 10 @@ -138,6 +142,7 @@ dep_tristate 'Microsoft Sound System support' CONFIG_SOUND_MSS $CONFIG_SOUND_OSS if [ "$CONFIG_SOUND_MSS" = "y" ]; then + bool 'Enable support for the SoundPro mixer' CONFIG_SOUND_SPRO hex 'MSS/WSS I/O base 530, 604, E80 or F40' CONFIG_MSS_BASE 530 int 'MSS/WSS IRQ 7, 9, 10 or 11' CONFIG_MSS_IRQ 11 int 'MSS/WSS DMA 0, 1 or 3' CONFIG_MSS_DMA 3 diff -ur --new-file old/linux/drivers/sound/ad1816.c new/linux/drivers/sound/ad1816.c --- old/linux/drivers/sound/ad1816.c Mon Jan 25 07:04:02 1999 +++ new/linux/drivers/sound/ad1816.c Mon May 10 22:01:21 1999 @@ -32,10 +32,10 @@ ------------------------------------------------------------------------------- -version: 1.2 -cvs: $Header: /home/tek/tmp/CVSROOT/sound21/ad1816.c,v 1.28 1999/01/16 19:01:36 tek Exp $ +version: 1.3 +cvs: $Header: /home/tek/CVSROOT/sound22/ad1816.c,v 1.3 1999/04/18 16:41:41 tek Exp $ status: experimental -date: 1999/01/16 +date: 1999/4/18 Changes: Oleg Drokin: Some cleanup of load/unload functions. 1998/11/24 @@ -44,6 +44,13 @@ some argument checks added 1998/11/30 Thorsten Knabe: Buggy isa bridge workaround added 1999/01/16 + + David Moews/Thorsten Knabe: Introduced options + parameter. Added slightly modified patch from + David Moews to disable dsp audio sources by setting + bit 0 of options parameter. This seems to be + required by some Aztech/Newcom SC-16 cards. 1999/04/18 + */ #include @@ -100,6 +107,8 @@ static int ad1816_clockfreq=33000; +static int options=0; + /* for backward mapping of irq to sound device */ static volatile char irq2dev[17] = {-1, -1, -1, -1, -1, -1, -1, -1, @@ -1091,12 +1100,14 @@ int tmp; printk("ad1816: AD1816 sounddriver Copyright (C) 1998 by Thorsten Knabe\n"); - printk("ad1816: $Header: /home/tek/tmp/CVSROOT/sound21/ad1816.c,v 1.28 1999/01/16 19:01:36 tek Exp $\n"); - printk("ad1816: io=0x%x, irq=%d, dma=%d, dma2=%d, isadmabug=%d\n", + printk("ad1816: $Header: /home/tek/CVSROOT/sound22/ad1816.c,v 1.3 1999/04/18 16:41:41 tek Exp $\n"); + printk("ad1816: io=0x%x, irq=%d, dma=%d, dma2=%d, clockfreq=%d, options=%d isadmabug=%d\n", hw_config->io_base, hw_config->irq, hw_config->dma, hw_config->dma2, + ad1816_clockfreq, + options, isa_dma_bridge_buggy); if (check_region (io_base, 16)) { @@ -1264,7 +1275,11 @@ nr_ad1816_devs++; ad_write(devc,32,0x80f0); /* sound system mode */ - ad_write(devc,33,0x03f8); /* enable all audiosources for dsp */ + if (options&1) { + ad_write(devc,33,0); /* disable all audiosources for dsp */ + } else { + ad_write(devc,33,0x03f8); /* enable all audiosources for dsp */ + } ad_write(devc,4,0x8080); /* default values for volumes (muted)*/ ad_write(devc,5,0x8080); ad_write(devc,6,0x8080); @@ -1274,7 +1289,7 @@ ad_write(devc,17,0x8888); ad_write(devc,18,0x8888); ad_write(devc,19,0xc888); /* +20db mic active */ - ad_write(devc,14,0x0000); /* Master volume unmuted full power */ + ad_write(devc,14,0x0000); /* Master volume unmuted */ ad_write(devc,39,0x009f); /* 3D effect on 0% phone out muted */ ad_write(devc,44,0x0080); /* everything on power, 3d enabled for d/a */ outb(0x10,devc->base+8); /* set dma mode */ @@ -1382,6 +1397,7 @@ MODULE_PARM(dma,"i"); MODULE_PARM(dma2,"i"); MODULE_PARM(ad1816_clockfreq,"i"); +MODULE_PARM(options,"i"); struct address_info cfg; diff -ur --new-file old/linux/drivers/sound/ad1848.c new/linux/drivers/sound/ad1848.c --- old/linux/drivers/sound/ad1848.c Tue Jan 19 23:47:48 1999 +++ new/linux/drivers/sound/ad1848.c Tue Apr 13 01:18:27 1999 @@ -100,6 +100,11 @@ static int nr_ad1848_devs = 0; int deskpro_xl = 0; +#ifdef CONFIG_SOUND_SPRO +int soundpro = 1; +#else +int soundpro = 0; +#endif static volatile char irq2dev[17] = { -1, -1, -1, -1, -1, -1, -1, -1, @@ -132,6 +137,21 @@ #define io_Status(d) ((d)->base+2) #define io_Polled_IO(d) ((d)->base+3) +static struct { + unsigned char flags; +#define CAP_F_TIMER 0x01 +} capabilities [9 /*devc->model */ ] = { + {0} + ,{0} /* MD_1848 */ + ,{CAP_F_TIMER} /* MD_4231 */ + ,{CAP_F_TIMER} /* MD_4231A */ + ,{CAP_F_TIMER} /* MD_1845 */ + ,{CAP_F_TIMER} /* MD_4232 */ + ,{0} /* MD_C930 */ + ,{CAP_F_TIMER} /* MD_IWAVE */ + ,{0} /* MD_4235 */ +}; + static int ad1848_open(int dev, int mode); static void ad1848_close(int dev); static void ad1848_output_block(int dev, unsigned long buf, int count, int intrflag); @@ -312,22 +332,21 @@ if (mask & (1 << i)) n++; - if (n == 0) - mask = SOUND_MASK_MIC; - else if (n != 1) /* Too many devices selected */ - { - mask &= ~devc->recmask; /* Filter out active settings */ + if (!soundpro) { + if (n == 0) + mask = SOUND_MASK_MIC; + else if (n != 1) { /* Too many devices selected */ + mask &= ~devc->recmask; /* Filter out active settings */ - n = 0; - for (i = 0; i < 32; i++) /* Count selected device bits */ - if (mask & (1 << i)) - n++; + n = 0; + for (i = 0; i < 32; i++) /* Count selected device bits */ + if (mask & (1 << i)) + n++; - if (n != 1) - mask = SOUND_MASK_MIC; - } - switch (mask) - { + if (n != 1) + mask = SOUND_MASK_MIC; + } + switch (mask) { case SOUND_MASK_MIC: recdev = 2; break; @@ -349,11 +368,38 @@ default: mask = SOUND_MASK_MIC; recdev = 2; - } + } - recdev <<= 6; - ad_write(devc, 0, (ad_read(devc, 0) & 0x3f) | recdev); - ad_write(devc, 1, (ad_read(devc, 1) & 0x3f) | recdev); + recdev <<= 6; + ad_write(devc, 0, (ad_read(devc, 0) & 0x3f) | recdev); + ad_write(devc, 1, (ad_read(devc, 1) & 0x3f) | recdev); + } else { /* soundpro */ + unsigned char val; + int set_rec_bit; + int j; + + for (i = 0; i < 32; i++) { /* For each bit */ + if ((devc->supported_rec_devices & (1 << i)) == 0) + continue; /* Device not supported */ + + for (j = LEFT_CHN; j <= RIGHT_CHN; j++) { + if (devc->mix_devices[i][j].nbits == 0) /* Inexistent channel */ + continue; + + /* + * This is tricky: + * set_rec_bit becomes 1 if the corresponding bit in mask is set + * then it gets flipped if the polarity is inverse + */ + set_rec_bit = ((mask & (1 << i)) != 0) ^ devc->mix_devices[i][j].recpol; + + val = ad_read(devc, devc->mix_devices[i][j].recreg); + val &= ~(1 << devc->mix_devices[i][j].recpos); + val |= (set_rec_bit << devc->mix_devices[i][j].recpos); + ad_write(devc, devc->mix_devices[i][j].recreg, val); + } + } + } /* Rename the mixer bits back if necessary */ for (i = 0; i < 32; i++) @@ -371,7 +417,8 @@ return mask; } -static void change_bits(ad1848_info * devc, unsigned char *regval, int dev, int chn, int newval) +static void change_bits(ad1848_info * devc, unsigned char *regval, + unsigned char *muteval, int dev, int chn, int newval) { unsigned char mask; int shift; @@ -379,7 +426,7 @@ int mutemask; int set_mute_bit; - set_mute_bit = (newval == 0); + set_mute_bit = (newval == 0) ^ devc->mix_devices[dev][chn].mutepol; if (devc->mix_devices[dev][chn].polarity == 1) /* Reverse */ newval = 100 - newval; @@ -399,8 +446,11 @@ } newval = (int) ((newval * mask) + 50) / 100; /* Scale it */ - *regval &= (~(mask << shift)) & (mutemask); /* Clear bits */ - *regval |= ((newval & mask) << shift) | mute; /* Set new value */ + *regval &= ~(mask << shift); /* Clear bits */ + *regval |= (newval & mask) << shift; /* Set new value */ + + *muteval &= mutemask; + *muteval |= mute; } static int ad1848_mixer_get(ad1848_info * devc, int dev) @@ -413,15 +463,36 @@ return devc->levels[dev]; } +static void ad1848_mixer_set_channel(ad1848_info *devc, int dev, int value, int channel) +{ + int regoffs, muteregoffs; + unsigned char val, muteval; + + regoffs = devc->mix_devices[dev][channel].regno; + muteregoffs = devc->mix_devices[dev][channel].mutereg; + val = ad_read(devc, regoffs); + + if (muteregoffs != regoffs) { + muteval = ad_read(devc, muteregoffs); + change_bits(devc, &val, &muteval, dev, channel, value); + } + else + change_bits(devc, &val, &val, dev, channel, value); + + ad_write(devc, regoffs, val); + devc->saved_regs[regoffs] = val; + if (muteregoffs != regoffs) { + ad_write(devc, muteregoffs, muteval); + devc->saved_regs[muteregoffs] = muteval; + } +} + static int ad1848_mixer_set(ad1848_info * devc, int dev, int value) { int left = value & 0x000000ff; int right = (value & 0x0000ff00) >> 8; int retvol; - int regoffs; - unsigned char val; - if (dev > 31) return -EINVAL; @@ -430,6 +501,9 @@ dev = devc->mixer_reroute[dev]; + if (devc->mix_devices[dev][LEFT_CHN].nbits == 0) + return -EINVAL; + if (left > 100) left = 100; if (right > 100) @@ -444,34 +518,21 @@ left = mix_cvt[left]; right = mix_cvt[right]; - if (devc->mix_devices[dev][LEFT_CHN].nbits == 0) - return -EINVAL; - devc->levels[dev] = retvol; /* * Set the left channel */ - - regoffs = devc->mix_devices[dev][LEFT_CHN].regno; - val = ad_read(devc, regoffs); - change_bits(devc, &val, dev, LEFT_CHN, left); - ad_write(devc, regoffs, val); - devc->saved_regs[regoffs] = val; + ad1848_mixer_set_channel(devc, dev, left, LEFT_CHN); /* * Set the right channel */ - if (devc->mix_devices[dev][RIGHT_CHN].nbits == 0) - return retvol; /* Was just a mono channel */ - - regoffs = devc->mix_devices[dev][RIGHT_CHN].regno; - val = ad_read(devc, regoffs); - change_bits(devc, &val, dev, RIGHT_CHN, right); - ad_write(devc, regoffs, val); - devc->saved_regs[regoffs] = val; + goto out; + ad1848_mixer_set_channel(devc, dev, right, RIGHT_CHN); + out: return retvol; } @@ -487,6 +548,8 @@ for (i = 0; i < 32; i++) devc->mixer_reroute[i] = i; + devc->supported_rec_devices = MODE1_REC_DEVICES; + switch (devc->model) { case MD_4231: @@ -509,11 +572,18 @@ devc->supported_devices = MODE3_MIXER_DEVICES; break; + case MD_1848: + if (soundpro) { + devc->supported_devices = SPRO_MIXER_DEVICES; + devc->supported_rec_devices = SPRO_REC_DEVICES; + devc->mix_devices = &(spro_mix_devices[0]); + break; + } + default: devc->supported_devices = MODE1_MIXER_DEVICES; } - devc->supported_rec_devices = MODE1_REC_DEVICES; devc->orig_devices = devc->supported_devices; devc->orig_rec_devices = devc->supported_rec_devices; @@ -528,10 +598,20 @@ ad1848_set_recmask(devc, SOUND_MASK_MIC); devc->mixer_output_port = devc->levels[31] | AUDIO_HEADPHONE | AUDIO_LINE_OUT; - if (devc->mixer_output_port & AUDIO_SPEAKER) - ad_write(devc, 26, ad_read(devc, 26) & ~0x40); /* Unmute mono out */ - else - ad_write(devc, 26, ad_read(devc, 26) | 0x40); /* Mute mono out */ + + if (!soundpro) { + if (devc->mixer_output_port & AUDIO_SPEAKER) + ad_write(devc, 26, ad_read(devc, 26) & ~0x40); /* Unmute mono out */ + else + ad_write(devc, 26, ad_read(devc, 26) | 0x40); /* Mute mono out */ + } else { + /* + * From the "wouldn't it be nice if the mixer API had (better) + * support for custom stuff" category + */ + /* Enable surround mode and SB16 mixer */ + ad_write(devc, 16, 0x60); + } } static int ad1848_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg) @@ -1357,6 +1437,8 @@ { devc->audio_flags &= ~DMA_DUPLEX; ad_write(devc, 9, ad_read(devc, 9) | 0x04); /* Single DMA mode */ + if (soundpro) + ad_write(devc, 12, ad_read(devc, 12) | 0x40); /* Mode2 = enabled */ } outb((0), io_Status(devc)); /* Clear pending interrupts */ @@ -1706,7 +1788,27 @@ DDB(printk("ad1848_detect() - step K\n")); } + } else if (tmp1 == 0x0a) { + /* + * Is it perhaps a SoundPro CMI8330? + * If so, then we should be able to change indirect registers + * greater than I15 after activating MODE2, even though reading + * back I12 does not show it. + */ + + /* + * Let's try comparing register values + */ + for (i = 0; i < 16; i++) { + if ((tmp1 = ad_read(devc, i)) != (tmp2 = ad_read(devc, i + 16))) { + DDB(printk("ad1848 detect step H(%d/%x/%x) - SoundPro chip?\n", i, tmp1, tmp2)); + soundpro = 1; + devc->chip_name = "SoundPro CMI 8330"; + break; + } + } } + DDB(printk("ad1848_detect() - step L\n")); if (ad_flags) { @@ -1807,7 +1909,7 @@ /* Don't free it either then.. */ devc->irq = 0; } - if (devc->model != MD_1848 && devc->model != MD_C930) + if (capabilities[devc->model].flags & CAP_F_TIMER) { #ifndef __SMP__ int x; @@ -1840,8 +1942,8 @@ irq2dev[-irq] = devc->dev_no = my_dev; #if defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS) - if (devc->model != MD_1848 && - devc->model != MD_C930 && devc->irq_ok) + if ((capabilities[devc->model].flags & CAP_F_TIMER) && + devc->irq_ok) ad1848_tmr_install(my_dev); #endif @@ -2302,7 +2404,8 @@ (hw_config->irq != 7) && (hw_config->irq != 9) && (hw_config->irq != 10) && - (hw_config->irq != 11)) + (hw_config->irq != 11) && + (hw_config->irq != 12)) { printk(KERN_ERR "MSS: Bad IRQ %d\n", hw_config->irq); return 0; @@ -2555,6 +2658,7 @@ MODULE_PARM(dma2, "i"); /* Second DMA channel */ MODULE_PARM(type, "i"); /* Card type */ MODULE_PARM(deskpro_xl, "i"); /* Special magic for Deskpro XL boxen */ +MODULE_PARM(soundpro, "i"); /* More special magic for SoundPro chips */ int io = -1; int irq = -1; diff -ur --new-file old/linux/drivers/sound/ad1848_mixer.h new/linux/drivers/sound/ad1848_mixer.h --- old/linux/drivers/sound/ad1848_mixer.h Fri Oct 9 20:56:59 1998 +++ new/linux/drivers/sound/ad1848_mixer.h Mon Mar 8 00:22:06 1999 @@ -24,7 +24,10 @@ * solution). */ #define MODE1_REC_DEVICES (SOUND_MASK_LINE3 | SOUND_MASK_MIC | \ - SOUND_MASK_LINE1|SOUND_MASK_IMIX) + SOUND_MASK_LINE1 | SOUND_MASK_IMIX) + +#define SPRO_REC_DEVICES (SOUND_MASK_LINE | SOUND_MASK_MIC | \ + SOUND_MASK_CD | SOUND_MASK_LINE1) #define MODE1_MIXER_DEVICES (SOUND_MASK_LINE1 | SOUND_MASK_MIC | \ SOUND_MASK_LINE2 | \ @@ -47,16 +50,27 @@ SOUND_MASK_LINE3 | \ SOUND_MASK_IGAIN | SOUND_MASK_PCM) +#define SPRO_MIXER_DEVICES (SOUND_MASK_VOLUME | SOUND_MASK_PCM | \ + SOUND_MASK_LINE | SOUND_MASK_SYNTH | \ + SOUND_MASK_CD | SOUND_MASK_MIC | \ + SOUND_MASK_SPEAKER | SOUND_MASK_LINE1 | \ + SOUND_MASK_OGAIN) + struct mixer_def { - unsigned int regno: 5; - unsigned int polarity:1; /* 0=normal, 1=reversed */ - unsigned int bitpos:3; - unsigned int nbits:3; - unsigned int mutepos:4; + unsigned int regno:5; /* register number for volume */ + unsigned int polarity:1; /* volume polarity: 0=normal, 1=reversed */ + unsigned int bitpos:3; /* position of bits in register for volume */ + unsigned int nbits:3; /* number of bits in register for volume */ + unsigned int mutereg:5; /* register number for mute bit */ + unsigned int mutepol:1; /* mute polarity: 0=normal, 1=reversed */ + unsigned int mutepos:4; /* position of mute bit in register */ + unsigned int recreg:5; /* register number for recording bit */ + unsigned int recpol:1; /* recording polarity: 0=normal, 1=reversed */ + unsigned int recpos:4; /* position of recording bit in register */ }; static char mix_cvt[101] = { - 0, 0,3,7,10,13,16,19,21,23,26,28,30,32,34,35,37,39,40,42, + 0, 0, 3, 7,10,13,16,19,21,23,26,28,30,32,34,35,37,39,40,42, 43,45,46,47,49,50,51,52,53,55,56,57,58,59,60,61,62,63,64,65, 65,66,67,68,69,70,70,71,72,73,73,74,75,75,76,77,77,78,79,79, 80,81,81,82,82,83,84,84,85,85,86,86,87,87,88,88,89,89,90,90, @@ -77,7 +91,17 @@ */ #define MIX_ENT(name, reg_l, pola_l, pos_l, len_l, reg_r, pola_r, pos_r, len_r, mute_bit) \ - {{reg_l, pola_l, pos_l, len_l, mute_bit}, {reg_r, pola_r, pos_r, len_r, mute_bit}} + [name] = {{reg_l, pola_l, pos_l, len_l, reg_l, 0, mute_bit, 0, 0, 8}, \ + {reg_r, pola_r, pos_r, len_r, reg_r, 0, mute_bit, 0, 0, 8}} + +#define MIX_ENT2(name, reg_l, pola_l, pos_l, len_l, mute_reg_l, mute_pola_l, mute_pos_l, \ + rec_reg_l, rec_pola_l, rec_pos_l, \ + reg_r, pola_r, pos_r, len_r, mute_reg_r, mute_pola_r, mute_pos_r, \ + rec_reg_r, rec_pola_r, rec_pos_r) \ + [name] = {{reg_l, pola_l, pos_l, len_l, mute_reg_l, mute_pola_l, mute_pos_l, \ + rec_reg_l, rec_pola_l, rec_pos_l}, \ + {reg_r, pola_r, pos_r, len_r, mute_reg_r, mute_pola_r, mute_pos_r, \ + rec_reg_r, rec_pola_r, rec_pos_r}} static mixer_ents ad1848_mix_devices[32] = { MIX_ENT(SOUND_MIXER_VOLUME, 27, 1, 0, 4, 29, 1, 0, 4, 8), @@ -142,6 +166,30 @@ MIX_ENT(SOUND_MIXER_LINE1, 2, 1, 1, 4, 3, 1, 1, 4, 7), MIX_ENT(SOUND_MIXER_LINE2, 4, 1, 1, 4, 5, 1, 1, 4, 7), MIX_ENT(SOUND_MIXER_LINE3, 18, 1, 1, 4, 19, 1, 1, 4, 7) +}; + +static mixer_ents spro_mix_devices[32] = { +MIX_ENT (SOUND_MIXER_VOLUME, 19, 0, 4, 4, 19, 0, 0, 4, 8), +MIX_ENT (SOUND_MIXER_BASS, 0, 0, 0, 0, 0, 0, 0, 0, 8), +MIX_ENT (SOUND_MIXER_TREBLE, 0, 0, 0, 0, 0, 0, 0, 0, 8), +MIX_ENT2(SOUND_MIXER_SYNTH, 4, 1, 1, 4, 23, 0, 3, 0, 0, 8, + 5, 1, 1, 4, 23, 0, 3, 0, 0, 8), +MIX_ENT (SOUND_MIXER_PCM, 6, 1, 1, 4, 7, 1, 1, 4, 8), +MIX_ENT (SOUND_MIXER_SPEAKER, 18, 0, 3, 2, 0, 0, 0, 0, 8), +MIX_ENT2(SOUND_MIXER_LINE, 20, 0, 4, 4, 17, 1, 4, 16, 0, 2, + 20, 0, 0, 4, 17, 1, 3, 16, 0, 1), +MIX_ENT2(SOUND_MIXER_MIC, 18, 0, 0, 3, 17, 1, 0, 16, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), +MIX_ENT2(SOUND_MIXER_CD, 21, 0, 4, 4, 17, 1, 2, 16, 0, 4, + 21, 0, 0, 4, 17, 1, 1, 16, 0, 3), +MIX_ENT (SOUND_MIXER_IMIX, 0, 0, 0, 0, 0, 0, 0, 0, 8), +MIX_ENT (SOUND_MIXER_ALTPCM, 0, 0, 0, 0, 0, 0, 0, 0, 8), +MIX_ENT (SOUND_MIXER_RECLEV, 0, 0, 0, 0, 0, 0, 0, 0, 8), +MIX_ENT (SOUND_MIXER_IGAIN, 0, 0, 0, 0, 0, 0, 0, 0, 8), +MIX_ENT (SOUND_MIXER_OGAIN, 17, 1, 6, 1, 0, 0, 0, 0, 8), +/* This is external wavetable */ +MIX_ENT2(SOUND_MIXER_LINE1, 22, 0, 4, 4, 23, 1, 1, 23, 0, 4, + 22, 0, 0, 4, 23, 1, 0, 23, 0, 5), }; static int default_mixer_levels[32] = diff -ur --new-file old/linux/drivers/sound/audio.c new/linux/drivers/sound/audio.c --- old/linux/drivers/sound/audio.c Wed Dec 16 21:52:01 1998 +++ new/linux/drivers/sound/audio.c Tue Apr 13 01:18:27 1999 @@ -60,7 +60,10 @@ else return audio_devs[dev]->local_format; - return audio_devs[dev]->local_format; + if (audio_devs[dev]->local_conversion) + return audio_devs[dev]->local_conversion; + else + return audio_devs[dev]->local_format; } int audio_open(int dev, struct file *file) @@ -387,7 +390,7 @@ return 0; case SNDCTL_DSP_GETFMTS: - val = audio_devs[dev]->format_mask; + val = audio_devs[dev]->format_mask | AFMT_MU_LAW; break; case SNDCTL_DSP_SETFMT: diff -ur --new-file old/linux/drivers/sound/awacs_defs.h new/linux/drivers/sound/awacs_defs.h --- old/linux/drivers/sound/awacs_defs.h Thu Aug 6 10:11:36 1998 +++ new/linux/drivers/sound/awacs_defs.h Thu Mar 11 06:48:46 1999 @@ -157,4 +157,68 @@ #define RATE_LOW 1 /* HIGH = 48kHz, etc; LOW = 44.1kHz, etc. */ + +/* Burgundy values */ + +#define MASK_ADDR_BURGUNDY_INPSEL21 (0x11 << 12) +#define MASK_ADDR_BURGUNDY_INPSEL3 (0x12 << 12) + +#define MASK_ADDR_BURGUNDY_GAINCH1 (0x13 << 12) +#define MASK_ADDR_BURGUNDY_GAINCH2 (0x14 << 12) +#define MASK_ADDR_BURGUNDY_GAINCH3 (0x15 << 12) +#define MASK_ADDR_BURGUNDY_GAINCH4 (0x16 << 12) + +#define MASK_ADDR_BURGUNDY_VOLCH1 (0x20 << 12) +#define MASK_ADDR_BURGUNDY_VOLCH2 (0x21 << 12) +#define MASK_ADDR_BURGUNDY_VOLCH3 (0x22 << 12) +#define MASK_ADDR_BURGUNDY_VOLCH4 (0x23 << 12) + +#define MASK_ADDR_BURGUNDY_OUTPUTSELECTS (0x2B << 12) +#define MASK_ADDR_BURGUNDY_OUTPUTENABLES (0x2F << 12) + +#define MASK_ADDR_BURGUNDY_MASTER_VOLUME (0x30 << 12) + +#define MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES (0x60 << 12) + +#define MASK_ADDR_BURGUNDY_ATTENSPEAKER (0x62 << 12) +#define MASK_ADDR_BURGUNDY_ATTENLINEOUT (0x63 << 12) +#define MASK_ADDR_BURGUNDY_ATTENHP (0x64 << 12) + +#define MASK_ADDR_BURGUNDY_VOLCD (MASK_ADDR_BURGUNDY_VOLCH1) +#define MASK_ADDR_BURGUNDY_VOLLINE (MASK_ADDR_BURGUNDY_VOLCH2) +#define MASK_ADDR_BURGUNDY_VOLMIC (MASK_ADDR_BURGUNDY_VOLCH3) +#define MASK_ADDR_BURGUNDY_VOLMODEM (MASK_ADDR_BURGUNDY_VOLCH4) + +#define MASK_ADDR_BURGUNDY_GAINCD (MASK_ADDR_BURGUNDY_GAINCH1) +#define MASK_ADDR_BURGUNDY_GAINLINE (MASK_ADDR_BURGUNDY_GAINCH2) +#define MASK_ADDR_BURGUNDY_GAINMIC (MASK_ADDR_BURGUNDY_GAINCH3) +#define MASK_ADDR_BURGUNDY_GAINMODEM (MASK_ADDR_BURGUNDY_VOLCH4) + + +/* These are all default values for the burgundy */ +#define DEF_BURGUNDY_INPSEL21 (0xAA) +#define DEF_BURGUNDY_INPSEL3 (0x0A) + +#define DEF_BURGUNDY_GAINCD (0x33) +#define DEF_BURGUNDY_GAINLINE (0x44) +#define DEF_BURGUNDY_GAINMIC (0x44) +#define DEF_BURGUNDY_GAINMODEM (0x06) + +/* Remember: lowest volume here is 0x9b */ +#define DEF_BURGUNDY_VOLCD (0xCCCCCCCC) +#define DEF_BURGUNDY_VOLLINE (0x00000000) +#define DEF_BURGUNDY_VOLMIC (0x00000000) +#define DEF_BURGUNDY_VOLMODEM (0xCCCCCCCC) + +#define DEF_BURGUNDY_OUTPUTSELECTS (0x010f010f) +#define DEF_BURGUNDY_OUTPUTENABLES (0x0A) + +#define DEF_BURGUNDY_MASTER_VOLUME (0xFFFFFFFF) + +#define DEF_BURGUNDY_MORE_OUTPUTENABLES (0x7E) + +#define DEF_BURGUNDY_ATTENSPEAKER (0x44) +#define DEF_BURGUNDY_ATTENLINEOUT (0xCC) +#define DEF_BURGUNDY_ATTENHP (0xCC) + #endif /* _AWACS_DEFS_H_ */ diff -ur --new-file old/linux/drivers/sound/dev_table.c new/linux/drivers/sound/dev_table.c --- old/linux/drivers/sound/dev_table.c Mon Jan 4 20:37:29 1999 +++ new/linux/drivers/sound/dev_table.c Tue Apr 13 01:18:27 1999 @@ -437,6 +437,7 @@ memset((char *) op, 0, sizeof(struct audio_operations)); init_waitqueue(&op->in_sleeper); init_waitqueue(&op->out_sleeper); + init_waitqueue(&op->poll_sleeper); if (driver_size < sizeof(struct audio_driver)) memset((char *) d, 0, sizeof(struct audio_driver)); diff -ur --new-file old/linux/drivers/sound/dev_table.h new/linux/drivers/sound/dev_table.h --- old/linux/drivers/sound/dev_table.h Thu Jan 7 18:24:00 1999 +++ new/linux/drivers/sound/dev_table.h Tue Apr 13 01:18:27 1999 @@ -236,6 +236,7 @@ /* fields formerly in dmabuf.c */ struct wait_queue *in_sleeper; struct wait_queue *out_sleeper; + struct wait_queue *poll_sleeper; /* fields formerly in audio.c */ int audio_mode; diff -ur --new-file old/linux/drivers/sound/dmabuf.c new/linux/drivers/sound/dmabuf.c --- old/linux/drivers/sound/dmabuf.c Wed Dec 16 21:52:01 1998 +++ new/linux/drivers/sound/dmabuf.c Tue Apr 13 01:18:27 1999 @@ -935,6 +935,7 @@ if (dmap->audio_callback != NULL) dmap->audio_callback(dev, dmap->callback_parm); wake_up(&adev->out_sleeper); + wake_up(&adev->poll_sleeper); } static void do_outputintr(int dev, int dummy) @@ -1103,7 +1104,10 @@ } dmap->flags |= DMA_ACTIVE; if (dmap->qlen > 0) + { wake_up(&adev->in_sleeper); + wake_up(&adev->poll_sleeper); + } } void DMAbuf_inputintr(int dev) @@ -1217,7 +1221,6 @@ if (!(adev->open_mode & OPEN_READ)) return 0; if (dmap->mapping_flags & DMA_MAP_MAPPED) { - poll_wait(file, &adev->in_sleeper, wait); if (dmap->qlen) return POLLIN | POLLRDNORM; return 0; @@ -1228,7 +1231,6 @@ !dmap->qlen && adev->go) { unsigned long flags; - poll_wait(file, &adev->in_sleeper, wait); save_flags(flags); cli(); DMAbuf_activate_recording(dev, dmap); @@ -1236,7 +1238,6 @@ } return 0; } - poll_wait(file, &adev->in_sleeper, wait); if (!dmap->qlen) return 0; return POLLIN | POLLRDNORM; @@ -1250,14 +1251,12 @@ if (!(adev->open_mode & OPEN_WRITE)) return 0; if (dmap->mapping_flags & DMA_MAP_MAPPED) { - poll_wait(file, &adev->out_sleeper, wait); if (dmap->qlen) return POLLOUT | POLLWRNORM; return 0; } if (dmap->dma_mode == DMODE_INPUT) return 0; - poll_wait(file, &adev->out_sleeper, wait); if (dmap->dma_mode == DMODE_NONE) return POLLOUT | POLLWRNORM; if (!DMAbuf_space_in_queue(dev)) @@ -1267,6 +1266,8 @@ unsigned int DMAbuf_poll(struct file * file, int dev, poll_table *wait) { + struct audio_operations *adev = audio_devs[dev]; + poll_wait(file, &adev->poll_sleeper, wait); return poll_input(file, dev, wait) | poll_output(file, dev, wait); } diff -ur --new-file old/linux/drivers/sound/dmasound.c new/linux/drivers/sound/dmasound.c --- old/linux/drivers/sound/dmasound.c Mon Jan 4 20:37:30 1999 +++ new/linux/drivers/sound/dmasound.c Thu Mar 11 06:48:46 1999 @@ -173,9 +173,11 @@ static volatile struct dbdma_regs *awacs_txdma, *awacs_rxdma; static int awacs_rate_index; static int awacs_subframe; -static int awacs_revision; static int awacs_spkr_vol; +static int awacs_revision; +#define AWACS_BURGUNDY 100 /* fake revision # for burgundy */ + /* * Space for the DBDMA command blocks. */ @@ -184,6 +186,7 @@ /* * Cached values of AWACS registers (we can't read them). + * Except on the burgundy. XXX */ int awacs_reg[5]; @@ -240,6 +243,14 @@ static volatile struct dbdma_cmd *beep_dbdma_cmd; static void (*orig_mksound)(unsigned int, unsigned int); +/* Burgundy functions */ +static void awacs_burgundy_wcw(unsigned addr,unsigned newval); +static unsigned awacs_burgundy_rcw(unsigned addr); +static void awacs_burgundy_write_volume(unsigned address, int volume); +static int awacs_burgundy_read_volume(unsigned address); +static void awacs_burgundy_write_mvolume(unsigned address, int volume); +static int awacs_burgundy_read_mvolume(unsigned address); + #ifdef CONFIG_PMAC_PBOOK /* * Stuff for restoring after a sleep. @@ -3007,6 +3018,9 @@ if (beep_buf) kfree(beep_buf); kd_mksound = orig_mksound; +#ifdef CONFIG_PMAC_PBOOK + notifier_chain_unregister(&sleep_notifier_list, &awacs_sleep_notifier); +#endif } #endif /* MODULE */ @@ -3040,8 +3054,9 @@ * If we have a sample rate which is within catchRadius percent * of the requested value, we don't have to expand the samples. * Otherwise choose the next higher rate. + * N.B.: burgundy awacs (iMac and later) only works at 44100 Hz. */ - i = 8; + i = (awacs_revision >= AWACS_BURGUNDY)? 1: 8; do { tolerance = catchRadius * awacs_freqs[--i] / 100; } while (sound.soft.speed > awacs_freqs[i] + tolerance && i > 0); @@ -3053,7 +3068,9 @@ awacs_rate_index = i; PMacSilence(); - out_le32(&awacs->control, MASK_IEPC | MASK_IEE | (i << 8) | 0x11); + /* XXX disable error interrupt on burgundy for now */ + out_le32(&awacs->control, MASK_IEPC | (i << 8) | 0x11 + | (awacs_revision < AWACS_BURGUNDY? MASK_IEE: 0)); awacs_reg[1] = (awacs_reg[1] & ~MASK_SAMPLERATE) | (i << 3); awacs_write(awacs_reg[1] | MASK_ADDR1); out_le32(&awacs->byteswap, sound.hard.format != AFMT_S16_BE); @@ -3213,8 +3230,9 @@ /* do something when headphone is plugged/unplugged? */ } if (ctrl & MASK_CNTLERR) { - printk(KERN_ERR "AWACS: error, status = %x\n", - in_le32(&awacs->codec_stat)); + int err = (in_le32(&awacs->codec_stat) & MASK_ERRCODE) >> 16; + if (err != 0 && awacs_revision < AWACS_BURGUNDY) + printk(KERN_ERR "AWACS: error %x\n", err); } /* Writing 1s to the CNTLERR and PORTCHG bits clears them... */ out_le32(&awacs->control, ctrl); @@ -3223,6 +3241,8 @@ static void awacs_write(int val) { + if (awacs_revision >= AWACS_BURGUNDY) + return; while (in_le32(&awacs->codec_ctrl) & MASK_NEWECMD) ; /* XXX should have timeout */ out_le32(&awacs->codec_ctrl, val | (awacs_subframe << 22)); @@ -3247,7 +3267,8 @@ static void awacs_mksound(unsigned int hz, unsigned int ticks) { unsigned long flags; - int srate = awacs_freqs[BEEP_SPEED]; + int beep_speed = (awacs_revision < AWACS_BURGUNDY)? BEEP_SPEED: 0; + int srate = awacs_freqs[beep_speed]; int period, ncycles, nsamples; int i, j, f; short *p; @@ -3308,7 +3329,7 @@ out_le32(&awacs_txdma->control, (RUN|WAKE|FLUSH|PAUSE) << 16); out_le32(&awacs->control, (in_le32(&awacs->control) & ~0x1f00) - | (BEEP_SPEED << 8)); + | (beep_speed << 8)); out_le32(&awacs->byteswap, 0); out_le32(&awacs_txdma->cmdptr, virt_to_bus(beep_dbdma_cmd)); out_le32(&awacs_txdma->control, RUN | (RUN << 16)); @@ -3330,8 +3351,9 @@ PMacSilence(); break; case PBOOK_WAKE: - out_le32(&awacs->control, MASK_IEPC | MASK_IEE | - (awacs_rate_index << 8) | 0x11); + out_le32(&awacs->control, MASK_IEPC + | (awacs_rate_index << 8) | 0x11 + | (awacs_revision < AWACS_BURGUNDY? MASK_IEE: 0)); awacs_write(awacs_reg[0] | MASK_ADDR0); awacs_write(awacs_reg[1] | MASK_ADDR1); awacs_write(awacs_reg[2] | MASK_ADDR2); @@ -3342,6 +3364,220 @@ } #endif /* CONFIG_PMAC_PBOOK */ + +/* All the burgundy functions: */ + +/* Waits for busy flag to clear */ +inline static void +awacs_burgundy_busy_wait(void) +{ + while (in_le32(&awacs->codec_ctrl) & MASK_NEWECMD) + ; +} + +inline static void +awacs_burgundy_extend_wait(void) +{ + while (!(in_le32(&awacs->codec_stat) & MASK_EXTEND)) + ; + while (in_le32(&awacs->codec_stat) & MASK_EXTEND) + ; +} + +static void +awacs_burgundy_wcw(unsigned addr, unsigned val) +{ + out_le32(&awacs->codec_ctrl, addr + 0x200c00 + (val & 0xff)); + awacs_burgundy_busy_wait(); + out_le32(&awacs->codec_ctrl, addr + 0x200d00 +((val>>8) & 0xff)); + awacs_burgundy_busy_wait(); + out_le32(&awacs->codec_ctrl, addr + 0x200e00 +((val>>16) & 0xff)); + awacs_burgundy_busy_wait(); + out_le32(&awacs->codec_ctrl, addr + 0x200f00 +((val>>24) & 0xff)); + awacs_burgundy_busy_wait(); +} + +static unsigned +awacs_burgundy_rcw(unsigned addr) +{ + unsigned val = 0; + int flags; + + /* should have timeouts here */ + save_flags(flags); cli(); + + out_le32(&awacs->codec_ctrl, addr + 0x100000); + awacs_burgundy_busy_wait(); + awacs_burgundy_extend_wait(); + val += (in_le32(&awacs->codec_stat) >> 4) & 0xff; + + out_le32(&awacs->codec_ctrl, addr + 0x100100); + awacs_burgundy_busy_wait(); + awacs_burgundy_extend_wait(); + val += ((in_le32(&awacs->codec_stat)>>4) & 0xff) <<8; + + out_le32(&awacs->codec_ctrl, addr + 0x100200); + awacs_burgundy_busy_wait(); + awacs_burgundy_extend_wait(); + val += ((in_le32(&awacs->codec_stat)>>4) & 0xff) <<16; + + out_le32(&awacs->codec_ctrl, addr + 0x100300); + awacs_burgundy_busy_wait(); + awacs_burgundy_extend_wait(); + val += ((in_le32(&awacs->codec_stat)>>4) & 0xff) <<24; + + restore_flags(flags); + + return val; +} + + +static void +awacs_burgundy_wcb(unsigned addr, unsigned val) +{ + out_le32(&awacs->codec_ctrl, addr + 0x300000 + (val & 0xff)); + awacs_burgundy_busy_wait(); +} + +static unsigned +awacs_burgundy_rcb(unsigned addr) +{ + unsigned val = 0; + int flags; + + /* should have timeouts here */ + save_flags(flags); cli(); + + out_le32(&awacs->codec_ctrl, addr + 0x100000); + awacs_burgundy_busy_wait(); + awacs_burgundy_extend_wait(); + val += (in_le32(&awacs->codec_stat) >> 4) & 0xff; + + restore_flags(flags); + + return val; +} + +static int +awacs_burgundy_check(void) +{ + /* Checks to see the chip is alive and kicking */ + int error = in_le32(&awacs->codec_ctrl) & MASK_ERRCODE; + + return error == 0xf0000; +} + +static int +awacs_burgundy_init(void) +{ + if (awacs_burgundy_check()) { + printk(KERN_WARNING "AWACS: disabled by MacOS :-(\n"); + return 1; + } + + awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_OUTPUTENABLES, + DEF_BURGUNDY_OUTPUTENABLES); + awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, + DEF_BURGUNDY_MORE_OUTPUTENABLES); + awacs_burgundy_wcw(MASK_ADDR_BURGUNDY_OUTPUTSELECTS, + DEF_BURGUNDY_OUTPUTSELECTS); + + awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_INPSEL21, + DEF_BURGUNDY_INPSEL21); + awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_INPSEL3, + DEF_BURGUNDY_INPSEL3); + awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_GAINCD, + DEF_BURGUNDY_GAINCD); + awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_GAINLINE, + DEF_BURGUNDY_GAINLINE); + awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_GAINMIC, + DEF_BURGUNDY_GAINMIC); + awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_GAINMODEM, + DEF_BURGUNDY_GAINMODEM); + + awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_ATTENSPEAKER, + DEF_BURGUNDY_ATTENSPEAKER); + awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_ATTENLINEOUT, + DEF_BURGUNDY_ATTENLINEOUT); + awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_ATTENHP, + DEF_BURGUNDY_ATTENHP); + + awacs_burgundy_wcw(MASK_ADDR_BURGUNDY_MASTER_VOLUME, + DEF_BURGUNDY_MASTER_VOLUME); + awacs_burgundy_wcw(MASK_ADDR_BURGUNDY_VOLCD, + DEF_BURGUNDY_VOLCD); + awacs_burgundy_wcw(MASK_ADDR_BURGUNDY_VOLLINE, + DEF_BURGUNDY_VOLLINE); + awacs_burgundy_wcw(MASK_ADDR_BURGUNDY_VOLMIC, + DEF_BURGUNDY_VOLMIC); + return 0; +} + +static void +awacs_burgundy_write_volume(unsigned address, int volume) +{ + int hardvolume,lvolume,rvolume; + + lvolume = (volume & 0xff) ? (volume & 0xff) + 155 : 0; + rvolume = ((volume >>8)&0xff) ? ((volume >> 8)&0xff ) + 155 : 0; + + hardvolume = lvolume + (rvolume << 16); + + awacs_burgundy_wcw(address, hardvolume); +} + +static int +awacs_burgundy_read_volume(unsigned address) +{ + int softvolume,wvolume; + + wvolume = awacs_burgundy_rcw(address); + + softvolume = (wvolume & 0xff) - 155; + softvolume += (((wvolume >> 16) & 0xff) - 155)<<8; + + return softvolume > 0 ? softvolume : 0; +} + + + + +static int +awacs_burgundy_read_mvolume(unsigned address) +{ + int lvolume,rvolume,wvolume; + + wvolume = awacs_burgundy_rcw(address); + + wvolume &= 0xffff; + + rvolume = (wvolume & 0xff) - 155; + lvolume = ((wvolume & 0xff00)>>8) - 155; + + return lvolume + (rvolume << 8); +} + + +static void +awacs_burgundy_write_mvolume(unsigned address, int volume) +{ + int lvolume,rvolume,hardvolume; + + lvolume = (volume &0xff) ? (volume & 0xff) + 155 :0; + rvolume = ((volume >>8) & 0xff) ? (volume >> 8) + 155 :0; + + hardvolume = lvolume + (rvolume << 8); + hardvolume += (hardvolume << 16); + + awacs_burgundy_wcw(address, hardvolume); +} + +/* End burgundy functions */ + + + + + /* Turn on sound output, needed on G3 desktop powermacs */ static void awacs_enable_amp(int spkr_vol) @@ -3715,117 +3951,244 @@ #ifdef CONFIG_PPC case DMASND_AWACS: - switch (cmd) { - case SOUND_MIXER_READ_DEVMASK: - data = SOUND_MASK_VOLUME | SOUND_MASK_SPEAKER - | SOUND_MASK_LINE | SOUND_MASK_MIC - | SOUND_MASK_CD | SOUND_MASK_RECLEV - | SOUND_MASK_ALTPCM; - return IOCTL_OUT(arg, data); - case SOUND_MIXER_READ_RECMASK: - data = SOUND_MASK_LINE | SOUND_MASK_MIC - | SOUND_MASK_CD; - return IOCTL_OUT(arg, data); - case SOUND_MIXER_READ_RECSRC: - data = 0; - if (awacs_reg[0] & MASK_MUX_AUDIN) - data |= SOUND_MASK_LINE; - if (awacs_reg[0] & MASK_MUX_MIC) - data |= SOUND_MASK_MIC; - if (awacs_reg[0] & MASK_MUX_CD) - data |= SOUND_MASK_CD; - return IOCTL_OUT(arg, data); - case SOUND_MIXER_WRITE_RECSRC: - IOCTL_IN(arg, data); - data &= (SOUND_MASK_LINE - | SOUND_MASK_MIC | SOUND_MASK_CD); - awacs_reg[0] &= ~(MASK_MUX_CD | MASK_MUX_MIC - | MASK_MUX_AUDIN); - if (data & SOUND_MASK_LINE) - awacs_reg[0] |= MASK_MUX_AUDIN; - if (data & SOUND_MASK_MIC) - awacs_reg[0] |= MASK_MUX_MIC; - if (data & SOUND_MASK_CD) - awacs_reg[0] |= MASK_MUX_CD; - awacs_write(awacs_reg[0] | MASK_ADDR0); - return IOCTL_OUT(arg, data); - case SOUND_MIXER_READ_STEREODEVS: - data = SOUND_MASK_VOLUME | SOUND_MASK_SPEAKER - | SOUND_MASK_RECLEV; - return IOCTL_OUT(arg, data); - case SOUND_MIXER_READ_CAPS: - return IOCTL_OUT(arg, 0); - case SOUND_MIXER_READ_VOLUME: - data = (awacs_reg[1] & MASK_AMUTE)? 0: - awacs_get_volume(awacs_reg[2], 6); - return IOCTL_OUT(arg, data); - case SOUND_MIXER_WRITE_VOLUME: - IOCTL_IN(arg, data); - return IOCTL_OUT(arg, sound_set_volume(data)); - case SOUND_MIXER_READ_SPEAKER: - if (awacs_revision >= 3 && adb_hardware == ADB_VIACUDA) - data = awacs_spkr_vol; - else - data = (awacs_reg[1] & MASK_CMUTE)? 0: - awacs_get_volume(awacs_reg[4], 6); - return IOCTL_OUT(arg, data); - case SOUND_MIXER_WRITE_SPEAKER: - IOCTL_IN(arg, data); - if (awacs_revision >= 3 && adb_hardware == ADB_VIACUDA) - awacs_enable_amp(data); - else - data = awacs_volume_setter(data, 4, MASK_CMUTE, 6); - return IOCTL_OUT(arg, data); - case SOUND_MIXER_WRITE_ALTPCM: /* really bell volume */ - IOCTL_IN(arg, data); - beep_volume = data & 0xff; - /* fall through */ - case SOUND_MIXER_READ_ALTPCM: - return IOCTL_OUT(arg, beep_volume); - case SOUND_MIXER_WRITE_LINE: - IOCTL_IN(arg, data); - awacs_reg[0] &= ~MASK_MUX_AUDIN; - if ((data & 0xff) >= 50) - awacs_reg[0] |= MASK_MUX_AUDIN; - awacs_write(MASK_ADDR0 | awacs_reg[0]); - /* fall through */ - case SOUND_MIXER_READ_LINE: - data = (awacs_reg[0] & MASK_MUX_AUDIN)? 100: 0; - return IOCTL_OUT(arg, data); - case SOUND_MIXER_WRITE_MIC: - IOCTL_IN(arg, data); - data &= 0xff; - awacs_reg[0] &= ~(MASK_MUX_MIC | MASK_GAINLINE); - if (data >= 25) { - awacs_reg[0] |= MASK_MUX_MIC; - if (data >= 75) - awacs_reg[0] |= MASK_GAINLINE; + if (awacs_revision= 50) + awacs_reg[0] |= MASK_MUX_AUDIN; + awacs_write(MASK_ADDR0 | awacs_reg[0]); + /* fall through */ + case SOUND_MIXER_READ_LINE: + data = (awacs_reg[0] & MASK_MUX_AUDIN)? 100: 0; + return IOCTL_OUT(arg, data); + case SOUND_MIXER_WRITE_MIC: + IOCTL_IN(arg, data); + data &= 0xff; + awacs_reg[0] &= ~(MASK_MUX_MIC | MASK_GAINLINE); + if (data >= 25) { + awacs_reg[0] |= MASK_MUX_MIC; + if (data >= 75) + awacs_reg[0] |= MASK_GAINLINE; + } + awacs_write(MASK_ADDR0 | awacs_reg[0]); + /* fall through */ + case SOUND_MIXER_READ_MIC: + data = (awacs_reg[0] & MASK_MUX_MIC)? + (awacs_reg[0] & MASK_GAINLINE? 100: 50): 0; + return IOCTL_OUT(arg, data); + case SOUND_MIXER_WRITE_CD: + IOCTL_IN(arg, data); + awacs_reg[0] &= ~MASK_MUX_CD; + if ((data & 0xff) >= 50) + awacs_reg[0] |= MASK_MUX_CD; + awacs_write(MASK_ADDR0 | awacs_reg[0]); + /* fall through */ + case SOUND_MIXER_READ_CD: + data = (awacs_reg[0] & MASK_MUX_CD)? 100: 0; + return IOCTL_OUT(arg, data); + case SOUND_MIXER_WRITE_RECLEV: + IOCTL_IN(arg, data); + data = awacs_volume_setter(data, 0, 0, 4); + return IOCTL_OUT(arg, data); + case SOUND_MIXER_READ_RECLEV: + data = awacs_get_volume(awacs_reg[0], 4); + return IOCTL_OUT(arg, data); } - awacs_write(MASK_ADDR0 | awacs_reg[0]); - /* fall through */ - case SOUND_MIXER_READ_MIC: - data = (awacs_reg[0] & MASK_MUX_MIC)? - (awacs_reg[0] & MASK_GAINLINE? 100: 50): 0; - return IOCTL_OUT(arg, data); - case SOUND_MIXER_WRITE_CD: - IOCTL_IN(arg, data); - awacs_reg[0] &= ~MASK_MUX_CD; - if ((data & 0xff) >= 50) - awacs_reg[0] |= MASK_MUX_CD; - awacs_write(MASK_ADDR0 | awacs_reg[0]); - /* fall through */ - case SOUND_MIXER_READ_CD: - data = (awacs_reg[0] & MASK_MUX_CD)? 100: 0; - return IOCTL_OUT(arg, data); - case SOUND_MIXER_WRITE_RECLEV: - IOCTL_IN(arg, data); - data = awacs_volume_setter(data, 0, 0, 4); - return IOCTL_OUT(arg, data); - case SOUND_MIXER_READ_RECLEV: - data = awacs_get_volume(awacs_reg[0], 4); - return IOCTL_OUT(arg, data); + break; + } else { + /* We are, we are, we are... Burgundy or better */ + switch(cmd) { + case SOUND_MIXER_READ_DEVMASK: + data = SOUND_MASK_VOLUME | SOUND_MASK_CD | + SOUND_MASK_LINE | SOUND_MASK_MIC | + SOUND_MASK_SPEAKER | SOUND_MASK_ALTPCM; + return IOCTL_OUT(arg, data); + case SOUND_MIXER_READ_RECMASK: + data = SOUND_MASK_LINE | SOUND_MASK_MIC + | SOUND_MASK_CD; + return IOCTL_OUT(arg, data); + case SOUND_MIXER_READ_RECSRC: + data = 0; + if (awacs_reg[0] & MASK_MUX_AUDIN) + data |= SOUND_MASK_LINE; + if (awacs_reg[0] & MASK_MUX_MIC) + data |= SOUND_MASK_MIC; + if (awacs_reg[0] & MASK_MUX_CD) + data |= SOUND_MASK_CD; + return IOCTL_OUT(arg, data); + case SOUND_MIXER_WRITE_RECSRC: + IOCTL_IN(arg, data); + data &= (SOUND_MASK_LINE + | SOUND_MASK_MIC | SOUND_MASK_CD); + awacs_reg[0] &= ~(MASK_MUX_CD | MASK_MUX_MIC + | MASK_MUX_AUDIN); + if (data & SOUND_MASK_LINE) + awacs_reg[0] |= MASK_MUX_AUDIN; + if (data & SOUND_MASK_MIC) + awacs_reg[0] |= MASK_MUX_MIC; + if (data & SOUND_MASK_CD) + awacs_reg[0] |= MASK_MUX_CD; + awacs_write(awacs_reg[0] | MASK_ADDR0); + return IOCTL_OUT(arg, data); + case SOUND_MIXER_READ_STEREODEVS: + data = SOUND_MASK_VOLUME | SOUND_MASK_SPEAKER + | SOUND_MASK_RECLEV | SOUND_MASK_CD + | SOUND_MASK_LINE; + return IOCTL_OUT(arg, data); + case SOUND_MIXER_READ_CAPS: + return IOCTL_OUT(arg, 0); + case SOUND_MIXER_WRITE_VOLUME: + IOCTL_IN(arg, data); + awacs_burgundy_write_mvolume(MASK_ADDR_BURGUNDY_MASTER_VOLUME, data); + /* Fall through */ + case SOUND_MIXER_READ_VOLUME: + return IOCTL_OUT(arg, awacs_burgundy_read_mvolume(MASK_ADDR_BURGUNDY_MASTER_VOLUME)); + case SOUND_MIXER_WRITE_SPEAKER: + IOCTL_IN(arg, data); + + if (!(data & 0xff)) { + /* Mute the left speaker */ + awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, + awacs_burgundy_rcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES) & ~0x2); + } else { + /* Unmute the left speaker */ + awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, + awacs_burgundy_rcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES) | 0x2); + } + if (!(data & 0xff00)) { + /* Mute the right speaker */ + awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, + awacs_burgundy_rcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES) & ~0x4); + } else { + /* Unmute the right speaker */ + awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, + awacs_burgundy_rcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES) | 0x4); + } + + data = (((data&0xff)*16)/100 > 0xf ? 0xf : + (((data&0xff)*16)/100)) + + ((((data>>8)*16)/100 > 0xf ? 0xf : + ((((data>>8)*16)/100)))<<4); + + awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_ATTENSPEAKER, ~data); + /* Fall through */ + case SOUND_MIXER_READ_SPEAKER: + data = awacs_burgundy_rcb(MASK_ADDR_BURGUNDY_ATTENSPEAKER); + data = (((data & 0xf)*100)/16) + ((((data>>4)*100)/16)<<8); + return IOCTL_OUT(arg, ~data); + case SOUND_MIXER_WRITE_ALTPCM: /* really bell volume */ + IOCTL_IN(arg, data); + beep_volume = data & 0xff; + /* fall through */ + case SOUND_MIXER_READ_ALTPCM: + return IOCTL_OUT(arg, beep_volume); + case SOUND_MIXER_WRITE_LINE: + IOCTL_IN(arg, data); + awacs_burgundy_write_volume(MASK_ADDR_BURGUNDY_VOLLINE, data); + + /* fall through */ + case SOUND_MIXER_READ_LINE: + data = awacs_burgundy_read_volume(MASK_ADDR_BURGUNDY_VOLLINE); + return IOCTL_OUT(arg, data); + case SOUND_MIXER_WRITE_MIC: + IOCTL_IN(arg, data); + /* Mic is mono device */ + data = (data << 8) + (data << 24); + awacs_burgundy_write_volume(MASK_ADDR_BURGUNDY_VOLMIC, data); + /* fall through */ + case SOUND_MIXER_READ_MIC: + data = awacs_burgundy_read_volume(MASK_ADDR_BURGUNDY_VOLMIC); + data <<= 24; + return IOCTL_OUT(arg, data); + case SOUND_MIXER_WRITE_CD: + IOCTL_IN(arg, data); + awacs_burgundy_write_volume(MASK_ADDR_BURGUNDY_VOLCD, data); + /* fall through */ + case SOUND_MIXER_READ_CD: + data = awacs_burgundy_read_volume(MASK_ADDR_BURGUNDY_VOLCD); + return IOCTL_OUT(arg, data); + case SOUND_MIXER_WRITE_RECLEV: + IOCTL_IN(arg, data); + data = awacs_volume_setter(data, 0, 0, 4); + return IOCTL_OUT(arg, data); + case SOUND_MIXER_READ_RECLEV: + data = awacs_get_volume(awacs_reg[0], 4); + return IOCTL_OUT(arg, data); + case SOUND_MIXER_OUTMASK: + break; + case SOUND_MIXER_OUTSRC: + break; + } + break; } - break; #endif } @@ -3946,9 +4309,7 @@ sq.front = sq.count = 0; sq.rear = -1; - sq.write_queue = sq.open_queue = sq.sync_queue = 0; sq.syncing = 0; - sq.playing = 0; #ifdef CONFIG_ATARI @@ -4129,21 +4490,21 @@ static int sq_release(struct inode *inode, struct file *file) { int rc = 0; - if (sq.busy) { + + if (sq.busy) rc = sq_fsync(file, file->f_dentry); - sq.busy = 0; - WAKE_UP(sq.open_queue); - /* Wake up a process waiting for the queue being released. - * Note: There may be several processes waiting for a call - * to open() returning. */ - } sound.soft = sound.dsp; sound.hard = sound.dsp; sound_silence(); - if (rc == 0) { - sq_release_buffers(); - MOD_DEC_USE_COUNT; - } + sq_release_buffers(); + MOD_DEC_USE_COUNT; + + sq.busy = 0; + WAKE_UP(sq.open_queue); + /* Wake up a process waiting for the queue being released. + * Note: There may be several processes waiting for a call + * to open() returning. */ + return rc; } @@ -4262,6 +4623,9 @@ if (sq_unit < 0) return; + sq.write_queue = sq.open_queue = sq.sync_queue = 0; + sq.busy = 0; + /* whatever you like as startup mode for /dev/dsp, * (/dev/audio hasn't got a startup mode). note that * once changed a new open() will *not* restore these! @@ -4332,7 +4696,7 @@ #endif /* CONFIG_AMIGA */ #ifdef CONFIG_PPC case DMASND_AWACS: - mach = "PowerMac "; + sprintf(mach, "PowerMac (AWACS rev %d) ", awacs_revision); break; #endif /* CONFIG_PPC */ } @@ -4510,6 +4874,7 @@ #ifdef CONFIG_PPC awacs_subframe = 0; + awacs_revision = 0; np = find_devices("awacs"); if (np == 0) { /* @@ -4524,6 +4889,8 @@ sfprop = (int *) get_property(sound, "sub-frame", 0); if (sfprop != 0 && *sfprop >= 0 && *sfprop < 16) awacs_subframe = *sfprop; + if (device_is_compatible(sound, "burgundy")) + awacs_revision = AWACS_BURGUNDY; } } if (np != NULL && np->n_addrs >= 3 && np->n_intrs >= 3) { @@ -4542,7 +4909,7 @@ awacs_tx_cmd_space = kmalloc((numBufs + 4) * sizeof(struct dbdma_cmd), GFP_KERNEL); if (awacs_tx_cmd_space == NULL) { - printk("DMA sound driver: Not enough buffer memory, driver disabled!\n"); + printk(KERN_ERR "DMA sound driver: Not enough buffer memory, driver disabled!\n"); return; } awacs_tx_cmds = (volatile struct dbdma_cmd *) @@ -4560,17 +4927,22 @@ awacs_write(awacs_reg[4] + MASK_ADDR4); /* Initialize recent versions of the awacs */ - awacs_revision = (in_le32(&awacs->codec_stat) >> 12) & 0xf; - if (awacs_revision >= 3) { - awacs_write(0x6000); - awacs_enable_amp(100 * 0x101); + if (awacs_revision == 0) { + awacs_revision = + (in_le32(&awacs->codec_stat) >> 12) & 0xf; + if (awacs_revision == 3) { + awacs_write(0x6000); + awacs_enable_amp(100 * 0x101); + } } + if (awacs_revision >= AWACS_BURGUNDY) + awacs_burgundy_init(); /* Initialize beep stuff */ beep_dbdma_cmd = awacs_tx_cmds + (numBufs + 1); orig_mksound = kd_mksound; kd_mksound = awacs_mksound; - beep_buf = (short *) kmalloc(BEEP_BUFLEN * 2, GFP_KERNEL); + beep_buf = (short *) kmalloc(BEEP_BUFLEN * 4, GFP_KERNEL); if (beep_buf == NULL) printk(KERN_WARNING "dmasound: no memory for " "beep buffer\n"); @@ -4596,15 +4968,15 @@ mixer_init(); if (!sound.mach.irqinit()) { - printk("DMA sound driver: Interrupt initialization failed\n"); + printk(KERN_ERR "DMA sound driver: Interrupt initialization failed\n"); return; } #ifdef MODULE irq_installed = 1; #endif - printk("DMA sound driver installed, using %d buffers of %dk.\n", numBufs, - bufSize); + printk(KERN_INFO "DMA sound driver installed, using %d buffers of %dk.\n", + numBufs, bufSize); return; } diff -ur --new-file old/linux/drivers/sound/es1370.c new/linux/drivers/sound/es1370.c --- old/linux/drivers/sound/es1370.c Thu Jan 7 18:24:00 1999 +++ new/linux/drivers/sound/es1370.c Tue Apr 13 01:18:27 1999 @@ -3,7 +3,7 @@ /* * es1370.c -- Ensoniq ES1370/Asahi Kasei AK4531 audio driver. * - * Copyright (C) 1998 Thomas Sailer (sailer@ife.ee.ethz.ch) + * Copyright (C) 1998-1999 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 @@ -83,6 +83,15 @@ * 16.12.98 0.16 Don't wake up app until there are fragsize bytes to read/write * 06.01.99 0.17 remove the silly SA_INTERRUPT flag. * hopefully killed the egcs section type conflict + * 12.03.99 0.18 cinfo.blocks should be reset after GETxPTR ioctl. + * reported by Johan Maes + * 22.03.99 0.19 return EAGAIN instead of EBUSY when O_NONBLOCK + * read/write cannot be executed + * 07.04.99 0.20 implemented the following ioctl's: SOUND_PCM_READ_RATE, + * SOUND_PCM_READ_CHANNELS, SOUND_PCM_READ_BITS; + * Alpha fixes reported by Peter Jones + * Note: joystick address handling might still be wrong on archs + * other than i386 * * some important things missing in Ensoniq documentation: * @@ -127,6 +136,8 @@ /* --------------------------------------------------------------------- */ #undef OSS_DOCUMENTED_MIXER_SEMANTICS +#define DBG(x) {} +/*#define DBG(x) {x}*/ /* --------------------------------------------------------------------- */ @@ -281,7 +292,8 @@ int dev_midi; /* hardware resources */ - unsigned int io, irq; + unsigned long io; /* long for SPARC */ + unsigned int irq; /* mixer registers; there is no HW readback */ struct { @@ -1019,7 +1031,7 @@ tmo = (count * HZ) / dac1_samplerate[(s->ctrl & CTRL_WTSRSEL) >> CTRL_SH_WTSRSEL]; tmo >>= sample_shift[(s->sctrl & SCTRL_P1FMT) >> SCTRL_SH_P1FMT]; if (!schedule_timeout(tmo ? : 1) && tmo) - printk(KERN_DEBUG "es1370: dma timed out??\n"); + DBG(printk(KERN_DEBUG "es1370: dma timed out??\n");) } remove_wait_queue(&s->dma_dac1.wait, &wait); current->state = TASK_RUNNING; @@ -1054,7 +1066,7 @@ tmo = (count * HZ) / DAC2_DIVTOSR((s->ctrl & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV); tmo >>= sample_shift[(s->sctrl & SCTRL_P2FMT) >> SCTRL_SH_P2FMT]; if (!schedule_timeout(tmo ? : 1) && tmo) - printk(KERN_DEBUG "es1370: dma timed out??\n"); + DBG(printk(KERN_DEBUG "es1370: dma timed out??\n");) } remove_wait_queue(&s->dma_dac2.wait, &wait); current->state = TASK_RUNNING; @@ -1095,7 +1107,7 @@ if (cnt <= 0) { start_adc(s); if (file->f_flags & O_NONBLOCK) - return ret ? ret : -EBUSY; + return ret ? ret : -EAGAIN; interruptible_sleep_on(&s->dma_adc.wait); if (signal_pending(current)) return ret ? ret : -ERESTARTSYS; @@ -1150,7 +1162,7 @@ if (cnt <= 0) { start_dac2(s); if (file->f_flags & O_NONBLOCK) - return ret ? ret : -EBUSY; + return ret ? ret : -EAGAIN; interruptible_sleep_on(&s->dma_dac2.wait); if (signal_pending(current)) return ret ? ret : -ERESTARTSYS; @@ -1228,8 +1240,6 @@ if (remap_page_range(vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot)) return -EAGAIN; db->mapped = 1; - vma->vm_file = file; - file->f_count++; return 0; } @@ -1455,7 +1465,7 @@ spin_lock_irqsave(&s->lock, flags); es1370_update_ptr(s); cinfo.bytes = s->dma_adc.total_bytes; - cinfo.blocks = s->dma_adc.total_bytes >> s->dma_adc.fragshift; + 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; @@ -1468,7 +1478,7 @@ spin_lock_irqsave(&s->lock, flags); es1370_update_ptr(s); cinfo.bytes = s->dma_dac2.total_bytes; - cinfo.blocks = s->dma_dac2.total_bytes >> s->dma_dac2.fragshift; + cinfo.blocks = s->dma_dac2.count >> s->dma_dac2.fragshift; cinfo.ptr = s->dma_dac2.hwptr; if (s->dma_dac2.mapped) s->dma_dac2.count &= s->dma_dac2.fragsize-1; @@ -1522,11 +1532,19 @@ s->dma_dac2.subdivision = val; return 0; - case SOUND_PCM_WRITE_FILTER: - case SNDCTL_DSP_SETSYNCRO: case SOUND_PCM_READ_RATE: + return put_user(DAC2_DIVTOSR((s->ctrl & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV), (int *)arg); + case SOUND_PCM_READ_CHANNELS: + return put_user((s->sctrl & ((file->f_mode & FMODE_READ) ? SCTRL_R1SMB : SCTRL_P2SMB)) ? + 2 : 1, (int *)arg); + case SOUND_PCM_READ_BITS: + return put_user((s->sctrl & ((file->f_mode & FMODE_READ) ? SCTRL_R1SEB : SCTRL_P2SEB)) ? + 16 : 8, (int *)arg); + + case SOUND_PCM_WRITE_FILTER: + case SNDCTL_DSP_SETSYNCRO: case SOUND_PCM_READ_FILTER: return -EINVAL; @@ -1597,6 +1615,7 @@ down(&s->open_sem); if (file->f_mode & FMODE_WRITE) { stop_dac2(s); + synchronize_irq(); dealloc_dmabuf(&s->dma_dac2); } if (file->f_mode & FMODE_READ) { @@ -1663,7 +1682,7 @@ if (cnt <= 0) { start_dac1(s); if (file->f_flags & O_NONBLOCK) - return ret ? ret : -EBUSY; + return ret ? ret : -EAGAIN; interruptible_sleep_on(&s->dma_dac1.wait); if (signal_pending(current)) return ret ? ret : -ERESTARTSYS; @@ -1725,8 +1744,6 @@ if (remap_page_range(vma->vm_start, virt_to_phys(s->dma_dac1.rawbuf), size, vma->vm_page_prot)) return -EAGAIN; s->dma_dac1.mapped = 1; - vma->vm_file = file; - file->f_count++; return 0; } @@ -1867,7 +1884,7 @@ spin_lock_irqsave(&s->lock, flags); es1370_update_ptr(s); cinfo.bytes = s->dma_dac1.total_bytes; - cinfo.blocks = s->dma_dac1.total_bytes >> s->dma_dac1.fragshift; + cinfo.blocks = s->dma_dac1.count >> s->dma_dac1.fragshift; cinfo.ptr = s->dma_dac1.hwptr; if (s->dma_dac1.mapped) s->dma_dac1.count &= s->dma_dac1.fragsize-1; @@ -1900,11 +1917,17 @@ s->dma_dac1.subdivision = val; return 0; - case SOUND_PCM_WRITE_FILTER: - case SNDCTL_DSP_SETSYNCRO: case SOUND_PCM_READ_RATE: + return put_user(dac1_samplerate[(s->ctrl & CTRL_WTSRSEL) >> CTRL_SH_WTSRSEL], (int *)arg); + case SOUND_PCM_READ_CHANNELS: + return put_user((s->sctrl & SCTRL_P1SMB) ? 2 : 1, (int *)arg); + case SOUND_PCM_READ_BITS: + return put_user((s->sctrl & SCTRL_P1SEB) ? 16 : 8, (int *)arg); + + case SOUND_PCM_WRITE_FILTER: + case SNDCTL_DSP_SETSYNCRO: case SOUND_PCM_READ_FILTER: return -EINVAL; @@ -2022,7 +2045,7 @@ cnt = count; if (cnt <= 0) { if (file->f_flags & O_NONBLOCK) - return ret ? ret : -EBUSY; + return ret ? ret : -EAGAIN; interruptible_sleep_on(&s->midi.iwait); if (signal_pending(current)) return ret ? ret : -ERESTARTSYS; @@ -2069,7 +2092,7 @@ cnt = count; if (cnt <= 0) { if (file->f_flags & O_NONBLOCK) - return ret ? ret : -EBUSY; + return ret ? ret : -EAGAIN; interruptible_sleep_on(&s->midi.owait); if (signal_pending(current)) return ret ? ret : -ERESTARTSYS; @@ -2192,7 +2215,7 @@ } tmo = (count * HZ) / 3100; if (!schedule_timeout(tmo ? : 1) && tmo) - printk(KERN_DEBUG "es1370: midi timed out??\n"); + DBG(printk(KERN_DEBUG "es1370: midi timed out??\n");) } remove_wait_queue(&s->midi.owait, &wait); current->state = TASK_RUNNING; @@ -2272,7 +2295,7 @@ if (!pci_present()) /* No PCI bus in this machine! */ return -ENODEV; - printk(KERN_INFO "es1370: version v0.17 time " __TIME__ " " __DATE__ "\n"); + printk(KERN_INFO "es1370: version v0.20 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 || @@ -2296,7 +2319,7 @@ s->io = pcidev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK; s->irq = pcidev->irq; if (check_region(s->io, ES1370_EXTENT)) { - printk(KERN_ERR "es1370: io ports %#x-%#x in use\n", s->io, s->io+ES1370_EXTENT-1); + printk(KERN_ERR "es1370: io ports %#lx-%#lx in use\n", s->io, s->io+ES1370_EXTENT-1); goto err_region; } request_region(s->io, ES1370_EXTENT, "es1370"); @@ -2317,7 +2340,7 @@ if (micz[index]) s->ctrl |= CTRL_XCTL1; s->sctrl = 0; - printk(KERN_INFO "es1370: found adapter at io %#06x irq %u\n" + printk(KERN_INFO "es1370: found adapter at io %#lx irq %u\n" KERN_INFO "es1370: features: joystick %s, line %s, mic impedance %s\n", s->io, s->irq, (s->ctrl & CTRL_JYSTK_EN) ? "on" : "off", (s->ctrl & CTRL_XCTL0) ? "out" : "in", diff -ur --new-file old/linux/drivers/sound/es1371.c new/linux/drivers/sound/es1371.c --- old/linux/drivers/sound/es1371.c Thu Jan 7 18:24:00 1999 +++ new/linux/drivers/sound/es1371.c Tue Apr 13 01:18:27 1999 @@ -54,6 +54,17 @@ * Don't wake up app until there are fragsize bytes to read/write * 06.01.99 0.8 remove the silly SA_INTERRUPT flag. * hopefully killed the egcs section type conflict + * 12.03.99 0.9 cinfo.blocks should be reset after GETxPTR ioctl. + * reported by Johan Maes + * 22.03.99 0.10 return EAGAIN instead of EBUSY when O_NONBLOCK + * read/write cannot be executed + * 07.04.99 0.11 implemented the following ioctl's: SOUND_PCM_READ_RATE, + * SOUND_PCM_READ_CHANNELS, SOUND_PCM_READ_BITS; + * Alpha fixes reported by Peter Jones + * Another Alpha fix (wait_src_ready in init routine) + * reported by "Ivan N. Kokshaysky" + * Note: joystick address handling might still be wrong on archs + * other than i386 * */ @@ -330,7 +341,8 @@ int dev_midi; /* hardware resources */ - unsigned int io, irq; + unsigned long io; /* long for SPARC */ + unsigned int irq; /* mixer registers; there is no HW readback */ struct { @@ -1542,7 +1554,7 @@ if (cnt <= 0) { start_adc(s); if (file->f_flags & O_NONBLOCK) - return ret ? ret : -EBUSY; + return ret ? ret : -EAGAIN; interruptible_sleep_on(&s->dma_adc.wait); if (signal_pending(current)) return ret ? ret : -ERESTARTSYS; @@ -1597,7 +1609,7 @@ if (cnt <= 0) { start_dac2(s); if (file->f_flags & O_NONBLOCK) - return ret ? ret : -EBUSY; + return ret ? ret : -EAGAIN; interruptible_sleep_on(&s->dma_dac2.wait); if (signal_pending(current)) return ret ? ret : -ERESTARTSYS; @@ -1675,8 +1687,6 @@ if (remap_page_range(vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot)) return -EAGAIN; db->mapped = 1; - vma->vm_file = file; - file->f_count++; return 0; } @@ -1899,7 +1909,7 @@ spin_lock_irqsave(&s->lock, flags); es1371_update_ptr(s); cinfo.bytes = s->dma_adc.total_bytes; - cinfo.blocks = s->dma_adc.total_bytes >> s->dma_adc.fragshift; + 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; @@ -1912,7 +1922,7 @@ spin_lock_irqsave(&s->lock, flags); es1371_update_ptr(s); cinfo.bytes = s->dma_dac2.total_bytes; - cinfo.blocks = s->dma_dac2.total_bytes >> s->dma_dac2.fragshift; + cinfo.blocks = s->dma_dac2.count >> s->dma_dac2.fragshift; cinfo.ptr = s->dma_dac2.hwptr; if (s->dma_dac2.mapped) s->dma_dac2.count &= s->dma_dac2.fragsize-1; @@ -1966,11 +1976,17 @@ s->dma_dac2.subdivision = val; return 0; - case SOUND_PCM_WRITE_FILTER: - case SNDCTL_DSP_SETSYNCRO: case SOUND_PCM_READ_RATE: + return put_user((file->f_mode & FMODE_READ) ? s->adcrate : s->dac2rate, (int *)arg); + case SOUND_PCM_READ_CHANNELS: + return put_user((s->sctrl & ((file->f_mode & FMODE_READ) ? SCTRL_R1SMB : SCTRL_P2SMB)) ? 2 : 1, (int *)arg); + case SOUND_PCM_READ_BITS: + return put_user((s->sctrl & ((file->f_mode & FMODE_READ) ? SCTRL_R1SEB : SCTRL_P2SEB)) ? 16 : 8, (int *)arg); + + case SOUND_PCM_WRITE_FILTER: + case SNDCTL_DSP_SETSYNCRO: case SOUND_PCM_READ_FILTER: return -EINVAL; @@ -2110,7 +2126,7 @@ if (cnt <= 0) { start_dac1(s); if (file->f_flags & O_NONBLOCK) - return ret ? ret : -EBUSY; + return ret ? ret : -EAGAIN; interruptible_sleep_on(&s->dma_dac1.wait); if (signal_pending(current)) return ret ? ret : -ERESTARTSYS; @@ -2172,8 +2188,6 @@ if (remap_page_range(vma->vm_start, virt_to_phys(s->dma_dac1.rawbuf), size, vma->vm_page_prot)) return -EAGAIN; s->dma_dac1.mapped = 1; - vma->vm_file = file; - file->f_count++; return 0; } @@ -2305,7 +2319,7 @@ spin_lock_irqsave(&s->lock, flags); es1371_update_ptr(s); cinfo.bytes = s->dma_dac1.total_bytes; - cinfo.blocks = s->dma_dac1.total_bytes >> s->dma_dac1.fragshift; + cinfo.blocks = s->dma_dac1.count >> s->dma_dac1.fragshift; cinfo.ptr = s->dma_dac1.hwptr; if (s->dma_dac1.mapped) s->dma_dac1.count &= s->dma_dac1.fragsize-1; @@ -2338,11 +2352,17 @@ s->dma_dac1.subdivision = val; return 0; - case SOUND_PCM_WRITE_FILTER: - case SNDCTL_DSP_SETSYNCRO: case SOUND_PCM_READ_RATE: + return put_user(s->dac1rate, (int *)arg); + case SOUND_PCM_READ_CHANNELS: + return put_user((s->sctrl & SCTRL_P1SMB) ? 2 : 1, (int *)arg); + case SOUND_PCM_READ_BITS: + return put_user((s->sctrl & SCTRL_P1SEB) ? 16 : 8, (int *)arg); + + case SOUND_PCM_WRITE_FILTER: + case SNDCTL_DSP_SETSYNCRO: case SOUND_PCM_READ_FILTER: return -EINVAL; @@ -2459,7 +2479,7 @@ cnt = count; if (cnt <= 0) { if (file->f_flags & O_NONBLOCK) - return ret ? ret : -EBUSY; + return ret ? ret : -EAGAIN; interruptible_sleep_on(&s->midi.iwait); if (signal_pending(current)) return ret ? ret : -ERESTARTSYS; @@ -2506,7 +2526,7 @@ cnt = count; if (cnt <= 0) { if (file->f_flags & O_NONBLOCK) - return ret ? ret : -EBUSY; + return ret ? ret : -EAGAIN; interruptible_sleep_on(&s->midi.owait); if (signal_pending(current)) return ret ? ret : -ERESTARTSYS; @@ -2712,7 +2732,7 @@ if (!pci_present()) /* No PCI bus in this machine! */ return -ENODEV; - printk(KERN_INFO "es1371: version v0.8 time " __TIME__ " " __DATE__ "\n"); + printk(KERN_INFO "es1371: version v0.11 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 || @@ -2736,7 +2756,7 @@ s->io = pcidev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK; s->irq = pcidev->irq; if (check_region(s->io, ES1371_EXTENT)) { - printk(KERN_ERR "es1371: io ports %#x-%#x in use\n", s->io, s->io+ES1371_EXTENT-1); + printk(KERN_ERR "es1371: io ports %#lx-%#lx in use\n", s->io, s->io+ES1371_EXTENT-1); goto err_region; } request_region(s->io, ES1371_EXTENT, "es1371"); @@ -2744,7 +2764,7 @@ printk(KERN_ERR "es1371: irq %u in use\n", s->irq); goto err_irq; } - printk(KERN_INFO "es1371: found adapter at io %#06x irq %u\n" + printk(KERN_INFO "es1371: found adapter at io %#lx irq %u\n" KERN_INFO "es1371: features: joystick 0x%x\n", s->io, s->irq, joystick[index]); /* register devices */ if ((s->dev_audio = register_sound_dsp(&es1371_audio_fops, -1)) < 0) @@ -2796,6 +2816,7 @@ * be stuck high, and I've found no way to rectify this other than * power cycle) */ + wait_src_ready(s); outl(0, s->io+ES1371_REG_SRCONV); /* codec init */ wrcodec(s, 0x00, 0); /* reset codec */ diff -ur --new-file old/linux/drivers/sound/gus_card.c new/linux/drivers/sound/gus_card.c --- old/linux/drivers/sound/gus_card.c Thu Jan 7 18:24:00 1999 +++ new/linux/drivers/sound/gus_card.c Thu Mar 11 02:03:52 1999 @@ -44,8 +44,6 @@ void attach_gus_card(struct address_info *hw_config) { - if(request_irq(hw_config->irq, gusintr, 0, "Gravis Ultrasound", hw_config)<0) - printk(KERN_ERR "gus_card.c: Unable to allocate IRQ %d\n", hw_config->irq); gus_wave_init(hw_config); @@ -60,6 +58,9 @@ #ifdef CONFIG_MIDI gus_midi_init(hw_config); #endif + if(request_irq(hw_config->irq, gusintr, 0, "Gravis Ultrasound", hw_config)<0) + printk(KERN_ERR "gus_card.c: Unable to allocate IRQ %d\n", hw_config->irq); + } int probe_gus(struct address_info *hw_config) diff -ur --new-file old/linux/drivers/sound/lowlevel/awe_compat.h new/linux/drivers/sound/lowlevel/awe_compat.h --- old/linux/drivers/sound/lowlevel/awe_compat.h Thu Jan 7 18:24:00 1999 +++ new/linux/drivers/sound/lowlevel/awe_compat.h Mon Mar 8 00:22:06 1999 @@ -54,7 +54,7 @@ #include "../soundvers.h" #endif -#if SOUND_INTERNAL_VERSION >= 0x30803 +#if defined(SOUND_INTERNAL_VERSION) && SOUND_INTERNAL_VERSION >= 0x30803 /* OSS/Free-3.8 */ #define AWE_NO_PATCHMGR #define AWE_OSS38 @@ -151,18 +151,9 @@ #define my_malloc_memptr() _mem_start #define my_free(ptr) /* do nothing */ -static void *my_malloc(int size) -{ - char *ptr; - PERMANENT_MALLOC(ptr, char*, size, _mem_start); - return (void*)ptr; -} -#define my_kmalloc(size) my_malloc(size) -#define kfree(ptr) /* do nothing */ - /* allocate buffer only once */ #define INIT_TABLE(buffer,index,nums,type) {\ -buffer = my_malloc(sizeof(type) * (nums)); index = (nums);\ +PERMANENT_MALLOC(buffer, char*, size, _mem_start); index = (nums);\ } #else @@ -173,8 +164,6 @@ #define my_malloc_memptr() 0 #define my_malloc(size) vmalloc(size) #define my_free(ptr) if (ptr) {vfree(ptr);} -#define my_kmalloc(size) kmalloc(size,GFP_KERNEL) -#define my_kfree(ptr) kfree(ptr) /* do not allocate buffer at beginning */ #define INIT_TABLE(buffer,index,nums,type) {buffer=NULL; index=0;} @@ -254,6 +243,14 @@ #define sound_unload_mididev(dev) /**/ #endif /* AWE_MODULE_SUPPORT */ + +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,0) +inline static void interruptible_sleep_on_timeout(struct wait_queue **q, unsigned long timeout) +{ + current->timeout = jiffies + timeout; + interruptible_sleep_on(q); +} +#endif #endif /* CONFIG_AWE32_SYNTH */ diff -ur --new-file old/linux/drivers/sound/lowlevel/awe_wave.c new/linux/drivers/sound/lowlevel/awe_wave.c --- old/linux/drivers/sound/lowlevel/awe_wave.c Wed Dec 16 21:52:01 1998 +++ new/linux/drivers/sound/lowlevel/awe_wave.c Mon Mar 8 00:22:06 1999 @@ -2,9 +2,9 @@ * sound/awe_wave.c * * The low level driver for the AWE32/SB32/AWE64 wave table synth. - * version 0.4.3; Nov. 1, 1998 + * version 0.4.3; Feb. 1, 1999 * - * Copyright (C) 1996-1998 Takashi Iwai + * Copyright (C) 1996-1999 Takashi Iwai * * 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 @@ -204,16 +204,20 @@ #if defined(AWE_MODULE_SUPPORT) && defined(MODULE) /* replace awe_port variable with exported variable */ #define awe_port io -#define BASEVAR_DECL /**/ +#define awe_mem_size memsize +int io = AWE_DEFAULT_BASE_ADDR; /* Emu8000 base address */ +int memsize = AWE_DEFAULT_MEM_SIZE; /* memory size in Kbytes */ +#ifdef MODULE_PARM +MODULE_PARM(io, "i"); +MODULE_PARM_DESC(io, "base i/o port of Emu8000"); +MODULE_PARM(memsize, "i"); +MODULE_PARM_DESC(memsize, "onboard DRAM size in Kbytes"); +#endif #else -#define BASEVAR_DECL static +static int awe_port = AWE_DEFAULT_BASE_ADDR; +static int awe_mem_size = AWE_DEFAULT_MEM_SIZE; #endif /* module */ -/* awe32 base address (overwritten at initialization) */ -BASEVAR_DECL int awe_port = AWE_DEFAULT_BASE_ADDR; -/* memory byte size */ -BASEVAR_DECL int memsize = AWE_DEFAULT_MEM_SIZE; /* for module option */ -static int awe_mem_size = -1; /* DRAM start offset */ static int awe_mem_start = AWE_DRAM_OFFSET; @@ -669,7 +673,7 @@ #include -BASEVAR_DECL int pnp = 1; /* use PnP as default */ +static int pnp = 1; /* use PnP as default */ #define AWE_NUM_CHIPS 3 static unsigned int pnp_ids[AWE_NUM_CHIPS] = { @@ -812,6 +816,7 @@ } #ifdef MODULE_PARM +EXPORT_NO_SYMBOLS; MODULE_AUTHOR("Takashi Iwai "); MODULE_DESCRIPTION("SB AWE32/64 WaveTable driver"); MODULE_SUPPORTED_DEVICE("sound"); @@ -975,23 +980,9 @@ #else static struct wait_queue *awe_sleeper = NULL; -static void awe_wakeup(unsigned long dummy) -{ - wake_up(&awe_sleeper); -} - -static struct timer_list awe_timer = -{NULL, NULL, 0, 0, awe_wakeup}; - static void awe_wait(unsigned short delay) { - unsigned long flags; - awe_timer.expires = jiffies + (HZ * (unsigned long)delay + 44099) / 44100; - add_timer(&awe_timer); - save_flags (flags); - cli(); - sleep_on(&awe_sleeper); - restore_flags(flags); + interruptible_sleep_on_timeout(&awe_sleeper, (HZ * (unsigned long)delay + 44099) / 44100); } #endif /* wait by loop */ @@ -1553,7 +1544,7 @@ vp->parm.moddcysus)); if (parm->volatk >= 0x80 && parm->voldelay >= 0x8000) { - awe_poke(AWE_ENVVAL(voice), 0xBFFF); + awe_poke(AWE_ENVVOL(voice), 0xBFFF); vtarget = voltarget[voices[voice].avol%0x10]>>(voices[voice].avol>>4); } else { awe_poke(AWE_ENVVOL(voice), @@ -3268,7 +3259,7 @@ sf_list *sf; /* search for all sharing lists */ - for (sf_id = rec->v.sf_id; sf_id > 0; sf_id = sf->shared) { + for (sf_id = rec->v.sf_id; sf_id > 0 && sf_id <= current_sf_id; sf_id = sf->shared) { sf = &sflists[sf_id - 1]; for (j = sf->infos; j >= 0; j = infos[j].next) { awe_voice_list *p = &infos[j]; @@ -4201,7 +4192,7 @@ if (id1 < id2) { /* make sure id1 > id2 */ int tmp; tmp = id1; id1 = id2; id2 = tmp; } - for (i = sflists[id1-1].shared; i > 0; i = sflists[i-1].shared) { + for (i = sflists[id1-1].shared; i > 0 && i <= current_sf_id; i = sflists[i-1].shared) { if (i == id2) return TRUE; } @@ -4223,10 +4214,10 @@ return i; } #ifdef AWE_ALLOW_SAMPLE_SHARING - if (sflists[sf-1].shared) { /* search recursively */ + if ((i = sflists[sf-1].shared) > 0 && i <= current_sf_id) { /* search recursively */ if (level > current_sf_id) return -1; /* strange sharing loop.. quit */ - return search_sample_index(sflists[sf-1].shared, sample, level + 1); + return search_sample_index(i, sample, level + 1); } #endif return -1; @@ -4272,10 +4263,12 @@ note <= infos[rec].v.high && velocity >= infos[rec].v.vellow && velocity <= infos[rec].v.velhigh) { - vlist[nvoices] = &infos[rec].v; - if (infos[rec].type == V_ST_MAPPED) /* mapper */ + if (infos[rec].type == V_ST_MAPPED) { + /* mapper */ + vlist[0] = &infos[rec].v; return -1; - nvoices++; + } + vlist[nvoices++] = &infos[rec].v; if (nvoices >= AWE_MAX_VOICES) break; } @@ -5009,8 +5002,6 @@ DEBUG(0,printk("AWE32 not found\n")); return 0; } - if (memsize >= 0) /* given by config file or module option */ - awe_mem_size = memsize * 1024; /* convert to Kbytes */ return 1; } @@ -5028,8 +5019,13 @@ static void awe_check_dram(void) { - if (awe_mem_size >= 0) /* already initialized */ + if (awe_present) /* already initialized */ return; + + if (awe_mem_size >= 0) { /* given by config file or module option */ + awe_mem_size *= 1024; /* convert to Kbytes */ + return; + } awe_open_dram_for_check(); diff -ur --new-file old/linux/drivers/sound/mad16.c new/linux/drivers/sound/mad16.c --- old/linux/drivers/sound/mad16.c Thu Jan 7 18:24:00 1999 +++ new/linux/drivers/sound/mad16.c Mon Mar 8 00:22:06 1999 @@ -800,7 +800,7 @@ mad_write(MC3_PORT, tmp | 0x04); hw_config->driver_use_1 = SB_MIDI_ONLY; - return sb_dsp_detect(hw_config); + return sb_dsp_detect(hw_config, 0, 0); #else return 0; #endif diff -ur --new-file old/linux/drivers/sound/midi_synth.c new/linux/drivers/sound/midi_synth.c --- old/linux/drivers/sound/midi_synth.c Thu May 14 19:33:17 1998 +++ new/linux/drivers/sound/midi_synth.c Sun Mar 21 16:11:37 1999 @@ -12,6 +12,7 @@ */ /* * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) + * Andrew Veliath : fixed running status in MIDI input state machine */ #include @@ -83,7 +84,7 @@ case 0xE0: STORE(SEQ_BENDER(synthno, msg[0] & 0x0f, - (msg[1] % 0x7f) | ((msg[2] & 0x7f) << 7))); + (msg[1] & 0x7f) | ((msg[2] & 0x7f) << 7))); break; default: @@ -196,13 +197,19 @@ inc->m_left = len_tab[(data >> 4) - 8]; inc->m_buf[0] = inc->m_prev_status = data; } - } else if (inc->m_prev_status & 0x80) /* Ignore if no previous status (yet) */ - { /* Data byte (use running status) */ - inc->m_state = MST_DATA; + } else if (inc->m_prev_status & 0x80) { + /* Data byte (use running status) */ inc->m_ptr = 2; - inc->m_left = len_tab[(data >> 4) - 8] - 1; - inc->m_buf[0] = inc->m_prev_status; inc->m_buf[1] = data; + inc->m_buf[0] = inc->m_prev_status; + inc->m_left = len_tab[(inc->m_buf[0] >> 4) - 8] - 1; + if (inc->m_left > 0) + inc->m_state = MST_DATA; /* Not done yet */ + else { + inc->m_state = MST_INIT; + do_midi_msg(dev, inc->m_buf, inc->m_ptr); + inc->m_ptr = 0; + } } break; /* MST_INIT */ diff -ur --new-file old/linux/drivers/sound/sb.h new/linux/drivers/sound/sb.h --- old/linux/drivers/sound/sb.h Fri Jan 15 07:59:47 1999 +++ new/linux/drivers/sound/sb.h Tue Apr 13 01:18:27 1999 @@ -47,17 +47,14 @@ #define MDL_AZTECH 13 /* Aztech Sound Galaxy family */ #define MDL_ES1868MIDI 14 /* MIDI port of ESS1868 */ #define MDL_AEDSP 15 /* Audio Excel DSP 16 */ +#define MDL_ESSPCI 16 /* ESS PCI card */ +#define MDL_YMPCI 17 /* Yamaha PCI sb in emulation */ -#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_ES1887 0x14 /* Subtype ES1887 for specific handling */ -#define SUBMDL_ES1888 0x14 /* Subtype ES1888 for specific handling */ #define SUBMDL_ALS007 42 /* ALS-007 differs from SB16 only in mixer */ /* register assignment */ #define SUBMDL_ALS100 43 /* ALS-100 allows sampling rates of up */ /* to 48kHz */ + /* * Config flags */ @@ -66,6 +63,7 @@ #define SB_NO_AUDIO 0x00000004 #define SB_NO_RECORDING 0x00000008 /* No audio recording */ #define SB_MIDI_ONLY (SB_NO_AUDIO|SB_NO_MIXER) +#define SB_PCI_IRQ 0x00000010 /* PCI shared IRQ */ struct mixer_def { unsigned int regno: 8; @@ -92,6 +90,8 @@ int base; int irq; int dma8, dma16; + + int pcibase; /* For ESS Maestro etc */ /* State variables */ int opened; @@ -134,13 +134,24 @@ void (*midi_input_intr) (int dev, unsigned char data); void *midi_irq_cookie; /* IRQ cookie for the midi */ } sb_devc; + +/* + * PCI card types + */ +#define SB_PCI_ESSMAESTRO 1 /* ESS Maestro Legacy */ +#define SB_PCI_YAMAHA 2 /* Yamaha Legacy */ + +/* + * Functions + */ + int sb_dsp_command (sb_devc *devc, unsigned char val); int sb_dsp_get_byte(sb_devc * devc); int sb_dsp_reset (sb_devc *devc); void sb_setmixer (sb_devc *devc, unsigned int port, unsigned int value); unsigned int sb_getmixer (sb_devc *devc, unsigned int port); -int sb_dsp_detect (struct address_info *hw_config); +int sb_dsp_detect (struct address_info *hw_config, int pci, int pciio); int sb_dsp_init (struct address_info *hw_config); void sb_dsp_unload(struct address_info *hw_config, int sbmpu); int sb_mixer_init(sb_devc *devc); diff -ur --new-file old/linux/drivers/sound/sb_card.c new/linux/drivers/sound/sb_card.c --- old/linux/drivers/sound/sb_card.c Thu Jan 28 19:58:47 1999 +++ new/linux/drivers/sound/sb_card.c Tue Apr 13 01:18:27 1999 @@ -103,7 +103,7 @@ printk(KERN_ERR "sb_card: I/O port %x is already in use\n\n", hw_config->io_base); return 0; } - return sb_dsp_detect(hw_config); + return sb_dsp_detect(hw_config, 0, 0); } void unload_sb(struct address_info *hw_config) @@ -113,7 +113,7 @@ } int sb_be_quiet=0; -int esstype = 0; /* ESS chip type */ +extern int esstype; /* ESS chip type */ #ifdef MODULE @@ -130,13 +130,14 @@ int io = -1; int irq = -1; int dma = -1; -int dma16 = -1; /* Set this for modules that need it */ -int type = 0; /* Can set this to a specific card type */ -int mad16 = 0; /* Set mad16=1 to load this as support for mad16 */ -int trix = 0; /* Set trix=1 to load this as support for trix */ -int pas2 = 0; /* Set pas2=1 to load this as support for pas2 */ +int dma16 = -1; /* Set this for modules that need it */ +int type = 0; /* Can set this to a specific card type */ +int mad16 = 0; /* Set mad16=1 to load this as support for mad16 */ +int trix = 0; /* Set trix=1 to load this as support for trix */ +int pas2 = 0; /* Set pas2=1 to load this as support for pas2 */ +int support = 0; /* Set support to load this as a support module */ int sm_games = 0; /* Mixer - see sb_mixer.c */ -int acer = 0; /* Do acer notebook init */ +int acer = 0; /* Do acer notebook init */ MODULE_PARM(io, "i"); MODULE_PARM(irq, "i"); @@ -145,6 +146,7 @@ MODULE_PARM(mpu_io, "i"); MODULE_PARM(type, "i"); MODULE_PARM(mad16, "i"); +MODULE_PARM(support, "i"); MODULE_PARM(trix, "i"); MODULE_PARM(pas2, "i"); MODULE_PARM(sm_games, "i"); @@ -156,7 +158,7 @@ { printk(KERN_INFO "Soundblaster audio driver Copyright (C) by Hannu Savolainen 1993-1996\n"); - if (mad16 == 0 && trix == 0 && pas2 == 0) + if (mad16 == 0 && trix == 0 && pas2 == 0 && support == 0) { if (io == -1 || dma == -1 || irq == -1) { @@ -191,7 +193,7 @@ { if (smw_free) vfree(smw_free); - if (!mad16 && !trix && !pas2) + if (!mad16 && !trix && !pas2 && !support) unload_sb(&config); if (sbmpu) unload_sbmpu(&config_mpu); @@ -220,5 +222,8 @@ EXPORT_SYMBOL(probe_sb); EXPORT_SYMBOL(unload_sb); EXPORT_SYMBOL(sb_be_quiet); +EXPORT_SYMBOL(attach_sbmpu); +EXPORT_SYMBOL(probe_sbmpu); +EXPORT_SYMBOL(unload_sbmpu); #endif diff -ur --new-file old/linux/drivers/sound/sb_common.c new/linux/drivers/sound/sb_common.c --- old/linux/drivers/sound/sb_common.c Mon Jan 25 07:04:02 1999 +++ new/linux/drivers/sound/sb_common.c Tue Apr 13 01:18:27 1999 @@ -179,13 +179,25 @@ status = inb(DSP_DATA_AVL16); } +static void pci_intr(sb_devc *devc) +{ + int src = inb(devc->pcibase+0x1A); + src&=3; + if(src) + sb_intr(devc); +} + static void sbintr(int irq, void *dev_id, struct pt_regs *dummy) { - sb_devc *devc = dev_id; + sb_devc *devc = dev_id; devc->irq_ok = 1; switch (devc->model) { + case MDL_ESSPCI: + pci_intr (devc); + break; + case MDL_ESS: ess_intr (devc); break; @@ -249,7 +261,7 @@ } } } - DDB(printk("DSP version %d.%d\n", devc->major, devc->minor)); + DDB(printk("DSP version %d.%02d\n", devc->major, devc->minor)); restore_flags(flags); } @@ -478,7 +490,7 @@ #endif } -int sb_dsp_detect(struct address_info *hw_config) +int sb_dsp_detect(struct address_info *hw_config, int pci, int pciio) { sb_devc sb_info; sb_devc *devc = &sb_info; @@ -508,7 +520,26 @@ devc->dma8 = hw_config->dma; devc->dma16 = -1; - + devc->pcibase = pciio; + + if(pci == SB_PCI_ESSMAESTRO) + { + devc->model = MDL_ESSPCI; + devc->caps |= SB_PCI_IRQ; + hw_config->driver_use_1 |= SB_PCI_IRQ; + hw_config->card_subtype = MDL_ESSPCI; + } + + if(pci == SB_PCI_YAMAHA) + { + devc->model = MDL_YMPCI; + devc->caps |= SB_PCI_IRQ; + hw_config->driver_use_1 |= SB_PCI_IRQ; + hw_config->card_subtype = MDL_YMPCI; + + printk("Yamaha PCI mode.\n"); + } + if (acer) { cli(); @@ -569,6 +600,16 @@ } } } + + if(devc->type == MDL_ESSPCI) + devc->model = MDL_ESSPCI; + + if(devc->type == MDL_YMPCI) + { + printk("YMPCI selected\n"); + devc->model = MDL_YMPCI; + } + /* * Save device information for sb_dsp_init() */ @@ -581,7 +622,7 @@ return 0; } memcpy((char *) detected_devc, (char *) devc, sizeof(sb_devc)); - MDB(printk(KERN_INFO "SB %d.%d detected OK (%x)\n", devc->major, devc->minor, hw_config->io_base)); + MDB(printk(KERN_INFO "SB %d.%02d detected OK (%x)\n", devc->major, devc->minor, hw_config->io_base)); return 1; } @@ -617,9 +658,17 @@ devc->caps = hw_config->driver_use_1; - if (!(devc->caps & SB_NO_AUDIO && devc->caps & SB_NO_MIDI) && hw_config->irq > 0) + if (!((devc->caps & SB_NO_AUDIO) && (devc->caps & SB_NO_MIDI)) && hw_config->irq > 0) { /* IRQ setup */ - if (request_irq(hw_config->irq, sbintr, 0, "soundblaster", devc) < 0) + + /* + * ESS PCI cards do shared PCI IRQ stuff. Since they + * will get shared PCI irq lines we must cope. + */ + + int i=(devc->caps&SB_PCI_IRQ)?SA_SHIRQ:0; + + if (request_irq(hw_config->irq, sbintr, i, "soundblaster", devc) < 0) { printk(KERN_ERR "SB: Can't allocate IRQ%d\n", hw_config->irq); return 0; @@ -768,7 +817,7 @@ if (hw_config->name == NULL) hw_config->name = "Sound Blaster (8 BIT/MONO ONLY)"; - sprintf(name, "%s (%d.%d)", hw_config->name, devc->major, devc->minor); + sprintf(name, "%s (%d.%02d)", hw_config->name, devc->major, devc->minor); conf_printf(name, hw_config); /* @@ -789,7 +838,7 @@ } else if (!sb_be_quiet && devc->model == MDL_SBPRO) { - printk(KERN_INFO "SB DSP version is just %d.%d which means that your card is\n", devc->major, devc->minor); + printk(KERN_INFO "SB DSP version is just %d.%02d which means that your card is\n", devc->major, devc->minor); printk(KERN_INFO "several years old (8 bit only device) or alternatively the sound driver\n"); printk(KERN_INFO "is incorrectly configured.\n"); } @@ -1194,6 +1243,10 @@ return 0; break; + case MDL_YMPCI: + hw_config->name = "Yamaha PCI Legacy"; + printk("Yamaha PCI legacy UART401 check.\n"); + break; default: return 0; } diff -ur --new-file old/linux/drivers/sound/sb_ess.c new/linux/drivers/sound/sb_ess.c --- old/linux/drivers/sound/sb_ess.c Mon Jan 25 22:44:17 1999 +++ new/linux/drivers/sound/sb_ess.c Mon May 10 22:01:21 1999 @@ -1,9 +1,46 @@ +#undef FKS_LOGGING +#undef FKS_TEST + /* - * Created: 9-Jan-1999 + * tabs should be 4 spaces, in vi(m): set tabstop=4 * * TODO: consistency speed calculations!! + * cleanup! * ????: Did I break MIDI support? * + * History: + * + * Rolf Fokkens (Dec 20 1998): ES188x recording level support on a per + * fokkensr@vertis.nl input basis. + * (Dec 24 1998): Recognition of ES1788, ES1887, ES1888, + * ES1868, ES1869 and ES1878. Could be used for + * specific handling in the future. All except + * ES1887 and ES1888 and ES688 are handled like + * ES1688. + * (Dec 27 1998): RECLEV for all (?) ES1688+ chips. ES188x now + * have the "Dec 20" support + RECLEV + * (Jan 2 1999): Preparation for Full Duplex. This means + * Audio 2 is now used for playback when dma16 + * is specified. The next step would be to use + * Audio 1 and Audio 2 at the same time. + * (Jan 9 1999): Put all ESS stuff into sb_ess.[ch], this + * includes both the ESS stuff that has been in + * sb_*[ch] before I touched it and the ESS support + * I added later + * (Jan 23 1999): Full Duplex seems to work. I wrote a small + * test proggy which works OK. Haven't found + * any applications to test it though. So why did + * I bother to create it anyway?? :) Just for + * fun. + * (May 2 1999): I tried to be too smart by "introducing" + * ess_calc_best_speed (). The idea was that two + * dividers could be used to setup a samplerate, + * ess_calc_best_speed () would choose the best. + * This works for playback, but results in + * recording problems for high samplerates. I + * fixed this by removing ess_calc_best_speed () + * and just doing what the documentation says. + * * 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 * file adds features like: @@ -19,27 +56,13 @@ * * ESS detection isn't full proof (yet). If it fails an additional module * parameter esstype can be specified to be one of the following: - * 688, 1688, 1868, 1869, 1788, 1887, 1888 - * - * History: - * - * Rolf Fokkens (Dec 20 1998): ES188x recording level support on a per - * input basis. - * (Dec 24 1998): Recognition of ES1788, ES1887, ES1888, - * ES1868, ES1869 and ES1878. Could be used for - * specific handling in the future. All except - * ES1887 and ES1888 and ES688 are handled like - * ES1688. - * (Dec 27 1998): RECLEV for all (?) ES1688+ chips. ES188x now - * have the "Dec 20" support + RECLEV - * (jan 2 1999): Preparation for Full Duplex. This means - * Audio 2 is now used for playback when dma16 - * is specified. The next step would be to use - * Audio 1 and Audio 2 at the same time. + * -1, 0, 688, 1688, 1868, 1869, 1788, 1887, 1888 + * -1 means: mimic 2.0 behaviour, + * 0 means: auto detect. + * others: explicitly specify chip + * -1 is default, cause auto detect still doesn't work. */ -#undef FKS_LOGGING - /* * About the documentation * @@ -156,13 +179,25 @@ * ES1946 yes This is a PCI chip; not handled by this driver */ +#include + #include "sound_config.h" #include "sb_mixer.h" #include "sb.h" #include "sb_ess.h" -extern int esstype; /* module parameter in sb_card.c */ +#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 */ + +#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_ES1887 0x14 /* Subtype ES1887 for specific handling */ +#define SUBMDL_ES1888 0x15 /* Subtype ES1888 for specific handling */ #ifdef FKS_LOGGING static void ess_show_mixerregs (sb_devc *devc); @@ -288,6 +323,7 @@ return retval; } +#ifdef OBSOLETE static int ess_calc_best_speed (int clock1, int rev1, int clock2, int rev2, int *divp, int *speedp) { @@ -311,6 +347,7 @@ return retval; } +#endif /* * Depending on the audiochannel ESS devices can @@ -322,7 +359,7 @@ */ static void ess_common_speed (sb_devc *devc, int *speedp, int *divp) { - int diff = 0, div, choice; + int diff = 0, div; if (devc->duplex) { /* @@ -330,8 +367,11 @@ */ div = 0x80 | ess_calc_div (795500, 128, speedp, &diff); } else { - choice = ess_calc_best_speed (397700, 128, 795500, 256, &div, speedp); - if (choice == 2) div |= 0x80; + if (*speedp > 22000) { + div = 0x80 | ess_calc_div (795500, 256, speedp, &diff); + } else { + div = 0x00 | ess_calc_div (397700, 128, speedp, &diff); + } } *divp = div; } @@ -370,45 +410,6 @@ } } -#if 0 -static void ess_speed(sb_devc * devc) -{ - int divider; - unsigned char bits = 0; - int speed = devc->speed; - - if (speed < 4000) - speed = 4000; - else if (speed > 48000) - speed = 48000; - - if (speed > 22000) - { - bits = 0x80; - divider = 256 - (795500 + speed / 2) / speed; - } - else - { - divider = 128 - (397700 + speed / 2) / speed; - } - - bits |= (unsigned char) divider; - - ess_write (devc, 0xa1, bits); - - /* - * Set filter divider register - */ - - speed = (speed * 9) / 20; /* Set filter roll-off to 90% of speed/2 */ - divider = 256 - 7160000 / (speed * 82); - - ess_write (devc, 0xa2, divider); - - return; -} -#endif - static int ess_audio_prepare_for_input(int dev, int bsize, int bcount) { sb_devc *devc = audio_devs[dev]->devc; @@ -931,6 +932,29 @@ return ess_common_set_irq_hw (devc); } +#ifdef FKS_TEST + +/* + * FKS_test: + * for ES1887: 00, 18, non wr bits: 0001 1000 + * for ES1868: 00, b8, non wr bits: 1011 1000 + * for ES1888: 00, f8, non wr bits: 1111 1000 + * for ES1688: 00, f8, non wr bits: 1111 1000 + * + ES968 + */ + +static void FKS_test (sb_devc * devc) +{ + int val1, val2; + val1 = ess_getmixer (devc, 0x64); + ess_setmixer (devc, 0x64, ~val1); + val2 = ess_getmixer (devc, 0x64) ^ ~val1; + ess_setmixer (devc, 0x64, val1); + val1 ^= ess_getmixer (devc, 0x64); +printk (KERN_INFO "FKS: FKS_test %02x, %02x\n", (val1 & 0x0ff), (val2 & 0x0ff)); +}; +#endif + static unsigned int ess_identify (sb_devc * devc) { unsigned int val; @@ -1025,42 +1049,55 @@ if (ess_major == 0x68 && (ess_minor & 0xf0) == 0x80) { char *chip = NULL; + int submodel = -1; - if (esstype) { - int submodel = -1; - - switch (esstype) { - case 688: - submodel = 0x00; - break; - case 1688: - submodel = 0x08; - break; - case 1868: - submodel = SUBMDL_ES1868; - break; - case 1869: - submodel = SUBMDL_ES1869; - break; - case 1788: - submodel = SUBMDL_ES1788; - break; - case 1887: - submodel = SUBMDL_ES1887; - break; - case 1888: - submodel = SUBMDL_ES1888; - break; - }; - if (submodel != -1) { - devc->submodel = submodel; - sprintf (modelname, "ES%d", esstype); - chip = modelname; - }; + switch (esstype) { + case ESSTYPE_DETECT: + case ESSTYPE_LIKE20: + break; + case 688: + submodel = 0x00; + break; + case 1688: + submodel = 0x08; + break; + case 1868: + submodel = SUBMDL_ES1868; + break; + case 1869: + submodel = SUBMDL_ES1869; + break; + case 1788: + submodel = SUBMDL_ES1788; + break; + case 1887: + submodel = SUBMDL_ES1887; + break; + case 1888: + submodel = SUBMDL_ES1888; + break; + default: + printk (KERN_ERR "Invalid esstype=%d specified\n", esstype); + return 0; + }; + if (submodel != -1) { + devc->submodel = submodel; + sprintf (modelname, "ES%d", esstype); + chip = modelname; }; if (chip == NULL && (ess_minor & 0x0f) < 8) { chip = "ES688"; }; +#ifdef FKS_TEST +FKS_test (devc); +#endif + /* + * If Nothing detected yet, and we want 2.0 behaviour... + * Then let's assume it's ES1688. + */ + if (chip == NULL && esstype == ESSTYPE_LIKE20) { + chip = "ES1688"; + }; if (chip == NULL) { int type; @@ -1080,6 +1117,10 @@ chip = "ES1878"; devc->submodel = SUBMDL_ES1878; break; + default: + if ((type & 0x00ff) != ((type >> 8) & 0x00ff)) { + printk ("ess_init: Unrecognized %04x\n", type); + } }; }; #if 0 @@ -1116,6 +1157,18 @@ if (chip == NULL) { chip = "ES1688"; }; + + printk ( KERN_INFO "ESS chip %s %s%s\n" + , chip + , ( esstype == ESSTYPE_DETECT || esstype == ESSTYPE_LIKE20 + ? "detected" + : "specified" + ) + , ( esstype == ESSTYPE_LIKE20 + ? " (kernel 2.0 compatible)" + : "" + ) + ); sprintf(name,"ESS %s AudioDrive (rev %d)", chip, ess_minor & 0x0f); } else { diff -ur --new-file old/linux/drivers/sound/sb_mixer.c new/linux/drivers/sound/sb_mixer.c --- old/linux/drivers/sound/sb_mixer.c Sat Jan 23 19:45:25 1999 +++ new/linux/drivers/sound/sb_mixer.c Tue Apr 13 01:18:27 1999 @@ -673,6 +673,8 @@ switch (devc->model) { + case MDL_ESSPCI: + case MDL_YMPCI: case MDL_SBPRO: case MDL_AZTECH: case MDL_JAZZ: diff -ur --new-file old/linux/drivers/sound/sequencer.c new/linux/drivers/sound/sequencer.c --- old/linux/drivers/sound/sequencer.c Sat Jan 16 02:46:27 1999 +++ new/linux/drivers/sound/sequencer.c Mon Mar 8 00:22:06 1999 @@ -1105,7 +1105,7 @@ */ for (i = 0; i < max_mididev; i++) - if (!midi_opened[i]) + if (!midi_opened[i] && midi_devs[i]) { if ((retval = midi_devs[i]->open(i, mode, sequencer_midi_input, sequencer_midi_output)) >= 0) @@ -1411,7 +1411,7 @@ case SNDCTL_SEQ_TESTMIDI: if (__get_user(midi_dev, (int *)arg)) return -EFAULT; - if (midi_dev < 0 || midi_dev >= max_mididev) + if (midi_dev < 0 || midi_dev >= max_mididev || !midi_devs[midi_dev]) return -ENXIO; if (!midi_opened[midi_dev] && @@ -1529,7 +1529,7 @@ case SNDCTL_MIDI_INFO: if (get_user(dev, (int *)(&(((struct midi_info *)arg)->device)))) return -EFAULT; - if (dev < 0 || dev >= max_mididev) + if (dev < 0 || dev >= max_mididev || !midi_devs[dev]) return -ENXIO; midi_devs[dev]->info.device = dev; return copy_to_user(arg, &midi_devs[dev]->info, sizeof(struct midi_info))?-EFAULT:0; diff -ur --new-file old/linux/drivers/sound/sonicvibes.c new/linux/drivers/sound/sonicvibes.c --- old/linux/drivers/sound/sonicvibes.c Thu Jan 7 18:24:00 1999 +++ new/linux/drivers/sound/sonicvibes.c Tue Apr 13 01:18:27 1999 @@ -3,7 +3,7 @@ /* * sonicvibes.c -- S3 Sonic Vibes audio driver. * - * Copyright (C) 1998 Thomas Sailer (sailer@ife.ee.ethz.ch) + * Copyright (C) 1998-1999 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 @@ -51,6 +51,23 @@ * 16.12.98 0.9 Fix a few f_file & FMODE_ bugs * 06.01.99 0.10 remove the silly SA_INTERRUPT flag. * hopefully killed the egcs section type conflict + * 12.03.99 0.11 cinfo.blocks should be reset after GETxPTR ioctl. + * reported by Johan Maes + * 22.03.99 0.12 return EAGAIN instead of EBUSY when O_NONBLOCK + * read/write cannot be executed + * 05.04.99 0.13 added code to sv_read and sv_write which should detect + * lockups of the sound chip and revive it. This is basically + * an ugly hack, but at least applications using this driver + * won't hang forever. I don't know why these lockups happen, + * it might well be the motherboard chipset (an early 486 PCI + * board with ALI chipset), since every busmastering 100MB + * ethernet card I've tried (Realtek 8139 and Macronix tulip clone) + * exhibit similar behaviour (they work for a couple of packets + * and then lock up and can be revived by ifconfig down/up). + * 07.04.99 0.14 implemented the following ioctl's: SOUND_PCM_READ_RATE, + * 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 * */ @@ -251,7 +268,8 @@ int dev_dmfm; /* hardware resources */ - unsigned int iosb, ioenh, iosynth, iomidi, iogame, iodmaa, iodmac, irq; + unsigned long iosb, ioenh, iosynth, iomidi, iogame; /* long for SPARC */ + unsigned int iodmaa, iodmac, irq; /* mixer stuff */ struct { @@ -1293,8 +1311,20 @@ if (cnt <= 0) { start_adc(s); if (file->f_flags & O_NONBLOCK) - return ret ? ret : -EBUSY; - interruptible_sleep_on(&s->dma_adc.wait); + return ret ? ret : -EAGAIN; + if (!interruptible_sleep_on_timeout(&s->dma_adc.wait, HZ)) { + printk(KERN_DEBUG "sv: 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 */ + 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; @@ -1353,8 +1383,20 @@ if (cnt <= 0) { start_dac(s); if (file->f_flags & O_NONBLOCK) - return ret ? ret : -EBUSY; - interruptible_sleep_on(&s->dma_dac.wait); + return ret ? ret : -EAGAIN; + if (!interruptible_sleep_on_timeout(&s->dma_dac.wait, HZ)) { + printk(KERN_DEBUG "sv: 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); + 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; @@ -1431,8 +1473,6 @@ if (remap_page_range(vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot)) return -EAGAIN; db->mapped = 1; - vma->vm_file = file; - file->f_count++; return 0; } @@ -1648,7 +1688,7 @@ spin_lock_irqsave(&s->lock, flags); sv_update_ptr(s); cinfo.bytes = s->dma_adc.total_bytes; - cinfo.blocks = s->dma_adc.total_bytes >> s->dma_adc.fragshift; + 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; @@ -1661,7 +1701,7 @@ spin_lock_irqsave(&s->lock, flags); sv_update_ptr(s); cinfo.bytes = s->dma_dac.total_bytes; - cinfo.blocks = s->dma_dac.total_bytes >> s->dma_dac.fragshift; + 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; @@ -1715,11 +1755,19 @@ s->dma_dac.subdivision = val; return 0; - case SOUND_PCM_WRITE_FILTER: - case SNDCTL_DSP_SETSYNCRO: 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) ? (SV_CFMT_STEREO << SV_CFMT_CSHIFT) + : (SV_CFMT_STEREO << SV_CFMT_ASHIFT))) ? 2 : 1, (int *)arg); + case SOUND_PCM_READ_BITS: + return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (SV_CFMT_16BIT << SV_CFMT_CSHIFT) + : (SV_CFMT_16BIT << SV_CFMT_ASHIFT))) ? 16 : 8, (int *)arg); + + case SOUND_PCM_WRITE_FILTER: + case SNDCTL_DSP_SETSYNCRO: case SOUND_PCM_READ_FILTER: return -EINVAL; @@ -1841,7 +1889,7 @@ cnt = count; if (cnt <= 0) { if (file->f_flags & O_NONBLOCK) - return ret ? ret : -EBUSY; + return ret ? ret : -EAGAIN; interruptible_sleep_on(&s->midi.iwait); if (signal_pending(current)) return ret ? ret : -ERESTARTSYS; @@ -1888,7 +1936,7 @@ cnt = count; if (cnt <= 0) { if (file->f_flags & O_NONBLOCK) - return ret ? ret : -EBUSY; + return ret ? ret : -EAGAIN; interruptible_sleep_on(&s->midi.owait); if (signal_pending(current)) return ret ? ret : -ERESTARTSYS; @@ -2273,7 +2321,7 @@ if (!pci_present()) /* No PCI bus in this machine! */ return -ENODEV; - printk(KERN_INFO "sv: version v0.10 time " __TIME__ " " __DATE__ "\n"); + printk(KERN_INFO "sv: version v0.14 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"); @@ -2327,7 +2375,7 @@ } pci_write_config_dword(pcidev, 0x40, s->iodmaa | 9); /* enable and use extended mode */ pci_write_config_dword(pcidev, 0x48, s->iodmac | 9); /* enable */ - printk(KERN_DEBUG "sv: io ports: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", + printk(KERN_DEBUG "sv: io ports: %#lx %#lx %#lx %#lx %#lx %#x %#x\n", s->iosb, s->ioenh, s->iosynth, s->iomidi, s->iogame, s->iodmaa, s->iodmac); if (s->ioenh == 0 || s->iodmaa == 0 || s->iodmac == 0) continue; @@ -2337,7 +2385,7 @@ pci_write_config_dword(pcidev, 0x60, wavetable_mem >> 12); /* wavetable base address */ if (check_region(s->ioenh, SV_EXTENT_ENH)) { - printk(KERN_ERR "sv: io ports %#x-%#x in use\n", s->ioenh, s->ioenh+SV_EXTENT_ENH-1); + printk(KERN_ERR "sv: io ports %#lx-%#lx in use\n", s->ioenh, s->ioenh+SV_EXTENT_ENH-1); goto err_region5; } request_region(s->ioenh, SV_EXTENT_ENH, "S3 SonicVibes PCM"); @@ -2352,12 +2400,12 @@ } request_region(s->iodmac, SV_EXTENT_DMA, "S3 SonicVibes DMAC"); if (check_region(s->iomidi, SV_EXTENT_MIDI)) { - printk(KERN_ERR "sv: io ports %#x-%#x in use\n", s->iomidi, s->iomidi+SV_EXTENT_MIDI-1); + printk(KERN_ERR "sv: io ports %#lx-%#lx in use\n", s->iomidi, s->iomidi+SV_EXTENT_MIDI-1); goto err_region2; } request_region(s->iomidi, SV_EXTENT_MIDI, "S3 SonicVibes Midi"); if (check_region(s->iosynth, SV_EXTENT_SYNTH)) { - printk(KERN_ERR "sv: io ports %#x-%#x in use\n", s->iosynth, s->iosynth+SV_EXTENT_SYNTH-1); + printk(KERN_ERR "sv: io ports %#lx-%#lx in use\n", s->iosynth, s->iosynth+SV_EXTENT_SYNTH-1); goto err_region1; } request_region(s->iosynth, SV_EXTENT_SYNTH, "S3 SonicVibes Synth"); @@ -2388,7 +2436,7 @@ printk(KERN_ERR "sv: irq %u in use\n", s->irq); goto err_irq; } - printk(KERN_INFO "sv: found adapter at io %#06x irq %u dmaa %#06x dmac %#06x revision %u\n", + printk(KERN_INFO "sv: found adapter at io %#lx irq %u dmaa %#06x dmac %#06x revision %u\n", s->ioenh, s->irq, s->iodmaa, s->iodmac, rdindir(s, SV_CIREVISION)); /* register devices */ if ((s->dev_audio = register_sound_dsp(&sv_audio_fops, -1)) < 0) diff -ur --new-file old/linux/drivers/sound/sound_core.c new/linux/drivers/sound/sound_core.c --- old/linux/drivers/sound/sound_core.c Sat Jan 16 02:46:27 1999 +++ new/linux/drivers/sound/sound_core.c Mon Mar 8 00:22:06 1999 @@ -39,7 +39,6 @@ #include #include #include -#include #include #include #include @@ -63,6 +62,10 @@ int n=low; if (index < 0) { /* first free */ + + while (*list && (*list)->unit_minornext); + while(n=top) - return -ENOMEM; + return -ENOENT; } else { n = low+(index*16); while (*list) { @@ -141,13 +144,13 @@ int r; struct sound_unit *s=(struct sound_unit *)kmalloc(sizeof(struct sound_unit), GFP_KERNEL); if(s==NULL) - return -1; + return -ENOMEM; spin_lock(&sound_loader_lock); r=__sound_insert_unit(s,list,fops,index,low,top); spin_unlock(&sound_loader_lock); - if(r==-1) + if(r<0) kfree(s); return r; } diff -ur --new-file old/linux/drivers/sound/soundcard.c new/linux/drivers/sound/soundcard.c --- old/linux/drivers/sound/soundcard.c Sat Jan 16 02:46:27 1999 +++ new/linux/drivers/sound/soundcard.c Mon Mar 8 00:22:06 1999 @@ -67,7 +67,11 @@ int sound_nblocks = 0; /* Persistent DMA buffers */ -int sound_dmap_flag = 0; /* Off by default */ +#ifdef CONFIG_SOUND_DMAP +int sound_dmap_flag = 1; +#else +int sound_dmap_flag = 0; +#endif static int soundcard_configured = 0; @@ -751,9 +755,6 @@ vma->vm_page_prot)) return -EAGAIN; - vma->vm_file = file; - file->f_count++; - dmap->mapping_flags |= DMA_MAP_MAPPED; if( audio_devs[dev]->d->mmap) @@ -802,13 +803,6 @@ return -1; } -static void destroy_special_devices(void) -{ - unregister_sound_special(6); - unregister_sound_special(1); - unregister_sound_special(8); -} - #ifdef MODULE static void #else @@ -849,11 +843,18 @@ #endif } +#ifdef MODULE + +static void destroy_special_devices(void) +{ + unregister_sound_special(6); + unregister_sound_special(1); + unregister_sound_special(8); +} + static int sound[20] = { 0 }; - -#ifdef MODULE int traceinit = 0; static int dmabuf = 0; diff -ur --new-file old/linux/drivers/sound/sscape.c new/linux/drivers/sound/sscape.c --- old/linux/drivers/sound/sscape.c Wed Nov 4 07:46:00 1998 +++ new/linux/drivers/sound/sscape.c Tue Apr 13 01:18:27 1999 @@ -943,7 +943,9 @@ mpu_config.irq = mpu_irq; mpu_config.io_base = mpu_io; - + /* WEH - Try to get right dma channel */ + mpu_config.dma = dma; + if(spea != -1) { old_hardware = spea; diff -ur --new-file old/linux/drivers/sound/sys_timer.c new/linux/drivers/sound/sys_timer.c --- old/linux/drivers/sound/sys_timer.c Thu May 14 19:33:17 1998 +++ new/linux/drivers/sound/sys_timer.c Mon Feb 1 23:04:42 1999 @@ -13,6 +13,7 @@ */ /* * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) + * Andrew Veliath : adapted tmr2ticks from level 1 sequencer (avoid overflow) */ #include @@ -39,11 +40,17 @@ tmr2ticks(int tmr_value) { /* - * Convert system timer ticks (HZ) to MIDI ticks - * (divide # of MIDI ticks/minute by # of system ticks/minute). + * Convert timer ticks to MIDI ticks */ - return ((tmr_value * curr_tempo * curr_timebase) + (30 * 100)) / (60 * HZ); + unsigned long tmp; + unsigned long scale; + + /* tmr_value (ticks per sec) * + 1000000 (usecs per sec) / HZ (ticks per sec) -=> usecs */ + tmp = tmr_value * (1000000 / HZ); + scale = (60 * 1000000) / (curr_tempo * curr_timebase); /* usecs per MIDI tick */ + return (tmp + scale / 2) / scale; } static void diff -ur --new-file old/linux/drivers/sound/trix.c new/linux/drivers/sound/trix.c --- old/linux/drivers/sound/trix.c Sun Dec 27 19:53:45 1998 +++ new/linux/drivers/sound/trix.c Mon Mar 8 00:22:06 1999 @@ -323,7 +323,7 @@ hw_config->name = "AudioTrix SB"; #ifdef CONFIG_SBDSP - return sb_dsp_detect(hw_config); + return sb_dsp_detect(hw_config, 0, 0); #else return 0; #endif diff -ur --new-file old/linux/drivers/usb/CREDITS new/linux/drivers/usb/CREDITS --- old/linux/drivers/usb/CREDITS Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/usb/CREDITS Tue May 11 19:04:03 1999 @@ -0,0 +1,154 @@ +Credits for the Simple Linux USB Driver: + +The following people have contributed to this code (in alphabetical +order by last name). I'm sure this list should be longer, its +difficult to maintain, add yourself with a patch if desired. + + Alan Cox + Johannes Erdfelt + ham + Bradley M Keryan + Vojtech Pavlik + Gregory P. Smith + Linus Torvalds + Roman Weissgaerber + + +Special thanks to: + + Inaky Perez Gonzalez for starting the + Linux USB driver effort and writing much of the larger uusbd driver. + Much has been learned from that effort. + + The NetBSD & FreeBSD USB developers. For being on the Linux USB list + and offering suggestions and sharing implementation experiences. + +Additional thanks to the following companies and people for donations +of hardware, support, time and development (this is from the original +THANKS file in Inaky's driver): + + The following corporations have helped us in the development +of Linux USB / UUSBD: + + - USAR Systems provided us with one of their excellent USB + Evaluation Kits. It allows us to test the Linux-USB driver + for compilance with the latest USB specification. USAR + Systems recognized the importance of an up-to-date open + Operating System and supports this project with + Hardware. Thanks!. + + - Thanks to Intel Corporation for their precious help. + + - We teamed up with Cherry to make Linux the first OS with + built-in USB support. Cherry is one of the biggest keyboard + makers in the world. + + - CMD Technology, Inc. sponsored us kindly donating a CSA-6700 + PCI-to-USB Controller Board to test the OHCI implementation. + + - Due to their support to us, Keytronic can be sure that they + will sell keyboards to some of the 3 million (at least) + Linux users. + + - Many thanks to ing büro h doran [http://www.ibhdoran.com]! + It was almost imposible to get a PC backplate USB connector + for the motherboard here at Europe (mine, home-made, was + quite lowsy :). Now I know where to adquire nice USB stuff! + + - Genius Germany donated a USB mouse to test the mouse boot + protocol. They've also donated a F-23 digital joystick and a + NetMouse Pro. Thanks! + + - AVM GmbH Berlin is supporting the development of the Linux + USB driver for the AVM ISDN Controller B1 USB. AVM is a + leading manufacturer for active and passive ISDN Controllers + and CAPI 2.0-based software. The active design of the AVM B1 + is open for all OS platforms, including Linux. + + - Thanks to Y-E Data, Inc. for donating their FlashBuster-U + USB Floppy Disk Drive, so we could test the bulk transfer + code. + + - Many thanks to Logitech for contributing a three axis USB + mouse. + + Logitech designs, manufactures and markets + Human Interface Devices, having a long history and + experience in making devices such as keyboards, mice, + trackballs, cameras, loudspeakers and control devices for + gaming and professional use. + + Being a recognized vendor and seller for all these devices, + they have donated USB mice, a joystick and a scanner, as a + way to acknowledge the importance of Linux and to allow + Logitech customers to enjoy support in their favorite + operating systems and all Linux users to use Logitech and + other USB hardware. + + Logitech is official sponsor of the Linux Conference on + Feb. 11th 1999 in Vienna, where we'll will present the + current state of the Linux USB effort. + + - CATC has provided means to uncover dark corners of the UHCI + inner workings with a USB Inspector. + + - Thanks to Entrega for providing PCI to USB cards, hubs and + converter products for development. + + + And thanks go to (hey! in no particular order :) + + - Oren Tirosh , for standing so patiently + all my doubts'bout USB and giving lots of cool ideas. + + - Jochen Karrer , for + pointing out mortal bugs and giving advice. + + - Edmund Humemberger , for it's great work on + public relationships and general management stuff for the + Linux-USB effort. + + - Alberto Menegazzi is starting the + documentation for the UUSBD. Go for it! + + - Ric Klaren for doing nice + introductory documents (compiting with Alberto's :). + + - Christian Groessler , for it's help on those + itchy bits ... :) + + - Paul MacKerras for polishing OHCI and pushing me harder for + the iMac support, giving improvements and enhancements. + + - Fernando Herrera has taken + charge of composing, maintaining and feeding the + long-awaited, unique and marvelous UUSBD FAQ! Tadaaaa!!! + + - Rasca Gmelch has revived the raw driver and + pointed bugs, as well as started the uusbd-utils package. + + - Peter Dettori is unconvering bugs like + crazy, as well as making cool suggestions, great :) + + - All the Free Software and Linux community, the FSF & the GNU + project, the MIT X consortium, the TeX people ... everyone! + You know who you are! + + - Big thanks to Richard Stallman for creating Emacs! + + - The people at the linux-usb mailing list, for reading so + many messages :) Ok, no more kidding; for all your advices! + + - All the people at the USB Implementors Forum for their + help and assistance. + + - Nathan Myers , for his advice! (hope you + liked Cibeles' party). + + - Linus Torvalds, for starting, developing and managing Linux. + + - Mike Smith, Craig Keithley, Thierry Giron and Janet Schank + for convincing me USB Standard hubs are not that standard + and that's good to allow for vendor specific quirks on the + standard hub driver. + diff -ur --new-file old/linux/drivers/usb/Config.in new/linux/drivers/usb/Config.in --- old/linux/drivers/usb/Config.in Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/usb/Config.in Mon May 10 19:18:34 1999 @@ -0,0 +1,30 @@ +# +# USB device configuration +# +# NOTE NOTE NOTE! This is still considered extremely experimental. +# Right now hubs, mice and keyboards work - at least with UHCI. +# But that may be more a lucky coincidence than anything else.. +# +# This was all developed modularly, but I've been lazy in cleaning +# it up, so right now they are all bools. +# +mainmenu_option next_comment +comment 'USB drivers - not for the faint of heart' + +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate 'Support for USB (EXPERIMENTAL!)' CONFIG_USB + if [ ! "$CONFIG_USB" = "n" ]; then + bool 'UHCI (intel PIIX4 and others) support?' CONFIG_USB_UHCI + bool 'OHCI (compaq and some others) support?' CONFIG_USB_OHCI + bool 'OHCI-HCD (other OHCI opt. Virt. Root Hub) support?' CONFIG_USB_OHCI_HCD + if [ "$CONFIG_USB_OHCI_HCD" = "y" ]; then + bool 'OHCI-HCD Virtual Root Hub' CONFIG_USB_OHCI_VROOTHUB + fi + + bool 'USB mouse support' CONFIG_USB_MOUSE + bool 'USB keyboard support' CONFIG_USB_KBD + bool 'USB audio parsing support' CONFIG_USB_AUDIO + fi +fi + +endmenu diff -ur --new-file old/linux/drivers/usb/Makefile new/linux/drivers/usb/Makefile --- old/linux/drivers/usb/Makefile Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/usb/Makefile Mon May 10 19:18:34 1999 @@ -0,0 +1,88 @@ +# +# Makefile for the kernel usb device drivers. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definitions are now inherited from the +# parent makes.. +# +# This isn't actually supported yet. Don't try to use it. + +SUB_DIRS := +MOD_SUB_DIRS := $(SUB_DIRS) +ALL_SUB_DIRS := $(SUB_DIRS) + +L_TARGET := usb.a +M_OBJS := +L_OBJS := +LX_OBJS := +USBX_OBJS := usb.o hub.o usb-debug.o + +ifeq ($(CONFIG_USB_MOUSE),y) + USBX_OBJS += mouse.o +endif + +ifeq ($(CONFIG_USB_KBD),y) + USBX_OBJS += keyboard.o keymap.o +endif + +ifeq ($(CONFIG_USB_AUDIO),y) + USBX_OBJS += audio.o +endif + +ifeq ($(CONFIG_USB), y) + L_OBJS += $(USBX_OBJS) +endif + +ifeq ($(CONFIG_USB_UHCI),y) + ifeq ($(CONFIG_USB), y) + L_OBJS += uhci.o uhci-debug.o + else + ifeq ($(CONFIG_USB),m) + M_OBJS += usb-uhci.o + MIX_OBJS += $(USBX_OBJS) + endif + endif +endif + +ifeq ($(CONFIG_USB_OHCI),y) + ifeq ($(CONFIG_USB), y) + L_OBJS += ohci.o ohci-debug.o + else + ifeq ($(CONFIG_USB),m) + USBO_OBJS += ohci.o ohci-debug.o + M_OBJS += usb-ohci.o + MIX_OBJS += $(USBX_OBJS) + endif + endif +endif + +ifeq ($(CONFIG_USB_OHCI_HCD),y) + ifeq ($(CONFIG_USB), y) + L_OBJS += ohci-hcd.o ohci-root-hub.o + else + ifeq ($(CONFIG_USB),m) + USBO_OBJS += ohci-hcd.o ohci-root-hub.o + M_OBJS += usb-ohci-hcd.o + MIX_OBJS += $(USBX_OBJS) + endif + endif +endif +include $(TOPDIR)/Rules.make + +keymap.o: keymap.c + +keymap.c: maps/serial.map maps/usb.map maps/fixup.map + ./mkmap > $@ + +usb-uhci.o: uhci.o uhci-debug.o $(USBX_OBJS) + $(LD) $(LD_RFLAG) -r -o $@ uhci.o uhci-debug.o $(USBX_OBJS) + +usb-ohci.o: ohci.o ohci-debug.o $(USBX_OBJS) + $(LD) $(LD_RFLAG) -r -o $@ ohci.o ohci-debug.o $(USBX_OBJS) + +usb-ohci-hcd.o: ohci-hcd.o ohci-root-hub.o $(USBX_OBJS) + $(LD) $(LD_RFLAG) -r -o $@ ohci-hcd.o ohci-root-hub.o $(USBX_OBJS) + diff -ur --new-file old/linux/drivers/usb/README.kbd new/linux/drivers/usb/README.kbd --- old/linux/drivers/usb/README.kbd Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/usb/README.kbd Wed Apr 21 19:29:09 1999 @@ -0,0 +1,65 @@ +This is a simple USB keyboard driver written from Linus' +USB driver (started with Greg's usb-0.03b.tar.gz source +tree) + +It works fine with my BTC keyboard but I'm still investigating +trouble with my MS keyboard (trouble starts with an inability +to set into boot protocol mode, though, this very well could +be all due to crappy hardware). + +Anyway, I would appreciate you taking a look if you have +any USB keyboards lying around. Oh also, I'm doing this on +UHCI so sorry if it breaks with OHCI. + +-ham + + + +Keyboard patch +-------------- + +Instead of using the multiple keyboard patch and then running into all +of the kernel version problems that the current Linux-USB project has +had, I'm just mapping the USB keycodes to the standard AT-101 keycodes +and sending them directly to "handle_scancode". + +This may or may not be considered a hack. Anyway it is effective, and +I think safe, and allows USB keyboards to coexist with a serial +keyboard (oh yeah, one side effect is that you can for example hold +down the control key on the serial keyboard and press "a" on the USB +keyboard and you get Control-a like with Windows USB) and works +fine for console and X. + +You do need to make a *tiny* patch the kernel source tree so that the +function "handle_scancode" is exported from keyboard.c though. + + $ cd /usr/src/linux + $ patch -p0 < kbd.patch + +And, of course, then, you need to rebuild and install the kernel. + +** [Vojtech]: Alternately, just 'insmod kbd-stub', if you don't want +to use the keyboard and are too lazy to patch the kernel. + +Keyboard map +------------ + +I'm including a stupid utility "mkmap" which generates the USB->serial +keymap. It takes in maps/serial.map (the current serial keymap, +generated by "dumpkeys"), maps/usb.map (the USB keymap), and +maps/fixup.map (fixes for e0 keys and misc.) and spits out keymap.c +Anyway, it is not beautiful but should serve its purpose for the +moment. + +Other changes +------------- +uhci.c: + * added a context value to the irq callback function + (this is exactly like the "dev_id" field to request_irq) + * played with uhci_reset_port to get better hot-plug results + (eg. do a wait_ms(200) before calling uhci_reset_port) +usb.c: + * disconnect all devices after uhci-control thread is killed + * skip over the HID descriptor + * disconnect the high-level driver in usb_disconnect + diff -ur --new-file old/linux/drivers/usb/README.ohci new/linux/drivers/usb/README.ohci --- old/linux/drivers/usb/README.ohci Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/usb/README.ohci Tue May 11 19:04:03 1999 @@ -0,0 +1,26 @@ +May 09, 1999 16:25:58 + +Cool, things are working "well" now. (I'm not getting oops's from the +OHCI code anyways.. ;). I can attach a usb hub and mouse in any +possible arrangement of the two and they get configured properly. + +You can see that the mouse Interrupt transfers are occuring and being +acknowledged because /proc/interrupts usb-ohci goes up accordingly with +mouse movements/events. That means the TD at least returns some data +and requeues itself. + +Device attach/detach from the root hub is not working well. Currently +every interrupt checks for root hub status changes and frame number +overflow interrupts are enabled. This means you shouldn't have to +wait more than 32-33 seconds for the change to occur, less if there is +other activity. (due to checking in the WDH caused interrupts) +My OHCI controller [SiS 5598 motherboard] doesn't seem to play well +with the RHSC interrupt so it has been disabled. The ohci_timer +should be polling but it not currently working, I haven't had time to +look into that problem. + +However, when I tried telling X to use /dev/psaux for the mouse my +machine locked up... + +- greg@electricrain.com + diff -ur --new-file old/linux/drivers/usb/README.ohci_hcd new/linux/drivers/usb/README.ohci_hcd --- old/linux/drivers/usb/README.ohci_hcd Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/usb/README.ohci_hcd Mon May 10 19:18:34 1999 @@ -0,0 +1,112 @@ + +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 -ur --new-file old/linux/drivers/usb/audio.c new/linux/drivers/usb/audio.c --- old/linux/drivers/usb/audio.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/usb/audio.c Wed Apr 28 20:14:03 1999 @@ -0,0 +1,126 @@ +#include +#include +#include +#include +#include +#include "usb.h" + +static int usb_audio_probe(struct usb_device *dev); +static void usb_audio_disconnect(struct usb_device *dev); +static LIST_HEAD(usb_audio_list); + +struct usb_audio +{ + struct usb_device *dev; + struct list_head list; +}; + +static struct usb_driver usb_audio_driver = +{ + "audio", + usb_audio_probe, + usb_audio_disconnect, + {NULL, NULL} +}; + + +static int usb_audio_irq(int state, void *buffer, void *dev_id) +{ + struct usb_audio *aud = (struct usb_audio*) dev_id; + return 1; +} + +static int usb_audio_probe(struct usb_device *dev) +{ + struct usb_interface_descriptor *interface; + struct usb_endpoint_descriptor *endpoint; + struct usb_audio *aud; + + int i; + int na=0; + + interface = &dev->config[0].interface[0]; + + for(i=0;iconfig[0].bNumInterfaces;i++) + { + int x; + + endpoint = &interface->endpoint[i]; + + if(interface->bInterfaceClass != 1) + continue; + + printk(KERN_INFO "USB audio device detected.\n"); + + switch(interface->bInterfaceSubClass) + { + case 0x01: + printk(KERN_INFO "audio: Control device.\n"); + break; + case 0x02: + printk(KERN_INFO "audio: streaming.\n"); + break; + case 0x03: + printk(KERN_INFO "audio: nonstreaming.\n"); + break; + } + na++; + } + + if(na==0) + return -1; + + aud = kmalloc(sizeof(struct usb_audio), GFP_KERNEL); + if(aud) + { + memset(aud, 0, sizeof(*aud)); + aud->dev = dev; + dev->private = aud; + + endpoint = &interface->endpoint[0]; + +// usb_set_configuration(dev, dev->config[0].bConfigurationValue); +// usb_set_protocol(dev, 0); +// usb_set_idle(dev, 0, 0); + + usb_request_irq(dev, + usb_rcvctrlpipe(dev, endpoint->bEndpointAddress), + usb_audio_irq, + endpoint->bInterval, + aud); + + list_add(&aud->list, &usb_audio_list); + } + return 0; +} + +static void usb_audio_disconnect(struct usb_device *dev) +{ + struct usb_audio *aud = (struct usb_audio*) dev->private; + if(aud) + { + dev->private = NULL; + list_del(&aud->list); + kfree(aud); + } + printk(KERN_INFO "USB audio driver removed.\n"); +} + +int usb_audio_init(void) +{ + usb_register(&usb_audio_driver); + return 0; +} + +/* + * Support functions for parsing + */ + +void usb_audio_interface(struct usb_interface_descriptor *interface, u8 *data) +{ +} + +void usb_audio_endpoint(struct usb_endpoint_descriptor *interface, u8 *data) +{ +} + diff -ur --new-file old/linux/drivers/usb/hub.c new/linux/drivers/usb/hub.c --- old/linux/drivers/usb/hub.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/usb/hub.c Fri Apr 30 17:20:01 1999 @@ -0,0 +1,422 @@ +/* + * USB hub driver. + * + * This is horrible, it knows about the UHCI driver + * internals, but it's just meant as a rough example, + * let's do the virtualization later when this works. + * + * (C) Copyright 1999 Linus Torvalds + * (C) Copyright 1999 Johannes Erdfelt + */ + +#include +#include +#include +#include +#include + +#include + +#include "usb.h" +#include "uhci.h" +#include "hub.h" + +extern struct usb_operations uhci_device_operations; + +/* Wakes up khubd */ +static struct wait_queue *usb_hub_wait = NULL; +static spinlock_t hub_event_lock = SPIN_LOCK_UNLOCKED; + +/* List of hubs needing servicing */ +static struct list_head hub_event_list; + +/* PID of khubd */ +static int khubd_pid = 0; + +/* + * A irq handler returns non-zero to indicate to + * the low-level driver that it wants to be re-activated, + * or zero to say "I'm done". + */ +static int hub_irq(int status, void *__buffer, void *dev_id) +{ + struct usb_hub *hub = dev_id; + unsigned long flags; + + if (waitqueue_active(&usb_hub_wait)) { + /* Add the hub to the event queue */ + spin_lock_irqsave(&hub_event_lock, flags); + if (hub->event_list.next == &hub->event_list) { + list_add(&hub->event_list, &hub_event_list); + /* Wake up khubd */ + wake_up(&usb_hub_wait); + } + spin_unlock_irqrestore(&hub_event_lock, flags); + } + + return 1; +} + +static void usb_hub_configure(struct usb_hub *hub) +{ + struct usb_device *dev = hub->dev; + unsigned char hubdescriptor[8], buf[4]; + int charac, i; + + usb_set_configuration(dev, dev->config[0].bConfigurationValue); + + if (usb_get_hub_descriptor(dev, hubdescriptor, 8)) + return; + + hub->nports = dev->maxchild = hubdescriptor[2]; + printk("hub: %d-port%s detected\n", hub->nports, + (hub->nports == 1) ? "" : "s"); + + charac = (hubdescriptor[4] << 8) + hubdescriptor[3]; + switch (charac & HUB_CHAR_LPSM) { + case 0x00: + printk("hub: ganged power switching\n"); + break; + case 0x01: + printk("hub: individual port power switching\n"); + break; + case 0x02: + case 0x03: + printk("hub: unknown reserved power switching mode\n"); + break; + } + + if (charac & HUB_CHAR_COMPOUND) + printk("hub: part of a compound device\n"); + else + printk("hub: standalone hub\n"); + + switch (charac & HUB_CHAR_OCPM) { + case 0x00: + printk("hub: global over current protection\n"); + break; + case 0x08: + printk("hub: individual port over current protection\n"); + break; + case 0x10: + case 0x18: + printk("hub: no over current protection\n"); + break; + } + + printk("hub: power on to power good time: %dms\n", + hubdescriptor[5] * 2); + + printk("hub: hub controller current requirement: %dmA\n", + hubdescriptor[6]); + + for (i = 0; i < dev->maxchild; i++) + printk("hub: port %d is%s removable\n", i + 1, + hubdescriptor[7 + ((i + 1)/8)] & (1 << ((i + 1) % 8)) + ? " not" : ""); + + if (usb_get_hub_status(dev, buf)) + return; + + printk("hub: local power source is %s\n", + (buf[0] & 1) ? "lost (inactive)" : "good"); + + printk("hub: %sover current condition exists\n", + (buf[0] & 2) ? "" : "no "); + +#if 0 + for (i = 0; i < hub->nports; i++) { + int portstat, portchange; + unsigned char portstatus[4]; + + if (usb_get_port_status(dev, i + 1, portstatus)) + return; + portstat = (portstatus[1] << 8) + portstatus[0]; + portchange = (portstatus[3] << 8) + portstatus[2]; + + printk("hub: port %d status\n", i + 1); + printk("hub: %sdevice present\n", (portstat & 1) ? "" : "no "); + printk("hub: %s\n", (portstat & 2) ? "enabled" : "disabled"); + printk("hub: %ssuspended\n", (portstat & 4) ? "" : "not "); + printk("hub: %sover current\n", (portstat & 8) ? "" : "not "); + printk("hub: has %spower\n", (portstat & 0x100) ? "" : "no "); + printk("hub: %s speed\n", (portstat & 0x200) ? "low" : "full"); + } +#endif + + /* Enable power to the ports */ + printk("enabling power on all ports\n"); + for (i = 0; i < hub->nports; i++) + usb_set_port_feature(dev, i + 1, USB_PORT_FEAT_POWER); +} + +static int hub_probe(struct usb_device *dev) +{ + struct usb_interface_descriptor *interface; + struct usb_endpoint_descriptor *endpoint; + struct usb_hub *hub; + + /* We don't handle multi-config hubs */ + if (dev->descriptor.bNumConfigurations != 1) + return -1; + + /* We don't handle multi-interface hubs */ + if (dev->config[0].bNumInterfaces != 1) + return -1; + + interface = &dev->config[0].interface[0]; + + /* Is it a hub? */ + if (interface->bInterfaceClass != 9) + return -1; + if ((interface->bInterfaceSubClass != 0) && + (interface->bInterfaceSubClass != 1)) + return -1; + + /* Multiple endpoints? What kind of mutant ninja-hub is this? */ + if (interface->bNumEndpoints != 1) + return -1; + + endpoint = &interface->endpoint[0]; + + /* Output endpoint? Curiousier and curiousier.. */ + if (!(endpoint->bEndpointAddress & 0x80)) + return -1; + + /* If it's not an interrupt endpoint, we'd better punt! */ + if ((endpoint->bmAttributes & 3) != 3) + return -1; + + /* We found a hub */ + printk("USB hub found\n"); + + if ((hub = kmalloc(sizeof(*hub), GFP_KERNEL)) == NULL) { + printk("couldn't kmalloc hub struct\n"); + return -1; + } + + memset(hub, 0, sizeof(*hub)); + + dev->private = hub; + + INIT_LIST_HEAD(&hub->event_list); + hub->dev = dev; + + usb_hub_configure(hub); + + usb_request_irq(dev, usb_rcvctrlpipe(dev, endpoint->bEndpointAddress), hub_irq, endpoint->bInterval, hub); + + /* Wake up khubd */ + wake_up(&usb_hub_wait); + + return 0; +} + +static void hub_disconnect(struct usb_device *dev) +{ + struct usb_hub *hub = dev->private; + unsigned long flags; + + spin_lock_irqsave(&hub_event_lock, flags); + + /* Delete it and then reset it */ + list_del(&hub->event_list); + INIT_LIST_HEAD(&hub->event_list); + + spin_unlock_irqrestore(&hub_event_lock, flags); + + /* Free the memory */ + kfree(hub); +} + +static void usb_hub_port_connect_change(struct usb_device *hub, int port) +{ + struct usb_device *usb; + unsigned char buf[4]; + unsigned short portstatus, portchange; + + usb_disconnect(&hub->children[port]); + + usb_set_port_feature(hub, port + 1, USB_PORT_FEAT_RESET); + + wait_ms(50); /* FIXME: This is from the *BSD stack, thanks! :) */ + + if (usb_get_port_status(hub, port + 1, buf)) { + printk("get_port_status failed\n"); + return; + } + + portstatus = *((unsigned short *)buf + 0); + portchange = *((unsigned short *)buf + 1); + + if ((!(portstatus & USB_PORT_STAT_CONNECTION)) && + (!(portstatus & USB_PORT_STAT_ENABLE))) { + /* We're done now, we already disconnected the device */ + /* printk("not connected/enabled\n"); */ + return; + } + + usb = hub->bus->op->allocate(hub); + if (!usb) { + printk("couldn't allocate usb_device\n"); + return; + } + + usb_connect(usb); + + usb->slow = (portstatus & USB_PORT_STAT_LOW_SPEED) ? 1 : 0; + + hub->children[port] = usb; + + usb_new_device(usb); +} + +static void usb_hub_events(void) +{ + unsigned long flags; + unsigned char buf[4]; + unsigned short portstatus, portchange; + int i; + struct list_head *next, *tmp, *head = &hub_event_list; + struct usb_device *dev; + struct usb_hub *hub; + + spin_lock_irqsave(&hub_event_lock, flags); + + tmp = head->next; + while (tmp != head) { + hub = list_entry(tmp, struct usb_hub, event_list); + dev = hub->dev; + + next = tmp->next; + + list_del(tmp); + INIT_LIST_HEAD(tmp); + + for (i = 0; i < hub->nports; i++) { + if (usb_get_port_status(dev, i + 1, buf)) { + printk("get_port_status failed\n"); + continue; + } + + portstatus = *((unsigned short *)buf + 0); + portchange = *((unsigned short *)buf + 1); + + if (portchange & USB_PORT_STAT_C_CONNECTION) { + printk("hub: port %d connection change\n", i + 1); + + usb_clear_port_feature(dev, i + 1, + USB_PORT_FEAT_C_CONNECTION); + + usb_hub_port_connect_change(dev, i); + } + + if (portchange & USB_PORT_STAT_C_ENABLE) { + printk("hub: port %d enable change\n", i + 1); + usb_clear_port_feature(dev, i + 1, + USB_PORT_FEAT_C_ENABLE); + } + + if (portchange & USB_PORT_STAT_C_SUSPEND) + printk("hub: port %d suspend change\n", i + 1); + + if (portchange & USB_PORT_STAT_C_OVERCURRENT) + printk("hub: port %d over-current change\n", i + 1); + + if (portchange & USB_PORT_STAT_C_RESET) { + printk("hub: port %d reset change\n", i + 1); + usb_clear_port_feature(dev, i + 1, + USB_PORT_FEAT_C_RESET); + } + +#if 0 + if (!portchange) + continue; + + if (usb_get_port_status(dev, i + 1, buf)) + return; + + portstatus = (buf[1] << 8) + buf[0]; + portchange = (buf[3] << 8) + buf[2]; + + printk("hub: port %d status\n", i + 1); + printk("hub: %sdevice present\n", (portstatus & 1) ? "" : "no "); + printk("hub: %s\n", (portstatus & 2) ? "enabled" : "disabled"); + printk("hub: %ssuspended\n", (portstatus & 4) ? "" : "not "); + printk("hub: %sover current\n", (portstatus & 8) ? "" : "not "); + printk("hub: has %spower\n", (portstatus & 0x100) ? "" : "no "); + printk("hub: %s speed\n", (portstatus & 0x200) ? "low" : "full"); +#endif + } + tmp = next; +#if 0 + wait_ms(1000); +#endif + } + + spin_unlock_irqrestore(&hub_event_lock, flags); +} + +static int usb_hub_thread(void *__hub) +{ + lock_kernel(); + + /* + * This thread doesn't need any user-level access, + * so get rid of all our resources + */ + printk("usb_hub_thread at %p\n", &usb_hub_thread); + exit_mm(current); + exit_files(current); + exit_fs(current); + + /* Setup a nice name */ + strcpy(current->comm, "khubd"); + + /* Send me a signal to get me die (for debugging) */ + do { + interruptible_sleep_on(&usb_hub_wait); + usb_hub_events(); + } while (!signal_pending(current)); + + printk("usb_hub_thread exiting\n"); + + return 0; +} + +static struct usb_driver hub_driver = { + "hub", + hub_probe, + hub_disconnect, + { NULL, NULL } +}; + +/* + * This should be a separate module. + */ +int hub_init(void) +{ + int pid; + + INIT_LIST_HEAD(&hub_event_list); + + usb_register(&hub_driver); + pid = kernel_thread(usb_hub_thread, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND); + if (pid >= 0) { + khubd_pid = pid; + return 0; + } + + /* Fall through if kernel_thread failed */ + usb_deregister(&hub_driver); + + return 0; +} + +void hub_cleanup(void) +{ + if (khubd_pid >= 0) + kill_proc(khubd_pid, SIGINT, 1); + + usb_deregister(&hub_driver); +} diff -ur --new-file old/linux/drivers/usb/hub.h new/linux/drivers/usb/hub.h --- old/linux/drivers/usb/hub.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/usb/hub.h Wed Apr 21 14:41:59 1999 @@ -0,0 +1,80 @@ +#ifndef __LINUX_HUB_H +#define __LINUX_HUB_H + +#include + +/* + * Hub feature numbers + */ +#define C_HUB_LOCAL_POWER 0 +#define C_HUB_OVER_CURRENT 1 + +/* + * Port feature numbers + */ +#define USB_PORT_FEAT_ENABLE 1 +#define USB_PORT_FEAT_SUSPEND 2 +#define USB_PORT_FEAT_OVER_CURRENT 3 +#define USB_PORT_FEAT_RESET 4 +#define USB_PORT_FEAT_POWER 8 +#define USB_PORT_FEAT_LOWSPEED 9 +#define USB_PORT_FEAT_C_CONNECTION 16 +#define USB_PORT_FEAT_C_ENABLE 17 +#define USB_PORT_FEAT_C_SUSPEND 18 +#define USB_PORT_FEAT_C_OVER_CURRENT 19 +#define USB_PORT_FEAT_C_RESET 20 + +/* wPortStatus */ +#define USB_PORT_STAT_CONNECTION 0x0001 +#define USB_PORT_STAT_ENABLE 0x0002 +#define USB_PORT_STAT_SUSPEND 0x0004 +#define USB_PORT_STAT_OVERCURRENT 0x0008 +#define USB_PORT_STAT_RESET 0x0010 +#define USB_PORT_STAT_POWER 0x0100 +#define USB_PORT_STAT_LOW_SPEED 0x0200 + +/* wPortChange */ +#define USB_PORT_STAT_C_CONNECTION 0x0001 +#define USB_PORT_STAT_C_ENABLE 0x0002 +#define USB_PORT_STAT_C_SUSPEND 0x0004 +#define USB_PORT_STAT_C_OVERCURRENT 0x0008 +#define USB_PORT_STAT_C_RESET 0x0010 + +/* Characteristics */ +#define HUB_CHAR_LPSM 0x0003 +#define HUB_CHAR_COMPOUND 0x0004 +#define HUB_CHAR_OCPM 0x0018 + +struct usb_device; + +typedef enum { + USB_PORT_UNPOWERED = 0, /* Default state */ + USB_PORT_POWERED, /* When we've put power to it */ + USB_PORT_ENABLED, /* When it's been enabled */ + USB_PORT_DISABLED, /* If it's been disabled */ + USB_PORT_ADMINDISABLED, /* Forced down */ +} usb_hub_port_state; + +struct usb_hub_port { + usb_hub_port_state cstate; /* Configuration state */ + + struct usb_device *child; /* Device attached to this port */ + + struct usb_hub *parent; /* Parent hub */ +}; + +struct usb_hub { + /* Device structure */ + struct usb_device *dev; + + /* Temporary event list */ + struct list_head event_list; + + /* Number of ports on the hub */ + int nports; + + struct usb_hub_port ports[0]; /* Dynamically allocated */ +}; + +#endif + diff -ur --new-file old/linux/drivers/usb/inits.h new/linux/drivers/usb/inits.h --- old/linux/drivers/usb/inits.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/usb/inits.h Fri Apr 30 17:20:30 1999 @@ -0,0 +1,6 @@ +int bp_mouse_init(void); +int usb_kbd_init(void); +int usb_audio_init(void); +int hub_init(void); +void hub_cleanup(void); +void usb_mouse_cleanup(void); diff -ur --new-file old/linux/drivers/usb/keyboard.c new/linux/drivers/usb/keyboard.c --- old/linux/drivers/usb/keyboard.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/usb/keyboard.c Mon Apr 26 22:35:01 1999 @@ -0,0 +1,226 @@ +#include +#include +#include +#include +#include +#include +#include "usb.h" + +#define PCKBD_PRESSED 0x00 +#define PCKBD_RELEASED 0x80 +#define PCKBD_NEEDS_E0 0x80 + +#define USBKBD_MODIFIER_BASE 120 +#define USBKBD_KEYCODE_OFFSET 2 +#define USBKBD_KEYCODE_COUNT 6 + +#define USBKBD_VALID_KEYCODE(key) ((unsigned char)(key) > 3) +#define USBKBD_FIND_KEYCODE(down, key, count) \ + ((unsigned char*) memscan((down), (key), (count)) < ((down) + (count))) + +#define USBKBD_REPEAT_DELAY (HZ / 4) +#define USBKBD_REPEAT_RATE (HZ / 20) + +struct usb_keyboard +{ + struct usb_device *dev; + unsigned long down[2]; + unsigned char repeat_key; + struct timer_list repeat_timer; + struct list_head list; +}; + +extern unsigned char usb_kbd_map[]; + +static int usb_kbd_probe(struct usb_device *dev); +static void usb_kbd_disconnect(struct usb_device *dev); +static void usb_kbd_repeat(unsigned long dummy); + +static LIST_HEAD(usb_kbd_list); + +static struct usb_driver usb_kbd_driver = +{ + "keyboard", + usb_kbd_probe, + usb_kbd_disconnect, + {NULL, NULL} +}; + + +static void +usb_kbd_handle_key(unsigned char key, int down) +{ + int scancode = (int) usb_kbd_map[key]; + if(scancode) + { + if(scancode & PCKBD_NEEDS_E0) + { + handle_scancode(0xe0, 1); + } + handle_scancode((scancode & ~PCKBD_NEEDS_E0), down); + } +} + +static void +usb_kbd_repeat(unsigned long dev_id) +{ + struct usb_keyboard *kbd = (struct usb_keyboard*) dev_id; + + unsigned long flags; + save_flags(flags); + cli(); + + if(kbd->repeat_key) + { + usb_kbd_handle_key(kbd->repeat_key, 1); + + /* reset repeat timer */ + kbd->repeat_timer.function = usb_kbd_repeat; + kbd->repeat_timer.expires = jiffies + USBKBD_REPEAT_RATE; + kbd->repeat_timer.data = (unsigned long) kbd; + kbd->repeat_timer.prev = NULL; + kbd->repeat_timer.next = NULL; + add_timer(&kbd->repeat_timer); + } + + restore_flags(flags); +} + +static int +usb_kbd_irq(int state, void *buffer, void *dev_id) +{ + struct usb_keyboard *kbd = (struct usb_keyboard*) dev_id; + unsigned long *down = (unsigned long*) buffer; + + if(kbd->down[0] != down[0] || kbd->down[1] != down[1]) + { + unsigned char *olddown, *newdown; + unsigned char modsdelta, key; + int i; + + /* handle modifier change */ + modsdelta = (*(unsigned char*) down ^ *(unsigned char*) kbd->down); + if(modsdelta) + { + for(i = 0; i < 8; i++) + { + if(modsdelta & 0x01) + { + int pressed = (*(unsigned char*) down >> i) & 0x01; + usb_kbd_handle_key( + i + USBKBD_MODIFIER_BASE, + pressed); + } + modsdelta >>= 1; + } + } + + olddown = (unsigned char*) kbd->down + USBKBD_KEYCODE_OFFSET; + newdown = (unsigned char*) down + USBKBD_KEYCODE_OFFSET; + + /* handle released keys */ + for(i = 0; i < USBKBD_KEYCODE_COUNT; i++) + { + key = olddown[i]; + if(USBKBD_VALID_KEYCODE(key) + && !USBKBD_FIND_KEYCODE(newdown, key, USBKBD_KEYCODE_COUNT)) + { + usb_kbd_handle_key(key, 0); + } + } + + /* handle pressed keys */ + kbd->repeat_key = 0; + for(i = 0; i < USBKBD_KEYCODE_COUNT; i++) + { + key = newdown[i]; + if(USBKBD_VALID_KEYCODE(key) + && !USBKBD_FIND_KEYCODE(olddown, key, USBKBD_KEYCODE_COUNT)) + { + usb_kbd_handle_key(key, 1); + kbd->repeat_key = key; + } + } + + /* set repeat timer if any keys were pressed */ + if(kbd->repeat_key) + { + del_timer(&kbd->repeat_timer); + kbd->repeat_timer.function = usb_kbd_repeat; + kbd->repeat_timer.expires = jiffies + USBKBD_REPEAT_DELAY; + kbd->repeat_timer.data = (unsigned long) kbd; + kbd->repeat_timer.prev = NULL; + kbd->repeat_timer.next = NULL; + add_timer(&kbd->repeat_timer); + } + + kbd->down[0] = down[0]; + kbd->down[1] = down[1]; + } + + return 1; +} + +static int +usb_kbd_probe(struct usb_device *dev) +{ + struct usb_interface_descriptor *interface; + struct usb_endpoint_descriptor *endpoint; + struct usb_keyboard *kbd; + + interface = &dev->config[0].interface[0]; + endpoint = &interface->endpoint[0]; + + if(interface->bInterfaceClass != 3 + || interface->bInterfaceSubClass != 1 + || interface->bInterfaceProtocol != 1) + { + return -1; + } + + printk(KERN_INFO "USB HID boot protocol keyboard detected.\n"); + + kbd = kmalloc(sizeof(struct usb_keyboard), GFP_KERNEL); + if(kbd) + { + memset(kbd, 0, sizeof(*kbd)); + kbd->dev = dev; + dev->private = kbd; + + usb_set_configuration(dev, dev->config[0].bConfigurationValue); + usb_set_protocol(dev, 0); + usb_set_idle(dev, 0, 0); + + usb_request_irq(dev, + usb_rcvctrlpipe(dev, endpoint->bEndpointAddress), + usb_kbd_irq, + endpoint->bInterval, + kbd); + + list_add(&kbd->list, &usb_kbd_list); + } + + return 0; +} + +static void +usb_kbd_disconnect(struct usb_device *dev) +{ + struct usb_keyboard *kbd = (struct usb_keyboard*) dev->private; + if(kbd) + { + dev->private = NULL; + list_del(&kbd->list); + del_timer(&kbd->repeat_timer); + kfree(kbd); + } + + printk(KERN_INFO "USB HID boot protocol keyboard removed.\n"); +} + +int +usb_kbd_init(void) +{ + usb_register(&usb_kbd_driver); + return 0; +} diff -ur --new-file old/linux/drivers/usb/keymap.c new/linux/drivers/usb/keymap.c --- old/linux/drivers/usb/keymap.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/usb/keymap.c Mon Apr 26 21:19:05 1999 @@ -0,0 +1,50 @@ +unsigned char usb_kbd_map[256] = +{ + 0x00, 0x00, 0x00, 0x00, 0x1e, 0x30, 0x2e, 0x20, + 0x12, 0x21, 0x22, 0x23, 0x17, 0x24, 0x25, 0x26, + + 0x32, 0x31, 0x18, 0x19, 0x10, 0x13, 0x1f, 0x14, + 0x16, 0x2f, 0x11, 0x2d, 0x15, 0x2c, 0x02, 0x03, + + 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, + 0x1c, 0x01, 0xd3, 0x0f, 0x39, 0x0c, 0x0d, 0x1a, + + 0x1b, 0x2b, 0x00, 0x27, 0x28, 0x29, 0x33, 0x34, + 0x35, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, + + 0x41, 0x42, 0x43, 0x44, 0x57, 0x58, 0xb7, 0x46, + 0x00, 0xd2, 0xc7, 0xc9, 0x63, 0xcf, 0xd1, 0xcd, + + 0xcb, 0xd0, 0xc8, 0x45, 0xb5, 0x37, 0x4a, 0x4e, + 0x9c, 0x4f, 0x50, 0x51, 0x4b, 0x4c, 0x4d, 0x47, + + 0x48, 0x49, 0x52, 0x53, 0x00, 0x6d, 0x00, 0x00, + 0xbd, 0xbe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1d, 0x2a, 0x38, 0xdb, 0x9d, 0x36, 0xb8, 0xdc, + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 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 -ur --new-file old/linux/drivers/usb/maps/fixup.map new/linux/drivers/usb/maps/fixup.map --- old/linux/drivers/usb/maps/fixup.map Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/usb/maps/fixup.map Sat Apr 17 00:38:24 1999 @@ -0,0 +1,31 @@ +# misc fixes +keycode 0 = Pause +keycode 29 = Control +keycode 99 = Remove +keycode 42 = Shift +keycode 54 = Shift_R +keycode 109 = Application + +# E0 keys (or'ed with 0x80) +keycode 156 = KP_Enter +keycode 157 = Control_R +keycode 181 = KP_Divide +keycode 183 = Print_Screen +keycode 184 = Alt_R +keycode 189 = F13 +keycode 190 = F14 +keycode 193 = F17 +keycode 198 = Break +keycode 199 = Home +keycode 200 = Up +keycode 201 = Prior +keycode 203 = Left +keycode 205 = Right +keycode 207 = End +keycode 208 = Down +keycode 209 = Next +keycode 210 = Insert +keycode 211 = Delete +keycode 219 = Window +keycode 220 = Window_R +keycode 221 = Menu diff -ur --new-file old/linux/drivers/usb/maps/serial.map new/linux/drivers/usb/maps/serial.map --- old/linux/drivers/usb/maps/serial.map Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/usb/maps/serial.map Mon Apr 19 20:47:54 1999 @@ -0,0 +1,370 @@ +keymaps 0-2,4-6,8-9,12 +keycode 1 = Escape + alt keycode 1 = Meta_Escape + shift alt keycode 1 = Meta_Escape + control alt keycode 1 = Meta_Escape +keycode 2 = one exclam + alt keycode 2 = Meta_one + shift alt keycode 2 = Meta_exclam +keycode 3 = two at at nul nul + alt keycode 3 = Meta_two + shift alt keycode 3 = Meta_at + control alt keycode 3 = Meta_nul +keycode 4 = three numbersign + control keycode 4 = Escape + alt keycode 4 = Meta_three + shift alt keycode 4 = Meta_numbersign +keycode 5 = four dollar dollar Control_backslash + alt keycode 5 = Meta_four + shift alt keycode 5 = Meta_dollar + control alt keycode 5 = Meta_Control_backslash +keycode 6 = five percent + control keycode 6 = Control_bracketright + alt keycode 6 = Meta_five + shift alt keycode 6 = Meta_percent +keycode 7 = six asciicircum + control keycode 7 = Control_asciicircum + alt keycode 7 = Meta_six + shift alt keycode 7 = Meta_asciicircum +keycode 8 = seven ampersand braceleft Control_underscore + alt keycode 8 = Meta_seven + shift alt keycode 8 = Meta_ampersand + control alt keycode 8 = Meta_Control_underscore +keycode 9 = eight asterisk bracketleft Delete + alt keycode 9 = Meta_eight + shift alt keycode 9 = Meta_asterisk + control alt keycode 9 = Meta_Delete +keycode 10 = nine parenleft bracketright + alt keycode 10 = Meta_nine + shift alt keycode 10 = Meta_parenleft +keycode 11 = zero parenright braceright + alt keycode 11 = Meta_zero + shift alt keycode 11 = Meta_parenright +keycode 12 = minus underscore backslash Control_underscore Control_underscore + alt keycode 12 = Meta_minus + shift alt keycode 12 = Meta_underscore + control alt keycode 12 = Meta_Control_underscore +keycode 13 = equal plus + alt keycode 13 = Meta_equal + shift alt keycode 13 = Meta_plus +keycode 14 = Delete + alt keycode 14 = Meta_Delete + shift alt keycode 14 = Meta_Delete + control alt keycode 14 = Meta_Delete +keycode 15 = Tab + alt keycode 15 = Meta_Tab + shift alt keycode 15 = Meta_Tab + control alt keycode 15 = Meta_Tab +keycode 16 = q +keycode 17 = w +keycode 18 = e +keycode 19 = r +keycode 20 = t +keycode 21 = y +keycode 22 = u +keycode 23 = i +keycode 24 = o +keycode 25 = p +keycode 26 = bracketleft braceleft + control keycode 26 = Escape + alt keycode 26 = Meta_bracketleft + shift alt keycode 26 = Meta_braceleft +keycode 27 = bracketright braceright asciitilde Control_bracketright + alt keycode 27 = Meta_bracketright + shift alt keycode 27 = Meta_braceright + control alt keycode 27 = Meta_Control_bracketright +keycode 28 = Return + alt keycode 28 = Meta_Control_m +keycode 29 = Control +keycode 30 = a +keycode 31 = s +keycode 32 = d +keycode 33 = f +keycode 34 = g +keycode 35 = h +keycode 36 = j +keycode 37 = k +keycode 38 = l +keycode 39 = semicolon colon + alt keycode 39 = Meta_semicolon + shift alt keycode 39 = Meta_colon +keycode 40 = apostrophe quotedbl + control keycode 40 = Control_g + alt keycode 40 = Meta_apostrophe + shift alt keycode 40 = Meta_quotedbl +keycode 41 = grave asciitilde + control keycode 41 = nul + alt keycode 41 = Meta_grave + shift alt keycode 41 = Meta_asciitilde +keycode 42 = Shift +keycode 43 = backslash bar + control keycode 43 = Control_backslash + alt keycode 43 = Meta_backslash + shift alt keycode 43 = Meta_bar +keycode 44 = z +keycode 45 = x +keycode 46 = c +keycode 47 = v +keycode 48 = b +keycode 49 = n +keycode 50 = m +keycode 51 = comma less + alt keycode 51 = Meta_comma + shift alt keycode 51 = Meta_less +keycode 52 = period greater + alt keycode 52 = Meta_period + shift alt keycode 52 = Meta_greater +keycode 53 = slash question + control keycode 53 = Delete + alt keycode 53 = Meta_slash + shift alt keycode 53 = Meta_question +keycode 54 = Shift +keycode 55 = KP_Multiply + altgr keycode 55 = Hex_C +keycode 56 = Alt +keycode 57 = space + control keycode 57 = nul + alt keycode 57 = Meta_space + shift alt keycode 57 = Meta_space + control alt keycode 57 = Meta_nul +keycode 58 = Caps_Lock +keycode 59 = F1 F13 Console_13 F25 + alt keycode 59 = Console_1 + control alt keycode 59 = Console_1 +keycode 60 = F2 F14 Console_14 F26 + alt keycode 60 = Console_2 + control alt keycode 60 = Console_2 +keycode 61 = F3 F15 Console_15 F27 + alt keycode 61 = Console_3 + control alt keycode 61 = Console_3 +keycode 62 = F4 F16 Console_16 F28 + alt keycode 62 = Console_4 + control alt keycode 62 = Console_4 +keycode 63 = F5 F17 Console_17 F29 + alt keycode 63 = Console_5 + control alt keycode 63 = Console_5 +keycode 64 = F6 F18 Console_18 F30 + alt keycode 64 = Console_6 + control alt keycode 64 = Console_6 +keycode 65 = F7 F19 Console_19 F31 + alt keycode 65 = Console_7 + control alt keycode 65 = Console_7 +keycode 66 = F8 F20 Console_20 F32 + alt keycode 66 = Console_8 + control alt keycode 66 = Console_8 +keycode 67 = F9 F21 Console_21 F33 + alt keycode 67 = Console_9 + control alt keycode 67 = Console_9 +keycode 68 = F10 F22 Console_22 F34 + alt keycode 68 = Console_10 + control alt keycode 68 = Console_10 +keycode 69 = Num_Lock + altgr keycode 69 = Hex_E +keycode 70 = Scroll_Lock Show_Memory Show_Registers Show_State + alt keycode 70 = Scroll_Lock +keycode 71 = KP_7 + altgr keycode 71 = Hex_7 + alt keycode 71 = Ascii_7 +keycode 72 = KP_8 + altgr keycode 72 = Hex_8 + alt keycode 72 = Ascii_8 +keycode 73 = KP_9 + altgr keycode 73 = Hex_9 + alt keycode 73 = Ascii_9 +keycode 74 = KP_Subtract +keycode 75 = KP_4 + altgr keycode 75 = Hex_4 + alt keycode 75 = Ascii_4 +keycode 76 = KP_5 + altgr keycode 76 = Hex_5 + alt keycode 76 = Ascii_5 +keycode 77 = KP_6 + altgr keycode 77 = Hex_6 + alt keycode 77 = Ascii_6 +keycode 78 = KP_Add +keycode 79 = KP_1 + altgr keycode 79 = Hex_1 + alt keycode 79 = Ascii_1 +keycode 80 = KP_2 + altgr keycode 80 = Hex_2 + alt keycode 80 = Ascii_2 +keycode 81 = KP_3 + altgr keycode 81 = Hex_3 + alt keycode 81 = Ascii_3 +keycode 82 = KP_0 + altgr keycode 82 = Hex_0 + alt keycode 82 = Ascii_0 +keycode 83 = KP_Period + altgr control keycode 83 = Boot + control alt keycode 83 = Boot +keycode 84 = Last_Console +keycode 85 = +keycode 86 = less greater bar + alt keycode 86 = Meta_less + shift alt keycode 86 = Meta_greater +keycode 87 = F11 F23 Console_23 F35 + alt keycode 87 = Console_11 + control alt keycode 87 = Console_11 +keycode 88 = F12 F24 Console_24 F36 + alt keycode 88 = Console_12 + control alt keycode 88 = Console_12 +keycode 89 = +keycode 90 = +keycode 91 = +keycode 92 = +keycode 93 = +keycode 94 = +keycode 95 = +keycode 96 = KP_Enter +keycode 97 = Control +keycode 98 = KP_Divide + altgr keycode 98 = Hex_B +keycode 99 = Control_backslash + alt keycode 99 = Meta_Control_backslash + shift alt keycode 99 = Meta_Control_backslash + control alt keycode 99 = Meta_Control_backslash +keycode 100 = AltGr +keycode 101 = Break +keycode 102 = Find +keycode 103 = Up + alt keycode 103 = KeyboardSignal +keycode 104 = Prior + shift keycode 104 = Scroll_Backward +keycode 105 = Left + alt keycode 105 = Decr_Console +keycode 106 = Right + alt keycode 106 = Incr_Console +keycode 107 = Select +keycode 108 = Down +keycode 109 = Next + shift keycode 109 = Scroll_Forward +keycode 110 = Insert +keycode 111 = Remove + altgr control keycode 111 = Boot + control alt keycode 111 = Boot +keycode 112 = Macro + altgr control keycode 112 = VoidSymbol + shift alt keycode 112 = VoidSymbol +keycode 113 = F13 + altgr control keycode 113 = VoidSymbol + shift alt keycode 113 = VoidSymbol +keycode 114 = F14 + altgr control keycode 114 = VoidSymbol + shift alt keycode 114 = VoidSymbol +keycode 115 = Help + altgr control keycode 115 = VoidSymbol + shift alt keycode 115 = VoidSymbol +keycode 116 = Do + altgr control keycode 116 = VoidSymbol + shift alt keycode 116 = VoidSymbol +keycode 117 = F17 + altgr control keycode 117 = VoidSymbol + shift alt keycode 117 = VoidSymbol +keycode 118 = KP_MinPlus + altgr control keycode 118 = VoidSymbol + shift alt keycode 118 = VoidSymbol +keycode 119 = Pause +keycode 120 = +keycode 121 = +keycode 122 = +keycode 123 = +keycode 124 = +keycode 125 = +keycode 126 = +keycode 127 = +string F1 = "\033[[A" +string F2 = "\033[[B" +string F3 = "\033[[C" +string F4 = "\033[[D" +string F5 = "\033[[E" +string F6 = "\033[17~" +string F7 = "\033[18~" +string F8 = "\033[19~" +string F9 = "\033[20~" +string F10 = "\033[21~" +string F11 = "\033[23~" +string F12 = "\033[24~" +string F13 = "\033[25~" +string F14 = "\033[26~" +string F15 = "\033[28~" +string F16 = "\033[29~" +string F17 = "\033[31~" +string F18 = "\033[32~" +string F19 = "\033[33~" +string F20 = "\033[34~" +string Find = "\033[1~" +string Insert = "\033[2~" +string Remove = "\033[3~" +string Select = "\033[4~" +string Prior = "\033[5~" +string Next = "\033[6~" +string Macro = "\033[M" +string Pause = "\033[P" +compose '`' 'A' to 'À' +compose '`' 'a' to 'à' +compose '\'' 'A' to 'Á' +compose '\'' 'a' to 'á' +compose '^' 'A' to 'Â' +compose '^' 'a' to 'â' +compose '~' 'A' to 'Ã' +compose '~' 'a' to 'ã' +compose '"' 'A' to 'Ä' +compose '"' 'a' to 'ä' +compose 'O' 'A' to 'Å' +compose 'o' 'a' to 'å' +compose '0' 'A' to 'Å' +compose '0' 'a' to 'å' +compose 'A' 'A' to 'Å' +compose 'a' 'a' to 'å' +compose 'A' 'E' to 'Æ' +compose 'a' 'e' to 'æ' +compose ',' 'C' to 'Ç' +compose ',' 'c' to 'ç' +compose '`' 'E' to 'È' +compose '`' 'e' to 'è' +compose '\'' 'E' to 'É' +compose '\'' 'e' to 'é' +compose '^' 'E' to 'Ê' +compose '^' 'e' to 'ê' +compose '"' 'E' to 'Ë' +compose '"' 'e' to 'ë' +compose '`' 'I' to 'Ì' +compose '`' 'i' to 'ì' +compose '\'' 'I' to 'Í' +compose '\'' 'i' to 'í' +compose '^' 'I' to 'Î' +compose '^' 'i' to 'î' +compose '"' 'I' to 'Ï' +compose '"' 'i' to 'ï' +compose '-' 'D' to 'Ð' +compose '-' 'd' to 'ð' +compose '~' 'N' to 'Ñ' +compose '~' 'n' to 'ñ' +compose '`' 'O' to 'Ò' +compose '`' 'o' to 'ò' +compose '\'' 'O' to 'Ó' +compose '\'' 'o' to 'ó' +compose '^' 'O' to 'Ô' +compose '^' 'o' to 'ô' +compose '~' 'O' to 'Õ' +compose '~' 'o' to 'õ' +compose '"' 'O' to 'Ö' +compose '"' 'o' to 'ö' +compose '/' 'O' to 'Ø' +compose '/' 'o' to 'ø' +compose '`' 'U' to 'Ù' +compose '`' 'u' to 'ù' +compose '\'' 'U' to 'Ú' +compose '\'' 'u' to 'ú' +compose '^' 'U' to 'Û' +compose '^' 'u' to 'û' +compose '"' 'U' to 'Ü' +compose '"' 'u' to 'ü' +compose '\'' 'Y' to 'Ý' +compose '\'' 'y' to 'ý' +compose 'T' 'H' to 'Þ' +compose 't' 'h' to 'þ' +compose 's' 's' to 'ß' +compose '"' 'y' to 'ÿ' +compose 's' 'z' to 'ß' +compose 'i' 'j' to 'ÿ' diff -ur --new-file old/linux/drivers/usb/maps/usb.map new/linux/drivers/usb/maps/usb.map --- old/linux/drivers/usb/maps/usb.map Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/usb/maps/usb.map Sat Apr 17 00:38:24 1999 @@ -0,0 +1,233 @@ +# USB kernel keymap. +keymaps 0-2,4-5,8,12 + +keycode 4 = a + altgr keycode 30 = Hex_A +keycode 5 = b + altgr keycode 48 = Hex_B +keycode 6 = c + altgr keycode 46 = Hex_C +keycode 7 = d + altgr keycode 32 = Hex_D +keycode 8 = e + altgr keycode 18 = Hex_E +keycode 9 = f + altgr keycode 33 = Hex_F +keycode 10 = g +keycode 11 = h +keycode 12 = i +keycode 13 = j +keycode 14 = k +keycode 15 = l +keycode 16 = m +keycode 17 = n +keycode 18 = o +keycode 19 = p +keycode 20 = q +keycode 21 = r +keycode 22 = s +keycode 23 = t +keycode 24 = u +keycode 25 = v +keycode 26 = w +keycode 27 = x +keycode 28 = y +keycode 29 = z +keycode 30 = one exclam + alt keycode 2 = Meta_one +keycode 31 = two at + control keycode 3 = nul + shift control keycode 3 = nul + alt keycode 3 = Meta_two +keycode 32 = three numbersign + control keycode 4 = Escape + alt keycode 4 = Meta_three +keycode 33 = four dollar + control keycode 5 = Control_backslash + alt keycode 5 = Meta_four +keycode 34 = five percent + control keycode 6 = Control_bracketright + alt keycode 6 = Meta_five +keycode 35 = six asciicircum + control keycode 7 = Control_asciicircum + alt keycode 7 = Meta_six +keycode 36 = seven ampersand + control keycode 8 = Control_underscore + alt keycode 8 = Meta_seven +keycode 37 = eight asterisk + control keycode 9 = Delete + alt keycode 9 = Meta_eight +keycode 38 = nine parenleft + alt keycode 10 = Meta_nine +keycode 39 = zero parenright + alt keycode 11 = Meta_zero +keycode 40 = Return + alt keycode 28 = Meta_Control_m +keycode 41 = Escape Escape + alt keycode 1 = Meta_Escape +keycode 42 = Delete Delete + control keycode 14 = BackSpace + alt keycode 14 = Meta_Delete +keycode 43 = Tab Tab + alt keycode 15 = Meta_Tab +keycode 44 = space space + control keycode 57 = nul + alt keycode 57 = Meta_space +keycode 45 = minus underscore backslash + control keycode 12 = Control_underscore + shift control keycode 12 = Control_underscore + alt keycode 12 = Meta_minus +keycode 46 = equal plus + alt keycode 13 = Meta_equal +keycode 47 = bracketleft braceleft + control keycode 26 = Escape + alt keycode 26 = Meta_bracketleft +keycode 48 = bracketright braceright asciitilde + control keycode 27 = Control_bracketright + alt keycode 27 = Meta_bracketright +keycode 49 = backslash bar + control keycode 43 = Control_backslash + alt keycode 43 = Meta_backslash +keycode 50 = +keycode 51 = semicolon colon + alt keycode 39 = Meta_semicolon +keycode 52 = apostrophe quotedbl + control keycode 40 = Control_g + alt keycode 40 = Meta_apostrophe +keycode 53 = grave asciitilde + control keycode 41 = nul + alt keycode 41 = Meta_grave +keycode 54 = comma less + alt keycode 51 = Meta_comma +keycode 55 = period greater + control keycode 52 = Compose + alt keycode 52 = Meta_period +keycode 56 = slash question + control keycode 53 = Delete + alt keycode 53 = Meta_slash +keycode 57 = Caps_Lock +keycode 58 = F1 F11 Console_13 + control keycode 59 = F1 + alt keycode 59 = Console_1 + control alt keycode 59 = Console_1 +keycode 59 = F2 F12 Console_14 + control keycode 60 = F2 + alt keycode 60 = Console_2 + control alt keycode 60 = Console_2 +keycode 60 = F3 F13 Console_15 + control keycode 61 = F3 + alt keycode 61 = Console_3 + control alt keycode 61 = Console_3 +keycode 61 = F4 F14 Console_16 + control keycode 62 = F4 + alt keycode 62 = Console_4 + control alt keycode 62 = Console_4 +keycode 62 = F5 F15 Console_17 + control keycode 63 = F5 + alt keycode 63 = Console_5 + control alt keycode 63 = Console_5 +keycode 63 = F6 F16 Console_18 + control keycode 64 = F6 + alt keycode 64 = Console_6 + control alt keycode 64 = Console_6 +keycode 64 = F7 F17 Console_19 + control keycode 65 = F7 + alt keycode 65 = Console_7 + control alt keycode 65 = Console_7 +keycode 65 = F8 F18 Console_20 + control keycode 66 = F8 + alt keycode 66 = Console_8 + control alt keycode 66 = Console_8 +keycode 66 = F9 F19 Console_21 + control keycode 67 = F9 + alt keycode 67 = Console_9 + control alt keycode 67 = Console_9 +keycode 67 = F10 F20 Console_22 + control keycode 68 = F10 + alt keycode 68 = Console_10 + control alt keycode 68 = Console_10 +keycode 68 = F11 F11 Console_23 + control keycode 87 = F11 + alt keycode 87 = Console_11 + control alt keycode 87 = Console_11 +keycode 69 = F12 F12 Console_24 + control keycode 88 = F12 + alt keycode 88 = Console_12 + control alt keycode 88 = Console_12 +keycode 70 = Print_Screen +keycode 71 = Scroll_Lock Show_Memory Show_Registers + control keycode 70 = Show_State + alt keycode 70 = Scroll_Lock +keycode 72 = Pause +keycode 73 = Insert +keycode 74 = Home +keycode 75 = Prior + shift keycode 104 = Scroll_Backward +keycode 76 = Remove +# altgr control keycode 111 = Boot + control alt keycode 111 = Boot +keycode 77 = End +keycode 78 = Next + shift keycode 109 = Scroll_Forward +keycode 79 = Right + alt keycode 106 = Incr_Console +keycode 80 = Left + alt keycode 105 = Decr_Console +keycode 81 = Down +keycode 82 = Up +keycode 83 = Num_Lock + shift keycode 69 = Bare_Num_Lock +keycode 84 = KP_Divide +keycode 85 = KP_Multiply +keycode 86 = KP_Subtract +keycode 87 = KP_Add +keycode 88 = KP_Enter +keycode 89 = KP_1 + alt keycode 79 = Ascii_1 + altgr keycode 79 = Hex_1 +keycode 90 = KP_2 + alt keycode 80 = Ascii_2 + altgr keycode 80 = Hex_2 +keycode 91 = KP_3 + alt keycode 81 = Ascii_3 + altgr keycode 81 = Hex_3 +keycode 92 = KP_4 + alt keycode 75 = Ascii_4 + altgr keycode 75 = Hex_4 +keycode 93 = KP_5 + alt keycode 76 = Ascii_5 + altgr keycode 76 = Hex_5 +keycode 94 = KP_6 + alt keycode 77 = Ascii_6 + altgr keycode 77 = Hex_6 +keycode 95 = KP_7 + alt keycode 71 = Ascii_7 + altgr keycode 71 = Hex_7 +keycode 96 = KP_8 + alt keycode 72 = Ascii_8 + altgr keycode 72 = Hex_8 +keycode 97 = KP_9 + alt keycode 73 = Ascii_9 + altgr keycode 73 = Hex_9 +keycode 98 = KP_0 + alt keycode 82 = Ascii_0 + altgr keycode 82 = Hex_0 +keycode 99 = KP_Period +# altgr control keycode 83 = Boot + control alt keycode 83 = Boot +keycode 100 = +keycode 101 = Application +keycode 102 = +keycode 103 = +keycode 104 = F13 +keycode 105 = F14 + +# modifiers +keycode 120 = Control +keycode 121 = Shift +keycode 122 = Alt +keycode 123 = Window +keycode 124 = Control_R +keycode 125 = Shift_R +keycode 126 = Alt_R +keycode 127 = Window_R diff -ur --new-file old/linux/drivers/usb/mkmap new/linux/drivers/usb/mkmap --- old/linux/drivers/usb/mkmap Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/usb/mkmap Mon Apr 19 20:53:27 1999 @@ -0,0 +1,83 @@ +#!/usr/bin/perl + +($ME = $0) =~ s|.*/||; + +$file = "maps/serial.map"; +$line = 1; +open(PC, $file) || die("$!"); +while() +{ + if(/^\s*keycode\s+(\d+)\s*=\s*(\S+)/) + { + my($idx) = int($1); + my($sym) = $2; + if(defined($map{uc($sym)})) + { + # print STDERR "$file:$line: warning: `$sym' redefined\n"; + } + $map{uc($sym)} = $idx; + } + $line++; +} +close(PC); + +$file = "maps/fixup.map"; +$line = 1; +open(FIXUP, $file) || die("$!"); +while() +{ + if(/^\s*keycode\s+(\d+)\s*=\s*/) + { + my($idx) = int($1); + for $sym (split(/\s+/, $')) + { + $map{uc($sym)} = $idx; + } + } + $line++; +} +close(FIXUP); + +$file = "maps/usb.map"; +$line = 1; +open(USB, $file) || die("$!"); +while() +{ + if(/^\s*keycode\s+(\d+)\s*=\s*/) + { + my($idx) = int($1); + for $sym (split(/\s+/, $')) + { + my($val) = $map{uc($sym)}; + $map[$idx] = $val; + if(!defined($val)) + { + print STDERR "$file:$line: warning: `$sym' undefined\n"; + } + else + { + last; + } + } + } + $line++; +} +close(USB); + +print "unsigned char usb_kbd_map[256] = \n{\n"; +for($x = 0; $x < 32; $x++) +{ + if($x && !($x % 2)) + { + print "\n"; + } + print " "; + for($y = 0; $y < 8; $y++) + { + my($idx) = $x * 8 + $y; + print sprintf(" 0x%02x,", + int(defined($map[$idx]) ? $map[$idx]:0)); + } + print "\n"; +} +print "};\n"; diff -ur --new-file old/linux/drivers/usb/mouse.c new/linux/drivers/usb/mouse.c --- old/linux/drivers/usb/mouse.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/usb/mouse.c Fri Apr 30 17:20:49 1999 @@ -0,0 +1,293 @@ +/* + * USB HID boot protocol mouse support based on MS BusMouse driver, psaux + * driver, and Linus's skeleton USB mouse driver. Fixed up a lot by Linus. + * + * Brad Keryan 4/3/1999 + * + * version 0.20: Linus rewrote read_mouse() to do PS/2 and do it + * correctly. Events are added together, not queued, to keep the rodent sober. + * + * version 0.02: Hmm, the mouse seems drunk because I'm queueing the events. + * This is wrong: when an application (like X or gpm) reads the mouse device, + * it wants to find out the mouse's current position, not its recent history. + * The button thing turned out to be UHCI not flipping data toggle, so half the + * packets were thrown out. + * + * version 0.01: Switched over to busmouse protocol, and changed the minor + * number to 32 (same as uusbd's hidbp driver). Buttons work more sanely now, + * but it still doesn't generate button events unless you move the mouse. + * + * version 0.0: Driver emulates a PS/2 mouse, stealing /dev/psaux (sorry, I + * know that's not very nice). Moving in the X and Y axes works. Buttons don't + * work right yet: X sees a lot of MotionNotify/ButtonPress/ButtonRelease + * combos when you hold down a button and drag the mouse around. Probably has + * some additional bugs on an SMP machine. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "usb.h" + +#define USB_MOUSE_MINOR 32 + +struct mouse_state { + unsigned char buttons; /* current button state */ + long dx; /* dx, dy, dz are change since last read */ + long dy; + long dz; + int present; /* this mouse is plugged in */ + int active; /* someone is has this mouse's device open */ + int ready; /* the mouse has changed state since the last read */ + struct wait_queue *wait; /* for polling */ + struct fasync_struct *fasync; + /* later, add a list here to support multiple mice */ + /* but we will also need a list of file pointers to identify it */ +}; + +static struct mouse_state static_mouse_state; + +spinlock_t usb_mouse_lock = SPIN_LOCK_UNLOCKED; + +static int mouse_irq(int state, void *__buffer, void *dev_id) +{ + signed char *data = __buffer; + /* finding the mouse is easy when there's only one */ + struct mouse_state *mouse = &static_mouse_state; + + /* if a mouse moves with no one listening, do we care? no */ + if(!mouse->active) + return 1; + + /* if the USB mouse sends an interrupt, then something noteworthy + must have happened */ + mouse->buttons = data[0] & 0x07; + mouse->dx += data[1]; /* data[] is signed, so this works */ + mouse->dy -= data[2]; /* y-axis is reversed */ + mouse->dz += data[3]; + mouse->ready = 1; + + add_mouse_randomness((mouse->buttons << 24) + (mouse->dz << 16 ) + + (mouse->dy << 8) + mouse->dx); + + wake_up_interruptible(&mouse->wait); + if (mouse->fasync) + kill_fasync(mouse->fasync, SIGIO); + + return 1; +} + +static int fasync_mouse(int fd, struct file *filp, int on) +{ + int retval; + struct mouse_state *mouse = &static_mouse_state; + + retval = fasync_helper(fd, filp, on, &mouse->fasync); + if (retval < 0) + return retval; + return 0; +} + +static int release_mouse(struct inode * inode, struct file * file) +{ + struct mouse_state *mouse = &static_mouse_state; + + fasync_mouse(-1, file, 0); + if (--mouse->active) + return 0; + return 0; +} + +static int open_mouse(struct inode * inode, struct file * file) +{ + struct mouse_state *mouse = &static_mouse_state; + + if (!mouse->present) + return -EINVAL; + if (mouse->active++) + return 0; + /* flush state */ + mouse->buttons = mouse->dx = mouse->dy = mouse->dz = 0; + return 0; +} + +static ssize_t write_mouse(struct file * file, + const char * buffer, size_t count, loff_t *ppos) +{ + return -EINVAL; +} + +/* + * Look like a PS/2 mouse, please.. + * + * The PS/2 protocol is fairly strange, but + * oh, well, it's at least common.. + */ +static ssize_t read_mouse(struct file * file, char * buffer, size_t count, loff_t *ppos) +{ + int retval = 0; + static int state = 0; + struct mouse_state *mouse = &static_mouse_state; + + if (count) { + mouse->ready = 0; + switch (state) { + case 0: { /* buttons and sign */ + int buttons = mouse->buttons; + mouse->buttons = 0; + if (mouse->dx < 0) + buttons |= 0x10; + if (mouse->dy < 0) + buttons |= 0x20; + put_user(buttons, buffer); + buffer++; + retval++; + state = 1; + if (!--count) + break; + } + case 1: { /* dx */ + int dx = mouse->dx; + mouse->dx = 0; + put_user(dx, buffer); + buffer++; + retval++; + state = 2; + if (!--count) + break; + } + case 2: { /* dy */ + int dy = mouse->dy; + mouse->dy = 0; + put_user(dy, buffer); + buffer++; + retval++; + state = 0; + } + break; + } + } + return retval; +} + +static unsigned int mouse_poll(struct file *file, poll_table * wait) +{ + struct mouse_state *mouse = &static_mouse_state; + + poll_wait(file, &mouse->wait, wait); + if (mouse->ready) + return POLLIN | POLLRDNORM; + return 0; +} + +struct file_operations usb_mouse_fops = { + NULL, /* mouse_seek */ + read_mouse, + write_mouse, + NULL, /* mouse_readdir */ + mouse_poll, /* mouse_poll */ + NULL, /* mouse_ioctl */ + NULL, /* mouse_mmap */ + open_mouse, + NULL, /* flush */ + release_mouse, + NULL, + fasync_mouse, +}; + +static struct miscdevice usb_mouse = { + USB_MOUSE_MINOR, "USB mouse", &usb_mouse_fops +}; + +static int mouse_probe(struct usb_device *dev) +{ + struct usb_interface_descriptor *interface; + struct usb_endpoint_descriptor *endpoint; + struct mouse_state *mouse = &static_mouse_state; + + /* We don't handle multi-config mice */ + if (dev->descriptor.bNumConfigurations != 1) + return -1; + + /* We don't handle multi-interface mice */ + if (dev->config[0].bNumInterfaces != 1) + return -1; + + /* Is it a mouse interface? */ + interface = &dev->config[0].interface[0]; + if (interface->bInterfaceClass != 3) + return -1; + if (interface->bInterfaceSubClass != 1) + return -1; + if (interface->bInterfaceProtocol != 2) + return -1; + + /* Multiple endpoints? What kind of mutant ninja-mouse is this? */ + if (interface->bNumEndpoints != 1) + return -1; + + endpoint = &interface->endpoint[0]; + + /* Output endpoint? Curiousier and curiousier.. */ + if (!(endpoint->bEndpointAddress & 0x80)) + return -1; + + /* If it's not an interrupt endpoint, we'd better punt! */ + if ((endpoint->bmAttributes & 3) != 3) + return -1; + + printk("USB mouse found\n"); + + usb_set_configuration(dev, dev->config[0].bConfigurationValue); + + usb_request_irq(dev, usb_rcvctrlpipe(dev, endpoint->bEndpointAddress), mouse_irq, endpoint->bInterval, NULL); + + mouse->present = 1; + return 0; +} + +static void mouse_disconnect(struct usb_device *dev) +{ + struct mouse_state *mouse = &static_mouse_state; + + /* this might need work */ + mouse->present = 0; +} + +static struct usb_driver mouse_driver = { + "mouse", + mouse_probe, + mouse_disconnect, + { NULL, NULL } +}; + +int usb_mouse_init(void) +{ + struct mouse_state *mouse = &static_mouse_state; + + misc_register(&usb_mouse); + + mouse->present = mouse->active = 0; + mouse->wait = NULL; + mouse->fasync = NULL; + + usb_register(&mouse_driver); + printk(KERN_INFO "USB HID boot protocol mouse registered.\n"); + return 0; +} + +void usb_mouse_cleanup(void) +{ + /* this, too, probably needs work */ + usb_deregister(&mouse_driver); + misc_deregister(&usb_mouse); +} diff -ur --new-file old/linux/drivers/usb/ohci-debug.c new/linux/drivers/usb/ohci-debug.c --- old/linux/drivers/usb/ohci-debug.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/usb/ohci-debug.c Tue May 11 19:04:03 1999 @@ -0,0 +1,178 @@ +/* + * OHCI debugging code. It's gross. + * + * (C) Copyright 1999 Gregory P. Smith + */ + +#include +#include + +#include "ohci.h" + +void show_ohci_status(struct ohci *ohci) +{ + struct ohci_regs regs; + int i; + + regs.revision = readl(&ohci->regs->revision); + regs.control = readl(&ohci->regs->control); + regs.cmdstatus = readl(&ohci->regs->cmdstatus); + regs.intrstatus = readl(&ohci->regs->intrstatus); + regs.intrenable = readl(&ohci->regs->intrenable); + regs.hcca = readl(&ohci->regs->hcca); + regs.ed_periodcurrent = readl(&ohci->regs->ed_periodcurrent); + regs.ed_controlhead = readl(&ohci->regs->ed_controlhead); + regs.ed_controlcurrent = readl(&ohci->regs->ed_controlcurrent); + regs.ed_bulkhead = readl(&ohci->regs->ed_bulkhead); + regs.ed_bulkcurrent = readl(&ohci->regs->ed_bulkcurrent); + regs.current_donehead = readl(&ohci->regs->current_donehead); + regs.fminterval = readl(&ohci->regs->fminterval); + regs.fmremaining = readl(&ohci->regs->fmremaining); + regs.fmnumber = readl(&ohci->regs->fmnumber); + regs.periodicstart = readl(&ohci->regs->periodicstart); + regs.lsthresh = readl(&ohci->regs->lsthresh); + regs.roothub.a = readl(&ohci->regs->roothub.a); + regs.roothub.b = readl(&ohci->regs->roothub.b); + regs.roothub.status = readl(&ohci->regs->roothub.status); + for (i=0; iregs->roothub.portstatus[i]); + + printk(KERN_DEBUG " ohci revision = %x\n", regs.revision); + printk(KERN_DEBUG " ohci control = %x\n", regs.control); + printk(KERN_DEBUG " ohci cmdstatus = %x\n", regs.cmdstatus); + printk(KERN_DEBUG " ohci intrstatus = %x\n", regs.intrstatus); + printk(KERN_DEBUG " ohci intrenable = %x\n", regs.intrenable); + + printk(KERN_DEBUG " ohci hcca = %x\n", regs.hcca); + printk(KERN_DEBUG " ohci ed_pdcur = %x\n", regs.ed_periodcurrent); + printk(KERN_DEBUG " ohci ed_ctrlhead = %x\n", regs.ed_controlhead); + printk(KERN_DEBUG " ohci ed_ctrlcur = %x\n", regs.ed_controlcurrent); + printk(KERN_DEBUG " ohci ed_bulkhead = %x\n", regs.ed_bulkhead); + printk(KERN_DEBUG " ohci ed_bulkcur = %x\n", regs.ed_bulkcurrent); + printk(KERN_DEBUG " ohci curdonehead = %x\n", regs.current_donehead); + + printk(KERN_DEBUG " ohci fminterval = %x\n", regs.fminterval); + printk(KERN_DEBUG " ohci fmremaining = %x\n", regs.fmremaining); + printk(KERN_DEBUG " ohci fmnumber = %x\n", regs.fmnumber); + printk(KERN_DEBUG " ohci pdstart = %x\n", regs.periodicstart); + printk(KERN_DEBUG " ohci lsthresh = %x\n", regs.lsthresh); + + printk(KERN_DEBUG " ohci roothub.a = %x\n", regs.roothub.a); + printk(KERN_DEBUG " ohci roothub.b = %x\n", regs.roothub.b); + printk(KERN_DEBUG " ohci root status = %x\n", regs.roothub.status); + printk(KERN_DEBUG " roothub.port0 = %x\n", regs.roothub.portstatus[0]); + printk(KERN_DEBUG " roothub.port1 = %x\n", regs.roothub.portstatus[1]); +} /* show_ohci_status() */ + + +void show_ohci_ed(struct ohci_ed *ed) +{ + int stat = ed->status; + int skip = (stat & OHCI_ED_SKIP); + int mps = (stat & OHCI_ED_MPS) >> 16; + int isoc = (stat & OHCI_ED_F_ISOC); + int low_speed = (stat & OHCI_ED_S_LOW); + int dir = (stat & OHCI_ED_D); + int endnum = (stat & OHCI_ED_EN) >> 7; + int funcaddr = (stat & OHCI_ED_FA); + int halted = (ed->_head_td & 1); + int toggle = (ed->_head_td & 2) >> 1; + + printk(KERN_DEBUG " ohci ED:\n"); + printk(KERN_DEBUG " status = 0x%x\n", stat); + printk(KERN_DEBUG " %sMPS %d%s%s%s%s tc%d e%d fa%d\n", + skip ? "Skip " : "", + mps, + isoc ? "Isoc. " : "", + low_speed ? " LowSpd" : "", + (dir == OHCI_ED_D_IN) ? " Input" : + (dir == OHCI_ED_D_OUT) ? " Output" : "", + halted ? " Halted" : "", + toggle, + endnum, + funcaddr); + printk(KERN_DEBUG " tail_td = 0x%x\n", ed->tail_td); + printk(KERN_DEBUG " head_td = 0x%x\n", ed_head_td(ed)); + printk(KERN_DEBUG " next_ed = 0x%x\n", ed->next_ed); +} /* show_ohci_ed() */ + + +void show_ohci_td(struct ohci_td *td) +{ + int td_round = td->info & OHCI_TD_ROUND; + int td_dir = td->info & OHCI_TD_D; + int td_int_delay = (td->info & OHCI_TD_IOC_DELAY) >> 21; + int td_toggle = (td->info & OHCI_TD_DT) >> 24; + int td_errcnt = td_errorcount(*td); + int td_cc = OHCI_TD_CC_GET(td->info); + + printk(KERN_DEBUG " ohci TD hardware fields:\n"); + printk(KERN_DEBUG " info = 0x%x\n", td->info); + printk(KERN_DEBUG " %s%s%s%d %s\n", + td_round ? "Rounding " : "", + (td_dir == OHCI_TD_D_IN) ? "Input " : + (td_dir == OHCI_TD_D_OUT) ? "Output " : + (td_dir == OHCI_TD_D_SETUP) ? "Setup " : "", + "IntDelay ", td_int_delay, + (td_toggle < 2) ? " " : + (td_toggle & 1) ? "Data1 " : "Data0 "); + printk(KERN_DEBUG " %s%d %s0x%x, %sAccessed, %sActive\n", + "ErrorCnt ", td_errcnt, + "ComplCode ", td_cc, + td_cc_accessed(*td) ? "" : "Not ", + td_active(*td) ? "" : "Not "); + + printk(KERN_DEBUG " cur_buf = 0x%x\n", td->cur_buf); + printk(KERN_DEBUG " next_td = 0x%x\n", td->next_td); + printk(KERN_DEBUG " buf_end = 0x%x\n", td->buf_end); + printk(KERN_DEBUG " ohci TD driver fields:\n"); + printk(KERN_DEBUG " data = %p\n", td->data); + printk(KERN_DEBUG " dev_id = %p\n", td->dev_id); + printk(KERN_DEBUG " ed = %p\n", td->ed); + if (td->data != NULL) { + unsigned char *d = td->data; + printk(KERN_DEBUG " DATA: %02x %02x %02x %02x %02x %02x %02x %02x\n", + d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7] ); + } +} /* show_ohci_td() */ + + +void show_ohci_device(struct ohci_device *dev) +{ + int idx; + printk(KERN_DEBUG " ohci_device usb = %p\n", dev->usb); + printk(KERN_DEBUG " ohci_device ohci = %p\n", dev->ohci); + printk(KERN_DEBUG " ohci_device ohci_hcca = %p\n", dev->hcca); + for (idx=0; idx<3 /*NUM_EDS*/; ++idx) { + printk(KERN_DEBUG " [ed num %d] ", idx); + show_ohci_ed(&dev->ed[idx]); + } + for (idx=0; idx<3 /*NUM_TDS*/; ++idx) { + printk(KERN_DEBUG " [td num %d] ", idx); + show_ohci_td(&dev->td[idx]); + } + printk(KERN_DEBUG " ohci_device data\n "); + for (idx=0; idx<4; ++idx) { + printk(KERN_DEBUG " %08lx", dev->data[idx]); + } + printk(KERN_DEBUG "\n"); +} /* show_ohci_device() */ + + +void show_ohci_hcca(struct ohci_hcca *hcca) +{ + int idx; + + printk(KERN_DEBUG " ohci_hcca\n"); + + for (idx=0; idxint_table +idx); + } + + printk(KERN_DEBUG " frame_no == %d\n", hcca->frame_no); + printk(KERN_DEBUG " donehead == 0x%08x\n", hcca->donehead); +} /* show_ohci_hcca() */ + + +/* vim:sw=8 + */ diff -ur --new-file old/linux/drivers/usb/ohci-hcd.c new/linux/drivers/usb/ohci-hcd.c --- old/linux/drivers/usb/ohci-hcd.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/usb/ohci-hcd.c Tue May 11 18:55:45 1999 @@ -0,0 +1,1489 @@ +/* + * OHCI HCD (Host Controller Driver) for USB. + * + * (C) Copyright 1999 Roman Weissgaerber + * + * 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) + * The layer on top of it, is for interfacing to the alternate-usb device-drivers. + * + * [ This is based on Linus' UHCI code and gregs OHCI fragments (0.03c source tree). ] + * [ Open Host Controller Interface driver for USB. ] + * [ (C) Copyright 1999 Linus Torvalds (uhci.c) ] + * [ (C) Copyright 1999 Gregory P. Smith ] + * [ $Log: ohci.c,v $ ] + * [ Revision 1.1 1999/04/05 08:32:30 greg ] + * + * + * v2.1 1999/05/09 ep_addr correction, code clean up + * v2.0 1999/05/04 + * virtual root hub is now an option, + * memory allocation based on kmalloc and kfree now, 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) (reset controller handling, hub) + * + * v1.0 1999/04/27 initial release + * ohci-hcd.c + */ + +/* #define OHCI_DBG */ /* printk some debug information */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "usb.h" +#include "ohci-hcd.h" +#include "inits.h" + + + +#ifdef CONFIG_APM +#include +static int handle_apm_event(apm_event_t event); +static int apm_resume = 0; +#endif + + + +static struct wait_queue *control_wakeup; +static struct wait_queue *root_hub = NULL; + +static __u8 cc_to_status[16] = { /* mapping of the OHCI CC to the UHCI status codes; first guess */ +/* Activ, Stalled, Data Buffer Err, Babble Detected : NAK recvd, CRC/Timeout, Bitstuff, reservd */ +/* No Error */ 0x00, +/* CRC Error */ 0x04, +/* Bit Stuff */ 0x02, +/* Data Togg */ 0x40, +/* Stall */ 0x40, +/* DevNotResp */ 0x04, +/* PIDCheck */ 0x04, +/* UnExpPID */ 0x40, +/* DataOver */ 0x20, +/* DataUnder */ 0x20, +/* reservd */ 0x40, +/* reservd */ 0x40, +/* BufferOver */ 0x20, +/* BuffUnder */ 0x20, +/* Not Access */ 0x80, +/* Not Access */ 0x80 + }; + + +/******** + **** Interface functions + ***********************************************/ + +static int sohci_int_handler(void * ohci_in, unsigned int ep_addr, int ctrl_len, void * ctrl, void * data, int data_len, int status, __OHCI_BAG lw0, __OHCI_BAG lw1) +{ + + struct ohci * ohci = ohci_in; + usb_device_irq handler=(void *) lw0; + void *dev_id = (void *) lw1; + int ret; + + OHCI_DEBUG({ int i; printk("USB HC IRQ <<<: %x: data(%d):", ep_addr, data_len);) + OHCI_DEBUG( for(i=0; i < data_len; i++ ) printk(" %02x", ((__u8 *) data)[i]);) + OHCI_DEBUG( printk(" ret_status: %x\n", status); }) + + ret = handler(cc_to_status[status & 0xf], data, dev_id); + if(ret == 0) return 0; /* 0 .. do not requeue */ + if(status > 0) return -1; /* error occured do not requeue ? */ + ohci_trans_req(ohci, ep_addr, 0, NULL, data, 8, (__OHCI_BAG) handler, (__OHCI_BAG) dev_id); /* requeue int request */ + return 0; +} + +static int sohci_ctrl_handler(void * ohci_in, unsigned int ep_addr, int ctrl_len, void * ctrl, void * data, int data_len, int status, __OHCI_BAG lw0, __OHCI_BAG lw) +{ + *(int * )lw0 = status; + wake_up(&control_wakeup); + + OHCI_DEBUG( { int i; printk("USB HC CTRL<<<: %x: ctrl(%d):", ep_addr, ctrl_len);) + OHCI_DEBUG( for(i=0; i < 8; i++ ) printk(" %02x", ((__u8 *) ctrl)[i]);) + OHCI_DEBUG( printk(" data(%d):", data_len);) + OHCI_DEBUG( for(i=0; i < data_len; i++ ) printk(" %02x", ((__u8 *) data)[i]);) + OHCI_DEBUG( printk(" ret_status: %x\n", status); }) + return 0; +} + +static int sohci_request_irq(struct usb_device *usb_dev, unsigned int pipe, usb_device_irq handler, int period, void *dev_id) +{ + struct ohci * ohci = usb_dev->bus->hcpriv; + union ep_addr_ ep_addr; + + ep_addr.iep = 0; + ep_addr.bep.ep = ((pipe >> 15) & 0x0f) /* endpoint address */ + | (pipe & 0x80) /* direction */ + | (1 << 5); /* type = int*/ + ep_addr.bep.fa = ((pipe >> 8) & 0x7f); /* device address */ + + OHCI_DEBUG( printk("USB HC IRQ >>>: %x: every %d ms\n", ep_addr.iep, period);) + + usb_ohci_add_ep(ohci, ep_addr.iep, period, 1, sohci_int_handler, 1 << ((pipe & 0x03) + 3) , (pipe >> 26) & 0x01); + + ohci_trans_req(ohci, ep_addr.iep, 0, NULL, ((struct ohci_device *) usb_dev->hcpriv)->data, 8, (__OHCI_BAG) handler, (__OHCI_BAG) dev_id); + return 0; +} + + +static int sohci_control_msg(struct usb_device *usb_dev, unsigned int pipe, void *cmd, void *data, int len) +{ + struct wait_queue wait = { current, NULL }; + struct ohci * ohci = usb_dev->bus->hcpriv; + int status; + union ep_addr_ ep_addr; + + ep_addr.iep = 0; + ep_addr.bep.ep = ((pipe >> 15) & 0x0f) /* endpoint address */ + | (pipe & 0x80) /* direction */ + | (1 << 6); /* type = ctrl*/ + ep_addr.bep.fa = ((pipe >> 8) & 0x7f); /* device address */ + + status = 0xf; /* CC not Accessed */ + OHCI_DEBUG( { int i; printk("USB HC CTRL>>>: %x: ctrl(%d):", ep_addr.iep, 8);) + OHCI_DEBUG( for(i=0; i < 8; i++ ) printk(" %02x", ((__u8 *) cmd)[i]);) + OHCI_DEBUG( printk(" data(%d):", len);) + OHCI_DEBUG( for(i=0; i < len; i++ ) printk(" %02x", ((__u8 *) data)[i]);) + OHCI_DEBUG( printk("\n"); }) + + usb_ohci_add_ep(ohci, ep_addr.iep, 0, 1, sohci_ctrl_handler, 1 << ((pipe & 0x03) + 3) , (pipe >> 26) & 0x01); + + current->state = TASK_UNINTERRUPTIBLE; + add_wait_queue(&control_wakeup, &wait); + + ohci_trans_req(ohci, ep_addr.iep, 8, cmd, data, len, (__OHCI_BAG) &status, 0); + + schedule_timeout(HZ/10); + + remove_wait_queue(&control_wakeup, &wait); + + OHCI_DEBUG(printk("USB HC status::: %x\n", cc_to_status[status & 0x0f]);) + + return cc_to_status[status & 0x0f]; +} + + +static int sohci_usb_deallocate(struct usb_device *usb_dev) { + struct ohci_device *dev = usb_to_ohci(usb_dev); + union ep_addr_ ep_addr; + + ep_addr.iep = 0; + + OHCI_DEBUG(printk("USB HC dealloc %x\n", usb_dev->devnum);) + + /* wait_ms(20); */ + + if(usb_dev->devnum >=0) { + ep_addr.bep.fa = usb_dev->devnum; + usb_ohci_rm_function(((struct ohci_device *)usb_dev->hcpriv)->ohci, ep_addr.iep); + } + + USB_FREE(dev); + USB_FREE(usb_dev); + + return 0; +} + +static struct usb_device *sohci_usb_allocate(struct usb_device *parent) { + + struct usb_device *usb_dev; + struct ohci_device *dev; + + + USB_ALLOC(usb_dev, sizeof(*usb_dev)); + if (!usb_dev) + return NULL; + + memset(usb_dev, 0, sizeof(*usb_dev)); + + USB_ALLOC(dev, sizeof(*dev)); + if (!dev) { + USB_FREE(usb_dev); + return NULL; + } + + /* Initialize "dev" */ + memset(dev, 0, sizeof(*dev)); + + usb_dev->hcpriv = dev; + dev->usb = usb_dev; + + usb_dev->parent = parent; + + if (parent) { + usb_dev->bus = parent->bus; + dev->ohci = usb_to_ohci(parent)->ohci; + } + return usb_dev; +} + +struct usb_operations sohci_device_operations = { + sohci_usb_allocate, + sohci_usb_deallocate, + sohci_control_msg, + sohci_request_irq, +}; + + +/****** + *** ED handling functions + ************************************/ + + + +/* + * search for the right place to insert an interrupt ed into the int tree + * do some load ballancing + * */ + +static int usb_ohci_int_ballance(struct ohci * ohci, int interval, int load) { + + int i,j; + + j = 0; /* search for the least loaded interrupt endpoint branch of all 32 branches */ + for(i=0; i< 32; i++) if(ohci->ohci_int_load[j] > ohci->ohci_int_load[i]) j=i; + + if(interval < 1) interval = 1; + if(interval > 32) interval = 32; + for(i= 0; ((interval >> i) > 1 ); interval &= (0xfffe << i++ )); /* interval = 2^int(ld(interval)) */ + + + for(i=j%interval; i< 32; i+=interval) ohci->ohci_int_load[i] += load; + j = interval + (j % interval); + + OHCI_DEBUG(printk("USB HC new int ed on pos : %x \n",j);) + + return j; +} + +/* get the ed from the endpoint / device adress */ + +struct usb_ohci_ed * ohci_find_ep(struct ohci *ohci, unsigned int ep_addr_in) { + +union ep_addr_ ep_addr; +struct usb_ohci_ed *tmp; +unsigned int mask; + +mask = 0; +ep_addr.iep = ep_addr_in; + +#ifdef VROOTHUB + if(ep_addr.bep.fa == ohci->root_hub_funct_addr) { + if((ep_addr.bep.ep & 0x0f) == 0) + return &ohci->ed_rh_ep0; /* root hub ep0 */ + else + return &ohci->ed_rh_epi; /* root hub int ep */ + } +#endif + + tmp = ohci->ed_func_ep0[ep_addr.bep.fa]; + mask = ((((ep_addr.bep.ep >> 5) & 0x03)==2)?0x7f:0xff); + ep_addr.bep.ep &= mask; /* mask out direction of ctrl ep */ + + while (tmp != NULL) { + if (tmp->ep_addr.iep == ep_addr.iep) + return tmp; + tmp = tmp->ed_list; + } + return NULL; +} + +spinlock_t usb_ed_lock = SPIN_LOCK_UNLOCKED; +/* add a new endpoint ep_addr */ +struct usb_ohci_ed *usb_ohci_add_ep(struct ohci * ohci, unsigned int ep_addr_in, int interval, int load, f_handler handler, int ep_size, int speed) { + + struct usb_ohci_ed * ed; + struct usb_ohci_td * td; + union ep_addr_ ep_addr; + + + int int_junk; + + struct usb_ohci_ed *tmp; + + ep_addr.iep = ep_addr_in ; + ep_addr.bep.ep &= ((((ep_addr.bep.ep >> 5) & 0x03)==2)?0x7f:0xff); /* mask out direction of ctrl ep */ + + spin_lock(&usb_ed_lock); + + tmp = ohci_find_ep(ohci, ep_addr.iep); + if (tmp != NULL) { + +#ifdef VROOTHUB + if(ep_addr.bep.fa == ohci->root_hub_funct_addr) { + if((ep_addr.bep.ep & 0x0f) != 0) { /* root hub int ep */ + ohci->ed_rh_epi.handler = handler; + ohci_init_rh_int_timer(ohci, interval); + } + else { /* root hub ep0 */ + ohci->ed_rh_ep0.handler = handler; + } + } + + else +#endif + + { + tmp->hw.info = ep_addr.bep.fa | ((ep_addr.bep.ep & 0xf) <<7) + + | (((ep_addr.bep.ep & 0x60) == 0)? 0x8000 : 0) + | (speed << 13) + | ep_size <<16; + + tmp->handler = handler; + } + spin_unlock(&usb_ed_lock); + return tmp; /* ed already in use */ + } + + + OHCI_ALLOC(td, sizeof(td)); /* dummy td; end of td list for ed */ + OHCI_ALLOC(ed, sizeof(ed)); + td->prev_td = NULL; + + ed->hw.tail_td = virt_to_bus(&td->hw); + ed->hw.head_td = ed->hw.tail_td; + ed->hw.info = ep_addr.bep.fa | ((ep_addr.bep.ep & 0xf) <<7) + /* | ((ep_addr.bep.port & 0x80)? 0x1000 : 0x0800 ) */ + | (((ep_addr.bep.ep & 0x60) == 0)? 0x8000 : 0) + | (speed << 13) + | ep_size <<16; + + ed->handler = handler; + + switch((ep_addr.bep.ep >> 5) & 0x03) { + case CTRL: + ed->hw.next_ed = 0; + if(ohci->ed_controltail == NULL) { + writel(virt_to_bus(&ed->hw), &ohci->regs->ed_controlhead); + } + else { + ohci->ed_controltail->hw.next_ed = virt_to_bus(&ed->hw); + } + ed->ed_prev = ohci->ed_controltail; + ohci->ed_controltail = ed; + break; + case BULK: + ed->hw.next_ed = 0; + if(ohci->ed_bulktail == NULL) { + writel(virt_to_bus(&ed->hw), &ohci->regs->ed_bulkhead); + } + else { + ohci->ed_bulktail->hw.next_ed = virt_to_bus(&ed->hw); + } + ed->ed_prev = ohci->ed_bulktail; + ohci->ed_bulktail = ed; + break; + case INT: + int_junk = usb_ohci_int_ballance(ohci, interval, load); + ed->hw.next_ed = ohci->hc_area->ed[int_junk].next_ed; + ohci->hc_area->ed[int_junk].next_ed = virt_to_bus(&ed->hw); + ed->ed_prev = (struct usb_ohci_ed *) &ohci->hc_area->ed[int_junk]; + break; + case ISO: + ed->hw.next_ed = 0; + ohci->ed_isotail->hw.next_ed = virt_to_bus(&ed->hw); + ed->ed_prev = ohci->ed_isotail; + ohci->ed_isotail = ed; + break; + } + ed->ep_addr = ep_addr; + + /* Add it to the "hash"-table of known endpoint descriptors */ + + ed->ed_list = ohci->ed_func_ep0[ed->ep_addr.bep.fa]; + ohci->ed_func_ep0[ed->ep_addr.bep.fa] = ed; + + spin_unlock(&usb_ed_lock); + + OHCI_DEBUG(printk("USB HC new ed %x: %x :", ep_addr.iep, (unsigned int ) ed); ) + OHCI_DEBUG({ int i; for( i= 0; i<8 ;i++) printk(" %4x", ((unsigned int *) ed)[i]) ; printk("\n"); }; ) + return 0; +} + +/***** + * Request the removal of an endpoint + * + * put the ep on the rm_list and request a stop of the bulk or ctrl list + * real removal is done at the next start of frame hardware interrupt + */ +int usb_ohci_rm_ep(struct ohci * ohci, struct usb_ohci_ed *ed) +{ + unsigned int flags; + struct usb_ohci_ed *tmp; + + OHCI_DEBUG(printk("USB HC remove ed %x: %x :\n", ed->ep_addr.iep, (unsigned int ) ed); ) + + spin_lock_irqsave(&usb_ed_lock, flags); + + tmp = ohci->ed_func_ep0[ed->ep_addr.bep.fa]; + if (tmp == NULL) { + spin_unlock_irqrestore(&usb_ed_lock, flags); + return 0; + } + + if(tmp == ed) { + ohci->ed_func_ep0[ed->ep_addr.bep.fa] = ed->ed_list; + } + else { + while (tmp->ed_list != ed) { + if (tmp->ed_list == NULL) { + spin_unlock_irqrestore(&usb_ed_lock, flags); + return 0; + } + tmp = tmp->ed_list; + } + tmp->ed_list = ed->ed_list; + } + ed->ed_list = ohci->ed_rm_list; + ohci->ed_rm_list = ed; + ed->hw.info |= OHCI_ED_SKIP; + + switch((ed->ep_addr.bep.ep >> 5) & 0x03) { + case CTRL: + writel_mask(~(0x01<<4), &ohci->regs->control); /* stop CTRL list */ + break; + case BULK: + writel_mask(~(0x01<<5), &ohci->regs->control); /* stop BULK list */ + break; + } + + + writel( OHCI_INTR_SF, &ohci->regs->intrenable); /* enable sof interrupt */ + + spin_unlock_irqrestore(&usb_ed_lock, flags); + + return 1; +} + +/* we have requested to stop the bulk or CTRL list, + * now we can remove the eds on the rm_list */ + +static int ohci_rm_eds(struct ohci * ohci) { + + unsigned int flags; + struct usb_ohci_ed *ed; + struct usb_ohci_ed *ed_tmp; + struct usb_ohci_td *td; + __u32 td_hw_tmp; + __u32 td_hw; + + spin_lock_irqsave(&usb_ed_lock, flags); + + ed = ohci->ed_rm_list; + + while (ed != NULL) { + + switch((ed->ep_addr.bep.ep >> 5) & 0x03) { + case CTRL: + if(ed->ed_prev == NULL) { + writel(ed->hw.next_ed, &ohci->regs->ed_controlhead); + } + else { + ed->ed_prev->hw.next_ed = ed->hw.next_ed; + } + if(ohci->ed_controltail == ed) { + ohci->ed_controltail = ed->ed_prev; + } + break; + case BULK: + if(ed->ed_prev == NULL) { + writel(ed->hw.next_ed, &ohci->regs->ed_bulkhead); + } + else { + ed->ed_prev->hw.next_ed = ed->hw.next_ed; + } + if(ohci->ed_bulktail == ed) { + ohci->ed_bulktail = ed->ed_prev; + } + break; + case INT: + ed->ed_prev->hw.next_ed = ed->hw.next_ed; + break; + case ISO: + ed->ed_prev->hw.next_ed = ed->hw.next_ed; + if(ohci->ed_isotail == ed) { + ohci->ed_isotail = ed->ed_prev; + } + break; + } + + if(ed->hw.next_ed != 0) ((struct usb_ohci_ed *) bus_to_virt(ed->hw.next_ed))->ed_prev = ed->ed_prev; + + +/* tds directly connected to ed */ + + td_hw = ed->hw.head_td & 0xfffffff0; + while(td_hw != 0) { + td = bus_to_virt(td_hw); + td_hw_tmp = td_hw; + td_hw = td->hw.next_td; + OHCI_FREE(td); /* free pending tds */ + if(td_hw_tmp == ed->hw.tail_td) break; + + } + + /* mark TDs on the hc done list (if there are any) */ + td_hw = readl(&ohci->regs->donehead) & 0xfffffff0; + while(td_hw != 0) { + td = bus_to_virt(td_hw); + td_hw = td->hw.next_td; + if(td->ep == ed) td->ep = 0; + } + + /* mark TDs on the hcca done list (if there are any) */ + td_hw = ohci->hc_area->hcca.done_head & 0xfffffff0 ; + + while(td_hw != 0) { + td = bus_to_virt(td_hw); + td_hw = td->hw.next_td; + if(td->ep == ed) td->ep = 0; + } + + ed_tmp = ed; + ed = ed->ed_list; + OHCI_FREE(ed_tmp); /* free ed */ + } + writel(0, &ohci->regs->ed_controlcurrent); /* reset CTRL list */ + writel(0, &ohci->regs->ed_bulkcurrent); /* reset BULK list */ + writel_set((0x01<<4), &ohci->regs->control); /* start CTRL u. (BULK list) */ + + spin_unlock_irqrestore(&usb_ed_lock, flags); + + ohci->ed_rm_list = NULL; + OHCI_DEBUG(printk("USB HC after rm ed control: %4x intrstat: %4x intrenable: %4x\n", readl(&ohci->regs->control),readl(&ohci->regs->intrstatus),readl(&ohci->regs->intrenable));) + + + return 0; +} + +/* remove all endpoints of a function (device) */ +int usb_ohci_rm_function( struct ohci * ohci, unsigned int ep_addr_in) +{ + struct usb_ohci_ed *ed; + struct usb_ohci_ed *tmp; + union ep_addr_ ep_addr; + + + + ep_addr.iep = ep_addr_in; + + for(ed = ohci->ed_func_ep0[ep_addr.bep.fa]; ed != NULL;) { + tmp = ed; + ed = ed->ed_list; + usb_ohci_rm_ep(ohci, tmp); + } + + + + return 1; +} + + + + + +/****** + *** TD handling functions + ************************************/ + + +#define FILL_TD(TD_PT, HANDLER, INFO, DATA, LEN, LW0, LW1) \ + td_pt = (TD_PT); \ + td_pt1 = (struct usb_ohci_td *) bus_to_virt(usb_ep->hw.tail_td); \ + td_pt1->ep = usb_ep; \ + td_pt1->handler = (HANDLER); \ + td_pt1->buffer_start = (DATA); \ + td_pt1->lw0 = (LW0); \ + td_pt1->lw1 = (LW1); \ + td_pt1->hw.info = (INFO); \ + td_pt1->hw.cur_buf = virt_to_bus(DATA); \ + td_pt1->hw.buf_end = td_pt1->hw.cur_buf + (LEN) - 1; \ + td_pt1->hw.next_td = virt_to_bus(td_pt); \ + usb_ep->hw.tail_td = virt_to_bus(td_pt); \ + td_pt->prev_td = td_pt1; \ + td_pt->hw.next_td = 0 + +spinlock_t usb_req_lock = SPIN_LOCK_UNLOCKED; + +int ohci_trans_req(struct ohci * ohci, unsigned int ep_addr, int ctrl_len, void *ctrl, void * data, int data_len, __OHCI_BAG lw0, __OHCI_BAG lw1) { + + int ed_type; + unsigned int flags; + struct usb_ohci_td *td_pt; + struct usb_ohci_td *td_pt1; + struct usb_ohci_td *td_pt_a1, *td_pt_a2, *td_pt_a3; + struct usb_ohci_ed *usb_ep; + f_handler handler; + + + td_pt_a1 =NULL; + td_pt_a2 =NULL; + td_pt_a3 =NULL; + + usb_ep = ohci_find_ep(ohci, ep_addr); + if(usb_ep == NULL ) return -1; /* not known ep */ + + handler = usb_ep->handler; + +#ifdef VROOTHUB + if(usb_ep == &ohci->ed_rh_ep0) { /* root hub ep 0 control endpoint */ + root_hub_control_msg(ohci, 8, ctrl, data, data_len, lw0, lw1, handler); + return 0; + } + + if(usb_ep == &ohci->ed_rh_epi) { /* root hub interrupt endpoint */ + + root_hub_int_req(ohci, 8, ctrl, data, data_len, lw0, lw1, handler); + return 0; + } +#endif + /* struct usb_ohci_ed * usb_ep = usb_ohci_add_ep(pipe, ohci, interval, 1); */ + + ed_type = ((((union ep_addr_)ep_addr).bep.ep >> 5) & 0x07); + + switch(ed_type) { + case BULK_IN: + case BULK_OUT: + case INT_IN: + case INT_OUT: + OHCI_ALLOC(td_pt_a1, sizeof(td_pt_a1)); + break; + + case CTRL_IN: + case CTRL_OUT: + OHCI_ALLOC(td_pt_a1, sizeof(td_pt_a1)); + OHCI_ALLOC(td_pt_a3, sizeof(td_pt_a3)); + if(data_len > 0) { + OHCI_ALLOC(td_pt_a2, sizeof(td_pt_a2)); + } + break; + + case ISO_IN: + case ISO_OUT: + + } + + spin_lock_irqsave(&usb_req_lock, flags); + + switch(ed_type) { + case BULK_IN: + FILL_TD( td_pt_a1, handler, TD_CC | TD_R | TD_DP_IN | TD_T_TOGGLE, data, data_len, lw0, lw1 ); + writel( OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */ + break; + + case BULK_OUT: + FILL_TD( td_pt_a1, handler, TD_CC | TD_DP_OUT | TD_T_TOGGLE, data, data_len, lw0, lw1 ); + writel( OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */ + break; + + case INT_IN: + FILL_TD( td_pt_a1, handler, TD_CC | TD_R | TD_DP_IN | TD_T_TOGGLE, data, data_len, lw0, lw1 ); + break; + + case INT_OUT: + FILL_TD( td_pt_a1, handler, TD_CC | TD_DP_OUT | TD_T_TOGGLE, data, data_len, lw0, lw1 ); + break; + + case CTRL_IN: + FILL_TD( td_pt_a1, NULL, TD_CC | TD_DP_SETUP | TD_T_DATA0, ctrl, ctrl_len, 0, 0 ); + if(data_len > 0) { + FILL_TD( td_pt_a2, NULL, TD_CC | TD_R | TD_DP_IN | TD_T_DATA1, data, data_len, 0, 0 ); + } + FILL_TD( td_pt_a3, handler, TD_CC | TD_DP_OUT | TD_T_DATA1, NULL, 0, lw0, lw1 ); + writel( OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */ + break; + + case CTRL_OUT: + FILL_TD( td_pt_a1, NULL, TD_CC | TD_DP_SETUP | TD_T_DATA0, ctrl, ctrl_len, 0, 0 ); + if(data_len > 0) { + FILL_TD( td_pt_a2, NULL, TD_CC | TD_R | TD_DP_OUT | TD_T_DATA1, data, data_len, 0, 0 ); + } + FILL_TD( td_pt_a3, handler, TD_CC | TD_DP_IN | TD_T_DATA1, NULL, 0, lw0, lw1 ); + writel( OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */ + break; + + case ISO_IN: + case ISO_OUT: + break; + } + + + + + td_pt1 = (struct usb_ohci_td *) bus_to_virt(usb_ep->hw.tail_td); + + + if(td_pt_a3 != NULL) td_pt_a3->prev_td = NULL; + else if (td_pt_a2 != NULL) td_pt_a2->prev_td = NULL; + else if (td_pt_a1 != NULL) td_pt_a1->prev_td = NULL; + + spin_unlock_irqrestore(&usb_req_lock, flags); + return 0; +} + + +/****** + *** Done List handling functions + ************************************/ + +/* replies to the request have to be on a FIFO basis so + * we reverse the reversed done-list */ + +static struct usb_ohci_td * ohci_reverse_done_list(struct ohci * ohci) { + + __u32 td_list_hc; + struct usb_ohci_td * td_list = NULL; + struct usb_ohci_td * td_rev = NULL; + + td_list_hc = ohci->hc_area->hcca.done_head & 0xfffffff0; + ohci->hc_area->hcca.done_head = 0; + + while(td_list_hc) { + + td_list = (struct usb_ohci_td *) bus_to_virt(td_list_hc); + td_list->next_dl_td = td_rev; + + td_rev = td_list; + td_list_hc = td_list->hw.next_td & 0xfffffff0; + } + return td_list; +} + +/* all done requests are replied here */ +static int usb_ohci_done_list(struct ohci * ohci) { + + struct usb_ohci_td * td = NULL; + struct usb_ohci_td * td_list; + struct usb_ohci_td * td_list_next = NULL; + struct usb_ohci_td * td_err = NULL; + __u32 td_hw; + + + td_list = ohci_reverse_done_list(ohci); + + while(td_list) { + td_list_next = td_list->next_dl_td; + td = td_list; + + if(td->ep == NULL) { /* removed ep */ + OHCI_FREE(td_list); + break; + } + + /* the HC halts an ED if an error occurs; put all pendings TDs of an halted ED on the + * done list; they are marked with an 0xf CC_error code + */ + + if(TD_CC_GET(td_list->hw.info) != TD_CC_NOERROR) { /* on error move all pending tds of an ed into the done list */ + printk("******* USB BUS error %x @ep %x\n", TD_CC_GET(td_list->hw.info), td_list->ep->ep_addr.iep); + td_err= td_list; + td_hw = td_list->ep->hw.head_td & 0xfffffff0; + while(td_hw != 0) { + if(td_hw == td_list->ep->hw.tail_td) break; + td = bus_to_virt(td_hw); + td_err->next_dl_td = td; + td_err= td; + td_hw = td->hw.next_td; + } + td_list->ep->hw.head_td = td_list->ep->hw.tail_td; + td->next_dl_td = td_list_next; + td_list_next = td_list->next_dl_td; + + } + /* send the reply */ + if(td_list->handler != NULL) { + if(td_list->prev_td == NULL) { + td_list->handler((void *) ohci, + td_list->ep->ep_addr.iep, + 0, + NULL, + td_list->buffer_start, + td_list->hw.buf_end-virt_to_bus(td_list->buffer_start)+1, + TD_CC_GET(td_list->hw.info), + td_list->lw0, + td_list->lw1); + OHCI_FREE(td_list); + } + else { + if(td_list->prev_td->prev_td == NULL) { /* cntrl 2 Transactions dataless */ + td_list->handler((void *) ohci, + td_list->ep->ep_addr.iep, + td_list->prev_td->hw.buf_end-virt_to_bus(td_list->prev_td->buffer_start)+1, + td_list->prev_td->buffer_start, + NULL, + 0, + (TD_CC_GET(td_list->prev_td->hw.info) > 0) ? TD_CC_GET(td_list->prev_td->hw.info) : TD_CC_GET(td_list->hw.info), + td_list->lw0, + td_list->lw1); + OHCI_FREE(td_list->prev_td); + OHCI_FREE(td_list); + } + else { /* cntrl 3 Transactions */ + td_list->handler((void *) ohci, + td_list->ep->ep_addr.iep, + td_list->prev_td->prev_td->hw.buf_end-virt_to_bus(td_list->prev_td->prev_td->buffer_start)+1, + td_list->prev_td->prev_td->buffer_start, + td_list->prev_td->buffer_start, + td_list->prev_td->hw.buf_end-virt_to_bus(td_list->prev_td->buffer_start)+1, + (TD_CC_GET(td_list->prev_td->prev_td->hw.info) > 0) ? TD_CC_GET(td_list->prev_td->prev_td->hw.info) + : (TD_CC_GET(td_list->prev_td->hw.info) > 0) ? TD_CC_GET(td_list->prev_td->hw.info) : TD_CC_GET(td_list->hw.info), + td_list->lw0, + td_list->lw1); + OHCI_FREE(td_list->prev_td->prev_td); + OHCI_FREE(td_list->prev_td); + OHCI_FREE(td_list); + + } + } + + } + td_list = td_list_next; + } + return 0; +} + + + +/****** + *** HC functions + ************************************/ + + + +void reset_hc(struct ohci *ohci) { + int retries = 5; + int timeout = 30; + int fminterval; + + if(readl(&ohci->regs->control) & 0x100) { /* SMM owns the HC */ + writel(0x08, &ohci->regs->cmdstatus); /* request ownership */ + printk("USB HC TakeOver from SMM\n"); + do { + wait_ms(100); + if(--retries) { + printk("USB HC TakeOver timed out!\n"); + break; + } + } + while(readl(&ohci->regs->control) & 0x100); + } + + writel((1<<31), &ohci->regs->intrdisable); /* Disable HC interrupts */ + OHCI_DEBUG(printk("USB HC reset_hc: %x ; retries: %d\n", readl(&ohci->regs->control), 5-retries);) + fminterval = readl(&ohci->regs->fminterval) & 0x3fff; + writel(1, &ohci->regs->cmdstatus); /* HC Reset */ + while ((readl(&ohci->regs->cmdstatus) & 0x01) != 0) { /* 10us Reset */ + if (--timeout == 0) { + printk("USB HC reset timed out!\n"); + return; + } + udelay(1); + } + /* set the timing */ + fminterval |= (((fminterval -210) * 6)/7)<<16; + writel(fminterval, &ohci->regs->fminterval); + writel(((fminterval&0x3fff)*9)/10, &ohci->regs->periodicstart); +} + + +/* + * Reset and start an OHCI controller + */ +void start_hc(struct ohci *ohci) +{ + /* int fminterval; */ + unsigned int mask; + /* fminterval = readl(&ohci->regs->fminterval) & 0x3fff; + reset_hc(ohci); */ + + + writel(virt_to_bus(&ohci->hc_area->hcca), &ohci->regs->hcca); /* a reset clears this */ + + /* Choose the interrupts we care about now, others later on demand */ + mask = OHCI_INTR_MIE | OHCI_INTR_WDH; + /* | OHCI_INTR_SO | OHCI_INTR_UE |OHCI_INTR_RHSC |OHCI_INTR_SF| + OHCI_INTR_FNO */ + + + + writel((0x00), &ohci->regs->control); /* USB Reset BUS */ + wait_ms(10); + + writel((0x97), &ohci->regs->control); /* USB Operational */ + + writel( 0x10000, &ohci->regs->roothub.status); /* root hub power on */ + wait_ms(50); + + OHCI_DEBUG(printk("USB HC rstart_hc_operational: %x\n", readl(&ohci->regs->control)); ) + OHCI_DEBUG(printk("USB HC roothubstata: %x \n", readl( &(ohci->regs->roothub.a) )); ) + OHCI_DEBUG(printk("USB HC roothubstatb: %x \n", readl( &(ohci->regs->roothub.b) )); ) + OHCI_DEBUG(printk("USB HC roothubstatu: %x \n", readl( &(ohci->regs->roothub.status) )); ) + OHCI_DEBUG(printk("USB HC roothubstat1: %x \n", readl( &(ohci->regs->roothub.portstatus[0]) )); ) + OHCI_DEBUG(printk("USB HC roothubstat2: %x \n", readl( &(ohci->regs->roothub.portstatus[1]) )); ) + + /* control_wakeup = NULL; */ + writel(mask, &ohci->regs->intrenable); + writel(mask, &ohci->regs->intrstatus); + +#ifdef VROOTHUB + { + + struct usb_device * usb_dev; + struct ohci_device *dev; + + usb_dev = sohci_usb_allocate(ohci->root_hub->usb); + dev = usb_dev->hcpriv; + + dev->ohci = ohci; + + usb_connect(usb_dev); + + ohci->root_hub->usb->children[0] = usb_dev; + + usb_new_device(usb_dev); + } +#endif + + + +} + + + + +static void ohci_interrupt(int irq, void *__ohci, struct pt_regs *r) +{ + struct ohci *ohci = __ohci; + struct ohci_regs *regs = ohci->regs; + + int ints; + + + if((ohci->hc_area->hcca.done_head != 0) && !(ohci->hc_area->hcca.done_head & 0x01)) { + ints = OHCI_INTR_WDH; + } + else { + if((ints = (readl(®s->intrstatus) & readl(®s->intrenable))) == 0) + return; + } + + ohci->intrstatus |= ints; + OHCI_DEBUG(printk("USB HC interrupt: %x (%x) \n", ints, readl(&ohci->regs->intrstatus));) + + /* ints &= ~(OHCI_INTR_WDH); WH Bit will be set by done list subroutine */ + /* if(ints & OHCI_INTR_FNO) { + writel(OHCI_INTR_FNO, ®s->intrstatus); + if (waitqueue_active(&ohci_tasks)) wake_up(&ohci_tasks); + } */ + + if(ints & OHCI_INTR_WDH) { + writel(OHCI_INTR_WDH, ®s->intrdisable); + ohci->intrstatus &= (~OHCI_INTR_WDH); + usb_ohci_done_list(ohci); /* prepare out channel list */ + writel(OHCI_INTR_WDH, &ohci->regs->intrstatus); + writel(OHCI_INTR_WDH, &ohci->regs->intrenable); + + } + + if(ints & OHCI_INTR_SF) { + writel(OHCI_INTR_SF, ®s->intrdisable); + writel(OHCI_INTR_SF, &ohci->regs->intrstatus); + ohci->intrstatus &= (~OHCI_INTR_SF); + if(ohci->ed_rm_list != NULL) { + ohci_rm_eds(ohci); + } + } +#ifndef VROOTHUB + if(ints & OHCI_INTR_RHSC) { + writel(OHCI_INTR_RHSC, ®s->intrdisable); + writel(OHCI_INTR_RHSC, &ohci->regs->intrstatus); + wake_up(&root_hub); + + } + #endif + + writel(OHCI_INTR_MIE, ®s->intrenable); + +} + +#ifndef VROOTHUB +/* + * This gets called if the connect status on the root + * hub (and the root hub only) changes. + */ +static void ohci_connect_change(struct ohci *ohci, unsigned int port_nr) +{ + struct usb_device *usb_dev; + struct ohci_device *dev; + OHCI_DEBUG(printk("uhci_connect_change: called for %d stat %x\n", port_nr,readl(&ohci->regs->roothub.portstatus[port_nr]) );) + + /* + * Even if the status says we're connected, + * the fact that the status bits changed may + * that we got disconnected and then reconnected. + * + * So start off by getting rid of any old devices.. + */ + usb_disconnect(&ohci->root_hub->usb->children[port_nr]); + + if(!(readl(&ohci->regs->roothub.portstatus[port_nr]) & RH_PS_CCS)) { + writel(RH_PS_CCS, &ohci->regs->roothub.portstatus[port_nr]); + return; /* nothing connected */ + } + /* + * Ok, we got a new connection. Allocate a device to it, + * and find out what it wants to do.. + */ + usb_dev = sohci_usb_allocate(ohci->root_hub->usb); + dev = usb_dev->hcpriv; + dev->ohci = ohci; + usb_connect(dev->usb); + ohci->root_hub->usb->children[port_nr] = usb_dev; + wait_ms(200); /* wait for powerup */ + /* reset port/device */ + writel(RH_PS_PRS, &ohci->regs->roothub.portstatus[port_nr]); /* reset port */ + while(!(readl( &ohci->regs->roothub.portstatus[port_nr]) & RH_PS_PRSC)) wait_ms(10); /* reset active ? */ + writel(RH_PS_PES, &ohci->regs->roothub.portstatus[port_nr]); /* enable port */ + wait_ms(10); + /* Get speed information */ + usb_dev->slow = (readl( &ohci->regs->roothub.portstatus[port_nr]) & RH_PS_LSDA) ? 1 : 0; + + /* + * Ok, all the stuff specific to the root hub has been done. + * The rest is generic for any new USB attach, regardless of + * hub type. + */ + usb_new_device(usb_dev); +} +#endif + + + +/* + * Allocate the resources required for running an OHCI controller. + * Host controller interrupts must not be running while calling this + * function. + * + * The mem_base parameter must be the usable -virtual- address of the + * host controller's memory mapped I/O registers. + * + * This is where OHCI triumphs over UHCI, because good is dumb. + * Note how much simpler this function is than in uhci.c. + * + * OHCI hardware takes care of most of the scheduling of different + * transfer types with the correct prioritization for us. + */ + + +static struct ohci *alloc_ohci(void* mem_base) +{ + int i,j; + struct ohci *ohci; + struct ohci_hc_area *hc_area; + struct usb_bus *bus; + struct ohci_device *dev; + struct usb_device *usb; + + /* + * Here we allocate some dummy EDs as well as the + * OHCI host controller communications area. The HCCA is just + * a nice pool of memory with pointers to endpoint descriptors + * for the different interrupts. + * + * The first page of memory contains the HCCA and ohci structure + */ + hc_area = (struct ohci_hc_area *) __get_free_pages(GFP_KERNEL, 1); + if (!hc_area) + return NULL; + memset(hc_area, 0, sizeof(*hc_area)); + ohci = &hc_area->ohci; + ohci->irq = -1; + ohci->regs = mem_base; + + ohci->hc_area = hc_area; + /* Tell the controller where the HCCA is */ + writel(virt_to_bus(&hc_area->hcca), &ohci->regs->hcca); + + + /* + * Initialize the ED polling "tree", full tree; + * dummy eds ed[i] (hc should skip them) + * i == 0 is the end of the iso list; + * 1 is the 1ms node, + * 2,3 2ms nodes, + * 4,5,6,7 4ms nodes, + * 8 ... 15 8ms nodes, + * 16 ... 31 16ms nodes, + * 32 ... 63 32ms nodes + * Sequenzes: + * 32-16- 8-4-2-1-0 + * 33-17- 9-5-3-1-0 + * 34-18-10-6-2-1-0 + * 35-19-11-7-3-1-0 + * 36-20-12-4-2-1-0 + * 37-21-13-5-3-1-0 + * 38-22-14-6-2-1-0 + * 39-23-15-7-3-1-0 + * 40-24- 8-4-2-1-0 + * 41-25- 9-5-3-1-0 + * 42-26-10-6-2-1-0 + * : : + * 63-31-15-7-3-1-0 + */ + hc_area->ed[ED_ISO].info |= OHCI_ED_SKIP; /* place holder, so skip it */ + hc_area->ed[ED_ISO].next_ed = 0x0000; /* end of iso list */ + + hc_area->ed[1].next_ed = virt_to_bus(&(hc_area->ed[ED_ISO])); + hc_area->ed[1].info |= OHCI_ED_SKIP; /* place holder, skip it */ + + j=1; + for (i = 2; i < (NUM_INTS * 2); i++) { + if (i >= NUM_INTS) + hc_area->hcca.int_table[i - NUM_INTS] = virt_to_bus(&(hc_area->ed[i])); + + if( i == j*4) j *= 2; + hc_area->ed[i].next_ed = virt_to_bus(&(hc_area->ed[j+ i%j])); + hc_area->ed[i].info |= OHCI_ED_SKIP; /* place holder, skip it */ + } + + + /* + * for load ballancing of the interrupt branches + */ + for (i = 0; i < NUM_INTS; i++) ohci->ohci_int_load[i] = 0; + + /* + * Store the end of control and bulk list eds. So, we know where we can add + * elements to these lists. + */ + ohci->ed_isotail = (struct usb_ohci_ed *) &(hc_area->ed[ED_ISO]); + ohci->ed_controltail = NULL; + ohci->ed_bulktail = NULL; + + /* + * Tell the controller where the control and bulk lists are + * The lists are empty now. + */ + writel(0, &ohci->regs->ed_controlhead); + writel(0, &ohci->regs->ed_bulkhead); + + + USB_ALLOC(bus, sizeof(*bus)); + if (!bus) + return NULL; + + memset(bus, 0, sizeof(*bus)); + + ohci->bus = bus; + bus->hcpriv = (void *) ohci; + bus->op = &sohci_device_operations; + + + usb = sohci_usb_allocate(NULL); + if (!usb) + return NULL; + + dev = ohci->root_hub = usb_to_ohci(usb); + + usb->bus = bus; + /* bus->root_hub = ohci_to_usb(ohci->root_hub); */ + dev->ohci = ohci; + + /* Initialize the root hub */ + + usb->maxchild = readl(&ohci->regs->roothub.a) & 0xff; + usb_init_root_hub(usb); + + return ohci; +} + + +/* + * De-allocate all resources.. + */ + +static void release_ohci(struct ohci *ohci) +{ + int i; + union ep_addr_ ep_addr; + ep_addr.iep = 0; + + OHCI_DEBUG(printk("USB HC release ohci \n");) + + if (ohci->irq >= 0) { + free_irq(ohci->irq, ohci); + ohci->irq = -1; + } + + /* stop hc */ + writel(OHCI_USB_SUSPEND, &ohci->regs->control); + + /* deallocate all EDs and TDs */ + for(i=0; i < 128; i ++) { + ep_addr.bep.fa = i; + usb_ohci_rm_function(ohci, ep_addr.iep); + } + ohci_rm_eds(ohci); /* remove eds */ + + /* disconnect all devices */ + if(ohci->root_hub) + for(i = 0; i < ohci->root_hub->usb->maxchild; i++) + usb_disconnect(ohci->root_hub->usb->children + i); + + USB_FREE(ohci->root_hub->usb); + USB_FREE(ohci->root_hub); + USB_FREE(ohci->bus); + + /* unmap the IO address space */ + iounmap(ohci->regs); + + + free_pages((unsigned int) ohci->hc_area, 1); + +} + + +void cleanup_drivers(void); + +static int ohci_roothub_thread(void * __ohci) +{ + struct ohci *ohci = (struct ohci *)__ohci; + lock_kernel(); + + /* + * This thread doesn't need any user-level access, + * so get rid of all our resources.. + */ + printk("ohci_roothub_thread at %p\n", &ohci_roothub_thread); + exit_mm(current); + exit_files(current); + exit_fs(current); + + + strcpy(current->comm, "root-hub"); + + + start_hc(ohci); + writel( 0x10000, &ohci->regs->roothub.status); + wait_ms(50); /* root hub power on */ + do { +#ifdef CONFIG_APM + if (apm_resume) { + apm_resume = 0; + start_hc(ohci); + continue; + } +#endif + + OHCI_DEBUG(printk("USB RH tasks: int: %x\n", ohci->intrstatus); ) +#ifndef VROOTHUB + /* if (ohci->intrstatus & OHCI_INTR_RHSC) */ + { + int port_nr; + for(port_nr=0; port_nr< ohci->root_hub->usb->maxchild; port_nr++) + if(readl(&ohci->regs->roothub.portstatus[port_nr]) & (RH_PS_CSC | RH_PS_PRSC)) { + ohci_connect_change(ohci, port_nr); + writel(0xffff0000, &ohci->regs->roothub.portstatus[port_nr]); + } + ohci->intrstatus &= ~(OHCI_INTR_RHSC); + writel(OHCI_INTR_RHSC, &ohci->regs->intrenable); + } +#endif + + interruptible_sleep_on(&root_hub); + + } while (!signal_pending(current)); + +#ifdef VROOTHUB + ohci_del_rh_int_timer(ohci); +#endif + + + cleanup_drivers(); + /* reset_hc(ohci); */ + + release_ohci(ohci); + MOD_DEC_USE_COUNT; + + printk("ohci_control_thread exiting\n"); + + return 0; +} + + + + +/* + * Increment the module usage count, start the control thread and + * return success. + */ +static int found_ohci(int irq, void* mem_base) +{ + int retval; + struct ohci *ohci; + OHCI_DEBUG(printk("USB HC found ohci: irq= %d membase= %x \n", irq, (int)mem_base);) + /* Allocate the running OHCI structures */ + ohci = alloc_ohci(mem_base); + if (!ohci) { + return -ENOMEM; + } + + reset_hc(ohci); + + retval = -EBUSY; + if (request_irq(irq, ohci_interrupt, SA_SHIRQ, "ohci-usb", ohci) == 0) { + int pid; + + MOD_INC_USE_COUNT; + ohci->irq = irq; + + pid = kernel_thread(ohci_roothub_thread, ohci, CLONE_FS | CLONE_FILES | CLONE_SIGHAND); + if (pid >= 0) + return 0; + + + MOD_DEC_USE_COUNT; + retval = pid; + } + + release_ohci(ohci); + return retval; +} + +static int start_ohci(struct pci_dev *dev) +{ + unsigned int mem_base = dev->base_address[0]; + + /* If its OHCI, its memory */ + if (mem_base & PCI_BASE_ADDRESS_SPACE_IO) + return -ENODEV; + + /* Get the memory address and map it for IO */ + mem_base &= PCI_BASE_ADDRESS_MEM_MASK; + + /* + * FIXME ioremap_nocache isn't implemented on all CPUs (such + * as the Alpha) [?] What should I use instead... + * + * The iounmap() is done on in release_ohci. + */ + mem_base = (unsigned int) ioremap_nocache(mem_base, 4096); + + if (!mem_base) { + printk("Error mapping OHCI memory\n"); + return -EFAULT; + } + + return found_ohci(dev->irq, (void *) mem_base); +} + + + +#ifdef CONFIG_APM +static int handle_apm_event(apm_event_t event) +{ + static int down = 0; + + switch (event) { + case APM_SYS_SUSPEND: + case APM_USER_SUSPEND: + if (down) { + printk(KERN_DEBUG "ohci: received extra suspend event\n"); + break; + } + down = 1; + break; + case APM_NORMAL_RESUME: + case APM_CRITICAL_RESUME: + if (!down) { + printk(KERN_DEBUG "ohci: received bogus resume event\n"); + break; + } + down = 0; + if (waitqueue_active(&root_hub)) { + apm_resume = 1; + wake_up(&root_hub); + } + break; + } + return 0; +} +#endif + + + int usb_mouse_init(void); +#ifdef MODULE + +void cleanup_module(void) +{ +#ifdef CONFIG_APM + apm_unregister_callback(&handle_apm_event); +#endif +} + +#define ohci_hcd_init init_module + +#endif + +#define PCI_CLASS_SERIAL_USB_OHCI 0x0C0310 +#define PCI_CLASS_SERIAL_USB_OHCI_PG 0x10 + + +int ohci_hcd_init(void) +{ + int retval; + struct pci_dev *dev = NULL; + + retval = -ENODEV; + + dev = NULL; + while((dev = pci_find_class(PCI_CLASS_SERIAL_USB_OHCI, dev))) { /* OHCI */ + retval = start_ohci(dev); + if (retval < 0) break; + + +#ifdef CONFIG_USB_MOUSE + usb_mouse_init(); +#endif +#ifdef CONFIG_USB_KBD + usb_kbd_init(); +#endif + hub_init(); +#ifdef CONFIG_USB_AUDIO + usb_audio_init(); +#endif +#ifdef CONFIG_APM + apm_register_callback(&handle_apm_event); +#endif + + return 0; + } + return retval; +} + +void cleanup_drivers(void) +{ + hub_cleanup(); +#ifdef CONFIG_USB_MOUSE + usb_mouse_cleanup(); +#endif +} + diff -ur --new-file old/linux/drivers/usb/ohci-hcd.h new/linux/drivers/usb/ohci-hcd.h --- old/linux/drivers/usb/ohci-hcd.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/usb/ohci-hcd.h Tue May 11 18:55:45 1999 @@ -0,0 +1,404 @@ + /* + * OHCI HCD (Host Controller Driver) for USB. + * + * (C) Copyright 1999 Roman Weissgaerber + * + * 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) + * The layer on top of it, is for interfacing to the alternate-usb device-drivers. + * + * [ This is based on Linus' UHCI code and gregs OHCI fragments (0.03c source tree). ] + * [ Open Host Controller Interface driver for USB. ] + * [ (C) Copyright 1999 Linus Torvalds (uhci.c) ] + * [ (C) Copyright 1999 Gregory P. Smith ] + * [ $Log: ohci.c,v $ ] + * [ Revision 1.1 1999/04/05 08:32:30 greg ] + * + * + * v2.1 1999/05/09 ep_addr correction, code clean up + * v2.0 1999/05/04 + * v1.0 1999/04/27 + * ohci-hcd.h + */ + +#include + +#ifdef CONFIG_USB_OHCI_VROOTHUB +#define VROOTHUB +#endif +/* enables virtual root hub + * (root hub will be managed by the hub controller + * hub.c of the alternate usb driver) + * last time I did more testing without virtual root hub + * -> the virtual root hub could be more unstable now */ + + + +#ifdef OHCI_DBG +#define OHCI_DEBUG(X) X +#else +#define OHCI_DEBUG(X) +#endif + +/* for readl writel functions */ +#include +#include + +/* for ED and TD structures */ + +typedef void * __OHCI_BAG; +typedef int (*f_handler )(void * ohci, unsigned int ep_addr, int cmd_len, void *cmd, void *data, int data_len, int status, __OHCI_BAG lw0, __OHCI_BAG lw1); + + + +struct ep_address { + __u8 ep; /* bit 7: IN/-OUT, 6,5: type 10..CTRL 00..ISO 11..BULK 10..INT, 3..0: ep nr */ + __u8 fa; /* function address */ + __u8 hc; + __u8 host; +}; + +union ep_addr_ { + unsigned int iep; + struct ep_address bep; +}; + +/* + * ED and TD descriptors has to be 16-byte aligned + */ +struct ohci_hw_ed { + __u32 info; + __u32 tail_td; /* TD Queue tail pointer */ + __u32 head_td; /* TD Queue head pointer */ + __u32 next_ed; /* Next ED */ +} __attribute((aligned(16))); + + +struct usb_ohci_ed { + struct ohci_hw_ed hw; + /* struct ohci * ohci; */ + f_handler handler; + union ep_addr_ ep_addr; + struct usb_ohci_ed *ed_list; + struct usb_ohci_ed *ed_prev; +} __attribute((aligned(32))); + + /* OHCI Hardware fields */ +struct ohci_hw_td { + __u32 info; + __u32 cur_buf; /* Current Buffer Pointer */ + __u32 next_td; /* Next TD Pointer */ + __u32 buf_end; /* Memory Buffer End Pointer */ +} __attribute((aligned(16))); + +/* TD info field */ +#define TD_CC 0xf0000000 +#define TD_CC_GET(td_p) ((td_p >>28) & 0x04) +#define TD_EC 0x0C000000 +#define TD_T 0x03000000 +#define TD_T_DATA0 0x02000000 +#define TD_T_DATA1 0x03000000 +#define TD_T_TOGGLE 0x00000000 +#define TD_R 0x00040000 +#define TD_DI 0x00E00000 +#define TD_DI_SET(X) (((X) & 0x07)<< 21) +#define TD_DP 0x00180000 +#define TD_DP_SETUP 0x00000000 +#define TD_DP_IN 0x00100000 +#define TD_DP_OUT 0x00080000 + +/* CC Codes */ +#define TD_CC_NOERROR 0x00 +#define TD_CC_CRC 0x01 +#define TD_CC_BITSTUFFING 0x02 +#define TD_CC_DATATOGGLEM 0x03 +#define TD_CC_STALL 0x04 +#define TD_DEVNOTRESP 0x05 +#define TD_PIDCHECKFAIL 0x06 +#define TD_UNEXPECTEDPID 0x07 +#define TD_DATAOVERRUN 0x08 +#define TD_DATAUNDERRUN 0x09 +#define TD_BUFFEROVERRUN 0x0C +#define TD_BUFFERUNDERRUN 0x0D +#define TD_NOTACCESSED 0x0F + + + +struct usb_ohci_td { + struct ohci_hw_td hw; + void * buffer_start; + f_handler handler; + struct usb_ohci_td *prev_td; + struct usb_ohci_ed *ep; + struct usb_ohci_td *next_dl_td; + __OHCI_BAG lw0; + __OHCI_BAG lw1; +} __attribute((aligned(32))); + + + +/* TD types */ +#define BULK 0x03 +#define INT 0x01 +#define CTRL 0x02 +#define ISO 0x00 +/* TD types with direction */ +#define BULK_IN 0x07 +#define BULK_OUT 0x03 +#define INT_IN 0x05 +#define INT_OUT 0x01 +#define CTRL_IN 0x06 +#define CTRL_OUT 0x02 +#define ISO_IN 0x04 +#define ISO_OUT 0x00 + +struct ohci_rep_td { + int cmd_len; + void * cmd; + void * data; + int data_len; + f_handler handler; + struct ohci_rep_td *next_td; + int ep_addr; + __OHCI_BAG lw0; + __OHCI_BAG lw1; + __u32 status; +} __attribute((aligned(32))); + +#define OHCI_ED_SKIP (1 << 14) +#define OHCI_ED_MPS (0x7ff << 16) +#define OHCI_ED_F_NORM (0) +#define OHCI_ED_F_ISOC (1 << 15) +#define OHCI_ED_S_LOW (1 << 13) +#define OHCI_ED_S_HIGH (0) +#define OHCI_ED_D (3 << 11) +#define OHCI_ED_D_IN (2 << 11) +#define OHCI_ED_D_OUT (1 << 11) +#define OHCI_ED_EN (0xf << 7) +#define OHCI_ED_FA (0x7f) + + +/* + * The HCCA (Host Controller Communications Area) is a 256 byte + * structure defined in the OHCI spec. that the host controller is + * told the base address of. It must be 256-byte aligned. + */ +#define NUM_INTS 32 /* part of the OHCI standard */ +struct ohci_hcca { + __u32 int_table[NUM_INTS]; /* Interrupt ED table */ + __u16 frame_no; /* current frame number */ + __u16 pad1; /* set to 0 on each frame_no change */ + __u32 done_head; /* info returned for an interrupt */ + u8 reserved_for_hc[116]; +} __attribute((aligned(256))); + + + +#define ED_INT_1 1 +#define ED_INT_2 2 +#define ED_INT_4 4 +#define ED_INT_8 8 +#define ED_INT_16 16 +#define ED_INT_32 32 +#define ED_CONTROL 64 +#define ED_BULK 65 +#define ED_ISO 0 /* same as 1ms interrupt queue */ + + +/* + * This is the maximum number of root hub ports. I don't think we'll + * ever see more than two as that's the space available on an ATX + * motherboard's case, but it could happen. The OHCI spec allows for + * up to 15... (which is insane!) + * + * Although I suppose several "ports" could be connected directly to + * internal laptop devices such as a keyboard, mouse, camera and + * serial/parallel ports. hmm... That'd be neat. + */ +#define MAX_ROOT_PORTS 15 /* maximum OHCI root hub ports */ + +/* + * This is the structure of the OHCI controller's memory mapped I/O + * region. This is Memory Mapped I/O. You must use the readl() and + * writel() macros defined in asm/io.h to access these!! + */ +struct ohci_regs { + /* control and status registers */ + __u32 revision; + __u32 control; + __u32 cmdstatus; + __u32 intrstatus; + __u32 intrenable; + __u32 intrdisable; + /* memory pointers */ + __u32 hcca; + __u32 ed_periodcurrent; + __u32 ed_controlhead; + __u32 ed_controlcurrent; + __u32 ed_bulkhead; + __u32 ed_bulkcurrent; + __u32 donehead; + /* frame counters */ + __u32 fminterval; + __u32 fmremaining; + __u32 fmnumber; + __u32 periodicstart; + __u32 lsthresh; + /* Root hub ports */ + struct ohci_roothub_regs { + __u32 a; + __u32 b; + __u32 status; + __u32 portstatus[MAX_ROOT_PORTS]; + } roothub; +} __attribute((aligned(32))); + + +/* + * Read a MMIO register and re-write it after ANDing with (m) + */ +#define writel_mask(m, a) writel( (readl((__u32)(a))) & (__u32)(m), (__u32)(a) ) + +/* + * Read a MMIO register and re-write it after ORing with (b) + */ +#define writel_set(b, a) writel( (readl((__u32)(a))) | (__u32)(b), (__u32)(a) ) + +/* + * cmdstatus register */ +#define OHCI_CLF 0x02 +#define OHCI_BLF 0x04 + +/* + * Interrupt register masks + */ +#define OHCI_INTR_SO (1) +#define OHCI_INTR_WDH (1 << 1) +#define OHCI_INTR_SF (1 << 2) +#define OHCI_INTR_RD (1 << 3) +#define OHCI_INTR_UE (1 << 4) +#define OHCI_INTR_FNO (1 << 5) +#define OHCI_INTR_RHSC (1 << 6) +#define OHCI_INTR_OC (1 << 30) +#define OHCI_INTR_MIE (1 << 31) + +/* + * Control register masks + */ +#define OHCI_USB_OPER (2 << 6) +#define OHCI_USB_SUSPEND (3 << 6) + +/* + * This is the full ohci controller description + * + * Note how the "proper" USB information is just + * a subset of what the full implementation needs. (Linus) + */ + + +struct ohci { + int irq; + struct ohci_regs *regs; /* OHCI controller's memory */ + struct ohci_hc_area *hc_area; /* hcca, int ed-tree, ohci itself .. */ + int root_hub_funct_addr; /* Address of Root Hub endpoint */ + int ohci_int_load[32]; /* load of the 32 Interrupt Chains (for load ballancing)*/ + struct usb_ohci_ed * ed_rm_list; /* list of all endpoints to be removed */ + struct usb_ohci_ed * ed_bulktail; /* last endpoint of bulk list */ + struct usb_ohci_ed * ed_controltail; /* last endpoint of control list */ + struct usb_ohci_ed * ed_isotail; /* last endpoint of iso list */ + struct ohci_device * root_hub; + struct usb_ohci_ed ed_rh_ep0; + struct usb_ohci_ed ed_rh_epi; + struct ohci_rep_td *td_rh_epi; + int intrstatus; + struct usb_ohci_ed *ed_func_ep0[128]; /* "hash"-table for ep to ed mapping */ + struct ohci_rep_td *repl_queue; /* for internal requests */ + int rh_int_interval; + int rh_int_timer; + struct usb_bus *bus; + + +}; + +/* + * Warning: This constant must not be so large as to cause the + * ohci_device structure to exceed one 4096 byte page. Or "weird + * things will happen" as the alloc_ohci() function assumes that + * its less than one page at the moment. (FIXME) + */ +#define NUM_TDS 4 /* num of preallocated transfer descriptors */ +#define NUM_EDS 80 /* num of preallocated endpoint descriptors */ + +struct ohci_hc_area { + + struct ohci_hcca hcca; /* OHCI mem. mapped IO area 256 Bytes*/ + + struct ohci_hw_ed ed[NUM_EDS]; /* Endpoint Descriptors 80 * 16 : 1280 Bytes */ + struct ohci_hw_td td[NUM_TDS]; /* Transfer Descriptors 2 * 32 : 64 Bytes */ + struct ohci ohci; + +}; +struct ohci_device { + struct usb_device *usb; + struct ohci *ohci; + unsigned long data[16]; +}; + +#define ohci_to_usb(uhci) ((ohci)->usb) +#define usb_to_ohci(usb) ((struct ohci_device *)(usb)->hcpriv) + +/* Debugging code */ +/*void show_ed(struct ohci_ed *ed); +void show_td(struct ohci_td *td); +void show_status(struct ohci *ohci); */ + +/* hcd */ +int ohci_trans_req(struct ohci * ohci, unsigned int ep_addr, int cmd_len, void *cmd, void * data, int data_len, __OHCI_BAG lw0, __OHCI_BAG lw1); +struct usb_ohci_ed *usb_ohci_add_ep(struct ohci * ohci, unsigned int ep_addr, int interval, int load, f_handler handler, int ep_size, int speed); +int usb_ohci_rm_function(struct ohci * ohci, unsigned int ep_addr); +int usb_ohci_rm_ep(struct ohci * ohci, struct usb_ohci_ed *ed); +struct usb_ohci_ed * ohci_find_ep(struct ohci *ohci, unsigned int ep_addr_in); + +/* roothub */ +int ohci_del_rh_int_timer(struct ohci * ohci); +int ohci_init_rh_int_timer(struct ohci * ohci, int interval); +int root_hub_int_req(struct ohci * ohci, int cmd_len, void * ctrl, void * data, int data_len, __OHCI_BAG lw0, __OHCI_BAG lw1, f_handler handler); +int root_hub_send_irq(struct ohci * ohci, void * data, int data_len ); +int root_hub_control_msg(struct ohci *ohci, int cmd_len, void *rh_cmd, void *rh_data, int len, __OHCI_BAG lw0, __OHCI_BAG lw1, f_handler handler); +int queue_reply(struct ohci * ohci, unsigned int ep_addr, int cmd_len,void * cmd, void * data,int len, __OHCI_BAG lw0, __OHCI_BAG lw1, f_handler handler); +int send_replies(struct ohci * ohci); + + + + +/* Root-Hub Register info */ + +#define RH_PS_CCS 0x00000001 +#define RH_PS_PES 0x00000002 +#define RH_PS_PSS 0x00000004 +#define RH_PS_POCI 0x00000008 +#define RH_PS_PRS 0x00000010 +#define RH_PS_PPS 0x00000100 +#define RH_PS_LSDA 0x00000200 +#define RH_PS_CSC 0x00010000 +#define RH_PS_PESC 0x00020000 +#define RH_PS_PSSC 0x00040000 +#define RH_PS_OCIC 0x00080000 +#define RH_PS_PRSC 0x00100000 + + +#ifdef OHCI_DBG +#define OHCI_FREE(x) kfree(x); printk("OHCI FREE: %d\n", -- __ohci_free_cnt) +#define OHCI_ALLOC(x,size) (x) = kmalloc(size, GFP_KERNEL); printk("OHCI ALLO: %d\n", ++ __ohci_free_cnt) +#define USB_FREE(x) kfree(x); printk("USB FREE: %d\n", -- __ohci_free1_cnt) +#define USB_ALLOC(x,size) (x) = kmalloc(size, GFP_KERNEL); printk("USB ALLO: %d\n", ++ __ohci_free1_cnt) +static int __ohci_free_cnt = 0; +static int __ohci_free1_cnt = 0; +#else +#define OHCI_FREE(x) kfree(x) +#define OHCI_ALLOC(x,size) (x) = kmalloc(size, GFP_KERNEL) +#define USB_FREE(x) kfree(x) +#define USB_ALLOC(x,size) (x) = kmalloc(size, GFP_KERNEL) +#endif + diff -ur --new-file old/linux/drivers/usb/ohci-root-hub.c new/linux/drivers/usb/ohci-root-hub.c --- old/linux/drivers/usb/ohci-root-hub.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/usb/ohci-root-hub.c Mon May 10 19:18:34 1999 @@ -0,0 +1,604 @@ +/* + * HCD (OHCI) Virtual Root Hub for USB. + * + * (C) Copyright 1999 Roman Weissgaerber (weissg@vienna.at) + * + * The Root Hub is build into the HC (UHCI or OHCI) hardware. + * This piece of code lets it look like it resides on the usb + * like the other hubs. + * (for anyone who wants to do a control operation on the root hub) + * + * v2.1 1999/05/09 + * v2.0 1999/05/04 + * v1.0 1999/04/27 + * ohci-root-hub.c + * + */ + + + +#include +#include +#include +#include +#include +#include + +#include "usb.h" +#include "ohci-hcd.h" + +#ifdef VROOTHUB + +#include "ohci-root-hub.h" + + +static __u8 root_hub_dev_des[] = +{ + 0x12, /* __u8 bLength; */ + 0x01, /* __u8 bDescriptorType; Device */ + 0x00, /* __u16 bcdUSB; v1.0 */ + 0x01, + 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */ + 0x00, /* __u8 bDeviceSubClass; */ + 0x00, /* __u8 bDeviceProtocol; */ + 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */ + 0x00, /* __u16 idVendor; */ + 0x00, + 0x00, /* __u16 idProduct; */ + 0x00, + 0x00, /* __u16 bcdDevice; */ + 0x00, + 0x00, /* __u8 iManufacturer; */ + 0x00, /* __u8 iProduct; */ + 0x00, /* __u8 iSerialNumber; */ + 0x01 /* __u8 bNumConfigurations; */ +}; + + +/* Configuration descriptor */ +static __u8 root_hub_config_des[] = +{ + 0x09, /* __u8 bLength; */ + 0x02, /* __u8 bDescriptorType; Configuration */ + 0x19, /* __u16 wTotalLength; */ + 0x00, + 0x01, /* __u8 bNumInterfaces; */ + 0x01, /* __u8 bConfigurationValue; */ + 0x00, /* __u8 iConfiguration; */ + 0x40, /* __u8 bmAttributes; + Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup, 4..0: resvd */ + 0x00, /* __u8 MaxPower; */ + + /* interface */ + 0x09, /* __u8 if_bLength; */ + 0x04, /* __u8 if_bDescriptorType; Interface */ + 0x00, /* __u8 if_bInterfaceNumber; */ + 0x00, /* __u8 if_bAlternateSetting; */ + 0x01, /* __u8 if_bNumEndpoints; */ + 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */ + 0x00, /* __u8 if_bInterfaceSubClass; */ + 0x00, /* __u8 if_bInterfaceProtocol; */ + 0x00, /* __u8 if_iInterface; */ + + /* endpoint */ + 0x07, /* __u8 ep_bLength; */ + 0x05, /* __u8 ep_bDescriptorType; Endpoint */ + 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */ + 0x03, /* __u8 ep_bmAttributes; Interrupt */ + 0x40, /* __u16 ep_wMaxPacketSize; 64 Bytes */ + 0x00, + 0xff /* __u8 ep_bInterval; 255 ms */ +}; + +/* +For OHCI we need just the 2nd Byte, so we +don't need this constant byte-array + +static __u8 root_hub_hub_des[] = +{ + 0x00, * __u8 bLength; * + 0x29, * __u8 bDescriptorType; Hub-descriptor * + 0x02, * __u8 bNbrPorts; * + 0x00, * __u16 wHubCharacteristics; * + 0x00, + 0x01, * __u8 bPwrOn2pwrGood; 2ms * + 0x00, * __u8 bHubContrCurrent; 0 mA * + 0x00, * __u8 DeviceRemovable; *** 8 Ports max *** * + 0xff * __u8 PortPwrCtrlMask; *** 8 ports max *** * +}; +*/ + + +int root_hub_control_msg(struct ohci *ohci, int cmd_len, void *rh_cmd, void *rh_data, int leni, __OHCI_BAG lw0, __OHCI_BAG lw1, f_handler handler) +{ + + __u32 stat; + __u32 rep_handler; + int req_reply=0; + union ep_addr_ ep_addr; + union ep_addr_ ep_addr_ret; + __u8 * cmd = rh_cmd; + __u8 * data = rh_data; + int i; + int len =leni; + + __u8 bmRequestType = cmd[0]; + __u8 bRequest = cmd[1]; + __u16 wValue = cmd[3] << 8 | cmd [2]; + __u16 wIndex = cmd[5] << 8 | cmd [4]; + __u16 wLength = cmd[7] << 8 | cmd [6]; +printk("USB root hub: adr: %8x cmd(%8x): ", ohci->root_hub_funct_addr, 8); +for(i=0;i<8;i++) + printk("%2x", ((char *)rh_cmd)[i]); + +printk(" ; \n"); + + ep_addr_ret.iep = 0; + ep_addr_ret.bep.fa = ohci->root_hub_funct_addr; + ep_addr_ret.bep.ep = (bmRequestType & 0x80) | 0x40; + + switch (bmRequestType | bRequest << 8) { + /* Request Destination: + without flags: Device, + RH_INTERFACE: interface, + RH_ENDPOINT: endpoint, + RH_CLASS means HUB here, + RH_OTHER | RH_CLASS almost ever means HUB_PORT here + */ + + case RH_GET_STATUS: + len = 2; + data[0] = 0x01; + data[1] = 0x00; + req_reply = RH_ACK; + break; + case RH_GET_STATUS | RH_INTERFACE: + len = 2; + data[0] = 0x00; + data[1] = 0x00; + req_reply = RH_ACK; + break; + case RH_GET_STATUS | RH_ENDPOINT: + len = 2; + data[0] = 0x00; + data[1] = 0x00; + req_reply = RH_ACK; + break; + case RH_GET_STATUS | RH_CLASS: /* HUB_STATUS */ + stat = readl(&ohci->regs->roothub.status) & 0x7fff7fff; /* bit 31 u. 15 has other meaning */ + data[0] = stat & 0xff; + data[1] = (stat >> 8) & 0xff; + data[2] = (stat >> 16) & 0xff; + data[3] = (stat >> 24) & 0xff; + len = 4; + req_reply = RH_ACK; + break; + case RH_GET_STATUS | RH_OTHER | RH_CLASS: /* PORT_STATUS */ + stat = readl(&ohci->regs->roothub.portstatus[wIndex-1]); + data[0] = stat & 0xff; + data[1] = (stat >> 8) & 0xff; + data[2] = (stat >> 16) & 0xff; + data[3] = (stat >> 24) & 0xff; + len = 4; + req_reply = RH_ACK; + printk("rh: stat %4x wIndex %4x;\n", stat , wIndex); + break; + + case RH_CLEAR_FEATURE: + switch (wValue) { + case (RH_DEVICE_REMOTE_WAKEUP): + default: + } + break; + + case RH_CLEAR_FEATURE | RH_ENDPOINT: + switch (wValue) { + case (RH_ENDPOINT_STALL): + len=0; + req_reply = RH_ACK; + break; + default: + } + break; + + case RH_CLEAR_FEATURE | RH_CLASS: + switch (wValue) { + /* case (RH_C_HUB_LOCAL_POWER): OHCI says: no switching of this one */ + case (RH_C_HUB_OVER_CURRENT): + writel(RH_PS_OCIC, &ohci->regs->roothub.status); + len=0; + req_reply = RH_ACK; + break; + default: + } + break; + case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS: + switch (wValue) { + case (RH_PORT_ENABLE): + writel(RH_PS_CCS, &ohci->regs->roothub.portstatus[wIndex-1]); + len=0; + req_reply = RH_ACK; + break; + case (RH_PORT_SUSPEND): + writel(RH_PS_POCI, &ohci->regs->roothub.portstatus[wIndex-1]); + len=0; + req_reply = RH_ACK; + break; + case (RH_PORT_POWER): + writel(RH_PS_LSDA, &ohci->regs->roothub.portstatus[wIndex-1]); + len=0; + req_reply = RH_ACK; + break; + case (RH_C_PORT_CONNECTION): + writel(RH_PS_CSC, &ohci->regs->roothub.portstatus[wIndex-1]); + len=0; + req_reply = RH_ACK; + break; + case (RH_C_PORT_ENABLE): + writel(RH_PS_PESC, &ohci->regs->roothub.portstatus[wIndex-1]); + len=0; + req_reply = RH_ACK; + break; + case (RH_C_PORT_SUSPEND): + writel(RH_PS_PSSC, &ohci->regs->roothub.portstatus[wIndex-1]); + len=0; + req_reply = RH_ACK; + break; + case (RH_C_PORT_OVER_CURRENT): + writel(RH_PS_OCIC, &ohci->regs->roothub.portstatus[wIndex-1]); + len=0; + req_reply = RH_ACK; + break; + case (RH_C_PORT_RESET): + writel(RH_PS_PRSC, &ohci->regs->roothub.portstatus[wIndex-1]); + len=0; + req_reply = RH_ACK; + break; + /* + case (RH_PORT_CONNECTION): + case (RH_PORT_OVER_CURRENT): + case (RH_PORT_RESET): + case (RH_PORT_LOW_SPEED): + */ + default: + } + break; + case RH_SET_FEATURE: + switch (wValue) { + case (RH_DEVICE_REMOTE_WAKEUP): + default: + } + break; + + case RH_SET_FEATURE | RH_ENDPOINT: + switch (wValue) { + case (RH_ENDPOINT_STALL): + default: + } + break; + + case RH_SET_FEATURE | RH_CLASS: + switch (wValue) { + /* case (RH_C_HUB_LOCAL_POWER): Root Hub has no local Power + case (RH_C_HUB_OVER_CURRENT): */ + default: + } + break; + case RH_SET_FEATURE | RH_OTHER | RH_CLASS: + switch (wValue) { + case (RH_PORT_SUSPEND): + writel(RH_PS_PSS, &ohci->regs->roothub.portstatus[wIndex-1]); + len=0; + req_reply = RH_ACK; + break; + case (RH_PORT_RESET): + if((readl(&ohci->regs->roothub.portstatus[wIndex-1]) &1) != 0) /* BUG IN HUP CODE *********/ + writel(RH_PS_PRS, &ohci->regs->roothub.portstatus[wIndex-1]); + len=0; + req_reply = RH_ACK; + break; + case (RH_PORT_POWER): + writel(RH_PS_PPS, &ohci->regs->roothub.portstatus[wIndex-1]); + len=0; + req_reply = RH_ACK; + break; + case (RH_PORT_ENABLE): + writel(RH_PS_PES, &ohci->regs->roothub.portstatus[wIndex-1]); + len=0; + req_reply = RH_ACK; + break; + /* + case (RH_PORT_CONNECTION): + case (RH_PORT_OVER_CURRENT): + case (RH_PORT_LOW_SPEED): + case (RH_C_PORT_CONNECTION): + case (RH_C_PORT_ENABLE): + case (RH_C_PORT_SUSPEND): + case (RH_C_PORT_OVER_CURRENT): + case (RH_C_PORT_RESET): + */ + default: + } + break; + + case RH_SET_ADDRESS: + ohci->root_hub_funct_addr = wValue; + /* ohci->ed_func_ep0[wValue] = &ohci->ed_rh_ep0; + ohci->ed_func_ep0[wValue]->ep_addr.bep.fa = wValue; + ohci->ed_func_ep0[wValue]->ed_list = &ohci->ed_rh_epi; */ + ohci->ed_rh_epi.ed_list = NULL; + ohci->ed_rh_epi.ep_addr.bep.fa = wValue; + ohci->ed_rh_epi.ep_addr.bep.ep = 0xa1; /* Int in port 1 */ + ohci->ed_func_ep0[0]= NULL; + len = 0; + req_reply = RH_ACK; + break; + + case RH_GET_DESCRIPTOR: + switch ((wValue & 0xff00) >> 8) { + case (0x01): /* device descriptor */ + len = min(sizeof(root_hub_dev_des), wLength); + memcpy(data, root_hub_dev_des, len); + req_reply = RH_ACK; + break; + case (0x02): /* configuration descriptor */ + len = min(sizeof(root_hub_config_des), wLength); + memcpy(data, root_hub_config_des, len); + req_reply = RH_ACK; + break; + case (0x03): /* string descriptors */ + default: + } + break; + case RH_GET_DESCRIPTOR | RH_CLASS: + data[1] = 0x29; + stat = readl(&ohci->regs->roothub.a); + data[2] = stat & 0xff; /* number of ports */ + data[0] = (data[2] / 8) * 2 + 9; /* length of descriptor */ + if(data[0] > wLength) { + req_reply = RH_REQ_ERR; + break; + } + data[3] = (stat >> 8) & 0xff; + data[4] = (stat >> 16) & 0xff; + data[5] = (stat >> 24) & 0xff; + data[6] = 0; /* Root Hub needs no current from bus */ + stat = readl(&ohci->regs->roothub.b); + if(data[2] <= 8) { /* less than 8 Ports */ + data[7] = stat & 0xff; + data[8] = (stat >> 16) & 0xff; /* 0xff for USB Rev. 1.1 ?, stat >> 16 for USB Rev. 1.0 */ + } + else { + data[7] = stat & 0xff; + data[8] = (stat >> 8) & 0xff; + data[9] = (stat >> 16) & 0xff; /* 0xff for USB Rev. 1.1?, stat >> 16 for USB Rev. 1.0 */ + data[10] = (stat >> 24) & 0xff; /* 0xff for USB Rev. 1.1?, stat >> 24 for USB Rev. 1.0 */ + } + len = data[0]; + req_reply = RH_ACK; + break; + + case RH_SET_DESCRIPTOR: + break; + + case RH_GET_CONFIGURATION: + len = 1; + data[0] = 0x01; + req_reply = RH_ACK; + break; + + case RH_SET_CONFIGURATION: /* start it up */ + writel( 0x10000, &ohci->regs->roothub.status); + /*writel( OHCI_INTR_RHSC, &ohci->regs->intrenable);*/ + len = 0; + req_reply = RH_ACK; + break; + /* Optional or meaningless requests + case RH_GET_STATE | RH_OTHER | RH_CLASS: + case RH_GET_INTERFACE | RH_INTERFACE: + case RH_SET_INTERFACE | RH_INTERFACE: + case RH_SYNC_FRAME | RH_ENDPOINT: + */ + + /* Vendor Requests, we are the vendor! + Will the USB-Consortium give us a Vendor Id + for a virtual hub-device :-) ? + We could use these requests for configuration purposes on the HCD Driver, not used in the altenate usb !*/ + + case RH_SET_FEATURE | RH_VENDOR: /* remove all endpoints of device wIndex = Dev << 8 */ + switch(wValue) { + case RH_REMOVE_EP: + ep_addr.iep = 0; + ep_addr.bep.ep = wIndex & 0xff; + ep_addr.bep.fa = (wIndex << 8) & 0xff00; + usb_ohci_rm_function(ohci, ep_addr.iep); + len=0; + req_reply = RH_ACK; + break; + } + break; + case RH_SET_FEATURE | RH_ENDPOINT | RH_VENDOR: /* remove endpoint wIndex = Dev << 8 | EP */ + switch(wValue) { + case RH_REMOVE_EP: + ep_addr.iep = 0; + ep_addr.bep.ep = wIndex & 0xff; + ep_addr.bep.fa = (wIndex << 8) & 0xff00; + usb_ohci_rm_ep(ohci, ohci_find_ep(ohci, ep_addr.iep)); + len=0; + req_reply = RH_ACK; + break; + } + break; + case RH_SET_EP | RH_ENDPOINT | RH_VENDOR: + ep_addr.bep.ep = data[0]; + ep_addr.bep.fa = data[1]; + ep_addr.bep.hc = data[2]; + ep_addr.bep.host = data[3]; + rep_handler = data[7] << 24 |data[6] << 16 | data[5] << 8 | data[4]; + /* struct usb_ohci_ed *usb_ohci_add_ep(union ep_addr_ ep_addr, + struct ohci * ohci, int interval, int load, int (*handler)(int, void*), int ep_size, int speed) */ + usb_ohci_add_ep(ohci, ep_addr.iep, data[8], data[9], (f_handler) rep_handler, data[11] << 8 | data[10] , data[12]); + len=0; + req_reply = RH_ACK; + break; + + default: + } + printk("USB HC roothubstat1: %x \n", readl( &(ohci->regs->roothub.portstatus[0]) )); + printk("USB HC roothubstat2: %x \n", readl( &(ohci->regs->roothub.portstatus[1]) )); + + /* if (req_reply == RH_ACK) len; */ + queue_reply(ohci, ep_addr_ret.iep, 8, rh_cmd, data, len, lw0, lw1, handler); + return 0; +} + +int root_hub_int_req(struct ohci * ohci, int cmd_len, void * ctrl, void * data, int data_len, __OHCI_BAG lw0, __OHCI_BAG lw1, f_handler handler){ + + struct ohci_rep_td *td; + struct ohci_rep_td *tmp; + union ep_addr_ ep_addr; + + td = kmalloc(sizeof(td),GFP_KERNEL); + tmp = ohci->td_rh_epi; + td->next_td = NULL; + if(tmp == NULL) { /* queue td */ + ohci->td_rh_epi = td; + } + else { + while(tmp->next_td != NULL) tmp = tmp->next_td; + tmp->next_td = td; + } + ep_addr.iep = 0; + ep_addr.bep.fa = ohci->root_hub_funct_addr; + ep_addr.bep.ep = 0xA1; /* INT IN EP endpoint 1 */ + td->cmd_len = 0; + td->cmd = NULL; + td->data = data; + td->data_len = data_len; + td->handler = handler; + td->next_td = NULL; + td->ep_addr = ep_addr.iep; + td->lw0 = lw0; + td->lw1 = lw1; + ohci_init_rh_int_timer(ohci, 255); + return 0; +} + + +/* prepare Interrupt pipe transaction data; HUP INTERRUPT ENDPOINT */ +int root_hub_send_irq(struct ohci * ohci, void * rh_data, int rh_len ) { + + int num_ports; + int i; + int ret; + int len; + + __u8 * data = rh_data; + + num_ports = readl(&ohci->regs->roothub.a) & 0xff; + data[0] = (readl(&ohci->regs->roothub.status) & 0x00030000)>0?1:0; + ret = data[0]; + + for(i=0; i < num_ports; i++) { + data[i/8] |= ((readl(&ohci->regs->roothub.portstatus[i]) & 0x001f0000)>0?1:0) << ((i+1) % 8); + ret += data[i/8]; + } + len = i/8 + 1; + + if (ret > 0) return len; + + return RH_NACK; +} + + + + + +static struct timer_list rh_int_timer; + +/* Virtual Root Hub INTs are polled by this timer every "intervall" ms */ +static void rh_int_timer_do(unsigned long ptr) { + int len; + int interval; + struct ohci * ohci = (struct ohci *) ptr; + struct ohci_rep_td *td = ohci->td_rh_epi; + + if(td != NULL) { /* if ther is a TD handle the INT request */ + + len = root_hub_send_irq(ohci, td->data, td->data_len ); + if(len > 0) { + ohci->td_rh_epi = td->next_td; + td->next_td = ohci->repl_queue; + ohci->repl_queue = td; + send_replies(ohci); + } + } + interval = ohci->rh_int_interval; + init_timer(& rh_int_timer); + rh_int_timer.function = rh_int_timer_do; + rh_int_timer.data = (unsigned long) ohci; + rh_int_timer.expires = jiffies + (HZ * (interval<30?30: interval)) /1000; + add_timer(&rh_int_timer); +} + +/* Root Hub INTs are polled by this timer */ +int ohci_init_rh_int_timer(struct ohci * ohci, int interval) { + + if(!(ohci->rh_int_timer)) { + ohci->rh_int_timer = 1; + ohci->rh_int_interval = interval; + init_timer(& rh_int_timer); + rh_int_timer.function = rh_int_timer_do; + rh_int_timer.data = (unsigned long) ohci; + rh_int_timer.expires = jiffies + (HZ * (interval<30?30: interval)) /1000; + add_timer(&rh_int_timer); + } + return 0; +} + +int ohci_del_rh_int_timer(struct ohci * ohci) { + del_timer(&rh_int_timer); + return 0; +} +/* for root hub replies, queue the reply, (it will be sent immediately now) */ + +int queue_reply(struct ohci * ohci, unsigned int ep_addr, int cmd_len,void * cmd, void * data,int len, __OHCI_BAG lw0, __OHCI_BAG lw1, f_handler handler) { + + struct ohci_rep_td *td; + int status = 0; + +printk("queue_reply ep: %x len: %x\n", ep_addr, len); +td = kmalloc(sizeof(td), GFP_KERNEL); + + if (len < 0) { status = len; len = 0;} + td->cmd_len = cmd_len; + td->cmd = cmd; + td->data = data; + td->data_len = len; + td->handler = handler; + td->next_td = ohci->repl_queue; ohci->repl_queue = td; + td->ep_addr = ep_addr; + td->lw0 = lw0; + td->lw1 = lw1; + td->status = status; + send_replies(ohci); +return 0; +} + +/* for root hub replies; send the reply */ +int send_replies(struct ohci * ohci) { + struct ohci_rep_td *td; + struct ohci_rep_td *tmp; + + td = ohci->repl_queue; ohci->repl_queue = NULL; + while ( td != NULL) { + td->handler((void *) ohci, td->ep_addr,td->cmd_len,td->cmd, td->data, td->data_len, td->status, td->lw0, td->lw1); + tmp = td; + td = td->next_td; + + kfree(tmp); + } + return 0; +} + +#endif diff -ur --new-file old/linux/drivers/usb/ohci-root-hub.h new/linux/drivers/usb/ohci-root-hub.h --- old/linux/drivers/usb/ohci-root-hub.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/usb/ohci-root-hub.h Mon May 10 19:18:34 1999 @@ -0,0 +1,71 @@ +/* + * HCD (OHCI) Virtual Root Hub Protocol for USB. + * + * (C) Copyright 1999 Roman Weissgaerber (weissg@vienna.at) + * + * The Root Hub is build into the HC (UHCI or OHCI) hardware. + * This piece of code lets it look like it resides on the bus + * like the other hubs. + * (for anyone who wants to do a control operation on the root hub) + * + * v1.0 1999/04/27 + * ohci-root-hub.h + * + */ + +/* destination of request */ +#define RH_INTERFACE 0x01 +#define RH_ENDPOINT 0x02 +#define RH_OTHER 0x03 + +#define RH_CLASS 0x20 +#define RH_VENDOR 0x40 + +/* Requests: bRequest << 8 | bmRequestType */ +#define RH_GET_STATUS 0x0080 +#define RH_CLEAR_FEATURE 0x0100 +#define RH_SET_FEATURE 0x0300 +#define RH_SET_ADDRESS 0x0500 +#define RH_GET_DESCRIPTOR 0x0680 +#define RH_SET_DESCRIPTOR 0x0700 +#define RH_GET_CONFIGURATION 0x0880 +#define RH_SET_CONFIGURATION 0x0900 +#define RH_GET_STATE 0x0280 +#define RH_GET_INTERFACE 0x0A80 +#define RH_SET_INTERFACE 0x0B00 +#define RH_SYNC_FRAME 0x0C80 +/* Our Vendor Specific Request */ +#define RH_SET_EP 0x2000 + + +/* Hub port features */ +#define RH_PORT_CONNECTION 0x00 +#define RH_PORT_ENABLE 0x01 +#define RH_PORT_SUSPEND 0x02 +#define RH_PORT_OVER_CURRENT 0x03 +#define RH_PORT_RESET 0x04 +#define RH_PORT_POWER 0x08 +#define RH_PORT_LOW_SPEED 0x09 +#define RH_C_PORT_CONNECTION 0x10 +#define RH_C_PORT_ENABLE 0x11 +#define RH_C_PORT_SUSPEND 0x12 +#define RH_C_PORT_OVER_CURRENT 0x13 +#define RH_C_PORT_RESET 0x14 + +/* Hub features */ +#define RH_C_HUB_LOCAL_POWER 0x00 +#define RH_C_HUB_OVER_CURRENT 0x01 + +#define RH_DEVICE_REMOTE_WAKEUP 0x00 +#define RH_ENDPOINT_STALL 0x01 + +/* Our Vendor Specific feature */ +#define RH_REMOVE_EP 0x00 + + +#define RH_ACK 0x01 +#define RH_REQ_ERR -1 +#define RH_NACK 0x00 + +#define min(a,b) (((a)<(b))?(a):(b)) + diff -ur --new-file old/linux/drivers/usb/ohci.c new/linux/drivers/usb/ohci.c --- old/linux/drivers/usb/ohci.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/usb/ohci.c Tue May 11 19:27:04 1999 @@ -0,0 +1,1669 @@ +/* + * Open Host Controller Interface driver for USB. + * + * (C) Copyright 1999 Gregory P. Smith + * + * This is the "other" host controller interface for USB. You will + * find this on many non-Intel based motherboards, and of course the + * Mac. As Linus hacked his UHCI driver together first, I modeled + * this after his.. (it should be obvious) + * + * From the programming standpoint the OHCI interface seems a little + * prettier and potentially less CPU intensive. This remains to be + * proven. In reality, I don't believe it'll make one darn bit of + * difference. USB v1.1 is a slow bus by today's standards. + * + * OHCI hardware takes care of most of the scheduling of different + * transfer types with the correct prioritization for us. + * + * To get started in USB, I used the "Universal Serial Bus System + * Architecture" book by Mindshare, Inc. It was a reasonable introduction + * and overview of USB and the two dominant host controller interfaces + * however you're better off just reading the real specs available + * from www.usb.org as you'll need them to get enough detailt to + * actually implement a HCD. The book has many typos and omissions + * Beware, the specs are the victim of a committee. + * + * This code was written with Guinness on the brain, xsnow on the desktop + * and Orbital, Orb, Enya & Massive Attack on the CD player. What a life! ;) + * + * No filesystems were harmed in the development of this code. + * + * $Id: ohci.c,v 1.26 1999/05/11 07:34:47 greg Exp $ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "ohci.h" +#include "inits.h" + +#ifdef CONFIG_APM +#include +static int handle_apm_event(apm_event_t event); +static int apm_resume = 0; +#endif + +static struct wait_queue *ohci_configure = NULL; + +#ifdef OHCI_TIMER +static struct timer_list ohci_timer; /* timer for root hub polling */ +#endif + + +static int ohci_td_result(struct ohci_device *dev, struct ohci_td *td) +{ + unsigned int status; + + status = td->info & OHCI_TD_CC; + + /* TODO Debugging code for TD failures goes here */ + + return status; +} /* ohci_td_result() */ + + +static spinlock_t ohci_edtd_lock = SPIN_LOCK_UNLOCKED; + +/* + * Add a TD to the end of the TD list on a given ED. If td->next_td + * points to any more TDs, they will be added as well (naturally). + * Otherwise td->next_td must be 0. + * + * The SKIP flag will be cleared after this function. + * + * Important! This function needs locking and atomicity as it works + * in parallel with the HC's DMA. Locking ohci_edtd_lock while using + * the function is a must. + * + * This function can be called by the interrupt handler. + */ +static void ohci_add_td_to_ed(struct ohci_td *td, struct ohci_ed *ed) +{ + /* don't let the HC pull anything from underneath us */ + ed->status |= OHCI_ED_SKIP; + + if (ed_head_td(ed) == 0) { /* empty list, put it on the head */ + set_ed_head_td(ed, virt_to_bus(td)); + ed->tail_td = 0; + } else { + struct ohci_td *tail, *head; + head = (ed_head_td(ed) == 0) ? NULL : bus_to_virt(ed_head_td(ed)); + tail = (ed->tail_td == 0) ? NULL : bus_to_virt(ed->tail_td); + if (!tail) { /* no tail, single element list */ + td->next_td = head->next_td; + head->next_td = virt_to_bus(td); + ed->tail_td = virt_to_bus(td); + } else { /* append to the list */ + td->next_td = tail->next_td; + tail->next_td = virt_to_bus(td); + ed->tail_td = virt_to_bus(td); + } + } + + /* save the ED link in each of the TDs added */ + td->ed = ed; + while (td->next_td != 0) { + td = bus_to_virt(td->next_td); + td->ed = ed; + } + + /* turn off the SKIP flag */ + ed->status &= ~OHCI_ED_SKIP; +} /* ohci_add_td_to_ed() */ + + +inline void ohci_start_control(struct ohci *ohci) +{ + /* tell the HC to start processing the control list */ + writel(OHCI_CMDSTAT_CLF, &ohci->regs->cmdstatus); +} + +inline void ohci_start_bulk(struct ohci *ohci) +{ + /* tell the HC to start processing the bulk list */ + writel(OHCI_CMDSTAT_BLF, &ohci->regs->cmdstatus); +} + +inline void ohci_start_periodic(struct ohci *ohci) +{ + /* enable processing periodc transfers starting next frame */ + writel_set(OHCI_USB_PLE, &ohci->regs->control); +} + +inline void ohci_start_isoc(struct ohci *ohci) +{ + /* enable processing isoc. transfers starting next frame */ + writel_set(OHCI_USB_IE, &ohci->regs->control); +} + +/* + * Add an ED to the hardware register ED list pointed to by hw_listhead_p + */ +static void ohci_add_ed_to_hw(struct ohci_ed *ed, void* hw_listhead_p) +{ + __u32 listhead; + unsigned long flags; + + spin_lock_irqsave(&ohci_edtd_lock, flags); + + listhead = readl(hw_listhead_p); + + /* if the list is not empty, insert this ED at the front */ + /* XXX should they go on the end? */ + if (listhead) { + ed->next_ed = listhead; + } + + /* update the hardware listhead pointer */ + writel(virt_to_bus(ed), hw_listhead_p); + + spin_unlock_irqrestore(&ohci_edtd_lock, flags); +} /* ohci_add_ed() */ + + +/* + * Put another control ED on the controller's list + */ +void ohci_add_control_ed(struct ohci *ohci, struct ohci_ed *ed) +{ + ohci_add_ed_to_hw(ed, &ohci->regs->ed_controlhead); + ohci_start_control(ohci); +} /* ohci_add_control_ed() */ + + +#if 0 +/* + * Put another control ED on the controller's list + */ +void ohci_add_periodic_ed(struct ohci *ohci, struct ohci_ed *ed, int period) +{ + ohci_add_ed_to_hw(ed, /* XXX */); + ohci_start_periodic(ohci); +} /* ohci_add_control_ed() */ +#endif + + +/* + * Remove an ED from the HC list whos bus headpointer is pointed to + * by hw_listhead_p + * + * Note that the SKIP bit is left on in the removed ED. + */ +void ohci_remove_ed_from_hw(struct ohci_ed *ed, __u32* hw_listhead_p) +{ + unsigned long flags; + struct ohci_ed *cur; + __u32 bus_ed = virt_to_bus(ed); + __u32 bus_cur; + + if (ed == NULL || !bus_ed) + return; + + /* tell the controller this skip ED */ + ed->status |= OHCI_ED_SKIP; + + bus_cur = readl(hw_listhead_p); + + if (bus_cur == 0) + return; /* the list is already empty */ + + cur = bus_to_virt(bus_cur); + + spin_lock_irqsave(&ohci_edtd_lock, flags); + + /* if its the head ED, move the head */ + if (bus_cur == bus_ed) { + writel(cur->next_ed, hw_listhead_p); + } else if (cur->next_ed != 0) { + struct ohci_ed *prev; + + /* walk the list and unlink the ED if found */ + for (;;) { + prev = cur; + cur = bus_to_virt(cur->next_ed); + + if (virt_to_bus(cur) == bus_ed) { + /* unlink from the list */ + prev->next_ed = cur->next_ed; + break; + } + + if (cur->next_ed == 0) + break; + } + } + + /* clear any links from the ED for safety */ + ed->next_ed = 0; + + spin_unlock_irqrestore(&ohci_edtd_lock, flags); +} /* ohci_remove_ed_from_hw() */ + +/* + * Remove an ED from the controller's control list. Note that the SKIP bit + * is left on in the removed ED. + */ +inline void ohci_remove_control_ed(struct ohci *ohci, struct ohci_ed *ed) +{ + ohci_remove_ed_from_hw(ed, &ohci->regs->ed_controlhead); +} + +/* + * Remove an ED from the controller's bulk list. Note that the SKIP bit + * is left on in the removed ED. + */ +inline void ohci_remove_bulk_ed(struct ohci *ohci, struct ohci_ed *ed) +{ + ohci_remove_ed_from_hw(ed, &ohci->regs->ed_bulkhead); +} + + +/* + * Remove a TD from the given EDs TD list. + */ +static void ohci_remove_td_from_ed(struct ohci_td *td, struct ohci_ed *ed) +{ + unsigned long flags; + struct ohci_td *head_td; + + if ((td == NULL) || (ed == NULL)) + return; + + spin_lock_irqsave(&ohci_edtd_lock, flags); + + if (ed_head_td(ed) == 0) + return; + + /* set the "skip me bit" in this ED */ + ed->status |= OHCI_ED_SKIP; + + /* XXX Assuming this list will never be circular */ + + head_td = bus_to_virt(ed_head_td(ed)); + if (virt_to_bus(td) == ed_head_td(ed)) { + /* It's the first TD, remove it. */ + set_ed_head_td(ed, head_td->next_td); + } else { + struct ohci_td *prev_td, *cur_td; + + /* FIXME: collapse this into a nice simple loop :) */ + if (head_td->next_td != 0) { + prev_td = head_td; + cur_td = bus_to_virt(head_td->next_td); + for (;;) { + if (td == cur_td) { + /* remove it */ + prev_td->next_td = cur_td->next_td; + break; + } + if (cur_td->next_td == 0) + break; + prev_td = cur_td; + cur_td = bus_to_virt(cur_td->next_td); + } + } + } + + td->next_td = 0; /* remove the TDs links */ + td->ed = NULL; + + /* TODO return this TD to the pool of free TDs */ + + /* unset the "skip me bit" in this ED */ + ed->status &= ~OHCI_ED_SKIP; + + spin_unlock_irqrestore(&ohci_edtd_lock, flags); +} /* ohci_remove_td_from_ed() */ + + +/* + * Get a pointer (virtual) to an available TD from the given device's + * pool. + * + * Return NULL if none are left. + */ +static struct ohci_td *ohci_get_free_td(struct ohci_device *dev) +{ + int idx; + + for (idx=0; idx < NUM_TDS; idx++) { + if (!td_allocated(dev->td[idx])) { + struct ohci_td *new_td = &dev->td[idx]; + /* zero out the TD */ + memset(new_td, 0, sizeof(*new_td)); + /* mark the new TDs as unaccessed */ + new_td->info = OHCI_TD_CC_NEW; + /* mark it as allocated */ + allocate_td(new_td); + return new_td; + } + } + + printk("usb-ohci error: unable to allocate a TD\n"); + return NULL; +} /* ohci_get_free_td() */ + + +/* + * Initialize a TD + * + * dir = OHCI_TD_D_IN, OHCI_TD_D_OUT, or OHCI_TD_D_SETUP + * toggle = TOGGLE_AUTO, TOGGLE_DATA0, TOGGLE_DATA1 + */ +inline struct ohci_td *ohci_fill_new_td(struct ohci_td *td, int dir, int toggle, __u32 flags, void *data, __u32 len, void *dev_id, usb_device_irq completed) +{ + /* hardware fields */ + td->info = OHCI_TD_CC_NEW | + (dir & OHCI_TD_D) | + (toggle & OHCI_TD_DT) | + flags; + td->cur_buf = (data == NULL) ? 0 : virt_to_bus(data); + td->buf_end = (len == 0) ? 0 : td->cur_buf + len - 1; + + /* driver fields */ + td->data = data; + td->dev_id = dev_id; + td->completed = completed; + + return td; +} /* ohci_fill_new_td() */ + + +/********************************** + * OHCI interrupt list operations * + **********************************/ + +/* + * Request an interrupt handler for one "pipe" of a USB device. + * (this function is pretty minimal right now) + * + * At the moment this is only good for input interrupts. (ie: for a + * mouse or keyboard) + * + * Period is desired polling interval in ms. The closest, shorter + * match will be used. Powers of two from 1-32 are supported by OHCI. + */ +static int ohci_request_irq(struct usb_device *usb, unsigned int pipe, + usb_device_irq handler, int period, void *dev_id) +{ + struct ohci_device *dev = usb_to_ohci(usb); + struct ohci_td *td; + struct ohci_ed *interrupt_ed; /* endpoint descriptor for this irq */ + + /* + * Pick a good frequency endpoint based on the requested period + */ + interrupt_ed = &dev->ohci->root_hub->ed[ms_to_ed_int(period)]; + + /* + * Set the max packet size, device speed, endpoint number, usb + * device number (function address), and type of TD. + * + * FIXME: Isochronous transfers need a pool of special 32 byte + * TDs (32 byte aligned) in order to be supported. + */ + interrupt_ed->status = \ + ed_set_maxpacket(usb_maxpacket(pipe)) | + ed_set_speed(usb_pipeslow(pipe)) | + usb_pipe_endpdev(pipe) | + OHCI_ED_F_NORM; + + td = ohci_get_free_td(dev); + /* FIXME: check for NULL */ + + /* Fill in the TD */ + ohci_fill_new_td(td, td_set_dir_out(usb_pipeout(pipe)), + TOGGLE_AUTO, + OHCI_TD_ROUND, + dev->data, DATA_BUF_LEN, + dev_id, handler); + /* + * TODO: be aware that OHCI won't advance out of the 4kb + * page cur_buf started in. It'll wrap around to the start + * of the page... annoying or useful? you decide. + * + * We should make sure dev->data doesn't cross a page... + */ + + /* FIXME: this just guarantees that its the end of the list */ + td->next_td = 0; + + /* Linus did this. see asm/system.h; scary concept... I don't + * know if its needed here or not but it won't hurt. */ + wmb(); + + /* + * Put the TD onto our ED + */ + { + unsigned long flags; + spin_lock_irqsave(&ohci_edtd_lock, flags); + ohci_add_td_to_ed(td, interrupt_ed); + spin_unlock_irqrestore(&ohci_edtd_lock, flags); + } + +#if 0 + /* Assimilate the new ED into the collective */ + /* + * When dynamic ED allocation is done, this call will be + * useful. For now, the correct ED already on the + * controller's proper periodic ED lists was chosen above. + */ + ohci_add_periodic_ed(dev->ohci, interrupt_ed, period); +#else + /* enable periodic (interrupt) transfers on the HC */ + ohci_start_periodic(dev->ohci); +#endif + + return 0; +} /* ohci_request_irq() */ + + +/* + * Control thread operations: + */ +static struct wait_queue *control_wakeup; + +/* + * This is the handler that gets called when a control transaction + * completes. + * + * This function is called from the interrupt handler. + */ +static int ohci_control_completed(int stats, void *buffer, void *dev_id) +{ + wake_up(&control_wakeup); + return 0; +} /* ohci_control_completed() */ + + +/* + * Send or receive a control message on a "pipe" + * + * The cmd parameter is a pointer to the 8 byte setup command to be + * sent. FIXME: This is a devrequest in usb.h. The function + * should be updated to accept a devrequest* instead of void*.. + * + * A control message contains: + * - The command itself + * - An optional data phase (if len > 0) + * - Status complete phase + */ +static int ohci_control_msg(struct usb_device *usb, unsigned int pipe, void *cmd, void *data, int len) +{ + struct ohci_device *dev = usb_to_ohci(usb); + /* + * ideally dev->ed should be linked into the root hub's + * control_ed list and used instead of just using it directly. + * This could present a problem as is with more than one + * device. (but who wants to use a keyboard AND a mouse + * anyways? ;) + */ + struct ohci_ed *control_ed = &dev->ohci->root_hub->ed[ED_CONTROL]; + struct ohci_td *setup_td, *data_td, *status_td; + struct wait_queue wait = { current, NULL }; + +#if 0 + printk(KERN_DEBUG "entering ohci_control_msg %p (ohci_dev: %p) pipe 0x%x, cmd %p, data %p, len %d\n", usb, dev, pipe, cmd, data, len); +#endif + + /* + * Set the max packet size, device speed, endpoint number, usb + * device number (function address), and type of TD. + * + */ + control_ed->status = \ + ed_set_maxpacket(usb_maxpacket(pipe)) | + ed_set_speed(usb_pipeslow(pipe)) | + usb_pipe_endpdev(pipe) | + OHCI_ED_F_NORM; + + /* + * Build the control TD + */ + + /* get a TD to send this control message with */ + setup_td = ohci_get_free_td(dev); + /* TODO check for NULL */ + + /* + * Set the not accessed condition code, allow odd sized data, + * and set the data transfer type to SETUP. Setup DATA always + * uses a DATA0 packet. + * + * The setup packet contains a devrequest (usb.h) which + * will always be 8 bytes long. FIXME: the cmd parameter + * should be a pointer to one of these instead of a void* !!! + */ + ohci_fill_new_td(setup_td, OHCI_TD_D_SETUP, TOGGLE_DATA0, + OHCI_TD_IOC_OFF, + cmd, 8, /* cmd is always 8 bytes long */ + NULL, NULL); + + /* allocate the next TD */ + data_td = ohci_get_free_td(dev); /* TODO check for NULL */ + + /* link to the next TD */ + setup_td->next_td = virt_to_bus(data_td); + + if (len > 0) { + + /* build the Control DATA TD, it starts with a DATA1. */ + ohci_fill_new_td(data_td, td_set_dir_out(usb_pipeout(pipe)), + TOGGLE_DATA1, + OHCI_TD_ROUND | OHCI_TD_IOC_OFF, + data, len, + NULL, NULL); + + /* + * XXX we should check that the data buffer doesn't + * cross a 4096 byte boundary. If so, it needs to be + * copied into a single 4096 byte aligned area for the + * OHCI's TD logic to see it all, or multiple TDs need + * to be made for each page. + * + * It's not likely a control transfer will run into + * this problem.. (famous last words) + */ + + status_td = ohci_get_free_td(dev); /* TODO check for NULL */ + data_td->next_td = virt_to_bus(status_td); + } else { + status_td = data_td; /* no data_td, use it for status */ + } + + /* The control status packet always uses a DATA1 */ + ohci_fill_new_td(status_td, + td_set_dir_in(usb_pipeout(pipe) | (len == 0)), + TOGGLE_DATA1, + 0, + NULL, 0, + NULL, ohci_control_completed); + status_td->next_td = 0; /* end of TDs */ + + /* + * Start the control transaction.. + */ + current->state = TASK_UNINTERRUPTIBLE; + add_wait_queue(&control_wakeup, &wait); + + /* + * Add the chain of 2-3 control TDs to the control ED's TD list + */ + { + unsigned long flags; + spin_lock_irqsave(&ohci_edtd_lock, flags); + ohci_add_td_to_ed(setup_td, control_ed); + spin_unlock_irqrestore(&ohci_edtd_lock, flags); + } + +#if 0 + /* complete transaction debugging output (before) */ + printk(KERN_DEBUG " Control ED %lx:\n", virt_to_bus(control_ed)); + show_ohci_ed(control_ed); + printk(KERN_DEBUG " Setup TD %lx:\n", virt_to_bus(setup_td)); + show_ohci_td(setup_td); + if (data_td != status_td) { + printk(KERN_DEBUG " Data TD %lx:\n", virt_to_bus(data_td)); + show_ohci_td(data_td); + } + printk(KERN_DEBUG " Status TD %lx:\n", virt_to_bus(status_td)); + show_ohci_td(status_td); +#endif + + /* Give the ED to the HC */ + ohci_add_control_ed(dev->ohci, control_ed); + + /* FIXME: + * this should really check to see that the transaction completed. + */ + schedule_timeout(HZ/10); + + remove_wait_queue(&control_wakeup, &wait); + +#if 0 + /* complete transaction debugging output (after) */ + printk(KERN_DEBUG " (after) Control ED:\n"); + show_ohci_ed(control_ed); + printk(KERN_DEBUG " (after) Setup TD:\n"); + show_ohci_td(setup_td); + if (data_td != status_td) { + printk(KERN_DEBUG " (after) Data TD:\n"); + show_ohci_td(data_td); + } + printk(KERN_DEBUG " (after) Status TD:\n"); + show_ohci_td(status_td); +#endif + + /* clean up incase it failed */ + /* XXX only do this if their ed pointer still points to control_ed + * incase they've been reclaimed and used by something else + * already. -greg */ + ohci_remove_td_from_ed(setup_td, control_ed); + ohci_remove_td_from_ed(data_td, control_ed); + ohci_remove_td_from_ed(status_td, control_ed); + + /* remove the control ED */ + ohci_remove_control_ed(dev->ohci, control_ed); + +#if 0 + printk(KERN_DEBUG "leaving ohci_control_msg\n"); +#endif + + return ohci_td_result(dev, status_td); +} /* ohci_control_msg() */ + + +/* + * Allocate a new USB device to be attached to an OHCI controller + */ +static struct usb_device *ohci_usb_allocate(struct usb_device *parent) +{ + struct usb_device *usb_dev; + struct ohci_device *dev; + + /* + * Allocate the generic USB device + */ + usb_dev = kmalloc(sizeof(*usb_dev), GFP_KERNEL); + if (!usb_dev) + return NULL; + + memset(usb_dev, 0, sizeof(*usb_dev)); + + /* + * Allocate an OHCI device (EDs and TDs for this device) + */ + dev = kmalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) { + kfree(usb_dev); + return NULL; + } + + memset(dev, 0, sizeof(*dev)); + + /* + * Link them together + */ + usb_dev->hcpriv = dev; + dev->usb = usb_dev; + + /* + * Link the device to its parent (hub, etc..) if any. + */ + usb_dev->parent = parent; + + if (parent) { + usb_dev->bus = parent->bus; + dev->ohci = usb_to_ohci(parent)->ohci; + } + + return usb_dev; +} /* ohci_usb_allocate() */ + + +/* + * Free a usb device. + * + * TODO This function needs to take better care of the EDs and TDs, etc. + */ +static int ohci_usb_deallocate(struct usb_device *usb_dev) +{ + kfree(usb_to_ohci(usb_dev)); + kfree(usb_dev); + return 0; +} + + +/* + * functions for the generic USB driver + */ +struct usb_operations ohci_device_operations = { + ohci_usb_allocate, + ohci_usb_deallocate, + ohci_control_msg, + ohci_request_irq, +}; + + +/* + * Reset an OHCI controller. Returns >= 0 on success. + * + * Afterwards the HC will be in the "suspend" state which prevents you + * from writing to some registers. Bring it to the operational state + * ASAP. + */ +static int reset_hc(struct ohci *ohci) +{ + int timeout = 1000; /* prevent an infinite loop */ + +#if 0 + printk(KERN_DEBUG "usb-ohci: resetting HC %p\n", ohci); +#endif + + writel(~0x0, &ohci->regs->intrdisable); /* Disable HC interrupts */ + writel(1, &ohci->regs->cmdstatus); /* HC Reset */ + writel_mask(0x3f, &ohci->regs->control); /* move to UsbReset state */ + + while ((readl(&ohci->regs->cmdstatus) & OHCI_CMDSTAT_HCR) != 0) { + if (!--timeout) { + printk("usb-ohci: USB HC reset timed out!\n"); + return -1; + } + udelay(1); + } + + printk(KERN_DEBUG "usb-ohci: HC %p reset.\n", ohci); + + return 0; +} /* reset_hc() */ + + +/* + * Reset and start an OHCI controller. Returns >= 0 on success. + */ +static int start_hc(struct ohci *ohci) +{ + int ret = 0; + int fminterval; + + fminterval = readl(&ohci->regs->fminterval) & 0x3fff; +#if 0 + printk(KERN_DEBUG "entering start_hc %p\n", ohci); +#endif + + if (reset_hc(ohci) < 0) + return -1; + + /* restore registers cleared by the reset */ + writel(virt_to_bus(ohci->root_hub->hcca), &ohci->regs->hcca); + + /* + * XXX Should fminterval also be set here? + * The spec suggests 0x2edf [11,999]. (FIXME: make this a constant) + */ + fminterval |= (0x2edf << 16); + writel(fminterval, &ohci->regs->fminterval); + /* Start periodic transfers at 90% of fminterval (fmremaining + * counts down; this will put them in the first 10% of the + * frame). */ + writel((0x2edf*9)/10, &ohci->regs->periodicstart); + + /* + * FNO (frame number overflow) could be enabled... they + * occur every 32768 frames (every 32-33 seconds). This is + * useful for debugging and as a bus heartbeat. -greg + */ + /* Choose the interrupts we care about */ + writel( OHCI_INTR_MIE | /* OHCI_INTR_RHSC | */ + OHCI_INTR_WDH | OHCI_INTR_FNO, + &ohci->regs->intrenable); + + /* Enter the USB Operational state & start the frames a flowing.. */ + writel_set(OHCI_USB_OPER, &ohci->regs->control); + + /* Enable control lists */ + writel_set(OHCI_USB_IE | OHCI_USB_CLE | OHCI_USB_BLE, &ohci->regs->control); + + /* Turn on power to the root hub ports (thanks Roman!) */ + writel( OHCI_ROOT_LPSC, &ohci->regs->roothub.status ); + + printk("usb-ohci: host controller operational\n"); + + return ret; +} /* start_hc() */ + + +/* + * Reset a root hub port + */ +static void ohci_reset_port(struct ohci *ohci, unsigned int port) +{ + int status; + + /* Don't allow overflows. */ + if (port >= MAX_ROOT_PORTS) { + printk("usb-ohci: bad port #%d in ohci_reset_port\n", port); + port = MAX_ROOT_PORTS-1; + } + + writel(PORT_PRS, &ohci->regs->roothub.portstatus[port]); /* Reset */ + + /* + * Wait for the reset to complete. + */ + wait_ms(10); + + /* check port status to see that the reset completed */ + status = readl(&ohci->regs->roothub.portstatus[port]); + if (status & PORT_PRS) { + /* reset failed, try harder? */ + printk("usb-ohci: port %d reset failed, retrying\n", port); + writel(PORT_PRS, &ohci->regs->roothub.portstatus[port]); + wait_ms(50); + } + + /* TODO we might need to re-enable the port here or is that + * done elsewhere? */ + +} /* ohci_reset_port */ + + +/* + * This gets called if the connect status on the root hub changes. + */ +static void ohci_connect_change(struct ohci * ohci, int port) +{ + struct usb_device *usb_dev; + struct ohci_device *dev; + /* memory I/O address of the port status register */ + void *portaddr = &ohci->regs->roothub.portstatus[port]; + int portstatus; + + printk(KERN_DEBUG "ohci_connect_change(%p, %d)\n", ohci, port); + + /* + * Because of the status change we have to forget + * everything we think we know about the device + * on this root hub port. It may have changed. + */ + usb_disconnect(ohci->root_hub->usb->children + port); + + portstatus = readl(portaddr); + + /* disable the port if nothing is connected */ + if (!(portstatus & PORT_CCS)) { + writel(PORT_CCS, portaddr); + return; + } + + /* + * Allocate a device for the new thingy that's been attached + */ + usb_dev = ohci_usb_allocate(ohci->root_hub->usb); + dev = usb_dev->hcpriv; + + dev->ohci = ohci; + + usb_connect(dev->usb); + + /* link it into the bus's device tree */ + ohci->root_hub->usb->children[port] = usb_dev; + + wait_ms(200); /* wait for powerup; XXX is this needed? */ + ohci_reset_port(ohci, port); + + /* Get information on speed by using LSD */ + usb_dev->slow = readl(portaddr) & PORT_LSDA ? 1 : 0; + + /* + * Do generic USB device tree processing on the new device. + */ + usb_new_device(usb_dev); + +} /* ohci_connect_change() */ + + +/* + * This gets called when the root hub configuration + * has changed. Just go through each port, seeing if + * there is something interesting happening. + */ +static void ohci_check_configuration(struct ohci *ohci) +{ + struct ohci_regs *regs = ohci->regs; + int num = 0; + int maxport = readl(&ohci->regs->roothub) & 0xff; + +#if 1 + printk(KERN_DEBUG "entering ohci_check_configuration %p\n", ohci); +#endif + + do { + if (readl(®s->roothub.portstatus[num]) & PORT_CSC) { + /* reset the connect status change bit */ + writel(PORT_CSC, ®s->roothub.portstatus[num]); + /* check the port for a nifty device */ + ohci_connect_change(ohci, num); + } + } while (++num < maxport); + +#if 0 + printk(KERN_DEBUG "leaving ohci_check_configuration %p\n", ohci); +#endif +} /* ohci_check_configuration() */ + + + +/* + * Check root hub port status and wake the control thread up if + * anything has changed. + * + * This function is called from the interrupt handler. + */ +static void ohci_root_hub_events(struct ohci *ohci) +{ + if (waitqueue_active(&ohci_configure)) { + int num = 0; + int maxport = ohci->root_hub->usb->maxchild; + + do { + if (readl(&ohci->regs->roothub.portstatus[num]) & + PORT_CSC) { + if (waitqueue_active(&ohci_configure)) + wake_up(&ohci_configure); + return; + } + } while (++num < maxport); + } +} /* ohci_root_hub_events() */ + + +/* + * The done list is in reverse order; we need to process TDs in the + * order they were finished (FIFO). This function builds the FIFO + * list using the next_dl_td pointer. + * + * This function originally by Roman Weissgaerber (weissg@vienna.at) + * + * This function is called from the interrupt handler. + */ +static struct ohci_td * ohci_reverse_donelist(struct ohci * ohci) +{ + __u32 td_list_hc; + struct ohci_hcca *hcca = ohci->root_hub->hcca; + struct ohci_td *td_list = NULL; + struct ohci_td *td_rev = NULL; + + td_list_hc = hcca->donehead & 0xfffffff0; + hcca->donehead = 0; + + while(td_list_hc) { + td_list = (struct ohci_td *) bus_to_virt(td_list_hc); + td_list->next_dl_td = td_rev; + + td_rev = td_list; + td_list_hc = td_list->next_td & 0xfffffff0; + } + + return td_list; +} /* ohci_reverse_donelist() */ + + +/* + * Collect this interrupt's goodies off of the list of finished TDs + * that the OHCI controller is kind enough to setup for us. + * + * This function is called from the interrupt handler. + */ +static void ohci_reap_donelist(struct ohci *ohci) +{ + struct ohci_td *td; /* used for walking the list */ + + spin_lock(&ohci_edtd_lock); + + /* create the FIFO ordered donelist */ + td = ohci_reverse_donelist(ohci); + + while (td != NULL) { + struct ohci_td *next_td = td->next_dl_td; + + /* FIXME: munge td->info into a future standard status format */ + /* Check if TD should be re-queued */ + if ((td->completed != NULL) && + (td->completed(OHCI_TD_CC_GET(td->info), td->data, td->dev_id))) + { + /* Mark the TD as active again: + * Set the not accessed condition code + * FIXME: should this reset OHCI_TD_ERRCNT? + */ + td->info |= OHCI_TD_CC_NEW; + + /* point it back to the start of the data buffer */ + td->cur_buf = virt_to_bus(td->data); + + /* XXX disabled for debugging reasons right now.. */ + /* insert it back on its ED */ + ohci_add_td_to_ed(td, td->ed); + } else { + /* return it to the pool of free TDs */ + ohci_free_td(td); + } + + td = next_td; + } + + spin_unlock(&ohci_edtd_lock); +} /* ohci_reap_donelist() */ + + +#if 0 +static int in_int = 0; +#endif +/* + * Get annoyed at the controller for bothering us. + * This pretty much follows the OHCI v1.0a spec, section 5.3. + */ +static void ohci_interrupt(int irq, void *__ohci, struct pt_regs *r) +{ + struct ohci *ohci = __ohci; + struct ohci_regs *regs = ohci->regs; + struct ohci_hcca *hcca = ohci->root_hub->hcca; + __u32 status, context; + +#if 0 + /* for debugging to keep IRQs from running away. */ + if (in_int >= 2) + return; + ++in_int; + return; +#endif + + /* Save the status of the interrupts that are enabled */ + status = readl(®s->intrstatus); + status &= readl(®s->intrenable); + + + /* make context = the interrupt status bits that we care about */ + if (hcca->donehead != 0) { + context = OHCI_INTR_WDH; /* hcca donehead needs processing */ + if (hcca->donehead & 1) { + context |= status; /* other status change to check */ + } + } else { + context = status; + if (!context) { + /* TODO increment a useless interrupt counter here */ + return; + } + } + + /* Disable HC interrupts */ + writel(OHCI_INTR_MIE, ®s->intrdisable); + + /* Process the done list */ + if (context & OHCI_INTR_WDH) { + /* See which TD's completed.. */ + ohci_reap_donelist(ohci); + + /* reset the done queue and tell the controller */ + hcca->donehead = 0; + writel(OHCI_INTR_WDH, ®s->intrstatus); + + context &= ~OHCI_INTR_WDH; /* mark this as checked */ + } + + /* Process any root hub status changes */ + if (context & OHCI_INTR_RHSC) { + /* Wake the thread to process root hub events */ + if (waitqueue_active(&ohci_configure)) + wake_up(&ohci_configure); + + writel(OHCI_INTR_RHSC, ®s->intrstatus); + /* + * Don't unset RHSC in context; it should be disabled. + * The control thread will re-enable it after it has + * checked the root hub status. + */ + } else { + /* check the root hub status anyways. Some controllers + * might not generate the interrupt properly. (?) */ + ohci_root_hub_events(ohci); + } + + /* Check those "other" pesky bits */ + if (context & (OHCI_INTR_FNO)) { + writel(OHCI_INTR_FNO, ®s->intrstatus); + context &= ~OHCI_INTR_FNO; /* mark this as checked */ + } + if (context & OHCI_INTR_SO) { + writel(OHCI_INTR_SO, ®s->intrstatus); + context &= ~OHCI_INTR_SO; /* mark this as checked */ + } + if (context & OHCI_INTR_RD) { + writel(OHCI_INTR_RD, ®s->intrstatus); + context &= ~OHCI_INTR_RD; /* mark this as checked */ + } + if (context & OHCI_INTR_UE) { + /* FIXME: need to have the control thread reset the + * controller now and keep a count of unrecoverable + * errors. If there are too many, it should just shut + * the broken controller down entirely. */ + writel(OHCI_INTR_UE, ®s->intrstatus); + context &= ~OHCI_INTR_UE; /* mark this as checked */ + } + if (context & OHCI_INTR_OC) { + writel(OHCI_INTR_OC, ®s->intrstatus); + context &= ~OHCI_INTR_OC; /* mark this as checked */ + } + + /* Mask out any remaining unprocessed interrupts so we don't + * get any more of them. */ + if (context & ~OHCI_INTR_MIE) { + writel(context, ®s->intrdisable); + } + + /* Re-enable HC interrupts */ + writel(OHCI_INTR_MIE, ®s->intrenable); + +} /* ohci_interrupt() */ + + +/* + * Allocate the resources required for running an OHCI controller. + * Host controller interrupts must not be running while calling this + * function or the penguins will get angry. + * + * The mem_base parameter must be the usable -virtual- address of the + * host controller's memory mapped I/O registers. + */ +static struct ohci *alloc_ohci(void* mem_base) +{ + int i; + struct ohci *ohci; + struct usb_bus *bus; + struct ohci_device *dev; + struct usb_device *usb; + +#if 0 + printk(KERN_DEBUG "entering alloc_ohci %p\n", mem_base); +#endif + + ohci = kmalloc(sizeof(*ohci), GFP_KERNEL); + if (!ohci) + return NULL; + + memset(ohci, 0, sizeof(*ohci)); + + ohci->irq = -1; + ohci->regs = mem_base; + INIT_LIST_HEAD(&ohci->interrupt_list); + + bus = kmalloc(sizeof(*bus), GFP_KERNEL); + if (!bus) + return NULL; + + memset(bus, 0, sizeof(*bus)); + + ohci->bus = bus; + bus->hcpriv = ohci; + bus->op = &ohci_device_operations; + + /* + * Allocate the USB device structure and root hub. + * + * Here we allocate our own root hub and TDs as well as the + * OHCI host controller communications area. The HCCA is just + * a nice pool of memory with pointers to endpoint descriptors + * for the different interrupts. + */ + usb = ohci_usb_allocate(NULL); + if (!usb) + return NULL; + + dev = ohci->root_hub = usb_to_ohci(usb); + + usb->bus = bus; + + /* Initialize the root hub */ + dev->ohci = ohci; /* link back to the controller */ + + /* + * Allocate the Host Controller Communications Area on a 256 + * byte boundary. XXX take the easy way out and just grab a + * page as that's guaranteed to have a nice boundary. + */ + dev->hcca = (struct ohci_hcca *) __get_free_page(GFP_KERNEL); + + /* Tell the controller where the HCCA is */ + writel(virt_to_bus(dev->hcca), &ohci->regs->hcca); + +#if 0 + printk(KERN_DEBUG "usb-ohci: HCCA allocated at %p (bus %p)\n", dev->hcca, (void*)virt_to_bus(dev->hcca)); +#endif + + /* Get the number of ports on the root hub */ + usb->maxchild = readl(&ohci->regs->roothub.a) & 0xff; + if (usb->maxchild > MAX_ROOT_PORTS) { + printk("usb-ohci: Limited to %d ports\n", MAX_ROOT_PORTS); + usb->maxchild = MAX_ROOT_PORTS; + } + if (usb->maxchild < 1) { + printk("usb-ohci: Less than one root hub port? Impossible!\n"); + usb->maxchild = 1; + } + printk("usb-ohci: %d root hub ports found\n", usb->maxchild); + + /* + * Initialize the ED polling "tree" (for simplicity's sake in + * this driver many nodes in the tree will be identical) + */ + dev->ed[ED_INT_32].next_ed = virt_to_bus(&dev->ed[ED_INT_16]); + dev->ed[ED_INT_16].next_ed = virt_to_bus(&dev->ed[ED_INT_8]); + dev->ed[ED_INT_8].next_ed = virt_to_bus(&dev->ed[ED_INT_4]); + dev->ed[ED_INT_4].next_ed = virt_to_bus(&dev->ed[ED_INT_2]); + dev->ed[ED_INT_2].next_ed = virt_to_bus(&dev->ed[ED_INT_1]); + + /* + * Initialize the polling table to call interrupts at the + * intended intervals. + */ + dev->hcca->int_table[0] = virt_to_bus(&dev->ed[ED_INT_32]); + for (i = 1; i < NUM_INTS; i++) { + if (i & 1) + dev->hcca->int_table[i] = + virt_to_bus(&dev->ed[ED_INT_16]); + else if (i & 2) + dev->hcca->int_table[i] = + virt_to_bus(&dev->ed[ED_INT_8]); + else if (i & 4) + dev->hcca->int_table[i] = + virt_to_bus(&dev->ed[ED_INT_4]); + else if (i & 8) + dev->hcca->int_table[i] = + virt_to_bus(&dev->ed[ED_INT_2]); + else if (i & 16) + dev->hcca->int_table[i] = + virt_to_bus(&dev->ed[ED_INT_1]); + } + + /* + * Tell the controller where the control and bulk lists are + * The lists start out empty. + */ + writel(0, &ohci->regs->ed_controlhead); + writel(0, &ohci->regs->ed_bulkhead); + /* + writel(virt_to_bus(&dev->ed[ED_CONTROL]), &ohci->regs->ed_controlhead); + writel(virt_to_bus(&dev->ed[ED_BULK]), &ohci->regs->ed_bulkhead); + */ + +#if 0 + printk(KERN_DEBUG "alloc_ohci(): controller\n"); + show_ohci_status(ohci); +#endif + +#if 0 + printk(KERN_DEBUG "leaving alloc_ohci %p\n", ohci); +#endif + + return ohci; +} /* alloc_ohci() */ + + +/* + * De-allocate all resoueces.. + */ +static void release_ohci(struct ohci *ohci) +{ + printk(KERN_DEBUG "entering release_ohci %p\n", ohci); + +#ifdef OHCI_TIMER + /* stop our timer */ + del_timer(&ohci_timer); +#endif + if (ohci->irq >= 0) { + free_irq(ohci->irq, ohci); + ohci->irq = -1; + } + + /* stop all OHCI interrupts */ + writel(~0x0, &ohci->regs->intrdisable); + + if (ohci->root_hub) { + /* ensure that HC is stopped before releasing the HCCA */ + writel(OHCI_USB_SUSPEND, &ohci->regs->control); + free_page((unsigned long) ohci->root_hub->hcca); + kfree(ohci->root_hub); + ohci->root_hub->hcca = NULL; + ohci->root_hub = NULL; + } + + /* unmap the IO address space */ + iounmap(ohci->regs); + + kfree(ohci); + + MOD_DEC_USE_COUNT; + + /* If the ohci itself were dynamic we'd free it here */ + + printk(KERN_DEBUG "usb-ohci: HC resources released.\n"); +} /* release_ohci() */ + + +/* + * USB OHCI control thread + */ +static int ohci_control_thread(void * __ohci) +{ + struct ohci *ohci = (struct ohci *)__ohci; + + /* + * I'm unfamiliar with the SMP kernel locking.. where should + * this be released and what does it do? -greg + */ + lock_kernel(); + + /* + * This thread doesn't need any user-level access, + * so get rid of all of our resources.. + */ + printk("ohci_control_thread code at %p\n", &ohci_control_thread); + exit_mm(current); + exit_files(current); + exit_fs(current); + + strcpy(current->comm, "ohci-control"); + + /* + * Damn the torpedoes, full speed ahead + */ + if (start_hc(ohci) < 0) { + printk("usb-ohci: failed to start the controller\n"); + release_ohci(ohci); + printk(KERN_DEBUG "leaving ohci_control_thread %p\n", __ohci); + return 0; + } + + for(;;) { + siginfo_t info; + int unsigned long signr; + + wait_ms(200); + + /* check the root hub configuration for changes. */ + ohci_check_configuration(ohci); + + /* re-enable root hub status change interrupts. */ +#if 0 + writel(OHCI_INTR_RHSC, &ohci->regs->intrenable); +#endif + + printk(KERN_DEBUG "ohci-control thread sleeping\n"); + interruptible_sleep_on(&ohci_configure); +#ifdef CONFIG_APM + if (apm_resume) { + apm_resume = 0; + if (start_hc(ohci) < 0) + break; + continue; + } +#endif + + /* + * If we were woken up by a signal, see if its useful, + * otherwise exit. + */ + if (signal_pending(current)) { + /* sending SIGUSR1 makes us print out some info */ + spin_lock_irq(¤t->sigmask_lock); + signr = dequeue_signal(¤t->blocked, &info); + spin_unlock_irq(¤t->sigmask_lock); + + if(signr == SIGUSR1) { + /* FIXME: have it do a full ed/td queue dump */ + printk(KERN_DEBUG "OHCI status dump:\n"); + show_ohci_status(ohci); + } else { + /* unknown signal, exit the thread */ + break; + } + } + } /* for (;;) */ + + reset_hc(ohci); + release_ohci(ohci); + + printk(KERN_DEBUG "leaving ohci_control_thread %p\n", __ohci); + + return 0; +} /* ohci_control_thread() */ + + +#ifdef CONFIG_APM +static int handle_apm_event(apm_event_t event) +{ + static int down = 0; + + switch (event) { + case APM_SYS_SUSPEND: + case APM_USER_SUSPEND: + if (down) { + printk(KERN_DEBUG "usb-ohci: received extra suspend event\n"); + break; + } + down = 1; + break; + case APM_NORMAL_RESUME: + case APM_CRITICAL_RESUME: + if (!down) { + printk(KERN_DEBUG "usb-ohci: received bogus resume event\n"); + break; + } + down = 0; + if (waitqueue_active(&ohci_configure)) { + apm_resume = 1; + wake_up(&ohci_configure); + } + break; + } + return 0; +} /* handle_apm_event() */ +#endif + + +#ifdef OHCI_TIMER +/* + * Inspired by Iñaky's driver. This function is a timer routine that + * is called OHCI_TIMER_FREQ times per second. It polls the root hub + * for status changes as on my system things are acting a bit odd at + * the moment.. + */ +static void ohci_timer_func (unsigned long ohci_ptr) +{ + struct ohci *ohci = (struct ohci*)ohci_ptr; + + ohci_root_hub_events(ohci); + + /* press the snooze button... */ + mod_timer(&ohci_timer, jiffies + (OHCI_TIMER_FREQ*HZ)); +} /* ohci_timer_func() */ +#endif + + +/* + * Increment the module usage count, start the control thread and + * return success if the controller is good. + */ +static int found_ohci(int irq, void* mem_base) +{ + int retval; + struct ohci *ohci; + +#if 0 + printk(KERN_DEBUG "entering found_ohci %d %p\n", irq, mem_base); +#endif + + /* Allocate the running OHCI structures */ + ohci = alloc_ohci(mem_base); + if (!ohci) { + return -ENOMEM; + } + +#ifdef OHCI_TIMER + init_timer(&ohci_timer); + ohci_timer.expires = jiffies + (OHCI_TIMER_FREQ*HZ); + ohci_timer.data = (unsigned long)ohci; + ohci_timer.function = ohci_timer_func; +#endif + + retval = -EBUSY; + if (request_irq(irq, ohci_interrupt, SA_SHIRQ, "usb-ohci", ohci) == 0) { + int pid; + + ohci->irq = irq; + +#if 0 + printk(KERN_DEBUG "usb-ohci: starting ohci-control thread\n"); +#endif + + /* fork off the handler */ + pid = kernel_thread(ohci_control_thread, ohci, + CLONE_FS | CLONE_FILES | CLONE_SIGHAND); + if (pid >= 0) { + return 0; + } + + retval = pid; + } else { + printk("usb-ohci: Couldn't allocate interrupt %d\n", irq); + } + release_ohci(ohci); + +#if 0 + printk(KERN_DEBUG "leaving found_ohci %d %p\n", irq, mem_base); +#endif + + return retval; +} /* found_ohci() */ + + +/* + * If this controller is for real, map the IO memory and proceed + */ +static int init_ohci(struct pci_dev *dev) +{ + unsigned long mem_base = dev->base_address[0]; + + /* If its OHCI, its memory */ + if (mem_base & PCI_BASE_ADDRESS_SPACE_IO) + return -ENODEV; + + /* Get the memory address and map it for IO */ + mem_base &= PCI_BASE_ADDRESS_MEM_MASK; + + /* no interrupt won't work... */ + if (dev->irq == 0) { + printk("usb-ohci: no irq assigned? check your BIOS settings.\n"); + return -ENODEV; + } + + /* + * FIXME ioremap_nocache isn't implemented on all CPUs (such + * as the Alpha) [?] What should I use instead... + * + * The iounmap() is done on in release_ohci. + */ + mem_base = (unsigned long) ioremap_nocache(mem_base, 4096); + + if (!mem_base) { + printk("Error mapping OHCI memory\n"); + return -EFAULT; + } + MOD_INC_USE_COUNT; + + if (found_ohci(dev->irq, (void *) mem_base) < 0) { + MOD_DEC_USE_COUNT; + return -1; + } + + return 0; +} /* init_ohci() */ + +#ifdef MODULE +/* + * Clean up when unloading the module + */ +void cleanup_module(void) +{ +#ifdef CONFIG_APM + apm_unregister_callback(&handle_apm_event); +#endif +#ifdef CONFIG_USB_MOUSE + usb_mouse_cleanup(); +#endif + printk("usb-ohci: module unloaded\n"); +} + +#define ohci_init init_module + +#endif + + +/* TODO this should be named following Linux convention and go in pci.h */ +#define PCI_CLASS_SERIAL_USB_OHCI ((PCI_CLASS_SERIAL_USB << 8) | 0x0010) + +/* + * Search the PCI bus for an OHCI USB controller and set it up + * + * If anyone wants multiple controllers this will need to be + * updated.. Right now, it just picks the first one it finds. + */ +int ohci_init(void) +{ + int retval; + struct pci_dev *dev = NULL; + /*u8 type;*/ + + if (sizeof(struct ohci_device) > 4096) { + printk("usb-ohci: struct ohci_device to large\n"); + return -ENODEV; + } + + printk("OHCI USB Driver loading\n"); + + retval = -ENODEV; + for (;;) { + /* Find an OHCI USB controller */ + dev = pci_find_class(PCI_CLASS_SERIAL_USB_OHCI, dev); + if (!dev) + break; + + /* Verify that its OpenHCI by checking for MMIO */ + /* pci_read_config_byte(dev, PCI_CLASS_PROG, &type); + if (!type) + continue; */ + + /* Ok, set it up */ + retval = init_ohci(dev); + if (retval < 0) + continue; + + /* TODO check module params here to determine what to load */ + +#ifdef CONFIG_USB_MOUSE + usb_mouse_init(); +#endif +#ifdef CONFIG_USB_KBD + usb_kbd_init(); +#endif + hub_init(); +#ifdef CONFIG_USB_AUDIO + usb_audio_init(); +#endif +#ifdef CONFIG_APM + apm_register_callback(&handle_apm_event); +#endif + + return 0; /* no error */ + } + return retval; +} /* ohci_init */ + +/* vim:sw=8 + */ diff -ur --new-file old/linux/drivers/usb/ohci.h new/linux/drivers/usb/ohci.h --- old/linux/drivers/usb/ohci.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/usb/ohci.h Tue May 11 19:04:03 1999 @@ -0,0 +1,349 @@ +#ifndef __LINUX_OHCI_H +#define __LINUX_OHCI_H + +/* + * Open Host Controller Interface data structures and defines. + * + * (C) Copyright 1999 Gregory P. Smith + * + * $Id: ohci.h,v 1.15 1999/05/09 23:25:49 greg Exp $ + */ + +#include +#include + +#include "usb.h" + +struct ohci_ed; + +/* + * Each TD must be aligned on a 16-byte boundary. From the OHCI v1.0 spec + * it does not state that TDs must be contiguious in memory (due to the + * use of the next_td field). This gives us extra room at the end of a + * TD for our own driver specific data. + * + * This structure's size must be a multiple of 16 bytes. ?? no way, I + * don't see why. Alignment should be all that matters. + */ +struct ohci_td { + /* OHCI Hardware fields */ + __u32 info; /* TD status & type flags */ + __u32 cur_buf; /* Current Buffer Pointer (bus address) */ + __u32 next_td; /* Next TD Pointer (bus address) */ + __u32 buf_end; /* Memory Buffer End Pointer (bus address) */ + + /* Driver specific fields */ + struct ohci_ed *ed; /* address of the ED this TD is on */ + struct ohci_td *next_dl_td; /* used during donelist processing */ + void *data; /* virt. address of the the buffer */ + usb_device_irq completed; /* Completion handler routine */ + int allocated; /* boolean: is this TD allocated? */ + + /* User or Device class driver specific fields */ + void *dev_id; /* user defined pointer passed to irq handler */ +} __attribute((aligned(16))); + +#define OHCI_TD_ROUND (1 << 18) /* buffer rounding bit */ +#define OHCI_TD_D (3 << 19) /* direction of xfer: */ +#define OHCI_TD_D_IN (2 << 19) +#define OHCI_TD_D_OUT (1 << 19) +#define OHCI_TD_D_SETUP (0 << 19) +#define td_set_dir_in(d) ((d) ? OHCI_TD_D_IN : OHCI_TD_D_OUT ) +#define td_set_dir_out(d) ((d) ? OHCI_TD_D_OUT : OHCI_TD_D_IN ) +#define OHCI_TD_IOC_DELAY (7 << 21) /* frame delay allowed before int. */ +#define OHCI_TD_IOC_OFF (OHCI_TD_IOC_DELAY) /* no interrupt on complete */ +#define OHCI_TD_DT (3 << 24) /* data toggle bits */ +#define TOGGLE_AUTO (0 << 24) /* automatic (from the ED) */ +#define TOGGLE_DATA0 (2 << 24) /* force Data0 */ +#define TOGGLE_DATA1 (3 << 24) /* force Data1 */ +#define td_force_toggle(b) (((b) | 2) << 24) +#define OHCI_TD_ERRCNT (3 << 26) /* error count */ +#define td_errorcount(td) (((td).info >> 26) & 3) +#define OHCI_TD_CC (0xf << 28) /* condition code */ +#define OHCI_TD_CC_GET(td_i) (((td_i) >> 28) & 0xf) +#define OHCI_TD_CC_NEW (OHCI_TD_CC) /* set this on all unaccessed TDs! */ +#define td_cc_notaccessed(td) (((td).info >> 29) == 7) +#define td_cc_accessed(td) (((td).info >> 29) != 7) +#define td_cc_noerror(td) ((((td).info) & OHCI_TD_CC) == 0) +#define td_active(td) (!td_cc_noerror((td)) && (td_errorcount((td)) < 3)) +#define td_done(td) (td_cc_noerror((td)) || (td_errorcount((td)) == 3)) + +#define td_allocated(td) ((td).allocated) +#define allocate_td(td) ((td)->allocated = 1) +#define ohci_free_td(td) ((td)->allocated = 0) + + +/* + * The endpoint descriptors also requires 16-byte alignment + */ +struct ohci_ed { + /* OHCI hardware fields */ + __u32 status; + __u32 tail_td; /* TD Queue tail pointer */ + __u32 _head_td; /* TD Queue head pointer, toggle carry & halted bits */ + __u32 next_ed; /* Next ED */ +} __attribute((aligned(16))); + +/* get the head_td */ +#define ed_head_td(ed) ((ed)->_head_td & 0xfffffff0) + +/* save the carry flag while setting the head_td */ +#define set_ed_head_td(ed, td) ((ed)->_head_td = (td) | ((ed)->_head_td & 3)) + +#define OHCI_ED_SKIP (1 << 14) +#define OHCI_ED_MPS (0x7ff << 16) +/* FIXME: should cap at the USB max packet size [0x4ff] */ +#define ed_set_maxpacket(s) (((s) << 16) & OHCI_ED_MPS) +#define OHCI_ED_F_NORM (0) +#define OHCI_ED_F_ISOC (1 << 15) +#define ed_set_type_isoc(i) ((i) ? OHCI_ED_F_ISOC : OHCI_ED_F_NORM) +#define OHCI_ED_S_LOW (1 << 13) +#define OHCI_ED_S_HIGH (0) +#define ed_set_speed(s) ((s) ? OHCI_ED_S_LOW : OHCI_ED_S_HIGH) +#define OHCI_ED_D (3 << 11) +#define OHCI_ED_D_IN (2 << 11) +#define OHCI_ED_D_OUT (1 << 11) +#define ed_set_dir_in(d) ((d) ? OHCI_ED_D_IN : OHCI_ED_D_OUT) +#define ed_set_dir_out(d) ((d) ? OHCI_ED_D_OUT : OHCI_ED_D_IN) +#define OHCI_ED_EN (0xf << 7) +#define OHCI_ED_FA (0x7f) + + +/* NOTE: bits 27-31 of the status dword are reserved for the driver */ +/* + * We'll use this status flag for to mark if an ED is in use by the + * driver or not. If the bit is set, it is used. + * + * FIXME: implement this! + */ +#define ED_USED (1 << 31) + +/* + * The HCCA (Host Controller Communications Area) is a 256 byte + * structure defined in the OHCI spec. that the host controller is + * told the base address of. It must be 256-byte aligned. + */ +#define NUM_INTS 32 /* part of the OHCI standard */ +struct ohci_hcca { + __u32 int_table[NUM_INTS]; /* Interrupt ED table */ + __u16 frame_no; /* current frame number */ + __u16 pad1; /* set to 0 on each frame_no change */ + __u32 donehead; /* info returned for an interrupt */ + u8 reserved_for_hc[116]; +} __attribute((aligned(256))); + +/* + * The TD entries here are pre-allocated as Linus did with his simple + * UHCI implementation. With the current state of this driver that + * shouldn't be a problem. However if someone ever connects 127 + * supported devices to this driver and tries to use them all at once: + * a) They're insane! + * b) They should code in dynamic allocation + */ +struct ohci; + +/* + * Warning: These constants must not be so large as to cause the + * ohci_device structure to exceed one 4096 byte page. Or "weird + * things will happen" as the alloc_ohci() function assumes that + * its less than one page. (FIXME) + */ +#define NUM_TDS 32 /* num of preallocated transfer descriptors */ +#define DATA_BUF_LEN 16 /* num of unsigned long's for the data buf */ + +/* + * For this "simple" driver we only support a single ED for each + * polling rate. + * + * Later on this driver should be extended to use a full tree of EDs + * so that there can be 32 different 32ms polling frames, etc. + * Individual devices shouldn't need as many as the root hub in that + * case; complicating how things are done at the moment. + * + * Bulk and Control transfers hang off of their own ED lists. + */ +#define NUM_EDS 16 /* num of preallocated endpoint descriptors */ + +#define ohci_to_usb(ohci) ((ohci)->usb) +#define usb_to_ohci(usb) ((struct ohci_device *)(usb)->hcpriv) + +/* The usb_device must be first! */ +struct ohci_device { + struct usb_device *usb; + + struct ohci *ohci; + struct ohci_hcca *hcca; /* OHCI mem. mapped IO area */ + + struct ohci_ed ed[NUM_EDS]; /* Endpoint Descriptors */ + struct ohci_td td[NUM_TDS]; /* Transfer Descriptors */ + + unsigned long data[DATA_BUF_LEN]; +}; + +/* .... */ + +#define ED_INT_1 0 +#define ED_INT_2 1 +#define ED_INT_4 2 +#define ED_INT_8 3 +#define ED_INT_16 4 +#define ED_INT_32 5 +#define ED_CONTROL 6 +#define ED_BULK 7 +#define ED_ISO ED_INT_1 /* same as 1ms interrupt queue */ +#define ED_FIRST_AVAIL 8 /* first non-reserved ED */ + +/* + * Given a period p in ms, convert it to the closest endpoint + * interrupt frequency; rounding down. This is a gross macro. + * Feel free to toss it for actual code. (gasp!) + */ +#define ms_to_ed_int(p) \ + ((p >= 32) ? ED_INT_32 : \ + ((p & 16) ? ED_INT_16 : \ + ((p & 8) ? ED_INT_8 : \ + ((p & 4) ? ED_INT_4 : \ + ((p & 2) ? ED_INT_2 : \ + ED_INT_1))))) /* hmm.. scheme or lisp anyone? */ + +/* + * This is the maximum number of root hub ports. I don't think we'll + * ever see more than two as that's the space available on an ATX + * motherboard's case, but it could happen. The OHCI spec allows for + * up to 15... (which is insane!) + * + * Although I suppose several "ports" could be connected directly to + * internal laptop devices such as a keyboard, mouse, camera and + * serial/parallel ports. hmm... That'd be neat. + */ +#define MAX_ROOT_PORTS 15 /* maximum OHCI root hub ports */ + +/* + * This is the structure of the OHCI controller's memory mapped I/O + * region. This is Memory Mapped I/O. You must use the readl() and + * writel() macros defined in asm/io.h to access these!! + */ +struct ohci_regs { + /* control and status registers */ + __u32 revision; + __u32 control; + __u32 cmdstatus; + __u32 intrstatus; + __u32 intrenable; + __u32 intrdisable; + /* memory pointers */ + __u32 hcca; + __u32 ed_periodcurrent; + __u32 ed_controlhead; + __u32 ed_controlcurrent; + __u32 ed_bulkhead; + __u32 ed_bulkcurrent; + __u32 current_donehead; /* The driver should get this from the HCCA */ + /* frame counters */ + __u32 fminterval; + __u32 fmremaining; + __u32 fmnumber; + __u32 periodicstart; + __u32 lsthresh; + /* Root hub ports */ + struct ohci_roothub_regs { + __u32 a; + __u32 b; + __u32 status; + __u32 portstatus[MAX_ROOT_PORTS]; + } roothub; +} __attribute((aligned(32))); + +/* + * Read a MMIO register and re-write it after ANDing with (m) + */ +#define writel_mask(m, a) writel( (readl((__u32)(a))) & (__u32)(m), (__u32)(a) ) + +/* + * Read a MMIO register and re-write it after ORing with (b) + */ +#define writel_set(b, a) writel( (readl((__u32)(a))) | (__u32)(b), (__u32)(a) ) + + +#define PORT_CCS (1) /* port current connect status */ +#define PORT_PES (1 << 1) /* port enable status */ +#define PORT_PSS (1 << 2) /* port suspend status */ +#define PORT_POCI (1 << 3) /* port overcurrent indicator */ +#define PORT_PRS (1 << 4) /* port reset status */ +#define PORT_PPS (1 << 8) /* port power status */ +#define PORT_LSDA (1 << 9) /* port low speed dev. attached */ +#define PORT_CSC (1 << 16) /* port connect status change */ +#define PORT_PESC (1 << 17) /* port enable status change */ +#define PORT_PSSC (1 << 18) /* port suspend status change */ +#define PORT_OCIC (1 << 19) /* port over current indicator chg */ +#define PORT_PRSC (1 << 20) /* port reset status change */ + +/* + * Root Hub status register masks + */ +#define OHCI_ROOT_LPS (1) /* turn off root hub ports power */ +#define OHCI_ROOT_OCI (1 << 1) /* Overcurrent Indicator */ +#define OHCI_ROOT_DRWE (1 << 15) /* Device remote wakeup enable */ +#define OHCI_ROOT_LPSC (1 << 16) /* turn on root hub ports power */ +#define OHCI_ROOT_OCIC (1 << 17) /* Overcurrent indicator change */ +#define OHCI_ROOT_CRWE (1 << 31) /* Clear RemoteWakeupEnable */ + +/* + * Interrupt register masks + */ +#define OHCI_INTR_SO (1) +#define OHCI_INTR_WDH (1 << 1) +#define OHCI_INTR_SF (1 << 2) +#define OHCI_INTR_RD (1 << 3) +#define OHCI_INTR_UE (1 << 4) +#define OHCI_INTR_FNO (1 << 5) +#define OHCI_INTR_RHSC (1 << 6) +#define OHCI_INTR_OC (1 << 30) +#define OHCI_INTR_MIE (1 << 31) + +/* + * Control register masks + */ +#define OHCI_USB_OPER (2 << 6) +#define OHCI_USB_SUSPEND (3 << 6) +#define OHCI_USB_PLE (1 << 2) /* Periodic (interrupt) list enable */ +#define OHCI_USB_IE (1 << 3) /* Isochronous list enable */ +#define OHCI_USB_CLE (1 << 4) /* Control list enable */ +#define OHCI_USB_BLE (1 << 5) /* Bulk list enable */ + +/* + * Command status register masks + */ +#define OHCI_CMDSTAT_HCR (1) +#define OHCI_CMDSTAT_CLF (1 << 1) +#define OHCI_CMDSTAT_BLF (1 << 2) +#define OHCI_CMDSTAT_OCR (1 << 3) +#define OHCI_CMDSTAT_SOC (3 << 16) + +/* + * This is the full ohci controller description + * + * Note how the "proper" USB information is just + * a subset of what the full implementation needs. (Linus) + */ +struct ohci { + int irq; + struct ohci_regs *regs; /* OHCI controller's memory */ + struct usb_bus *bus; + struct ohci_device *root_hub; /* Root hub & controller */ + struct list_head interrupt_list; /* List of interrupt active TDs for this OHCI */ +}; + +#define OHCI_TIMER +#define OHCI_TIMER_FREQ (1) /* frequency of OHCI status checks */ + +/* Debugging code */ +void show_ohci_ed(struct ohci_ed *ed); +void show_ohci_td(struct ohci_td *td); +void show_ohci_status(struct ohci *ohci); +void show_ohci_device(struct ohci_device *dev); +void show_ohci_hcca(struct ohci_hcca *hcca); + +#endif +/* vim:sw=8 + */ diff -ur --new-file old/linux/drivers/usb/restart new/linux/drivers/usb/restart --- old/linux/drivers/usb/restart Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/usb/restart Tue May 11 19:04:03 1999 @@ -0,0 +1,38 @@ +#!/bin/sh + +ME=`basename $0` + +#UMOD=`lsmod | grep '^bp-mouse' | grep -v grep` +#if test "$UMOD"; then +# echo "$ME: removing bp-mouse.o" +# if ! rmmod bp-mouse; then +# echo "$ME: cannot remove bp-mouse.o" +# exit 1 +# fi +#fi + +UPID=`ps aux | grep ohci-control | grep -v grep | awk '{print $2}'` +if test "$UPID"; then + echo "$ME: killing $UPID" + kill $UPID +fi + +UMOD=`lsmod | grep '^usb-ohci' | grep -v grep` +if test "$UMOD"; then + echo "$ME: removing usb-ohci.o" + sleep 1 + if ! rmmod usb-ohci; then + echo "$ME: cannot remove usb-ohci.o" + exit 1 + fi +fi + +dmesg -c > /dev/null + +echo "$ME: starting usb-ohci.o" +insmod -m usb-ohci.o > usb-ohci.map + +sleep 1 +UPID=`ps aux | grep ohci-control | grep -v grep | awk '{print $2}'` +if test "$UPID"; then echo "$ME: ohci-control is pid $UPID" ; fi + diff -ur --new-file old/linux/drivers/usb/stopusb new/linux/drivers/usb/stopusb --- old/linux/drivers/usb/stopusb Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/usb/stopusb Tue May 11 19:04:03 1999 @@ -0,0 +1,7 @@ +#!/bin/sh + +killall ohci-control + +sleep 2 + +rmmod usb-ohci diff -ur --new-file old/linux/drivers/usb/uhci-debug.c new/linux/drivers/usb/uhci-debug.c --- old/linux/drivers/usb/uhci-debug.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/usb/uhci-debug.c Mon Apr 26 21:22:58 1999 @@ -0,0 +1,168 @@ +/* + * UHCI-specific debugging code. Invaluable when something + * goes wrong, but don't get in my face. + * + * (C) Copyright 1999 Linus Torvalds + */ + +#include +#include + +#include "uhci.h" + +void show_td(struct uhci_td * td) +{ + printk("%08x ", td->link); + printk("%se%d %s%s%s%s%s%s%s%s%s%sLength=%x ", + ((td->status >> 29) & 1) ? "SPD " : "", + ((td->status >> 27) & 3), + ((td->status >> 26) & 1) ? "LS " : "", + ((td->status >> 25) & 1) ? "IOS " : "", + ((td->status >> 24) & 1) ? "IOC " : "", + ((td->status >> 23) & 1) ? "Active " : "", + ((td->status >> 22) & 1) ? "Stalled " : "", + ((td->status >> 21) & 1) ? "DataBufErr " : "", + ((td->status >> 20) & 1) ? "Babble " : "", + ((td->status >> 19) & 1) ? "NAK " : "", + ((td->status >> 18) & 1) ? "CRC/Timeo " : "", + ((td->status >> 17) & 1) ? "BitStuff " : "", + td->status & 0x7ff); + printk("MaxLen=%x %sEndPt=%x Dev=%x, PID=%x ", + td->info >> 21, + ((td->info >> 19) & 1) ? "DT " : "", + (td->info >> 15) & 15, + (td->info >> 8) & 127, + td->info & 0xff); + printk("(buf=%08x)\n", td->buffer); +} + +static void show_sc(int port, unsigned short status) +{ + printk(" stat%d = %04x %s%s%s%s%s%s%s%s\n", + port, + status, + (status & (1 << 12)) ? " PortSuspend" : "", + (status & (1 << 9)) ? " PortReset" : "", + (status & (1 << 8)) ? " LowSpeed" : "", + (status & 0x40) ? " ResumeDetect" : "", + (status & 0x08) ? " EnableChange" : "", + (status & 0x04) ? " PortEnabled" : "", + (status & 0x02) ? " ConnectChange" : "", + (status & 0x01) ? " PortConnected" : ""); +} + +void show_status(struct uhci *uhci) +{ + unsigned int io_addr = uhci->io_addr; + unsigned short usbcmd, usbstat, usbint, usbfrnum; + unsigned int flbaseadd; + unsigned char sof; + unsigned short portsc1, portsc2; + + usbcmd = inw(io_addr + 0); + usbstat = inw(io_addr + 2); + usbint = inw(io_addr + 4); + usbfrnum = inw(io_addr + 6); + flbaseadd = inl(io_addr + 8); + sof = inb(io_addr + 12); + portsc1 = inw(io_addr + 16); + portsc2 = inw(io_addr + 18); + + printk(" usbcmd = %04x %s%s%s%s%s%s%s%s\n", + usbcmd, + (usbcmd & 0x80) ? " Maxp64" : " Maxp32", + (usbcmd & 0x40) ? " CF" : "", + (usbcmd & 0x20) ? " SWDBG" : "", + (usbcmd & 0x10) ? " FGR" : "", + (usbcmd & 0x08) ? " EGSM" : "", + (usbcmd & 0x04) ? " GRESET" : "", + (usbcmd & 0x02) ? " HCRESET" : "", + (usbcmd & 0x01) ? " RS" : ""); + + printk(" usbstat = %04x %s%s%s%s%s%s\n", + usbstat, + (usbstat & 0x20) ? " HCHalted" : "", + (usbstat & 0x10) ? " HostControllerProcessError" : "", + (usbstat & 0x08) ? " HostSystemError" : "", + (usbstat & 0x04) ? " ResumeDetect" : "", + (usbstat & 0x02) ? " USBError" : "", + (usbstat & 0x01) ? " USBINT" : ""); + + printk(" usbint = %04x\n", usbint); + printk(" usbfrnum = (%d)%03x\n", (usbfrnum >> 10) & 1, 0xfff & (4*(unsigned int)usbfrnum)); + printk(" flbaseadd = %08x\n", flbaseadd); + printk(" sof = %02x\n", sof); + show_sc(1, portsc1); + show_sc(2, portsc2); +} + +#define uhci_link_to_qh(x) ((struct uhci_qh *) uhci_link_to_td(x)) + +struct uhci_td * uhci_link_to_td(unsigned int link) +{ + if (link & 1) + return NULL; + + return bus_to_virt(link & ~15); +} + +void show_queue(struct uhci_qh *qh) +{ + struct uhci_td *td; + int i = 0; + +#if 0 + printk(" link = %p, element = %p\n", qh->link, qh->element); +#endif + if(!qh->element) { + printk(" td 0 = NULL\n"); + return; + } + + for(td = uhci_link_to_td(qh->element); td; + td = uhci_link_to_td(td->link)) { + printk(" td %d = %p\n", i++, td); + printk(" "); + show_td(td); + } +} + +int is_skeleton_qh(struct uhci *uhci, struct uhci_qh *qh) +{ + int j; + + for (j = 0; j < UHCI_MAXQH; j++) + if (qh == uhci->root_hub->qh + j) + return 1; + + return 0; +} + +static const char *qh_names[] = {"isochronous", "interrupt2", "interrupt4", + "interrupt8", "interrupt16", "interrupt32", + "interrupt64", "interrupt128", "interrupt256", + "control", "bulk0", "bulk1", "bulk2", "bulk3", + "unused", "unused"}; + +void show_queues(struct uhci *uhci) +{ + int i; + struct uhci_qh *qh; + + for (i = 0; i < UHCI_MAXQH; ++i) { + printk(" %s:\n", qh_names[i]); +#if 0 + printk(" qh #%d, %p\n", i, virt_to_bus(uhci->root_hub->qh + i)); + show_queue(uhci->root_hub->qh + i); +#endif + + qh = uhci_link_to_qh(uhci->root_hub->qh[i].link); + for (; qh; qh = uhci_link_to_qh(qh->link)) { + if (is_skeleton_qh(uhci, qh)) + break; + + show_queue(qh); + } + } +} + diff -ur --new-file old/linux/drivers/usb/uhci.c new/linux/drivers/usb/uhci.c --- old/linux/drivers/usb/uhci.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/usb/uhci.c Fri Apr 30 17:20:53 1999 @@ -0,0 +1,1213 @@ +/* + * Universal Host Controller Interface driver for USB. + * + * (C) Copyright 1999 Linus Torvalds + * + * Intel documents this fairly well, and as far as I know there + * are no royalties or anything like that, but even so there are + * people who decided that they want to do the same thing in a + * completely different way. + * + * Oh, well. The intel version is the more common by far. As such, + * that's the one I care about right now. + * + * WARNING! The USB documentation is downright evil. Most of it + * is just crap, written by a committee. You're better off ignoring + * most of it, the important stuff is: + * - the low-level protocol (fairly simple but lots of small details) + * - working around the horridness of the rest + */ + +/* 4/4/1999 added data toggle for interrupt pipes -keryan */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "uhci.h" +#include "inits.h" + +#ifdef CONFIG_APM +#include +static int handle_apm_event(apm_event_t event); +static int apm_resume = 0; +#endif + +#define compile_assert(x) do { switch (0) { case 1: case !(x): } } while (0) + +static struct wait_queue *uhci_configure = NULL; + +/* + * Return the result of a TD.. + */ +static int uhci_td_result(struct uhci_device *dev, struct uhci_td *td) +{ + unsigned int status; + + status = (td->status >> 16) & 0xff; + + /* Some debugging code */ + if (status) { + int i = 10; + struct uhci_td *tmp = dev->control_td; + printk("uhci_td_result() failed with status %d\n", status); + show_status(dev->uhci); + do { + show_td(tmp); + tmp++; + if (!--i) + break; + } while (tmp <= td); + } + return status; +} + +/* + * Inserts a td into qh list at the top. + * + * Careful about atomicity: even on UP this + * requires a locked access due to the concurrent + * DMA engine. + * + * NOTE! This assumes that first->last is a valid + * list of TD's with the proper backpointers set + * up and all.. + */ +static void uhci_insert_tds_in_qh(struct uhci_qh *qh, struct uhci_td *first, struct uhci_td *last) +{ + unsigned int link = qh->element; + unsigned int new = 4 | virt_to_bus(first); + + for (;;) { + unsigned char success; + + last->link = link; + first->backptr = &qh->element; + asm volatile("lock ; cmpxchg %4,%2 ; sete %0" + :"=q" (success), "=a" (link) + :"m" (qh->element), "1" (link), "r" (new) + :"memory"); + if (success) { + /* Was there a successor entry? Fix it's backpointer.. */ + if ((link & 1) == 0) { + struct uhci_td *next = bus_to_virt(link & ~15); + next->backptr = &last->link; + } + break; + } + } +} + +static inline void uhci_insert_td_in_qh(struct uhci_qh *qh, struct uhci_td *td) +{ + uhci_insert_tds_in_qh(qh, td, td); +} + +static void uhci_insert_qh(struct uhci_qh *qh, struct uhci_qh *newqh) +{ + newqh->link = qh->link; + qh->link = virt_to_bus(newqh) | 2; +} + +static void uhci_remove_qh(struct uhci_qh *qh, struct uhci_qh *remqh) +{ + unsigned int remphys = virt_to_bus(remqh); + struct uhci_qh *lqh = qh; + + while ((lqh->link & ~0xF) != remphys) { + if (lqh->link & 1) + break; + + lqh = bus_to_virt(lqh->link & ~0xF); + } + + if (lqh->link & 1) { + printk("couldn't find qh in chain!\n"); + return; + } + + lqh->link = remqh->link; +} + +/* + * Removes td from qh if present. + * + * NOTE! We keep track of both forward and back-pointers, + * so this should be trivial, right? + * + * Wrong. While all TD insert/remove operations are synchronous + * on the CPU, the UHCI controller can (and does) play with the + * very first forward pointer. So we need to validate the backptr + * before we change it, so that we don't by mistake reset the QH + * head to something old. + */ +static void uhci_remove_td(struct uhci_td *td) +{ + unsigned int *backptr = td->backptr; + unsigned int link = td->link; + unsigned int me; + + if (!backptr) + return; + + td->backptr = NULL; + + /* + * This is the easy case: the UHCI will never change "td->link", + * so we can always just look at that and fix up the backpointer + * of any next element.. + */ + if (!(link & 1)) { + struct uhci_td *next = bus_to_virt(link & ~15); + next->backptr = backptr; + } + + /* + * The nasty case is "backptr->next", which we need to + * update to "link" _only_ if "backptr" still points + * to us (it may not: maybe backptr is a QH->element + * pointer and the UHCI has changed the value). + */ + me = virt_to_bus(td) | (0xe & *backptr); + asm volatile("lock ; cmpxchg %0,%1" + : + :"r" (link), "m" (*backptr), "a" (me) + :"memory"); +} + +static struct uhci_qh *uhci_qh_allocate(struct uhci_device *dev) +{ + struct uhci_qh *qh; + int inuse; + + qh = dev->qh; + for (; (inuse = test_and_set_bit(0, &qh->inuse)) != 0 && qh < &dev->qh[UHCI_MAXQH]; qh++) + ; + + if (!inuse) + return(qh); + + printk("ran out of qh's for dev %p\n", dev); + return(NULL); +} + +static void uhci_qh_deallocate(struct uhci_qh *qh) +{ + if (qh->element != 1) + printk("qh %p leaving dangling entries? (%X)\n", qh, qh->element); + + qh->element = 1; + qh->link = 1; + + clear_bit(0, &qh->inuse); +} + +static struct uhci_td *uhci_td_allocate(struct uhci_device *dev) +{ + struct uhci_td *td; + int inuse; + + td = dev->td; + for (; (inuse = test_and_set_bit(0, &td->inuse)) != 0 && td < &dev->td[UHCI_MAXTD]; td++) + ; + + if (!inuse) + return(td); + + printk("ran out of td's for dev %p\n", dev); + return(NULL); +} + +/* + * This MUST only be called when it has been removed from a QH already (or + * the QH has been removed from the skeleton + */ +static void uhci_td_deallocate(struct uhci_td *td) +{ + td->link = 1; + + clear_bit(0, &td->inuse); +} + +/* + * UHCI interrupt list operations.. + */ +static spinlock_t irqlist_lock = SPIN_LOCK_UNLOCKED; + +static void uhci_add_irq_list(struct uhci *uhci, struct uhci_td *td, usb_device_irq completed, void *dev_id) +{ + unsigned long flags; + + td->completed = completed; + td->dev_id = dev_id; + + spin_lock_irqsave(&irqlist_lock, flags); + list_add(&td->irq_list, &uhci->interrupt_list); + spin_unlock_irqrestore(&irqlist_lock, flags); +} + +static void uhci_remove_irq_list(struct uhci_td *td) +{ + unsigned long flags; + + spin_lock_irqsave(&irqlist_lock, flags); + list_del(&td->irq_list); + spin_unlock_irqrestore(&irqlist_lock, flags); +} + +/* + * Request a interrupt handler.. + */ +static int uhci_request_irq(struct usb_device *usb_dev, unsigned int pipe, usb_device_irq handler, int period, void *dev_id) +{ + struct uhci_device *dev = usb_to_uhci(usb_dev); + struct uhci_td *td = uhci_td_allocate(dev); + struct uhci_qh *interrupt_qh = uhci_qh_allocate(dev); + + unsigned int destination, status; + + /* Destination: pipe destination with INPUT */ + destination = (pipe & 0x0007ff00) | 0x69; + + /* Status: slow/fast, Interrupt, Active, Short Packet Detect Infinite Errors */ + status = (pipe & (1 << 26)) | (1 << 24) | (1 << 23) | (1 << 29) | (0 << 27); + + if(interrupt_qh->element != 1) + printk("interrupt_qh->element = 0x%x\n", + interrupt_qh->element); + + td->link = 1; + td->status = status; /* In */ + td->info = destination | (7 << 21); /* 8 bytes of data */ + td->buffer = virt_to_bus(dev->data); + td->qh = interrupt_qh; + interrupt_qh->skel = &dev->uhci->root_hub->skel_int8_qh; + + uhci_add_irq_list(dev->uhci, td, handler, dev_id); + + uhci_insert_td_in_qh(interrupt_qh, td); + + /* Add it into the skeleton */ + uhci_insert_qh(&dev->uhci->root_hub->skel_int8_qh, interrupt_qh); + return 0; +} + +/* + * Control thread operations: we just mark the last TD + * in a control thread as an interrupt TD, and wake up + * the front-end on completion. + * + * We need to remove the TD from the lists (both interrupt + * list and TD lists) by hand if something bad happens! + */ +static struct wait_queue *control_wakeup; + +static int uhci_control_completed(int status, void *buffer, void *dev_id) +{ + wake_up(&control_wakeup); + return 0; /* Don't re-instate */ +} + +/* td points to the last td in the list, which interrupts on completion */ +static int uhci_run_control(struct uhci_device *dev, struct uhci_td *first, struct uhci_td *last) +{ + struct wait_queue wait = { current, NULL }; + struct uhci_qh *ctrl_qh = uhci_qh_allocate(dev); + struct uhci_td *curtd; + + current->state = TASK_UNINTERRUPTIBLE; + add_wait_queue(&control_wakeup, &wait); + + uhci_add_irq_list(dev->uhci, last, uhci_control_completed, NULL); + + /* FIXME: This is kinda kludged */ + /* Walk the TD list and update the QH pointer */ + { + int maxcount = 100; + + curtd = first; + do { + curtd->qh = ctrl_qh; + if (curtd->link & 1) + break; + + curtd = bus_to_virt(curtd->link & ~0xF); + if (!--maxcount) { + printk("runaway tds!\n"); + break; + } + } while (1); + } + + uhci_insert_tds_in_qh(ctrl_qh, first, last); + + /* Add it into the skeleton */ + uhci_insert_qh(&dev->uhci->root_hub->skel_control_qh, ctrl_qh); + + schedule_timeout(HZ/10); + + remove_wait_queue(&control_wakeup, &wait); + + /* Clean up in case it failed.. */ + uhci_remove_irq_list(last); + +#if 0 + printk("Looking for tds [%p, %p]\n", dev->control_td, td); +#endif + + /* Remove it from the skeleton */ + uhci_remove_qh(&dev->uhci->root_hub->skel_control_qh, ctrl_qh); + + uhci_qh_deallocate(ctrl_qh); + + return uhci_td_result(dev, last); +} + +/* + * Send or receive a control message on a pipe. + * + * Note that the "pipe" structure is set up to map + * easily to the uhci destination fields. + * + * A control message is built up from three parts: + * - The command itself + * - [ optional ] data phase + * - Status complete phase + * + * The data phase can be an arbitrary number of TD's + * although we currently had better not have more than + * 29 TD's here (we have 31 TD's allocated for control + * operations, and two of them are used for command and + * status). + * + * 29 TD's is a minimum of 232 bytes worth of control + * information, that's just ridiculously high. Most + * control messages have just a few bytes of data. + */ +static int uhci_control_msg(struct usb_device *usb_dev, unsigned int pipe, void *cmd, void *data, int len) +{ + struct uhci_device *dev = usb_to_uhci(usb_dev); + struct uhci_td *first, *td, *prevtd; + unsigned long destination, status; + int ret; + + if (len > usb_maxpacket(usb_dev->maxpacketsize) * 29) + printk("Warning, too much data for a control packet, crashing\n"); + + first = td = uhci_td_allocate(dev); + + /* The "pipe" thing contains the destination in bits 8--18, 0x2D is SETUP */ + destination = (pipe & 0x0007ff00) | 0x2D; + + /* Status: slow/fast, Active, Short Packet Detect Three Errors */ + status = (pipe & (1 << 26)) | (1 << 23) | (1 << 29) | (3 << 27); + + /* + * Build the TD for the control request + */ + td->status = status; /* Try forever */ + td->info = destination | (7 << 21); /* 8 bytes of data */ + td->buffer = virt_to_bus(cmd); + + /* + * If direction is "send", change the frame from SETUP (0x2D) + * to OUT (0xE1). Else change it from SETUP to IN (0x69) + */ + destination ^= (0x2D ^ 0x69); /* SETUP -> IN */ + if (usb_pipeout(pipe)) + destination ^= (0xE1 ^ 0x69); /* IN -> OUT */ + + prevtd = td; + td = uhci_td_allocate(dev); + prevtd->link = 4 | virt_to_bus(td); + + /* + * Build the DATA TD's + */ + while (len > 0) { + /* Build the TD for control status */ + int pktsze = len; + int maxsze = usb_maxpacket(pipe); + + if (pktsze > maxsze) + pktsze = maxsze; + + /* Alternate Data0/1 (start with Data1) */ + destination ^= 1 << 19; + + td->status = status; /* Status */ + td->info = destination | ((pktsze-1) << 21); /* pktsze bytes of data */ + td->buffer = virt_to_bus(data); + td->backptr = &prevtd->link; + + prevtd = td; + td = uhci_td_allocate(dev); + prevtd->link = 4 | virt_to_bus(td); /* Update previous TD */ + + data += maxsze; + len -= maxsze; + } + + /* + * Build the final TD for control status + */ + destination ^= (0xE1 ^ 0x69); /* OUT -> IN */ + destination |= 1 << 19; /* End in Data1 */ + + td->link = 1; /* Terminate */ + td->status = status | (1 << 24); /* IOC */ + td->info = destination | (0x7ff << 21); /* 0 bytes of data */ + td->buffer = 0; + td->backptr = &prevtd->link; + + /* Start it up.. */ + ret = uhci_run_control(dev, first, td); + + { + int maxcount = 100; + struct uhci_td *curtd = first; + unsigned int nextlink; + + do { + nextlink = curtd->link; + uhci_remove_td(curtd); + uhci_td_deallocate(curtd); + if (nextlink & 1) /* Tail? */ + break; + + curtd = bus_to_virt(nextlink & ~0xF); + if (!--maxcount) { + printk("runaway td's!?\n"); + break; + } + } while (1); + } + + return ret; +} + +static struct usb_device *uhci_usb_allocate(struct usb_device *parent) +{ + struct usb_device *usb_dev; + struct uhci_device *dev; + int i; + + usb_dev = kmalloc(sizeof(*usb_dev), GFP_KERNEL); + if (!usb_dev) + return NULL; + + memset(usb_dev, 0, sizeof(*usb_dev)); + + dev = kmalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) { + usb_destroy_configuration(usb_dev); + kfree(usb_dev); + return NULL; + } + + /* Initialize "dev" */ + memset(dev, 0, sizeof(*dev)); + + usb_dev->hcpriv = dev; + dev->usb = usb_dev; + + usb_dev->parent = parent; + + if (parent) { + usb_dev->bus = parent->bus; + dev->uhci = usb_to_uhci(parent)->uhci; + } + + /* Reset the QH's and TD's */ + for (i = 0; i < UHCI_MAXQH; i++) { + dev->qh[i].link = 1; + dev->qh[i].element = 1; + dev->qh[i].inuse = 0; + } + + for (i = 0; i < UHCI_MAXTD; i++) { + dev->td[i].link = 1; + dev->td[i].inuse = 0; + } + + return usb_dev; +} + +static int uhci_usb_deallocate(struct usb_device *usb_dev) +{ + struct uhci_device *dev = usb_to_uhci(usb_dev); + int i; + + /* There are UHCI_MAXTD preallocated tds */ + for (i = 0; i < UHCI_MAXTD; ++i) { + struct uhci_td *td = dev->td + i; + + /* And remove it from the irq list, if it's active */ + if (td->status & (1 << 23)) + uhci_remove_irq_list(td); + + if (td->inuse) + uhci_remove_td(td); + } + + /* Remove the td from any queues */ + for (i = 0; i < UHCI_MAXQH; ++i) { + struct uhci_qh *qh = dev->qh + i; + + if (qh->inuse) + uhci_remove_qh(qh->skel, qh); + } + + kfree(dev); + usb_destroy_configuration(usb_dev); + kfree(usb_dev); + + return 0; +} + +struct usb_operations uhci_device_operations = { + uhci_usb_allocate, + uhci_usb_deallocate, + uhci_control_msg, + uhci_request_irq, +}; + +/* + * This is just incredibly fragile. The timings must be just + * right, and they aren't really documented very well. + * + * Note the short delay between disabling reset and enabling + * the port.. + */ +static void uhci_reset_port(unsigned int port) +{ + unsigned short status; + + status = inw(port); + outw(status | USBPORTSC_PR, port); /* reset port */ + wait_ms(10); + outw(status & ~USBPORTSC_PR, port); + udelay(5); + + status = inw(port); + outw(status | USBPORTSC_PE, port); /* enable port */ + wait_ms(10); + + status = inw(port); + if(!(status & USBPORTSC_PE)) { + outw(status | USBPORTSC_PE, port); /* one more try at enabling port */ + wait_ms(50); + } + +} + + +/* + * This gets called if the connect status on the root + * hub (and the root hub only) changes. + */ +static void uhci_connect_change(struct uhci *uhci, unsigned int port, unsigned int nr) +{ + struct usb_device *usb_dev; + struct uhci_device *dev; + unsigned short status; + + printk("uhci_connect_change: called for %d\n", nr); + + /* + * Even if the status says we're connected, + * the fact that the status bits changed may + * that we got disconnected and then reconnected. + * + * So start off by getting rid of any old devices.. + */ + usb_disconnect(&uhci->root_hub->usb->children[nr]); + + status = inw(port); + + /* If we have nothing connected, then clear change status and disable the port */ + status = (status & ~USBPORTSC_PE) | USBPORTSC_PEC; + if (!(status & USBPORTSC_CCS)) { + outw(status, port); + return; + } + + /* + * Ok, we got a new connection. Allocate a device to it, + * and find out what it wants to do.. + */ + usb_dev = uhci_usb_allocate(uhci->root_hub->usb); + dev = usb_dev->hcpriv; + + dev->uhci = uhci; + + usb_connect(usb_dev); + + uhci->root_hub->usb->children[nr] = usb_dev; + + wait_ms(200); /* wait for powerup */ + uhci_reset_port(port); + + /* Get speed information */ + usb_dev->slow = (inw(port) & USBPORTSC_LSDA) ? 1 : 0; + + /* + * Ok, all the stuff specific to the root hub has been done. + * The rest is generic for any new USB attach, regardless of + * hub type. + */ + usb_new_device(usb_dev); +} + +/* + * This gets called when the root hub configuration + * has changed. Just go through each port, seeing if + * there is something interesting happening. + */ +static void uhci_check_configuration(struct uhci *uhci) +{ + unsigned int io_addr = uhci->io_addr + USBPORTSC1; + int maxchild = uhci->root_hub->usb->maxchild; + int nr = 0; + + do { + unsigned short status = inw(io_addr); + + if (status & USBPORTSC_CSC) + uhci_connect_change(uhci, io_addr, nr); + + nr++; io_addr += 2; + } while (nr < maxchild); +} + +static void uhci_interrupt_notify(struct uhci *uhci) +{ + struct list_head *head = &uhci->interrupt_list; + struct list_head *tmp; + + spin_lock(&irqlist_lock); + tmp = head->next; + while (tmp != head) { + struct uhci_td *td = list_entry(tmp, struct uhci_td, irq_list); + struct list_head *next; + + next = tmp->next; + + if (!(td->status & (1 << 23))) { /* No longer active? */ + /* remove from IRQ list */ + __list_del(tmp->prev, next); + INIT_LIST_HEAD(tmp); + if (td->completed(td->status, bus_to_virt(td->buffer), td->dev_id)) { + struct uhci_qh *interrupt_qh = td->qh; + + list_add(&td->irq_list, &uhci->interrupt_list); + td->info ^= 1 << 19; /* toggle between data0 and data1 */ + td->status = (td->status & 0x2f000000) | (1 << 23) | (1 << 24); /* active */ + + /* Remove then readd? Is that necessary */ + uhci_remove_td(td); + uhci_insert_td_in_qh(interrupt_qh, td); + } + /* If completed wants to not reactivate, then it's */ + /* responsible for free'ing the TD's and QH's */ + /* or another function (such as run_control) */ + } + tmp = next; + } + spin_unlock(&irqlist_lock); +} + +/* + * Check port status - Connect Status Change - for + * each of the attached ports (defaults to two ports, + * but at least in theory there can be more of them). + * + * Wake up the configurator if something happened, we + * can't really do much at interrupt time. + */ +static void uhci_root_hub_events(struct uhci *uhci, unsigned int io_addr) +{ + if (waitqueue_active(&uhci_configure)) { + int ports = uhci->root_hub->usb->maxchild; + io_addr += USBPORTSC1; + do { + if (inw(io_addr) & USBPORTSC_CSC) { + wake_up(&uhci_configure); + return; + } + io_addr += 2; + } while (--ports > 0); + } +} + +static void uhci_interrupt(int irq, void *__uhci, struct pt_regs *regs) +{ + struct uhci *uhci = __uhci; + unsigned int io_addr = uhci->io_addr; + unsigned short status; + + /* + * Read the interrupt status, and write it back to clear the interrupt cause + */ + status = inw(io_addr + USBSTS); + outw(status, io_addr + USBSTS); + + /* Walk the list of pending TD's to see which ones completed.. */ + uhci_interrupt_notify(uhci); + + /* Check if there are any events on the root hub.. */ + uhci_root_hub_events(uhci, io_addr); +} + +/* + * We init one packet, and mark it just IOC and _not_ + * active. Which will result in no actual USB traffic, + * but _will_ result in an interrupt every second. + * + * Which is exactly what we want. + */ +static void uhci_init_ticktd(struct uhci *uhci) +{ + struct uhci_device *dev = uhci->root_hub; + struct uhci_td *td = uhci_td_allocate(dev); + + td->link = 1; + td->status = (1 << 24); /* interrupt on completion */ + td->info = (15 << 21) | 0x7f69; /* (ignored) input packet, 16 bytes, device 127 */ + td->buffer = 0; + td->qh = NULL; + + uhci->fl->frame[0] = virt_to_bus(td); +} + +static void reset_hc(struct uhci *uhci) +{ + unsigned int io_addr = uhci->io_addr; + + /* Global reset for 50ms */ + outw(USBCMD_GRESET, io_addr+USBCMD); + wait_ms(50); + outw(0, io_addr+USBCMD); + wait_ms(10); +} + +static void start_hc(struct uhci *uhci) +{ + unsigned int io_addr = uhci->io_addr; + int timeout = 1000; + + uhci_init_ticktd(uhci); + + /* + * Reset the HC - this will force us to get a + * new notification of any already connected + * ports due to the virtual disconnect that it + * implies. + */ + outw(USBCMD_HCRESET, io_addr + USBCMD); + while (inw(io_addr + USBCMD) & USBCMD_HCRESET) { + if (!--timeout) { + printk("USBCMD_HCRESET timed out!\n"); + break; + } + } + + outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP, io_addr + USBINTR); + outw(0, io_addr + USBFRNUM); + outl(virt_to_bus(uhci->fl), io_addr + USBFLBASEADD); + + /* Run and mark it configured with a 64-byte max packet */ + outw(USBCMD_RS | USBCMD_CF, io_addr + USBCMD); +} + +/* + * Allocate a frame list, and four regular queues. + * + * The hardware doesn't really know any difference + * in the queues, but the order does matter for the + * protocols higher up. The order is: + * + * - any isochronous events handled before any + * of the queues. We don't do that here, because + * we'll create the actual TD entries on demand. + * - The first queue is the "interrupt queue". + * - The second queue is the "control queue". + * - The third queue is "bulk data". + * + * We could certainly have multiple queues of the same + * type, and maybe we should. We could have per-device + * queues, for example. We begin small. + */ +static struct uhci *alloc_uhci(unsigned int io_addr) +{ + int i; + struct uhci *uhci; + struct usb_bus *bus; + struct uhci_device *dev; + struct usb_device *usb; + + uhci = kmalloc(sizeof(*uhci), GFP_KERNEL); + if (!uhci) + return NULL; + + memset(uhci, 0, sizeof(*uhci)); + + uhci->irq = -1; + uhci->io_addr = io_addr; + INIT_LIST_HEAD(&uhci->interrupt_list); + + /* We need exactly one page (per UHCI specs), how convenient */ + uhci->fl = (void *)__get_free_page(GFP_KERNEL); + + bus = kmalloc(sizeof(*bus), GFP_KERNEL); + if (!bus) + return NULL; + + memset(bus, 0, sizeof(*bus)); + + uhci->bus = bus; + bus->hcpriv = uhci; + bus->op = &uhci_device_operations; + + /* + * We allocate a 8kB area for the UHCI hub. The area + * is described by the uhci_device structure, and basically + * contains everything needed for normal operation. + * + * The first page is the actual device descriptor for the + * hub. + * + * The second page is used for the frame list. + */ + usb = uhci_usb_allocate(NULL); + if (!usb) + return NULL; + + dev = uhci->root_hub = usb_to_uhci(usb); + + usb->bus = bus; + + /* Initialize the root hub */ + /* UHCI specs says devices must have 2 ports, but goes on to say */ + /* they may have more but give no way to determine how many they */ + /* have, so default to 2 */ + usb->maxchild = 2; + usb_init_root_hub(usb); + + /* + * Initialize the queues. They all start out empty, + * linked to each other in the proper order. + */ + for (i = 1 ; i < 9; i++) { + dev->qh[i].link = 2 | virt_to_bus(&dev->skel_control_qh); + dev->qh[i].element = 1; + } + + dev->skel_control_qh.link = 2 | virt_to_bus(&dev->skel_bulk0_qh); + dev->skel_control_qh.element = 1; + + dev->skel_bulk0_qh.link = 2 | virt_to_bus(&dev->skel_bulk1_qh); + dev->skel_bulk0_qh.element = 1; + + dev->skel_bulk1_qh.link = 2 | virt_to_bus(&dev->skel_bulk2_qh); + dev->skel_bulk1_qh.element = 1; + + dev->skel_bulk2_qh.link = 2 | virt_to_bus(&dev->skel_bulk3_qh); + dev->skel_bulk2_qh.element = 1; + + dev->skel_bulk3_qh.link = 1; + dev->skel_bulk3_qh.element = 1; + + /* + * Fill the frame list: make all entries point to + * the proper interrupt queue. + * + * This is probably silly, but it's a simple way to + * scatter the interrupt queues in a way that gives + * us a reasonable dynamic range for irq latencies. + */ + for (i = 0; i < 1024; i++) { + struct uhci_qh * irq = &dev->skel_int2_qh; + if (i & 1) { + irq++; + if (i & 2) { + irq++; + if (i & 4) { + irq++; + if (i & 8) { + irq++; + if (i & 16) { + irq++; + if (i & 32) { + irq++; + if (i & 64) { + irq++; + } + } + } + } + } + } + } + uhci->fl->frame[i] = 2 | virt_to_bus(irq); + } + + return uhci; +} + + +/* + * De-allocate all resources.. + */ +static void release_uhci(struct uhci *uhci) +{ + if (uhci->irq >= 0) { + free_irq(uhci->irq, uhci); + uhci->irq = -1; + } + +#if 0 + if (uhci->root_hub) { + uhci_usb_deallocate(uhci_to_usb(uhci->root_hub)); + uhci->root_hub = NULL; + } +#endif + + if (uhci->fl) { + free_page((unsigned long)uhci->fl); + uhci->fl = NULL; + } + + kfree(uhci->bus); + kfree(uhci); +} + +void cleanup_drivers(void); + +static int uhci_control_thread(void * __uhci) +{ + struct uhci *uhci = (struct uhci *)__uhci; + + lock_kernel(); + request_region(uhci->io_addr, 32, "usb-uhci"); + + /* + * This thread doesn't need any user-level access, + * so get rid of all our resources.. + */ + printk("uhci_control_thread at %p\n", &uhci_control_thread); + exit_mm(current); + exit_files(current); + exit_fs(current); + + strcpy(current->comm, "uhci-control"); + + /* + * Ok, all systems are go.. + */ + start_hc(uhci); + for(;;) { + siginfo_t info; + int unsigned long signr; + + interruptible_sleep_on(&uhci_configure); +#ifdef CONFIG_APM + if (apm_resume) { + apm_resume = 0; + start_hc(uhci); + continue; + } +#endif + uhci_check_configuration(uhci); + + if(signal_pending(current)) { + /* sending SIGUSR1 makes us print out some info */ + spin_lock_irq(¤t->sigmask_lock); + signr = dequeue_signal(¤t->blocked, &info); + spin_unlock_irq(¤t->sigmask_lock); + + if(signr == SIGUSR1) { + printk("UHCI queue dump:\n"); + show_queues(uhci); + } else { + break; + } + } + } + +#if 0 + if(uhci->root_hub) + for(i = 0; i < uhci->root_hub->usb->maxchild; i++) + usb_disconnect(uhci->root_hub->usb->children + i); +#endif + + cleanup_drivers(); + + reset_hc(uhci); + release_region(uhci->io_addr, 32); + + release_uhci(uhci); + MOD_DEC_USE_COUNT; + + printk("uhci_control_thread exiting\n"); + + return 0; +} + +/* + * If we've successfully found a UHCI, now is the time to increment the + * module usage count, start the control thread, and return success.. + */ +static int found_uhci(int irq, unsigned int io_addr) +{ + int retval; + struct uhci *uhci; + + uhci = alloc_uhci(io_addr); + if (!uhci) + return -ENOMEM; + + reset_hc(uhci); + + retval = -EBUSY; + if (request_irq(irq, uhci_interrupt, SA_SHIRQ, "usb", uhci) == 0) { + int pid; + + MOD_INC_USE_COUNT; + uhci->irq = irq; + pid = kernel_thread(uhci_control_thread, uhci, CLONE_FS | CLONE_FILES | CLONE_SIGHAND); + if (pid >= 0) + return 0; + + MOD_DEC_USE_COUNT; + retval = pid; + } + release_uhci(uhci); + return retval; +} + +static int start_uhci(struct pci_dev *dev) +{ + int i; + + /* Search for the IO base address.. */ + for (i = 0; i < 6; i++) { + unsigned int io_addr = dev->base_address[i]; + + /* IO address? */ + if (!(io_addr & 1)) + continue; + + io_addr &= PCI_BASE_ADDRESS_IO_MASK; + + /* Is it already in use? */ + if (check_region(io_addr, 32)) + break; + + return found_uhci(dev->irq, io_addr); + } + return -1; +} + +#ifdef CONFIG_APM +static int handle_apm_event(apm_event_t event) +{ + static int down = 0; + + switch (event) { + case APM_SYS_SUSPEND: + case APM_USER_SUSPEND: + if (down) { + printk(KERN_DEBUG "uhci: received extra suspend event\n"); + break; + } + down = 1; + break; + case APM_NORMAL_RESUME: + case APM_CRITICAL_RESUME: + if (!down) { + printk(KERN_DEBUG "uhci: received bogus resume event\n"); + break; + } + down = 0; + if (waitqueue_active(&uhci_configure)) { + apm_resume = 1; + wake_up(&uhci_configure); + } + break; + } + return 0; +} +#endif + +#ifdef MODULE + +void cleanup_module(void) +{ +#ifdef CONFIG_APM + apm_unregister_callback(&handle_apm_event); +#endif +} + +#define uhci_init init_module + +#endif + +int uhci_init(void) +{ + int retval; + struct pci_dev *dev = NULL; + u8 type; + + retval = -ENODEV; + for (;;) { + dev = pci_find_class(PCI_CLASS_SERIAL_USB<<8, dev); + if (!dev) + break; + /* Is it UHCI */ + pci_read_config_byte(dev, PCI_CLASS_PROG, &type); + if(type != 0) + continue; + /* Ok set it up */ + retval = start_uhci(dev); + if (retval < 0) + continue; + +#ifdef CONFIG_USB_MOUSE + usb_mouse_init(); +#endif +#ifdef CONFIG_USB_KBD + usb_kbd_init(); +#endif + hub_init(); +#ifdef CONFIG_USB_AUDIO + usb_audio_init(); +#endif +#ifdef CONFIG_APM + apm_register_callback(&handle_apm_event); +#endif + + return 0; + } + return retval; +} + +void cleanup_drivers(void) +{ + hub_cleanup(); +#ifdef CONFIG_USB_MOUSE + usb_mouse_cleanup(); +#endif +} diff -ur --new-file old/linux/drivers/usb/uhci.h new/linux/drivers/usb/uhci.h --- old/linux/drivers/usb/uhci.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/usb/uhci.h Wed Apr 28 20:14:03 1999 @@ -0,0 +1,229 @@ +#ifndef __LINUX_UHCI_H +#define __LINUX_UHCI_H + +#include + +#include "usb.h" + +/* + * Universal Host Controller Interface data structures and defines + */ + +/* Command register */ +#define USBCMD 0 +#define USBCMD_RS 0x0001 /* Run/Stop */ +#define USBCMD_HCRESET 0x0002 /* Host reset */ +#define USBCMD_GRESET 0x0004 /* Global reset */ +#define USBCMD_EGSM 0x0008 /* Global Suspend Mode */ +#define USBCMD_FGR 0x0010 /* Force Global Resume */ +#define USBCMD_SWDBG 0x0020 /* SW Debug mode */ +#define USBCMD_CF 0x0040 /* Config Flag (sw only) */ +#define USBCMD_MAXP 0x0080 /* Max Packet (0 = 32, 1 = 64) */ + +/* Status register */ +#define USBSTS 2 +#define USBSTS_USBINT 0x0001 /* Interrupt due to IOC */ +#define USBSTS_ERROR 0x0002 /* Interrupt due to error */ +#define USBSTS_RD 0x0004 /* Resume Detect */ +#define USBSTS_HSE 0x0008 /* Host System Error - basically PCI problems */ +#define USBSTS_HCPE 0x0010 /* Host Controller Process Error - the scripts were buggy */ +#define USBSTS_HCH 0x0020 /* HC Halted */ + +/* Interrupt enable register */ +#define USBINTR 4 +#define USBINTR_TIMEOUT 0x0001 /* Timeout/CRC error enable */ +#define USBINTR_RESUME 0x0002 /* Resume interrupt enable */ +#define USBINTR_IOC 0x0004 /* Interrupt On Complete enable */ +#define USBINTR_SP 0x0008 /* Short packet interrupt enable */ + +#define USBFRNUM 6 +#define USBFLBASEADD 8 +#define USBSOF 12 + +/* USB port status and control registers */ +#define USBPORTSC1 16 +#define USBPORTSC2 18 +#define USBPORTSC_CCS 0x0001 /* Current Connect Status ("device present") */ +#define USBPORTSC_CSC 0x0002 /* Connect Status Change */ +#define USBPORTSC_PE 0x0004 /* Port Enable */ +#define USBPORTSC_PEC 0x0008 /* Port Enable Change */ +#define USBPORTSC_LS 0x0030 /* Line Status */ +#define USBPORTSC_RD 0x0040 /* Resume Detect */ +#define USBPORTSC_LSDA 0x0100 /* Low Speed Device Attached */ +#define USBPORTSC_PR 0x0200 /* Port Reset */ +#define USBPORTSC_SUSP 0x1000 /* Suspend */ + +struct uhci_qh { + unsigned int link; /* Next queue */ + unsigned int element; /* Queue element pointer */ + int inuse; /* Inuse? */ + struct uhci_qh *skel; /* Skeleton head */ +} __attribute__((aligned(16))); + +struct uhci_framelist { + unsigned int frame[1024]; +} __attribute__((aligned(4096))); + +/* + * The documentation says "4 words for hardware, 4 words for software". + * + * That's silly, the hardware doesn't care. The hardware only cares that + * the hardware words are 16-byte aligned, and we can have any amount of + * sw space after the TD entry as far as I can tell. + * + * But let's just go with the documentation, at least for 32-bit machines. + * On 64-bit machines we probably want to take advantage of the fact that + * hw doesn't really care about the size of the sw-only area. + * + * Alas, not anymore, we have more than 4 words of software, woops + */ +struct uhci_td { + /* Hardware fields */ + __u32 link; + __u32 status; + __u32 info; + __u32 buffer; + + /* Software fields */ + struct list_head irq_list; /* Active interrupt list.. */ + usb_device_irq completed; /* Completion handler routine */ + unsigned int *backptr; /* Where to remove this from.. */ + void *dev_id; + int inuse; /* Inuse? */ + struct uhci_qh *qh; +} __attribute__((aligned(32))); + +/* + * Note the alignment requirements of the entries + * + * Each UHCI device has pre-allocated QH and TD entries. + * You can use more than the pre-allocated ones, but I + * don't see you usually needing to. + */ +struct uhci; + +#define UHCI_MAXTD 64 + +#define UHCI_MAXQH 16 + +/* The usb device part must be first! */ +struct uhci_device { + struct usb_device *usb; + + struct uhci *uhci; + struct uhci_qh qh[UHCI_MAXQH]; /* These are the "common" qh's for each device */ + struct uhci_td td[UHCI_MAXTD]; + + unsigned long data[16]; +}; + +#define uhci_to_usb(uhci) ((uhci)->usb) +#define usb_to_uhci(usb) ((struct uhci_device *)(usb)->hcpriv) + +/* + * The root hub pre-allocated QH's and TD's have + * some special global uses.. + */ +#define control_td td /* Td's 0-30 */ +/* This is only for the root hub's TD list */ +#define tick_td td[31] + +/* + * There are various standard queues. We set up several different + * queues for each of the three basic queue types: interrupt, + * control, and bulk. + * + * - There are various different interrupt latencies: ranging from + * every other USB frame (2 ms apart) to every 256 USB frames (ie + * 256 ms apart). Make your choice according to how obnoxious you + * want to be on the wire, vs how critical latency is for you. + * - The control list is done every frame. + * - There are 4 bulk lists, so that up to four devices can have a + * bulk list of their own and when run concurrently all four lists + * will be be serviced. + * + * This is a bit misleading, there are various interrupt latencies, but they + * vary a bit, interrupt2 isn't exactly 2ms, it can vary up to 4ms since the + * other queues can "override" it. interrupt4 can vary up to 8ms, etc. Minor + * problem + * + * In the case of the root hub, these QH's are just head's of qh's. Don't + * be scared, it kinda makes sense. Look at this wonderful picture care of + * Linus: + * + * generic-iso-QH -> dev1-iso-QH -> generic-irq-QH -> dev1-irq-QH -> ... + * | | | | + * End dev1-iso-TD1 End dev1-irq-TD1 + * | + * dev1-iso-TD2 + * | + * .... + * + * This may vary a bit (the UHCI docs don't explicitly say you can put iso + * transfers in QH's and all of their pictures don't have that either) but + * other than that, that is what we're doing now + * + * To keep with Linus' nomenclature, this is called the qh skeleton. These + * labels (below) are only signficant to the root hub's qh's + */ +#define skel_iso_qh qh[0] + +#define skel_int2_qh qh[1] +#define skel_int4_qh qh[2] +#define skel_int8_qh qh[3] +#define skel_int16_qh qh[4] +#define skel_int32_qh qh[5] +#define skel_int64_qh qh[6] +#define skel_int128_qh qh[7] +#define skel_int256_qh qh[8] + +#define skel_control_qh qh[9] + +#define skel_bulk0_qh qh[10] +#define skel_bulk1_qh qh[11] +#define skel_bulk2_qh qh[12] +#define skel_bulk3_qh qh[13] + +/* + * These are significant to the devices allocation of QH's + */ +#if 0 +#define iso_qh qh[0] +#define int_qh qh[1] /* We have 2 "common" interrupt QH's */ +#define control_qh qh[3] +#define bulk_qh qh[4] /* We have 4 "common" bulk QH's */ +#define extra_qh qh[8] /* The rest, anything goes */ +#endif + +/* + * This describes the full uhci information. + * + * Note how the "proper" USB information is just + * a subset of what the full implementation needs. + */ +struct uhci { + int irq; + unsigned int io_addr; + + struct usb_bus *bus; + +#if 0 + /* These are "standard" QH's for the entire bus */ + struct uhci_qh qh[UHCI_MAXQH]; +#endif + struct uhci_device *root_hub; /* Root hub device descriptor.. */ + + struct uhci_framelist *fl; /* Frame list */ + struct list_head interrupt_list; /* List of interrupt-active TD's for this uhci */ +}; + +/* needed for the debugging code */ +struct uhci_td *uhci_link_to_td(unsigned int element); + +/* Debugging code */ +void show_td(struct uhci_td * td); +void show_status(struct uhci *uhci); +void show_queues(struct uhci *uhci); + +#endif + diff -ur --new-file old/linux/drivers/usb/usb-debug.c new/linux/drivers/usb/usb-debug.c --- old/linux/drivers/usb/usb-debug.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/usb/usb-debug.c Wed Apr 21 11:32:59 1999 @@ -0,0 +1,127 @@ +/* + * debug.c - USB debug helper routines. + * + * I just want these out of the way where they aren't in your + * face, but so that you can still use them.. + */ +#include + +#include "usb.h" + +static void usb_show_endpoint(struct usb_endpoint_descriptor *endpoint) +{ + usb_show_endpoint_descriptor(endpoint); +} + +static void usb_show_interface(struct usb_interface_descriptor *interface) +{ + int i; + + usb_show_interface_descriptor(interface); + for (i = 0 ; i < interface->bNumEndpoints; i++) + usb_show_endpoint(interface->endpoint + i); +} + +static void usb_show_config(struct usb_config_descriptor *config) +{ + int i; + + usb_show_config_descriptor(config); + for (i = 0 ; i < config->bNumInterfaces; i++) + usb_show_interface(config->interface + i); +} + +void usb_show_device(struct usb_device *dev) +{ + int i; + + usb_show_device_descriptor(&dev->descriptor); + for (i = 0; i < dev->descriptor.bNumConfigurations; i++) + usb_show_config(dev->config + i); +} + + +/* + * Parse and show the different USB descriptors. + */ +void usb_show_device_descriptor(struct usb_device_descriptor *desc) +{ + printk(" USB version %x.%02x\n", desc->bcdUSB >> 8, desc->bcdUSB & 0xff); + printk(" Vendor: %04x\n", desc->idVendor); + printk(" Product: %04x\n", desc->idProduct); + printk(" Configurations: %d\n", desc->bNumConfigurations); + + printk(" Device Class: %d\n", desc->bDeviceClass); + switch (desc->bDeviceClass) { + case 0: + printk(" Per-interface classes\n"); + break; + case 9: + printk(" Hub device class\n"); + break; + case 0xff: + printk(" Vendor class\n"); + break; + default: + printk(" Unknown class\n"); + } +} + +void usb_show_config_descriptor(struct usb_config_descriptor * desc) +{ + printk("Configuration:\n"); + printk(" bLength = %4d%s\n", desc->bLength, + desc->bLength == 9 ? "" : " (!!!)"); + printk(" bDescriptorType = %02x\n", desc->bDescriptorType); + printk(" wTotalLength = %04x\n", desc->wTotalLength); + printk(" bNumInterfaces = %02x\n", desc->bNumInterfaces); + printk(" bConfigurationValue = %02x\n", desc->bConfigurationValue); + printk(" iConfiguration = %02x\n", desc->iConfiguration); + printk(" bmAttributes = %02x\n", desc->bmAttributes); + printk(" MaxPower = %4dmA\n", desc->MaxPower * 2); +} + +void usb_show_interface_descriptor(struct usb_interface_descriptor * desc) +{ + printk(" Interface:\n"); + printk(" bLength = %4d%s\n", desc->bLength, + desc->bLength == 9 ? "" : " (!!!)"); + printk(" bDescriptorType = %02x\n", desc->bDescriptorType); + printk(" bInterfaceNumber = %02x\n", desc->bInterfaceNumber); + printk(" bAlternateSetting = %02x\n", desc->bAlternateSetting); + printk(" bNumEndpoints = %02x\n", desc->bNumEndpoints); + printk(" bInterfaceClass = %02x\n", desc->bInterfaceClass); + printk(" bInterfaceSubClass = %02x\n", desc->bInterfaceSubClass); + printk(" bInterfaceProtocol = %02x\n", desc->bInterfaceProtocol); + printk(" iInterface = %02x\n", desc->iInterface); +} + +void usb_show_endpoint_descriptor(struct usb_endpoint_descriptor * desc) +{ + char *EndpointType[4] = { "Control", "Isochronous", "Bulk", "Interrupt" }; + printk(" Endpoint:\n"); + printk(" bLength = %4d%s\n", desc->bLength, + desc->bLength == 7 ? "" : " (!!!)"); + printk(" bDescriptorType = %02x\n", desc->bDescriptorType); + printk(" bEndpointAddress = %02x (%s)\n", desc->bEndpointAddress, + (desc->bEndpointAddress & 0x80) ? "in" : "out"); + printk(" bmAttributes = %02x (%s)\n", desc->bmAttributes, + EndpointType[3 & desc->bmAttributes]); + printk(" wMaxPacketSize = %04x\n", desc->wMaxPacketSize); + printk(" bInterval = %02x\n", desc->bInterval); +} + +void usb_show_hub_descriptor(struct usb_hub_descriptor * desc) +{ + int len = 7; + unsigned char *ptr = (unsigned char *) desc; + + printk("Interface:"); + while (len) { + printk(" %02x", *ptr); + ptr++; len--; + } + printk("\n"); +} + + diff -ur --new-file old/linux/drivers/usb/usb.c new/linux/drivers/usb/usb.c --- old/linux/drivers/usb/usb.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/usb/usb.c Sat May 8 00:16:04 1999 @@ -0,0 +1,673 @@ +/* + * driver/usb/usb.c + * + * (C) Copyright Linus Torvalds 1999 + * + * NOTE! This is not actually a driver at all, rather this is + * just a collection of helper routines that implement the + * generic USB things that the real drivers can use.. + * + * Think of this as a "USB library" rather than anything else. + * It should be considered a slave, with no callbacks. Callbacks + * are evil. + */ + +/* + * Table 9-2 + * + * Offset Field Size Value Desc + * 0 bmRequestType 1 Bitmap D7: Direction + * 0 = Host-to-device + * 1 = Device-to-host + * D6..5: Type + * 0 = Standard + * 1 = Class + * 2 = Vendor + * 3 = Reserved + * D4..0: Recipient + * 0 = Device + * 1 = Interface + * 2 = Endpoint + * 3 = Other + * 4..31 = Reserved + * 1 bRequest 1 Value Specific request (9-3) + * 2 wValue 2 Value Varies + * 4 wIndex 2 Index/Offset Varies + * 6 wLength 2 Count Bytes for data + */ + +#include +#include +#include + +#include "usb.h" + +/* + * We have a per-interface "registered driver" list. + */ +static LIST_HEAD(usb_driver_list); + +int usb_register(struct usb_driver *new_driver) +{ + /* Add it to the list of known drivers */ + list_add(&new_driver->driver_list, &usb_driver_list); + + /* + * We should go through all existing devices, and see if any of + * them would be acceptable to the new driver.. Let's do that + * in version 2.0. + */ + return 0; +} + +void usb_deregister(struct usb_driver *driver) +{ + list_del(&driver->driver_list); +} + +/* + * This entrypoint gets called for each new device. + * + * We now walk the list of registered USB drivers, + * looking for one that will accept this device as + * his.. + */ +void usb_device_descriptor(struct usb_device *dev) +{ + struct list_head *tmp = usb_driver_list.next; + + while (tmp != &usb_driver_list) { + struct usb_driver *driver = list_entry(tmp, struct usb_driver, driver_list); + tmp = tmp->next; + if (driver->probe(dev)) + continue; + dev->driver = driver; + return; + } + + /* + * Ok, no driver accepted the device, so show the info + * for debugging.. + */ + printk("Unknown new USB device:\n"); + usb_show_device(dev); +} + +/* + * Parse the fairly incomprehensible output of + * the USB configuration data, and build up the + * USB device database. + */ +static int usb_expect_descriptor(unsigned char *ptr, int len, unsigned char desctype, unsigned char descindex) +{ + int parsed = 0; + int n_len; + unsigned short n_desc; + + for (;;) { + int i; + + if (len < descindex) + return -1; + n_desc = *(unsigned short *)ptr; + n_len = n_desc & 0xff; + + if (n_desc == ((desctype << 8) + descindex)) + break; + + if (((n_desc >> 8)&0xFF) == desctype && + n_len > descindex) + { + printk("bug: oversized descriptor.\n"); + break; + } + + if (n_len < 2 || n_len > len) + { + printk("Short descriptor.\n"); + return -1; + } + printk( + "Expected descriptor %02X/%02X, got %02X/%02X - skipping\n", + desctype, descindex, + (n_desc >> 8) & 0xFF, n_desc & 0xFF); + for (i = 0 ; i < n_len; i++) + printk(" %d %02x\n", i, ptr[i]); + len -= n_len; + ptr += n_len; + parsed += n_len; + } + + printk("Found %02X:%02X\n", + desctype, descindex); + return parsed; +} + +/* + * Parse the even more incomprehensible mess made of the USB spec + * by USB audio having private magic to go with it. + */ + +static int usb_check_descriptor(unsigned char *ptr, int len, unsigned char desctype) +{ + int n_len = ptr[0]; + + if (n_len < 2 || n_len > len) + { + printk("Short descriptor.\n"); + return -1; + } + + if (ptr[1] == desctype) + return 0; + + return -1; +} + + +static int usb_parse_endpoint(struct usb_device *dev, struct usb_endpoint_descriptor *endpoint, unsigned char *ptr, int len) +{ + int parsed = usb_expect_descriptor(ptr, len, USB_DT_ENDPOINT, 7); + int i; + + if (parsed < 0) + return parsed; + memcpy(endpoint, ptr + parsed, ptr[parsed]); + + parsed += ptr[parsed]; + len -= ptr[parsed]; + + while((i = usb_check_descriptor(ptr+parsed, len, 0x25))>=0) + { + usb_audio_endpoint(endpoint, ptr+parsed+i); + len -= ptr[parsed+i]; + parsed += ptr[parsed+i]; + } + + return parsed;// + ptr[parsed]; +} + +static int usb_parse_interface(struct usb_device *dev, struct usb_interface_descriptor *interface, unsigned char *ptr, int len) +{ + int i; + int parsed = usb_expect_descriptor(ptr, len, USB_DT_INTERFACE, 9); + int retval; + + if (parsed < 0) + return parsed; + + memcpy(interface, ptr + parsed, *ptr); + len -= ptr[parsed]; + parsed += ptr[parsed]; + + while((i=usb_check_descriptor(ptr+parsed, len, 0x24))>=0) + { + usb_audio_interface(interface, ptr+parsed+i); + len -= ptr[parsed+i]; + parsed += ptr[parsed+i]; + } + + if (interface->bNumEndpoints > USB_MAXENDPOINTS) + { + printk(KERN_WARNING "usb: too many endpoints.\n"); + return -1; + } + + interface->endpoint = (struct usb_endpoint_descriptor *) + kmalloc(interface->bNumEndpoints * sizeof(struct usb_endpoint_descriptor), GFP_KERNEL); + if(interface->endpoint==NULL) + { + printk(KERN_WARNING "usb: out of memory.\n"); + return -1; + } + memset(interface->endpoint, 0, interface->bNumEndpoints*sizeof(struct usb_endpoint_descriptor)); + + for (i = 0; i < interface->bNumEndpoints; i++) { +// if(((USB_DT_HID << 8) | 9) == *(unsigned short*)(ptr + parsed)) { +// parsed += 9; /* skip over the HID descriptor for now */ +// len -= 9; +// } + retval = usb_parse_endpoint(dev, interface->endpoint + i, ptr + parsed, len); + if (retval < 0) return retval; + parsed += retval; + len -= retval; + } + return parsed; +} + +static int usb_parse_config(struct usb_device *dev, struct usb_config_descriptor *config, unsigned char *ptr, int len) +{ + int i; + int parsed = usb_expect_descriptor(ptr, len, USB_DT_CONFIG, 9); + + if (parsed < 0) + return parsed; + + memcpy(config, ptr + parsed, *ptr); + len -= *ptr; + parsed += *ptr; + + if (config->bNumInterfaces > USB_MAXINTERFACES) + { + printk(KERN_WARNING "usb: too many interfaces.\n"); + return -1; + + } + + config->interface = (struct usb_interface_descriptor *) + kmalloc(config->bNumInterfaces * sizeof(struct usb_interface_descriptor), GFP_KERNEL); + if(config->interface==NULL) + { + printk(KERN_WARNING "usb: out of memory.\n"); + return -1; + } + memset(config->interface, 0, config->bNumInterfaces*sizeof(struct usb_interface_descriptor)); + + for (i = 0; i < config->bNumInterfaces; i++) { + int retval = usb_parse_interface(dev, config->interface + i, ptr + parsed, len); + if (retval < 0) + return parsed; // HACK +// return retval; + parsed += retval; + len -= retval; + } + return parsed; +} + +int usb_parse_configuration(struct usb_device *dev, void *__buf, int bytes) +{ + int i; + unsigned char *ptr = __buf; + + if (dev->descriptor.bNumConfigurations > USB_MAXCONFIG) + { + printk(KERN_WARNING "usb: too many configurations.\n"); + return -1; + } + + dev->config = (struct usb_config_descriptor *) + kmalloc(dev->descriptor.bNumConfigurations * sizeof(struct usb_config_descriptor), GFP_KERNEL); + if(dev->config==NULL) + { + printk(KERN_WARNING "usb: out of memory.\n"); + return -1; + } + memset(dev->config, 0, dev->descriptor.bNumConfigurations*sizeof(struct usb_config_descriptor)); + for (i = 0; i < dev->descriptor.bNumConfigurations; i++) { + int retval = usb_parse_config(dev, dev->config + i, ptr, bytes); + if (retval < 0) + return retval; + ptr += retval; + bytes += retval; + } + return 0; +} + +void usb_destroy_configuration(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; + kfree(ifp->endpoint); + } + kfree(cf->interface); + } + kfree(dev->config); +} + +void usb_init_root_hub(struct usb_device *dev) +{ + dev->devnum = -1; + dev->slow = 0; +} + +/* + * Something got disconnected. Get rid of it, and all of its children. + */ +void usb_disconnect(struct usb_device **pdev) +{ + struct usb_device * dev = *pdev; + + if (dev) { + int i; + + *pdev = NULL; + + printk("USB disconnect on device %d\n", dev->devnum); + + if(dev->driver) dev->driver->disconnect(dev); + + /* Free up all the children.. */ + for (i = 0; i < USB_MAXCHILDREN; i++) { + struct usb_device **child = dev->children + i; + usb_disconnect(child); + } + + /* Free up the device itself, including its device number */ + if (dev->devnum > 0) + clear_bit(dev->devnum, &dev->bus->devmap.devicemap); + dev->bus->op->deallocate(dev); + } +} + + +/* + * Connect a new USB device. This basically just initializes + * the USB device information and sets up the topology - it's + * up to the low-level driver to reset the port and actually + * do the setup (the upper levels don't know how to do that). + */ +void usb_connect(struct usb_device *dev) +{ + int devnum; + + dev->descriptor.bMaxPacketSize0 = 8; /* XXX fixed 8 bytes for now */ + + devnum = find_next_zero_bit(dev->bus->devmap.devicemap, 128, 1); + if (devnum < 128) { + set_bit(devnum, dev->bus->devmap.devicemap); + dev->devnum = devnum; + } +} + +/* + * These are the actual routines to send + * and receive control messages. + */ +int usb_set_address(struct usb_device *dev) +{ + devrequest dr; + + dr.requesttype = 0; + dr.request = USB_REQ_SET_ADDRESS; + dr.value = dev->devnum; + dr.index = 0; + dr.length = 0; + + return dev->bus->op->control_msg(dev, usb_snddefctrl(dev), &dr, NULL, 0); +} + +int usb_get_descriptor(struct usb_device *dev, unsigned char type, unsigned char index, void *buf, int size) +{ + devrequest dr; + + dr.requesttype = 0x80; + dr.request = USB_REQ_GET_DESCRIPTOR; + dr.value = (type << 8) + index; + dr.index = 0; + dr.length = size; + + return dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, buf, size); +} + +int usb_get_device_descriptor(struct usb_device *dev) +{ + return usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor, sizeof(dev->descriptor)); +} + +int usb_get_hub_descriptor(struct usb_device *dev, void *data, int size) +{ + devrequest dr; + + dr.requesttype = USB_RT_HUB | 0x80; + dr.request = USB_REQ_GET_DESCRIPTOR; + dr.value = (USB_DT_HUB << 8); + dr.index = 0; + dr.length = size; + + return dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, data, size); +} + +int usb_clear_port_feature(struct usb_device *dev, int port, int feature) +{ + devrequest dr; + + dr.requesttype = USB_RT_PORT; + dr.request = USB_REQ_CLEAR_FEATURE; + dr.value = feature; + dr.index = port; + dr.length = 0; + + return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0); +} + +int usb_set_port_feature(struct usb_device *dev, int port, int feature) +{ + devrequest dr; + + dr.requesttype = USB_RT_PORT; + dr.request = USB_REQ_SET_FEATURE; + dr.value = feature; + dr.index = port; + dr.length = 0; + + return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0); +} + +int usb_get_hub_status(struct usb_device *dev, void *data) +{ + devrequest dr; + + dr.requesttype = USB_RT_HUB | 0x80; + dr.request = USB_REQ_GET_STATUS; + dr.value = 0; + dr.index = 0; + dr.length = 4; + + return dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, data, 4); +} + +int usb_get_port_status(struct usb_device *dev, int port, void *data) +{ + devrequest dr; + + dr.requesttype = USB_RT_PORT | 0x80; + dr.request = USB_REQ_GET_STATUS; + dr.value = 0; + dr.index = port; + dr.length = 4; + + return dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, data, 4); +} + +int usb_get_protocol(struct usb_device *dev) +{ + unsigned char buf[8]; + devrequest dr; + + dr.requesttype = USB_RT_HIDD | 0x80; + dr.request = USB_REQ_GET_PROTOCOL; + dr.value = 0; + dr.index = 1; + dr.length = 1; + + if (dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev, 0), &dr, buf, 1)) + return -1; + + return buf[0]; +} + +int usb_set_protocol(struct usb_device *dev, int protocol) +{ + devrequest dr; + + dr.requesttype = USB_RT_HIDD; + dr.request = USB_REQ_SET_PROTOCOL; + dr.value = protocol; + dr.index = 1; + dr.length = 0; + + if (dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev, 0), &dr, NULL, 0)) + return -1; + + return 0; +} + +/* keyboards want a nonzero duration according to HID spec, but + mice should use infinity (0) -keryan */ +int usb_set_idle(struct usb_device *dev, int duration, int report_id) +{ + devrequest dr; + + dr.requesttype = USB_RT_HIDD; + dr.request = USB_REQ_SET_IDLE; + dr.value = (duration << 8) | report_id; + dr.index = 1; + dr.length = 0; + + if (dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev, 0), &dr, NULL, 0)) + return -1; + + return 0; +} + +int usb_set_configuration(struct usb_device *dev, int configuration) +{ + devrequest dr; + + dr.requesttype = 0; + dr.request = USB_REQ_SET_CONFIGURATION; + dr.value = configuration; + dr.index = 0; + dr.length = 0; + + if (dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev, 0), &dr, NULL, 0)) + return -1; + + return 0; +} + +int usb_get_report(struct usb_device *dev) +{ + unsigned char buf[8]; + devrequest dr; + + dr.requesttype = USB_RT_HIDD | 0x80; + dr.request = USB_REQ_GET_REPORT; + dr.value = 0x100; + dr.index = 1; + dr.length = 3; + + if (dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev, 0), &dr, buf, 3)) + return -1; + + return buf[0]; +} + +int usb_get_configuration(struct usb_device *dev) +{ + unsigned int cfgno,size; + unsigned char buffer[400]; + unsigned char * bufptr; + + bufptr=buffer; + for (cfgno=0;cfgnodescriptor.bNumConfigurations;cfgno++) { + /* Get the first 8 bytes - guaranteed */ + if (usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, bufptr, 8)) + return -1; + + /* Get the full buffer */ + size = *(unsigned short *)(bufptr+2); + if (bufptr+size > buffer+sizeof(buffer)) + { + printk(KERN_INFO "usb: truncated DT_CONFIG (want %d).\n", size); + size = buffer+sizeof(buffer)-bufptr; + } + if (usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, bufptr, size)) + return -1; + + /* Prepare for next configuration */ + bufptr+=size; + } + return usb_parse_configuration(dev, buffer, size); +} + +/* + * By the time we get here, the device has gotten a new device ID + * and is in the default state. We need to identify the thing and + * get the ball rolling.. + */ +void usb_new_device(struct usb_device *dev) +{ + int addr, i; + + printk("USB new device connect, assigned device number %d\n", + dev->devnum); + + dev->maxpacketsize = 0; /* Default to 8 byte max packet size */ + + addr = dev->devnum; + dev->devnum = 0; + + /* Slow devices */ + for (i = 0; i < 5; i++) { + if (!usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor, 8)) + break; + + printk("get_descriptor failed, waiting\n"); + wait_ms(200); + } + if (i == 5) { + printk("giving up\n"); + return; + } + +#if 0 + printk("maxpacketsize: %d\n", dev->descriptor.bMaxPacketSize0); +#endif + switch (dev->descriptor.bMaxPacketSize0) { + case 8: dev->maxpacketsize = 0; break; + case 16: dev->maxpacketsize = 1; break; + case 32: dev->maxpacketsize = 2; break; + case 64: dev->maxpacketsize = 3; break; + } +#if 0 + printk("dev->mps: %d\n", dev->maxpacketsize); +#endif + + dev->devnum = addr; + + if (usb_set_address(dev)) { + printk("Unable to set address\n"); + /* FIXME: We should disable the port */ + return; + } + + wait_ms(10); /* Let the SET_ADDRESS settle */ + + if (usb_get_device_descriptor(dev)) { + printk("Unable to get device descriptor\n"); + return; + } + + if (usb_get_configuration(dev)) { + printk("Unable to get configuration\n"); + return; + } + +#if 0 + printk("Vendor: %X\n", dev->descriptor.idVendor); + printk("Product: %X\n", dev->descriptor.idProduct); +#endif + + usb_device_descriptor(dev); +} + +int usb_request_irq(struct usb_device *dev, unsigned int pipe, usb_device_irq handler, int period, void *dev_id) +{ + return dev->bus->op->request_irq(dev, pipe, handler, period, dev_id); +} + diff -ur --new-file old/linux/drivers/usb/usb.h new/linux/drivers/usb/usb.h --- old/linux/drivers/usb/usb.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/usb/usb.h Tue May 11 19:04:03 1999 @@ -0,0 +1,376 @@ +#ifndef __LINUX_USB_H +#define __LINUX_USB_H + +#include +#include +#include +#include + +static __inline__ void wait_ms(unsigned int ms) +{ + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(1 + ms * HZ / 1000); +} + + +typedef struct { + unsigned char requesttype; + unsigned char request; + unsigned short value; + unsigned short index; + unsigned short length; +} devrequest; + +/* + * Class codes + */ +#define USB_CLASS_HUB 9 + +/* + * Descriptor types + */ +#define USB_DT_DEVICE 0x01 +#define USB_DT_CONFIG 0x02 +#define USB_DT_STRING 0x03 +#define USB_DT_INTERFACE 0x04 +#define USB_DT_ENDPOINT 0x05 + +#define USB_DT_HUB 0x29 +#define USB_DT_HID 0x21 + +/* + * Standard requests + */ +#define USB_REQ_GET_STATUS 0x00 +#define USB_REQ_CLEAR_FEATURE 0x01 +/* 0x02 is reserved */ +#define USB_REQ_SET_FEATURE 0x03 +/* 0x04 is reserved */ +#define USB_REQ_SET_ADDRESS 0x05 +#define USB_REQ_GET_DESCRIPTOR 0x06 +#define USB_REQ_SET_DESCRIPTOR 0x07 +#define USB_REQ_GET_CONFIGURATION 0x08 +#define USB_REQ_SET_CONFIGURATION 0x09 +#define USB_REQ_GET_INTERFACE 0x0A +#define USB_REQ_SET_INTERFACE 0x0B +#define USB_REQ_SYNCH_FRAME 0x0C + +/* + * HIDD requests + */ +#define USB_REQ_GET_REPORT 0x01 +#define USB_REQ_GET_IDLE 0x02 +#define USB_REQ_GET_PROTOCOL 0x03 +#define USB_REQ_SET_REPORT 0x09 +#define USB_REQ_SET_IDLE 0x0A +#define USB_REQ_SET_PROTOCOL 0x0B + +#define USB_TYPE_STANDARD (0x00 << 5) +#define USB_TYPE_CLASS (0x01 << 5) +#define USB_TYPE_VENDOR (0x02 << 5) +#define USB_TYPE_RESERVED (0x03 << 5) + +#define USB_RECIP_DEVICE 0x00 +#define USB_RECIP_INTERFACE 0x01 +#define USB_RECIP_ENDPOINT 0x02 +#define USB_RECIP_OTHER 0x03 + +/* + * Request target types. + */ +#define USB_RT_DEVICE 0x00 +#define USB_RT_INTERFACE 0x01 +#define USB_RT_ENDPOINT 0x02 + +#define USB_RT_HUB (USB_TYPE_CLASS | USB_RECIP_DEVICE) +#define USB_RT_PORT (USB_TYPE_CLASS | USB_RECIP_OTHER) + +#define USB_RT_HIDD (USB_TYPE_CLASS | USB_RECIP_INTERFACE) + +/* + * USB device number allocation bitmap. There's one bitmap + * per USB tree. + */ +struct usb_devmap { + unsigned long devicemap[128 / (8*sizeof(unsigned long))]; +}; + +/* + * This is a USB device descriptor. + * + * USB device information + * + */ + +#define USB_MAXCONFIG 8 +#define USB_MAXINTERFACES 32 +#define USB_MAXENDPOINTS 32 + +struct usb_device_descriptor { + __u8 bLength; + __u8 bDescriptorType; + __u16 bcdUSB; + __u8 bDeviceClass; + __u8 bDeviceSubClass; + __u8 bDeviceProtocol; + __u8 bMaxPacketSize0; + __u16 idVendor; + __u16 idProduct; + __u16 bcdDevice; + __u8 iManufacturer; + __u8 iProduct; + __u8 iSerialNumber; + __u8 bNumConfigurations; +}; + +/* Endpoint descriptor */ +struct usb_endpoint_descriptor { + __u8 bLength; + __u8 bDescriptorType; + __u8 bEndpointAddress; + __u8 bmAttributes; + __u16 wMaxPacketSize; + __u8 bInterval; + void *audio; +}; + +/* Interface descriptor */ +struct usb_interface_descriptor { + __u8 bLength; + __u8 bDescriptorType; + __u8 bInterfaceNumber; + __u8 bAlternateSetting; + __u8 bNumEndpoints; + __u8 bInterfaceClass; + __u8 bInterfaceSubClass; + __u8 bInterfaceProtocol; + __u8 iInterface; + + struct usb_endpoint_descriptor *endpoint; + void *audio; +}; + +/* Configuration descriptor information.. */ +struct usb_config_descriptor { + __u8 bLength; + __u8 bDescriptorType; + __u16 wTotalLength; + __u8 bNumInterfaces; + __u8 bConfigurationValue; + __u8 iConfiguration; + __u8 bmAttributes; + __u8 MaxPower; + + struct usb_interface_descriptor *interface; +}; + +/* String descriptor */ +struct usb_string_descriptor { + __u8 bLength; + __u8 bDescriptorType; +}; + +/* Hub descriptor */ +struct usb_hub_descriptor { + __u8 bLength; + __u8 bDescriptorType; + __u8 bNbrPorts; + __u16 wHubCharacteristics; + __u8 bPwrOn2PwrGood; + __u8 bHubContrCurrent; + /* DeviceRemovable and PortPwrCtrlMask want to be variable-length + bitmaps that hold max 256 entries, but for now they're ignored */ + __u8 filler; +}; + +struct usb_device; + +struct usb_driver { + const char * name; + int (*probe)(struct usb_device *); + void (*disconnect)(struct usb_device *); + struct list_head driver_list; +}; + +/* + * Pointer to a device endpoint interrupt function -greg + * Parameters: + * int status - This needs to be defined. Right now each HCD + * passes different transfer status bits back. Don't use it + * until we come up with a common meaning. + * void *buffer - This is a pointer to the data used in this + * USB transfer. + * void *dev_id - This is a user defined pointer set when the IRQ + * is requested that is passed back. + */ +typedef int (*usb_device_irq)(int, void *, void *); + +struct usb_operations { + struct usb_device *(*allocate)(struct usb_device *); + int (*deallocate)(struct usb_device *); + int (*control_msg)(struct usb_device *, unsigned int, void *, void *, int); + int (*request_irq)(struct usb_device *, unsigned int, usb_device_irq, int, void *); +}; + +/* + * Allocated per bus we have + */ +struct usb_bus { + struct usb_devmap devmap; /* Device map */ + struct usb_operations *op; /* Operations (specific to the HC) */ + struct usb_device *root_hub; /* Root hub */ + void *hcpriv; /* Host Controller private data */ +}; + + +#define USB_MAXCHILDREN (8) + +struct usb_device { + int devnum; /* Device number on USB bus */ + int slow; /* Slow device? */ + int maxpacketsize; /* Maximum packet size */ + + struct usb_bus *bus; /* Bus we're apart of */ + struct usb_driver *driver; /* Driver */ + struct usb_device_descriptor descriptor; /* Descriptor */ + struct usb_config_descriptor *config; /* All of the configs */ + struct usb_device *parent; + + /* + * Child devices - these can be either new devices + * (if this is a hub device), or different instances + * of this same device. + * + * Each instance needs its own set of data structuctures. + */ + + int maxchild; /* Number of ports if hub */ + struct usb_device *children[USB_MAXCHILDREN]; + + void *hcpriv; /* Host Controller private data */ + void *private; /* Upper layer private data */ +}; + +extern int usb_register(struct usb_driver *); +extern void usb_deregister(struct usb_driver *); + +extern int usb_request_irq(struct usb_device *, unsigned int, usb_device_irq, int, void *); + +extern void usb_init_root_hub(struct usb_device *dev); +extern void usb_connect(struct usb_device *dev); +extern void usb_disconnect(struct usb_device **); +extern void usb_device_descriptor(struct usb_device *dev); + +extern int usb_parse_configuration(struct usb_device *dev, void *buf, int len); + +/* + * Calling this entity a "pipe" is glorifying it. A USB pipe + * is something embarrassingly simple: it basically consists + * of the following information: + * - device number (7 bits) + * - endpoint number (4 bits) + * - current Data0/1 state (1 bit) + * - direction (1 bit) + * - speed (1 bit) + * - max packet size (2 bits: 8, 16, 32 or 64) + * - pipe type (2 bits: control, interrupt, bulk, isochronous) + * + * That's 18 bits. Really. Nothing more. And the USB people have + * documented these eighteen bits as some kind of glorious + * virtual data structure. + * + * Let's not fall in that trap. We'll just encode it as a simple + * unsigned int. The encoding is: + * + * - device: bits 8-14 + * - endpoint: bits 15-18 + * - Data0/1: bit 19 + * - direction: bit 7 (0 = Host-to-Device, 1 = Device-to-Host) + * - speed: bit 26 (0 = High, 1 = Low Speed) + * - max size: bits 0-1 (00 = 8, 01 = 16, 10 = 32, 11 = 64) + * - pipe type: bits 30-31 (00 = isochronous, 01 = interrupt, 10 = control, 11 = bulk) + * + * Why? Because it's arbitrary, and whatever encoding we select is really + * up to us. This one happens to share a lot of bit positions with the UCHI + * specification, so that much of the uhci driver can just mask the bits + * appropriately. + */ + +#define usb_maxpacket(pipe) (8 << ((pipe) & 3)) +#define usb_packetid(pipe) (((pipe) & 0x80) ? 0x69 : 0xE1) + +#define usb_pipedevice(pipe) (((pipe) >> 8) & 0x7f) +#define usb_pipeendpoint(pipe) (((pipe) >> 15) & 0xf) +#define usb_pipedata(pipe) (((pipe) >> 19) & 1) +#define usb_pipeout(pipe) (((pipe) & 0x80) == 0) +#define usb_pipeslow(pipe) (((pipe) >> 26) & 1) + +#define usb_pipetype(pipe) (((pipe) >> 30) & 3) +#define usb_pipeisoc(pipe) (usb_pipetype((pipe)) == 0) +#define usb_pipeint(pipe) (usb_pipetype((pipe)) == 1) +#define usb_pipecontrol(pipe) (usb_pipetype((pipe)) == 2) +#define usb_pipebulk(pipe) (usb_pipetype((pipe)) == 3) + +#define usb_pipe_endpdev(pipe) (((pipe) >> 8) & 0x7ff) + +static inline unsigned int __create_pipe(struct usb_device *dev, unsigned int endpoint) +{ + return (dev->devnum << 8) | (endpoint << 15) | (dev->slow << 26) | dev->maxpacketsize; +} + +static inline unsigned int __default_pipe(struct usb_device *dev) +{ + return (dev->slow << 26); +} + +/* Create control pipes.. */ +#define usb_sndctrlpipe(dev,endpoint) ((2 << 30) | __create_pipe(dev,endpoint)) +#define usb_rcvctrlpipe(dev,endpoint) ((2 << 30) | __create_pipe(dev,endpoint) | 0x80) +#define usb_snddefctrl(dev) ((2 << 30) | __default_pipe(dev)) +#define usb_rcvdefctrl(dev) ((2 << 30) | __default_pipe(dev) | 0x80) + +/* Create .. */ + +/* + * Send and receive control messages.. + */ +void usb_new_device(struct usb_device *dev); +int usb_set_address(struct usb_device *dev); +int usb_get_descriptor(struct usb_device *dev, unsigned char desctype, unsigned +char descindex, void *buf, int size); +int usb_get_device_descriptor(struct usb_device *dev); +int usb_get_hub_descriptor(struct usb_device *dev, void *data, int size); +int usb_clear_port_feature(struct usb_device *dev, int port, int feature); +int usb_set_port_feature(struct usb_device *dev, int port, int feature); +int usb_get_hub_status(struct usb_device *dev, void *data); +int usb_get_port_status(struct usb_device *dev, int port, void *data); +int usb_get_protocol(struct usb_device *dev); +int usb_set_protocol(struct usb_device *dev, int protocol); +int usb_set_idle(struct usb_device *dev, int duration, int report_id); +int usb_set_configuration(struct usb_device *dev, int configuration); +int usb_get_report(struct usb_device *dev); + +/* + * Debugging helpers.. + */ +void usb_show_device_descriptor(struct usb_device_descriptor *); +void usb_show_config_descriptor(struct usb_config_descriptor *); +void usb_show_interface_descriptor(struct usb_interface_descriptor *); +void usb_show_endpoint_descriptor(struct usb_endpoint_descriptor *); +void usb_show_hub_descriptor(struct usb_hub_descriptor *); +void usb_show_device(struct usb_device *); + +/* + * Audio parsing helpers + */ + +#ifdef CONFIG_USB_AUDIO +void usb_audio_interface(struct usb_interface_descriptor *, u8 *); +void usb_audio_endpoint(struct usb_endpoint_descriptor *, u8 *); +#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) {} +#endif + +#endif + diff -ur --new-file old/linux/drivers/video/Config.in new/linux/drivers/video/Config.in --- old/linux/drivers/video/Config.in Tue Jan 19 19:48:17 1999 +++ new/linux/drivers/video/Config.in Wed May 12 01:30:36 1999 @@ -4,21 +4,32 @@ if [ "$CONFIG_FB" = "y" ]; then define_bool CONFIG_DUMMY_CONSOLE y - if [ "$CONFIG_APUS" = "y" ]; then - bool 'Permedia2 support' CONFIG_FB_PM2 - if [ "$CONFIG_FB_PM2" = "y" ]; then - bool ' enable FIFO disconnect feature' CONFIG_FB_PM2_FIFO_DISCONNECT - if [ "$CONFIG_APUS" = "y" ]; then - bool ' Phase5 CVisionPPC/BVisionPPC support' CONFIG_FB_PM2_CVPPC + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + if [ "$CONFIG_AMIGA" = "y" -o "$CONFIG_PCI" = "y" ]; then + bool 'Permedia2 support (experimental)' CONFIG_FB_PM2 + if [ "$CONFIG_FB_PM2" = "y" ]; then + if [ "$CONFIG_PCI" = "y" ]; then + bool ' enable FIFO disconnect feature' CONFIG_FB_PM2_FIFO_DISCONNECT + bool ' generic Permedia2 PCI board support' CONFIG_FB_PM2_PCI + fi + if [ "$CONFIG_AMIGA" = "y" ]; then + bool ' Phase5 CVisionPPC/BVisionPPC support' CONFIG_FB_PM2_CVPPC + fi fi fi fi if [ "$CONFIG_ARCH_ACORN" = "y" ]; then bool 'Acorn VIDC support' CONFIG_FB_ACORN fi + if [ "$CONFIG_ARCH_NETWINDER" = "y" ]; then + tristate 'Cyber2000 support' CONFIG_FB_CYBER2000 + fi if [ "$CONFIG_APOLLO" = "y" ]; then define_bool CONFIG_FB_APOLLO y fi + if [ "$CONFIG_Q40" = "y" ]; then + define_bool CONFIG_FB_Q40 y + fi if [ "$CONFIG_AMIGA" = "y" ]; then bool 'Amiga native chipset support' CONFIG_FB_AMIGA if [ "$CONFIG_FB_AMIGA" != "n" ]; then @@ -33,6 +44,7 @@ bool 'Amiga CyberVision3D support (experimental)' CONFIG_FB_VIRGE tristate 'Amiga RetinaZ3 support' CONFIG_FB_RETINAZ3 tristate 'Amiga CLgen driver' CONFIG_FB_CLGEN + bool 'Amiga FrameMaster II/Rainbow II support (experimental)' CONFIG_FB_FM2 fi fi if [ "$CONFIG_ATARI" = "y" ]; then @@ -64,6 +76,9 @@ bool 'VESA VGA graphics console' CONFIG_FB_VESA define_bool CONFIG_VIDEO_SELECT y fi + if [ "$CONFIG_VISWS" = "y" ]; then + tristate 'SGI Visual Workstation framebuffer support' CONFIG_FB_SGIVW + fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then if [ "$CONFIG_PCI" != "n" ]; then tristate 'Matrox acceleration' CONFIG_FB_MATROX @@ -165,7 +180,8 @@ "$CONFIG_FB_VIRGE" = "y" -o "$CONFIG_FB_CYBER" = "y" -o \ "$CONFIG_FB_VALKYRIE" = "y" -o "$CONFIG_FB_PLATINUM" = "y" -o \ "$CONFIG_FB_IGA" = "y" -o "$CONFIG_FB_MATROX" = "y" -o \ - "$CONFIG_FB_CT65550" = "y" -o "$CONFIG_FB_PM2" = "y" ]; then + "$CONFIG_FB_CT65550" = "y" -o "$CONFIG_FB_PM2" = "y" -o \ + "$CONFIG_FB_SGIVW" = "y" -o "$CONFIG_FB_CYBER2000" = "y" ]; then define_bool CONFIG_FBCON_CFB8 y else if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_ATARI" = "m" -o \ @@ -178,39 +194,46 @@ "$CONFIG_FB_VIRGE" = "m" -o "$CONFIG_FB_CYBER" = "m" -o \ "$CONFIG_FB_VALKYRIE" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \ "$CONFIG_FB_IGA" = "m" -o "$CONFIG_FB_MATROX" = "m" -o \ - "$CONFIG_FB_CT65550" = "m" -o "$CONFIG_FB_PM2" = "m" ]; then + "$CONFIG_FB_CT65550" = "m" -o "$CONFIG_FB_PM2" = "m" -o \ + "$CONFIG_FB_SGIVW" = "m" -o "$CONFIG_FB_CYBER2000" = "m" ]; then define_bool CONFIG_FBCON_CFB8 m fi fi if [ "$CONFIG_FB_ATARI" = "y" -o "$CONFIG_FB_ATY" = "y" -o \ "$CONFIG_FB_MAC" = "y" -o "$CONFIG_FB_VESA" = "y" -o \ "$CONFIG_FB_VIRTUAL" = "y" -o "$CONFIG_FB_TBOX" = "y" -o \ + "$CONFIG_FB_Q40" = "y" -o \ "$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "y" -o \ "$CONFIG_FB_VIRGE" = "y" -o "$CONFIG_FB_CYBER" = "y" -o \ "$CONFIG_FB_VALKYRIE" = "y" -o "$CONFIG_FB_PLATINUM" = "y" -o \ "$CONFIG_FB_CT65550" = "y" -o "$CONFIG_FB_MATROX" = "y" -o \ - "$CONFIG_FB_PM2" = "y" ]; then + "$CONFIG_FB_PM2" = "y" -o "$CONFIG_FB_SGIVW" = "y" -o \ + "$CONFIG_FB_CYBER2000" = "y" ]; then define_bool CONFIG_FBCON_CFB16 y else if [ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_ATY" = "m" -o \ "$CONFIG_FB_MAC" = "m" -o "$CONFIG_FB_VESA" = "m" -o \ "$CONFIG_FB_VIRTUAL" = "m" -o "$CONFIG_FB_TBOX" = "m" -o \ + "$CONFIG_FB_Q40" = "m" -o \ "$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" -o \ "$CONFIG_FB_VIRGE" = "m" -o "$CONFIG_FB_CYBER" = "m" -o \ "$CONFIG_FB_VALKYRIE" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \ - "$CONFIG_FB_CT65550" = "m" -o "$CONFIG_FB_MATROX" = "m" -o \ - "$CONFIG_FB_PM2" = "m" ]; then + "$CONFIG_FB_CT65550" = "m" -o "$CONFIG_FB_MATROX" = "m" -o \ + "$CONFIG_FB_PM2" = "y" -o "$CONFIG_FB_SGIVW" = "m" -o \ + "$CONFIG_FB_CYBER2000" = "m" ]; then define_bool CONFIG_FBCON_CFB16 m fi fi if [ "$CONFIG_FB_ATY" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \ "$CONFIG_FB_CLGEN" = "y" -o "$CONFIG_FB_VESA" = "y" -o \ - "$CONFIG_FB_MATROX" = "y" -o "$CONFIG_FB_PM2" = "y" ]; then + "$CONFIG_FB_MATROX" = "y" -o "$CONFIG_FB_PM2" = "y" -o \ + "$CONFIG_FB_CYBER2000" = "y" ]; then define_bool CONFIG_FBCON_CFB24 y else if [ "$CONFIG_FB_ATY" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \ "$CONFIG_FB_CLGEN" = "m" -o "$CONFIG_FB_VESA" = "m" -o \ - "$CONFIG_FB_MATROX" = "m" -o "$CONFIG_FB_PM2" = "m" ]; then + "$CONFIG_FB_MATROX" = "m" -o "$CONFIG_FB_PM2" = "m" -o \ + "$CONFIG_FB_CYBER2000" = "m" ]; then define_bool CONFIG_FBCON_CFB24 m fi fi @@ -218,14 +241,16 @@ "$CONFIG_FB_VESA" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \ "$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "y" -o \ "$CONFIG_FB_TGA" = "y" -o "$CONFIG_FB_PLATINUM" = "y" -o \ - "$CONFIG_FB_MATROX" = "y" -o "$CONFIG_FB_PM2" = "y" ]; then + "$CONFIG_FB_MATROX" = "y" -o "$CONFIG_FB_PM2" = "y" -o \ + "$CONFIG_FB_FM2" = "y" -o "$CONFIG_FB_SGIVW" = "y" ]; then define_bool CONFIG_FBCON_CFB32 y else if [ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_ATY" = "m" -o \ "$CONFIG_FB_VESA" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \ "$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" -o \ "$CONFIG_FB_TGA" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \ - "$CONFIG_FB_MATROX" = "m" -o "$CONFIG_FB_PM2" = "m" ]; then + "$CONFIG_FB_MATROX" = "m" -o "$CONFIG_FB_PM2" = "m" -o \ + "$CONFIG_FB_SGIVW" = "m" ]; then define_bool CONFIG_FBCON_CFB32 m fi fi @@ -305,7 +330,7 @@ if [ "$CONFIG_AMIGA" = "y" ]; then define_bool CONFIG_FONT_PEARL_8x8 y fi - if [ "$CONFIG_ARM" = "y" ]; then + if [ "$CONFIG_ARM" = "y" -a "$CONFIG_ARCH_ACORN" = "y" ]; then define_bool CONFIG_FONT_ACORN_8x8 y fi fi diff -ur --new-file old/linux/drivers/video/Makefile new/linux/drivers/video/Makefile --- old/linux/drivers/video/Makefile Tue Jan 19 19:48:17 1999 +++ new/linux/drivers/video/Makefile Wed May 12 01:30:36 1999 @@ -88,6 +88,10 @@ L_OBJS += dnfb.o endif +ifeq ($(CONFIG_FB_Q40),y) +L_OBJS += q40fb.o +endif + ifeq ($(CONFIG_FB_ATARI),y) L_OBJS += atafb.o else @@ -128,6 +132,22 @@ endif endif +ifeq ($(CONFIG_FB_CYBER2000),y) +L_OBJS += cyber2000fb.o +else + ifeq ($(CONFIG_FB_CYBER2000),m) + M_OBJS += cyber2000fb.o + endif +endif + +ifeq ($(CONFIG_FB_SGIVW),y) +L_OBJS += sgivwfb.o +else + ifeq ($(CONFIG_FB_SGIVW),m) + M_OBJS += sgivwfb.o + endif +endif + ifeq ($(CONFIG_FB_MAC),y) L_OBJS += macfb.o endif @@ -192,6 +212,10 @@ ifdef CONFIG_FB_G364 L_OBJS := $(L_OBJS) g364fb.o +endif + +ifdef CONFIG_FB_FM2 +L_OBJS := $(L_OBJS) fm2fb.o endif ifeq ($(CONFIG_FB_SBUS),y) diff -ur --new-file old/linux/drivers/video/acornfb.c new/linux/drivers/video/acornfb.c --- old/linux/drivers/video/acornfb.c Thu Oct 1 19:02:21 1998 +++ new/linux/drivers/video/acornfb.c Wed May 12 01:30:36 1999 @@ -1,15 +1,22 @@ /* * linux/drivers/video/acorn.c * - * Copyright (C) 1998 Russell King + * Copyright (C) 1998,1999 Russell King * * Frame buffer code for Acorn platforms + * + * NOTE: Most of the modes with X!=640 will disappear shortly. + * NOTE: Startup setting of HS & VS polarity not supported. + * (do we need to support it if we're coming up in 640x480?) */ + +#include #include #include #include #include #include +#include #include #include #include @@ -21,245 +28,898 @@ #include #include +#include